Files: 08cc79deadf85dd2e68e2c46d595570f1b665c91 / lib / util.js
5748 bytesRaw
1 | var pull = require('pull-stream') |
2 | var h = require('pull-hyperscript') |
3 | var paramap = require('pull-paramap') |
4 | var Highlight = require('highlight.js') |
5 | var u = exports |
6 | |
7 | u.imgMimes = { |
8 | png: 'image/png', |
9 | jpeg: 'image/jpeg', |
10 | jpg: 'image/jpeg', |
11 | gif: 'image/gif', |
12 | tif: 'image/tiff', |
13 | svg: 'image/svg+xml', |
14 | bmp: 'image/bmp' |
15 | } |
16 | |
17 | u.getExtension = function(filename) { |
18 | return (/\.([^.]+)$/.exec(filename) || [,filename])[1] |
19 | } |
20 | |
21 | u.readNext = function (fn) { |
22 | var next |
23 | return function (end, cb) { |
24 | if (next) return next(end, cb) |
25 | fn(function (err, _next) { |
26 | if (err) return cb(err) |
27 | next = _next |
28 | next(null, cb) |
29 | }) |
30 | } |
31 | } |
32 | |
33 | u.readOnce = function (fn) { |
34 | var ended |
35 | return function (end, cb) { |
36 | fn(function (err, data) { |
37 | if (err || ended) return cb(err || ended) |
38 | ended = true |
39 | cb(null, data) |
40 | }) |
41 | } |
42 | } |
43 | |
44 | u.when = function (bool, el) { |
45 | return bool |
46 | ? el |
47 | : pull.once('') |
48 | } |
49 | |
50 | u.sourceMap = function (source, fn) { |
51 | return pull( |
52 | source, |
53 | pull.filter(Boolean), |
54 | pull.map(fn) |
55 | ) |
56 | } |
57 | |
58 | u.paraSourceMap = function paraSourceMap (source, fn) { |
59 | return pull( |
60 | pull.values(source), |
61 | paramap(fn, 8) |
62 | ) |
63 | } |
64 | |
65 | u.escape = function (str) { |
66 | return String(str) |
67 | .replace(/&/g, '&') |
68 | .replace(/</g, '<') |
69 | .replace(/>/g, '>') |
70 | .replace(/"/g, '"') |
71 | } |
72 | |
73 | u.encodeLink = function (url) { |
74 | if (!Array.isArray(url)) url = [url] |
75 | return '/' + url.map(encodeURIComponent).join('/') |
76 | } |
77 | |
78 | u.link = function (parts, text, raw, props) { |
79 | if (text == null) text = parts[parts.length-1] |
80 | if (!raw) text = u.escape(text) |
81 | return '<a href="' + u.encodeLink(parts) + '"' + |
82 | (props ? ' ' + props : '') + |
83 | '>' + text + '</a>' |
84 | } |
85 | |
86 | u.timestamp = function (time, req) { |
87 | time = Number(time) |
88 | var d = new Date(time) |
89 | return '<span title="' + time + '">' + |
90 | d.toLocaleString(req._locale) + '</span>' |
91 | } |
92 | |
93 | u.nav = function (links, page, after) { |
94 | return h('nav', [ |
95 | u.sourceMap(pull.values(links), link => { |
96 | return h('a', { |
97 | href: (typeof link[0] == 'string') ? link[0] : u.encodeLink(link[0]), |
98 | class: (link[2] == page) ? 'active' : '' |
99 | }, |
100 | link[1]) |
101 | }), |
102 | pull.once(after || '') |
103 | ]) |
104 | } |
105 | |
106 | //return pull.once(['<nav>'].concat( |
107 | //links.map(function (link) { |
108 | //var href = typeof link[0] == 'string' ? link[0] : u.encodeLink(link[0]) |
109 | //var props = link[2] == page ? ' class="active"' : '' |
110 | //return '<a href="' + href + '"' + props + '>' + link[1] + '</a>' |
111 | //}), after || '', '</nav>').join('') |
112 | //) |
113 | //} |
114 | |
115 | u.hiddenInputs = function (values) { |
116 | return Object.keys(values).map(function (key) { |
117 | return '<input type="hidden"' + |
118 | ' name="' + u.escape(key) + '"' + |
119 | ' value="' + u.escape(values[key]) + '"/>' |
120 | }).join('') |
121 | } |
122 | |
123 | u.highlight = function(code, lang) { |
124 | if (code.length > 100000) return u.escape(code) |
125 | try { |
126 | return lang |
127 | ? Highlight.highlight(lang, code).value |
128 | : Highlight.highlightAuto(code).value |
129 | } catch(e) { |
130 | if (/^Unknown language/.test(e.message)) |
131 | return u.escape(code) |
132 | throw e |
133 | } |
134 | } |
135 | |
136 | u.pre = function (text) { |
137 | return '<pre>' + u.escape(text) + '</pre>' |
138 | } |
139 | |
140 | u.json = function (obj) { |
141 | return u.linkify(u.pre(JSON.stringify(obj, null, 2))) |
142 | } |
143 | |
144 | u.linkify = function (text) { |
145 | // regex is from ssb-ref |
146 | return text.replace(/(@|%|&|&)[A-Za-z0-9\/+]{43}=\.[\w\d]+/g, function (str) { |
147 | return '<a href="/' + encodeURIComponent(str) + '">' + str + '</a>' |
148 | }) |
149 | } |
150 | |
151 | u.readObjectString = function (obj, cb) { |
152 | pull(obj.read, pull.collect(function (err, bufs) { |
153 | if (err) return cb(err) |
154 | cb(null, Buffer.concat(bufs, obj.length).toString('utf8')) |
155 | })) |
156 | } |
157 | |
158 | u.pullReverse = function () { |
159 | return function (read) { |
160 | return u.readNext(function (cb) { |
161 | pull(read, pull.collect(function (err, items) { |
162 | cb(err, items && pull.values(items.reverse())) |
163 | })) |
164 | }) |
165 | } |
166 | } |
167 | |
168 | function compareMsgs(a, b) { |
169 | return (a.value.timestamp - b.value.timestamp) || (a.key - b.key) |
170 | } |
171 | |
172 | u.pullSort = function (comparator, descending) { |
173 | return function (read) { |
174 | return u.readNext(function (cb) { |
175 | pull(read, pull.collect(function (err, items) { |
176 | if (err) return cb(err) |
177 | items.sort(comparator) |
178 | if (descending) items.reverse() |
179 | cb(null, pull.values(items)) |
180 | })) |
181 | }) |
182 | } |
183 | } |
184 | |
185 | u.sortMsgs = function (descending) { |
186 | return u.pullSort(compareMsgs, descending) |
187 | } |
188 | |
189 | u.truncate = function (str, len) { |
190 | str = String(str) |
191 | return str.length < len ? str : str.substr(0, len) + '…' |
192 | } |
193 | |
194 | u.messageTitle = function (msg) { |
195 | var c = msg.value.content |
196 | return u.truncate(c.title || c.text || msg.key, 40) |
197 | } |
198 | |
199 | u.ifModifiedSince = function (req, lastMod) { |
200 | var ifModSince = req.headers['if-modified-since'] |
201 | if (!ifModSince) return false |
202 | var d = new Date(ifModSince) |
203 | return d && Math.floor(d/1000) >= Math.floor(lastMod/1000) |
204 | } |
205 | |
206 | u.decryptMessages = function (sbot) { |
207 | return paramap(function (msg, cb) { |
208 | var c = msg && msg.value && msg.value.content |
209 | if (c && typeof c === 'string' && c.slice(-4) === '.box') { |
210 | sbot.private.unbox(msg.value.content, function (err, content) { |
211 | if (err) return cb(null, msg) // leave message encrypted |
212 | var msg1 = {} |
213 | for (var k in msg) msg1[k] = msg[k] |
214 | msg1.value = {} |
215 | for (var j in msg.value) msg1.value[j] = msg.value[j] |
216 | msg1.value.private = true |
217 | msg1.value.content = content |
218 | if (!content.recps) { |
219 | sbot.whoami(function (err, feed) { |
220 | if (err) return cb(err) |
221 | content.recps = [msg1.value.author] |
222 | if (feed.id !== msg1.value.author) content.recps.push(feed.id) |
223 | cb(null, msg1) |
224 | }) |
225 | } else cb(null, msg1) |
226 | }) |
227 | } else cb(null, msg) |
228 | }, 4) |
229 | } |
230 |
Built with git-ssb-web