git ssb

16+

Dominic / patchbay



Tree: bd801655ad6ba5f09a31d3037c468c45f3ff0bb7

Files: bd801655ad6ba5f09a31d3037c468c45f3ff0bb7 / modules_core / tabs.js

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

Built with git-ssb-web