git ssb

16+

cel / patchfoo



Tree: 7cbc5c587105a7add08d250458303c47bcd0e57a

Files: 7cbc5c587105a7add08d250458303c47bcd0e57a / lib / render.js

6414 bytesRaw
1var fs = require('fs')
2var path = require('path')
3var pull = require('pull-stream')
4var cat = require('pull-cat')
5var paramap = require('pull-paramap')
6var h = require('hyperscript')
7var marked = require('ssb-marked')
8var emojis = require('emoji-named-characters')
9var qs = require('querystring')
10var u = require('./util')
11var multicb = require('multicb')
12var RenderMsg = require('./render-msg')
13
14module.exports = Render
15
16function MdRenderer(render) {
17 marked.Renderer.call(this, {})
18 this.render = render
19}
20MdRenderer.prototype = new marked.Renderer()
21
22MdRenderer.prototype.urltransform = function (href) {
23 return this.render.toUrl(href)
24}
25
26MdRenderer.prototype.image = function (href, title, text) {
27 href = this.render.imageUrl(href)
28 var name = text || title
29 if (name) href += '?name=' + encodeURIComponent(name)
30 return h('img', {
31 src: href,
32 alt: text,
33 title: title || undefined
34 }).outerHTML
35}
36
37MdRenderer.prototype.link = function(href, title, text) {
38 href = this.urltransform(href)
39 var name = href && /^\/(&|%26)/.test(href) && (title || text)
40 return '<a'
41 + (href !== false
42 ? ' href="' + href + '"'
43 : ' class="bad"')
44 + (title ? ' title="' + title + '"' : '')
45 + (name ? ' download="' + encodeURIComponent(name) + '"' : '')
46 + '>' + text + '</a>'
47};
48
49
50function lexerRenderEmoji(emoji) {
51 var el = this.renderer.render.emoji(emoji)
52 return el && el.outerHTML || el
53}
54
55function Render(app, opts) {
56 this.app = app
57 this.opts = opts
58
59 this.markedOpts = {
60 gfm: true,
61 mentions: true,
62 tables: true,
63 breaks: true,
64 pedantic: false,
65 sanitize: true,
66 smartLists: true,
67 smartypants: false,
68 emoji: lexerRenderEmoji,
69 renderer: new MdRenderer(this),
70 }
71}
72
73Render.prototype.emoji = function (emoji) {
74 var name = ':' + emoji + ':'
75 return emoji in emojis ?
76 h('img.ssb-emoji', {
77 src: this.opts.emoji_base + emoji + '.png',
78 alt: name,
79 title: name,
80 }) : name
81}
82
83/* disabled until it can be done safely without breaking html
84function fixSymbols(str) {
85 // Dillo doesn't do fallback fonts, so specifically render fancy characters
86 // with Symbola
87 return str.replace(/[^\u0000-\u00ff]+/, function ($0) {
88 return '<span class="symbol">' + $0 + '</span>'
89 })
90}
91*/
92
93Render.prototype.markdown = function (text, mentions) {
94 if (!text) return ''
95 var mentionsObj = this._mentions = {}
96 if (Array.isArray(mentions)) mentions.forEach(function (link) {
97 if (!link) return
98 else if (link.name)
99 mentionsObj['@' + link.name] = link.link
100 else if (link.host === 'http://localhost:7777')
101 mentionsObj[link.href] = link.link
102 })
103 var out = marked(String(text), this.markedOpts)
104 delete this._mentions
105 return out //fixSymbols(out)
106}
107
108Render.prototype.imageUrl = function (ref) {
109 var m = /^blobstore:(.*)/.exec(ref)
110 if (m) ref = m[1]
111 return this.opts.img_base + ref
112}
113
114Render.prototype.toUrl = function (href) {
115 if (!href) return href
116 var mentions = this._mentions
117 if (mentions && href in this._mentions) href = this._mentions[href]
118 if (/^ssb:\/\//.test(href)) href = href.substr(6)
119 switch (href[0]) {
120 case '%':
121 if (!u.isRef(href)) return false
122 return this.opts.base + encodeURIComponent(href)
123 case '@':
124 if (!u.isRef(href)) return false
125 return this.opts.base + href
126 case '&':
127 if (!u.isRef(href)) return false
128 return this.opts.blob_base + href
129 case '#': return this.opts.base + encodeURIComponent(href)
130 case '/': return this.opts.base + href.substr(1)
131 case '?': return this.opts.base + 'search?q=' + encodeURIComponent(href)
132 }
133 var m = /^blobstore:(.*)/.exec(href)
134 if (m) return this.opts.blob_base + m[1]
135 if (/^javascript:/.test(href)) return false
136 return href
137}
138
139Render.prototype.lockIcon = function () {
140 return this.emoji('lock')
141}
142
143Render.prototype.avatarImage = function (link, cb) {
144 var self = this
145 if (!link) return cb(), ''
146 if (typeof link === 'string') link = {link: link}
147 var img = h('img.ssb-avatar-image', {
148 alt: ' '
149 })
150 if (link.image) gotAbout(null, link)
151 else self.app.getAbout(link.link, gotAbout)
152 function gotAbout(err, about) {
153 if (err) return cb(err)
154 if (!about.image) img.src = self.toUrl('/static/fallback.png')
155 else img.src = self.imageUrl(about.image)
156 cb()
157 }
158 return img
159}
160
161Render.prototype.prepareLink = function (link, cb) {
162 if (typeof link === 'string') link = {link: link}
163 if (link.name || !link.link) cb(null, link)
164 else this.app.getAbout(link.link, function (err, about) {
165 if (err) return cb(err)
166 link.name = about.name || (link.link.substr(0, 8) + '…')
167 if (link.name && link.name[0] === link.link[0]) {
168 link.name = link.name.substr(1)
169 }
170 cb(null, link)
171 })
172}
173
174Render.prototype.prepareLinks = function (links, cb) {
175 var self = this
176 if (!links) return cb()
177 var done = multicb({pluck: 1})
178 if (Array.isArray(links)) links.forEach(function (link) {
179 self.prepareLink(link, done())
180 })
181 done(cb)
182}
183
184Render.prototype.idLink = function (link, cb) {
185 var self = this
186 if (!link) return cb(), ''
187 var a = h('a', ' ')
188 self.prepareLink(link, function (err, link) {
189 if (err) return cb(err)
190 a.href = self.toUrl(link.link)
191 a.childNodes[0].textContent = '@' + link.name
192 cb()
193 })
194 return a
195}
196
197Render.prototype.privateLine = function (recps, cb) {
198 var done = multicb({pluck: 1, spread: true})
199 var self = this
200 var el = h('div.recps',
201 self.lockIcon(),
202 Array.isArray(recps)
203 ? recps.map(function (recp) {
204 return [' ', self.idLink(recp, done())]
205 }) : '')
206 done(cb)
207 return el
208}
209
210Render.prototype.msgLink = function (msg, cb) {
211 var self = this
212 var el = h('span')
213 var a = h('a', {href: self.toUrl(msg.key)}, msg.key)
214 self.app.unboxMsg(msg, function (err, msg) {
215 if (err) return el.appendChild(u.renderError(err)), cb()
216 var renderMsg = new RenderMsg(self, self.app, msg, {wrap: false})
217 renderMsg.title(function (err, title) {
218 if (err) return el.appendChild(u.renderError(err)), cb()
219 a.childNodes[0].textContent = title
220 cb()
221 })
222 })
223 return a
224}
225
226Render.prototype.renderMsg = function (msg, raw, cb) {
227 new RenderMsg(this, this.app, msg).message(raw, cb)
228}
229
230Render.prototype.renderFeeds = function (raw) {
231 var self = this
232 return paramap(function (msg, cb) {
233 self.renderMsg(msg, raw, cb)
234 }, 4)
235}
236

Built with git-ssb-web