git ssb

30+

cel / git-ssb-web



Tree: 9a8720ca9018b2b2fb70a0c670cdaf5de4069fb0

Files: 9a8720ca9018b2b2fb70a0c670cdaf5de4069fb0 / lib / util.js

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

Built with git-ssb-web