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