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