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