Files: eb7933358238526bccf4c320ca689b9269c61f95 / message / html / markdown.js
2918 bytesRaw
1 | const renderer = require('ssb-markdown') |
2 | const h = require('mutant/h') |
3 | const ref = require('ssb-ref') |
4 | const nest = require('depnest') |
5 | var htmlEscape = require('html-escape') |
6 | var watch = require('mutant/watch') |
7 | const querystring = require('querystring'); |
8 | |
9 | exports.needs = nest({ |
10 | 'blob.sync.url': 'first', |
11 | 'blob.obs.has': 'first', |
12 | 'emoji.sync.url': 'first' |
13 | }) |
14 | |
15 | exports.gives = nest('message.html.markdown') |
16 | |
17 | exports.create = function (api) { |
18 | return nest('message.html.markdown', markdown) |
19 | |
20 | function markdown (content) { |
21 | if (typeof content === 'string') { content = {text: content} } |
22 | // handle patchwork style mentions and custom emoji. |
23 | var mentions = {} |
24 | var typeLookup = {} |
25 | var emojiMentions = {} |
26 | if (Array.isArray(content.mentions)) { |
27 | content.mentions.forEach(function (link) { |
28 | if (link && link.link && link.type) { |
29 | typeLookup[link.link] = link.type |
30 | } |
31 | if (link && link.name && link.link) { |
32 | if (link.emoji) emojiMentions[link.name] = link.link |
33 | else mentions['@' + link.name] = link.link |
34 | } |
35 | }) |
36 | } |
37 | |
38 | return h('Markdown', { |
39 | hooks: [ |
40 | LoadingBlobHook(api.blob.obs.has) |
41 | ], |
42 | innerHTML: renderer.block(content.text, { |
43 | emoji: (emoji) => { |
44 | var url = emojiMentions[emoji] |
45 | ? api.blob.sync.url(emojiMentions[emoji]) |
46 | : api.emoji.sync.url(emoji) |
47 | return renderEmoji(emoji, url) |
48 | }, |
49 | toUrl: (id) => { |
50 | if (ref.isBlob(id)) { |
51 | var blob = ref.parseBlob(id) |
52 | var url = api.blob.sync.url(blob.link) |
53 | var query = {} |
54 | if (blob.query && blob.query.unbox) query['unbox'] = blob.query.unbox |
55 | if (typeLookup[blob.link]) query['contentType'] = typeLookup[blob.link] |
56 | return url + '?' + querystring.stringify(query) |
57 | } |
58 | if (mentions[id]) { |
59 | return mentions[id] |
60 | } else if (ref.isLink(id) || id.startsWith('#') || id.startsWith('?')) { |
61 | return id |
62 | } |
63 | return false |
64 | }, |
65 | imageLink: (id) => id |
66 | }) |
67 | }) |
68 | } |
69 | |
70 | function renderEmoji (emoji, url) { |
71 | if (!url) return ':' + emoji + ':' |
72 | return ` |
73 | <img |
74 | src="${htmlEscape(url)}" |
75 | alt=":${htmlEscape(emoji)}:" |
76 | title=":${htmlEscape(emoji)}:" |
77 | class="emoji" |
78 | > |
79 | ` |
80 | } |
81 | } |
82 | |
83 | function LoadingBlobHook (hasBlob) { |
84 | return function (element) { |
85 | var releases = [] |
86 | element.querySelectorAll('img').forEach(img => { |
87 | var id = ref.extract(img.src) |
88 | if (id) { |
89 | releases.push(watch(hasBlob(id), has => { |
90 | if (has === false) { |
91 | img.classList.add('-pending') |
92 | } else { |
93 | img.classList.remove('-pending') |
94 | } |
95 | })) |
96 | } |
97 | }) |
98 | return function () { |
99 | while (releases.length) { |
100 | releases.pop()() |
101 | } |
102 | } |
103 | } |
104 | } |
105 |
Built with git-ssb-web