git ssb

16+

Dominic / patchbay



Tree: de80e702316a3f736dcb1f65f3840baf28f51ab9

Files: de80e702316a3f736dcb1f65f3840baf28f51ab9 / modules_core / tabs.js

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

Built with git-ssb-web