Files: 6ae6f1ce78d440dea5e42c9ab6d0112732b161f6 / modules_core / tabs.js
5760 bytesRaw
1 | var Tabs = require('hypertabs') |
2 | var h = require('../h') |
3 | var keyscroll = require('../keyscroll') |
4 | var open = require('open-external') |
5 | |
6 | function ancestor (el) { |
7 | if(!el) return |
8 | if(el.tagName !== 'A') return ancestor(el.parentElement) |
9 | return el |
10 | } |
11 | |
12 | exports.needs = { |
13 | build_scroller: 'first', |
14 | screen_view: 'first', |
15 | search_box: 'first', |
16 | menu: 'first', |
17 | external_confirm:'first' |
18 | } |
19 | |
20 | exports.gives = 'screen_view' |
21 | |
22 | exports.create = function (api) { |
23 | return function (path) { |
24 | if(path !== 'tabs') return |
25 | |
26 | function setSelected (indexes) { |
27 | var ids = indexes.map(function (index) { |
28 | return tabs.get(index).id |
29 | }) |
30 | if(search) |
31 | if(ids.length > 1) |
32 | search.value = 'split('+ids.join(',')+')' |
33 | else |
34 | search.value = ids[0] |
35 | } |
36 | |
37 | var search |
38 | var tabs = Tabs(setSelected) |
39 | |
40 | search = api.search_box(function (path, change) { |
41 | |
42 | if(tabs.has(path)) { |
43 | tabs.select(path) |
44 | return true |
45 | } |
46 | var el = api.screen_view(path) |
47 | |
48 | if(el) { |
49 | if(!el.title) el.title = path |
50 | el.scroll = keyscroll(el.querySelector('.Scroller .\\.content')) |
51 | tabs.add(el, change) |
52 | // localStorage.openTabs = JSON.stringify(tabs.tabs) |
53 | return change |
54 | } |
55 | }) |
56 | |
57 | // TODO add a Tabs(setSelected, { append: el }) to hypertabs |
58 | tabs.firstChild.appendChild( |
59 | h('div.extra', [ |
60 | search, |
61 | api.menu() |
62 | ]) |
63 | ) |
64 | |
65 | var saved = [] |
66 | // try { saved = JSON.parse(localStorage.openTabs) } |
67 | // catch (_) { } |
68 | |
69 | if(!saved || saved.length < 3) |
70 | saved = ['/public', '/private', '/notifications', '/data'] |
71 | |
72 | saved.forEach(function (path) { |
73 | var el = api.screen_view(path) |
74 | if(!el) return |
75 | el.id = el.id || path |
76 | if (!el) return |
77 | el.scroll = keyscroll(el.querySelector('.Scroller .\\.content')) |
78 | if(el) tabs.add(el, false, false) |
79 | }) |
80 | |
81 | tabs.select(0) |
82 | |
83 | //handle link clicks |
84 | window.onclick = function (ev) { |
85 | var link = ancestor(ev.target) |
86 | if(!link) return |
87 | var path = link.hash.substring(1) |
88 | |
89 | ev.preventDefault() |
90 | ev.stopPropagation() |
91 | |
92 | //let the application handle this link |
93 | if (link.getAttribute('href') === '#') return |
94 | |
95 | //open external links. |
96 | //this ought to be made into something more runcible |
97 | if(link.href && open.isExternal(link.href)) return api.external_confirm(link.href) |
98 | |
99 | if(tabs.has(path)) |
100 | return tabs.select(path, !ev.ctrlKey, !!ev.shiftKey) |
101 | |
102 | var el = api.screen_view(path) |
103 | if(el) { |
104 | el.id = el.id || path |
105 | el.scroll = keyscroll(el.querySelector('.Scroller .\\.content')) |
106 | tabs.add(el, !ev.ctrlKey, !!ev.shiftKey) |
107 | // localStorage.openTabs = JSON.stringify(tabs.tabs) |
108 | } |
109 | |
110 | return false |
111 | } |
112 | |
113 | var gPressed = false |
114 | window.addEventListener('keydown', function (ev) { |
115 | if (ev.target.nodeName === 'INPUT' || ev.target.nodeName === 'TEXTAREA') |
116 | return |
117 | |
118 | // scroll to top |
119 | if (ev.keyCode == 71) { // g |
120 | if (!gPressed) return gPressed = true |
121 | var el = tabs.get(tabs.selected[0]).firstChild.scroll('first') |
122 | gPressed = false |
123 | } else { |
124 | gPressed = false |
125 | } |
126 | |
127 | switch(ev.keyCode) { |
128 | // scroll through tabs |
129 | case 72: // h |
130 | return tabs.selectRelative(-1) |
131 | case 76: // l |
132 | return tabs.selectRelative(1) |
133 | |
134 | // scroll through messages |
135 | case 74: // j |
136 | return tabs.get(tabs.selected[0]).firstChild.scroll(1) |
137 | case 75: // k |
138 | return tabs.get(tabs.selected[0]).firstChild.scroll(-1) |
139 | |
140 | // close a tab |
141 | case 88: // x |
142 | if (tabs.selected) { |
143 | var sel = tabs.selected |
144 | var i = sel.reduce(function (a, b) { return Math.min(a, b) }) |
145 | tabs.remove(sel) |
146 | tabs.select(Math.max(i-1, 0)) |
147 | } |
148 | return |
149 | |
150 | // activate the search field |
151 | case 191: // / |
152 | if (ev.shiftKey) |
153 | search.activate('?', ev) |
154 | else |
155 | search.activate('/', ev) |
156 | return |
157 | |
158 | // navigate to a feed |
159 | case 50: // 2 |
160 | if (ev.shiftKey) |
161 | search.activate('@', ev) |
162 | return |
163 | |
164 | // navigate to a channel |
165 | case 51: // 3 |
166 | if (ev.shiftKey) |
167 | search.activate('#', ev) |
168 | return |
169 | |
170 | // navigate to a message |
171 | case 53: // 5 |
172 | if (ev.shiftKey) |
173 | search.activate('%', ev) |
174 | return |
175 | } |
176 | }) |
177 | |
178 | // errors tab |
179 | var { |
180 | container: errors, |
181 | content: errorsContent |
182 | } = api.build_scroller() |
183 | |
184 | // remove loader error handler |
185 | if (window.onError) { |
186 | window.removeEventListener('error', window.onError) |
187 | delete window.onError |
188 | } |
189 | |
190 | // put errors in a tab |
191 | window.addEventListener('error', function (ev) { |
192 | var err = ev.error || ev |
193 | if(!tabs.has('errors')) |
194 | tabs.add(errors, false) |
195 | var el = h('div.message', |
196 | h('strong', err.message), |
197 | h('pre', err.stack)) |
198 | if (errorsContent.firstChild) |
199 | errorsContent.insertBefore(el, errorsContent.firstChild) |
200 | else |
201 | errorsContent.appendChild(el) |
202 | }) |
203 | |
204 | if (process.versions.electron) { |
205 | window.addEventListener('contextmenu', function (ev) { |
206 | ev.preventDefault() |
207 | var remote = require('electron').remote |
208 | var Menu = remote.Menu |
209 | var MenuItem = remote.MenuItem |
210 | var menu = new Menu() |
211 | menu.append(new MenuItem({ |
212 | label: 'Inspect Element', |
213 | click: function () { |
214 | remote.getCurrentWindow().inspectElement(ev.x, ev.y) |
215 | } |
216 | })) |
217 | menu.popup(remote.getCurrentWindow()) |
218 | }) |
219 | } |
220 | |
221 | return tabs |
222 | } |
223 | |
224 | } |
225 |
Built with git-ssb-web