git ssb

0+

dangerousbeans / yap



forked from Dominic / yap

Tree: 85f4193eae88cdee0f08d19cc1b5d4a5475bd1b1

Files: 85f4193eae88cdee0f08d19cc1b5d4a5475bd1b1 / util.js

5645 bytesRaw
1var URL = require('url')
2var QS = require('querystring')
3var hyperscript = require('hyperscript')
4var cpara = require('cont').para
5var pull = require('pull-stream')
6var paramap = require('pull-paramap')
7var nested = require('libnested')
8var renderer = require('ssb-markdown')
9var ref = require('ssb-ref')
10var htmlEscape = require('html-escape')
11function isFunction (f) {
12 return 'function' === typeof f
13}
14
15var isArray = Array.isArray
16
17function isEmpty (e) {
18 for(var k in e) return false
19 return true
20}
21
22function isString (s) {
23 return 'string' === typeof s
24}
25
26exports.toUrl = function toUrl(path, opts) {
27 return '/'+(
28 Array.isArray(path) ? path.join('/') : ''+path
29 ) + (
30 !isEmpty(opts) ? '?'+QS.encode(opts) : ''
31 )
32}
33exports.h = function () {
34 return [].slice.call(arguments)
35}
36
37function toCont (f) {
38 if(f.length === 1) return function (cb) {
39 f(function (err, hs) {
40 exports.toHTML(hs)(cb)
41 })
42 }
43 else if(f.length === 2)
44 return function (cb) {
45 pull(
46 f,
47 paramap(function (e, cb) {
48 exports.toHTML(e)(cb)
49 }, 32),
50 pull.collect(cb)
51 )
52 }
53}
54
55function flatten (a) {
56 var _a = []
57 for(var i = 0; i < a.length; i++)
58 if(isArray(a[i]) && !isString(a[i][0]))
59 _a = _a.concat(flatten(a[i]))
60 else
61 _a.push(a[i])
62 return _a
63}
64
65
66//even better would be streaming html,
67//not just into arrays.
68var k = 0
69exports.toHTML = function toHTML (hs) {
70 return function (cb) {
71 if(!isFunction(cb)) throw new Error('cb must be a function, was:'+cb)
72 var called = false
73 var C = (
74 isFunction(hs) ? toCont(hs)
75 : isArray(hs) ? cpara(hs.map(toHTML))
76 : function (cb) {
77 if(!called) {
78 called = true
79 cb(null, hs)
80 }
81 else
82 throw new Error('called twice')
83 }
84 )
85
86 C(function (err, val) {
87 if(err) cb(err)
88 else if(isArray(val) && isString(val[0])) {
89 cb(null, hyperscript.apply(null, flatten(val)))
90 } else
91 cb(null, val)
92 })
93 }
94}
95
96exports.createHiddenInputs = function createHiddenInputs (meta, _path) {
97 _path = _path ? [].concat(_path) : []
98 var hidden = []
99 nested.each(meta, function (value, path) {
100 if(value !== undefined)
101 hidden.push(['input', {
102 name: _path.concat(path).map(function (e) { return '['+e+']' }).join(''),
103 value: value,
104 type: 'hidden'
105 }])
106 }, true)
107 return hidden
108}
109
110var cacheId = exports.cacheId = function (id) {
111 if('string' === typeof id)
112 return '_'+Buffer.from(id.substring(1, 12), 'base64').toString('hex')
113 else
114 return 'R'+id.lte+'-'+(id.lte - id.gte)
115}
116exports.cacheTag = function (url, id, time) {
117 if(time)
118 return ['link', {
119 rel: 'partial-refresh', href: url, id: cacheId(id), 'data-cache': ''+time
120 }]
121}
122
123
124function renderEmoji (emoji, url) {
125 if (!url) return ':' + emoji + ':'
126 return `
127 <img
128 src="${htmlEscape(url)}"
129 alt=":${htmlEscape(emoji)}:"
130 title=":${htmlEscape(emoji)}:"
131 class="emoji"
132 >
133 `
134}
135
136//copied from patchwork
137exports.markdown = function markdown (content) {
138 if (typeof content === 'string') { content = { text: content } }
139 var mentions = {}
140 var typeLookup = {}
141 var emojiMentions = {}
142 if (Array.isArray(content.mentions)) {
143 content.mentions.forEach(function (link) {
144 if (link && link.link && link.type) {
145 typeLookup[link.link] = link.type
146 }
147 if (link && link.name && link.link) {
148 if (link.emoji) {
149 // handle custom emoji
150 emojiMentions[link.name] = link.link
151 } else {
152 // handle old-style patchwork v2 mentions (deprecated)
153 mentions['@' + link.name] = link.link
154 }
155 }
156 })
157 }
158
159 var blobsUrl = '/blobs/get/'
160 var emojiUrl = '/img/emoji/'
161
162 function id2Url (id) {
163 return (
164 ref.isMsg(id) ? '/thread?id='+encodeURIComponent(id)
165 : ref.isBlobLink(id) ? blobsUrl+encodeURIComponent(id)
166 : ref.isFeed(id) ? '/public?author='+encodeURIComponent(id)
167 : id[0] == '#' ? '/public?channel='+id.substring(1)
168 : id
169 )
170 }
171
172 return ['div.Markdown', {
173 innerHTML: renderer.block(content.text, {
174 emoji: (emoji) => {
175 var url = emojiMentions[emoji]
176 ? blobsUrl + emojiMentions[emoji]
177 : emojiUrl + emoji + '.png'
178 return renderEmoji(emoji, url)
179 },
180 toUrl: (id) => {
181 var link = ref.parseLink(id)
182 if (link && ref.isBlob(link.link)) {
183 var url = blobsUrl+link.link
184 var query = {}
185 if (link.query && link.query.unbox) query['unbox'] = link.query.unbox
186 if (typeLookup[link.link]) query['contentType'] = typeLookup[link.link]
187 return url + '?' + QS.stringify(query)
188 } else if (link || id.startsWith('#') || id.startsWith('?')) {
189 return id2Url(id)
190 } else if (mentions[id]) {
191 // handle old-style patchwork v2 mentions (deprecated)
192 return id2Url(mentions[id])
193 }
194 return false
195 },
196 imageLink: function (id) {
197 return id2Url(id)
198 }
199 })
200 }]
201}
202
203exports.createRenderer = function (render) {
204 return function (sbot) {
205 return function (opts, apply) {
206 if(opts.id && ref.isMsgLink(opts.id))
207 return function (cb) {
208 sbot.get({id:opts.id, private: true}, function (err, msg) {
209 if(err) return cb(err)
210 var data = {key: opts.id, value: msg, timestamp: msg.timestamp || Date.now() }
211 cb(null, render(data, apply))
212 })
213 }
214 else if(opts.key && opts.value)
215 return render(opts, apply)
216 }
217 }
218}
219
220
221
222
223

Built with git-ssb-web