Files: 51aae5719eca887b566cf7799cfe9f098483427b / message / html / markdown.js
2250 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 | |
8 | exports.needs = nest({ |
9 | 'blob.sync.url': 'first', |
10 | 'blob.obs.has': 'first', |
11 | 'emoji.sync.url': 'first' |
12 | }) |
13 | |
14 | exports.gives = nest('message.html.markdown') |
15 | |
16 | exports.create = function (api) { |
17 | return nest('message.html.markdown', markdown) |
18 | |
19 | function markdown (content) { |
20 | if (typeof content === 'string') { content = {text: content} } |
21 | // handle patchwork style mentions and custom emoji. |
22 | var mentions = {} |
23 | var emojiMentions = {} |
24 | if (Array.isArray(content.mentions)) { |
25 | content.mentions.forEach(function (link) { |
26 | if (link && link.name && link.link) { |
27 | if (link.emoji) emojiMentions[link.name] = link.link |
28 | else mentions['@' + link.name] = link.link |
29 | } |
30 | }) |
31 | } |
32 | |
33 | return h('Markdown', { |
34 | hooks: [ |
35 | LoadingBlobHook(api.blob.obs.has) |
36 | ], |
37 | innerHTML: renderer.block(content.text, { |
38 | emoji: (emoji) => { |
39 | var url = emojiMentions[emoji] |
40 | ? api.blob.sync.url(emojiMentions[emoji]) |
41 | : api.emoji.sync.url(emoji) |
42 | return renderEmoji(emoji, url) |
43 | }, |
44 | toUrl: (id) => { |
45 | if (ref.isBlob(id)) return api.blob.sync.url(id) |
46 | return mentions[id] || id |
47 | }, |
48 | imageLink: (id) => id |
49 | }) |
50 | }) |
51 | } |
52 | |
53 | function renderEmoji (emoji, url) { |
54 | if (!url) return ':' + emoji + ':' |
55 | return ` |
56 | <img |
57 | src="${htmlEscape(url)}" |
58 | alt=":${htmlEscape(emoji)}:" |
59 | title=":${htmlEscape(emoji)}:" |
60 | class="emoji" |
61 | > |
62 | ` |
63 | } |
64 | } |
65 | |
66 | function LoadingBlobHook (hasBlob) { |
67 | return function (element) { |
68 | var releases = [] |
69 | element.querySelectorAll('img').forEach(img => { |
70 | var id = ref.extract(img.src) |
71 | if (id) { |
72 | releases.push(watch(hasBlob(id), has => { |
73 | if (has === false) { |
74 | img.classList.add('-pending') |
75 | } else { |
76 | img.classList.remove('-pending') |
77 | } |
78 | })) |
79 | } |
80 | }) |
81 | return function () { |
82 | while (releases.length) { |
83 | releases.pop()() |
84 | } |
85 | } |
86 | } |
87 | } |
88 |
Built with git-ssb-web