git ssb

16+

Dominic / patchbay



Tree: edabe8be49e24684f650eea0bbebd38e65df4f9f

Files: edabe8be49e24684f650eea0bbebd38e65df4f9f / modules_core / tabs.js

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

Built with git-ssb-web