diff --git a/libs/markdown.js b/libs/markdown.js index e06ad40..7d4304f 100644 --- a/libs/markdown.js +++ b/libs/markdown.js @@ -64,32 +64,35 @@ function render(s, cb) { return hlID[id] = uuid(); }, mathRenderer: function(str, display) { - if (cacheOption.math) { - let x = cache.get('M_' + display + '_' + str); - if (x !== undefined) return x; + let mathFinish = (error, result) => { + if (error) maths[id] = '

' + data.errors.toString() + '

'; + else if (display) maths[id] = '

' + result + '

'; + else maths[id] = result; + if (cacheOption.math) cache.set('M_' + display + '_' + str, maths[id]); + if (!--mathPending) finish(); } + + const id = mathCnt; + mathCnt++, mathPending++; + try { - let res = katex.renderToString(str, { displayMode: display }); - if (cacheOption.math) cache.set('M_' + display + '_' + str, res); - return res; + let x = cache.get('M_' + display + '_' + str); + if (x !== undefined) process.nextTick(() => mathFinish(null, x)); + else { + let res = katex.renderToString(str, { displayMode: display }); + process.nextTick(() => mathFinish(null, '' + res + '')); + } } catch (e) { - const id = mathCnt; - mathCnt++, mathPending++; mj.typeset({ math: str, format: display ? 'TeX' : 'inline-TeX', - html: true, css: true, + svg: true, width: 0 - }, function (data) { - if (data.errors) maths[id] = '

' + data.errors.toString() + '

'; - else if (display) maths[id] = '

' + data.html + '

'; - else maths[id] = data.html; - if (cacheOption.math) cache.set('M_' + display + '_' + str, maths[id]); - if (!--mathPending) finish(); + }, data => { + mathFinish(data.errors, data.svg); }); - - return mathID[id] = uuid(); } + return mathID[id] = uuid(); } }); @@ -109,7 +112,28 @@ function render(s, cb) { } try { - res = MoeMark(s); + let XSS = require('xss'); + let CSSFilter = require('cssfilter'); + let whiteList = Object.assign({}, require('xss/lib/default').whiteList); + delete whiteList.audio; + delete whiteList.video; + for (let tag in whiteList) whiteList[tag] = whiteList[tag].concat(['style', 'class']); + let xss = new XSS.FilterXSS({ + whiteList: whiteList, + stripIgnoreTag: true, + onTagAttr: (tag, name, value, isWhiteAttr) => { + if (tag.toLowerCase() === 'img' && name.toLowerCase() === 'src' && value.startsWith('data:image/')) return name + '="' + XSS.escapeAttrValue(value) + '"'; + } + }); + let replaceXSS = s => { + s = xss.process(s); + if (s) { + s = `
${s}
`; + } + return s; + }; + + res = replaceXSS(MoeMark(s)); if (mathPending == 0 && hlPending == 0) { finish(); } diff --git a/utility.js b/utility.js index 6b70d11..36c3b69 100644 --- a/utility.js +++ b/utility.js @@ -34,36 +34,6 @@ module.exports = { return path.resolve.apply(null, a); }, markdown(obj, keys, noReplaceUI) { - let XSS = require('xss'); - let CSSFilter = require('cssfilter'); - let whiteList = Object.assign({}, require('xss/lib/default').whiteList); - delete whiteList.audio; - delete whiteList.video; - for (let tag in whiteList) whiteList[tag] = whiteList[tag].concat(['style', 'class']); - let xss = new XSS.FilterXSS({ - css: { - whiteList: Object.assign({}, require('cssfilter/lib/default').whiteList, { - 'vertical-align': true, - top: true, - bottom: true, - left: true, - right: true, - "white-space": true - }) - }, - whiteList: whiteList, - stripIgnoreTag: true, - onTagAttr: (tag, name, value, isWhiteAttr) => { - if (tag.toLowerCase() === 'img' && name.toLowerCase() === 'src' && value.startsWith('data:image/')) return name + '="' + XSS.escapeAttrValue(value) + '"'; - } - }); - let replaceXSS = s => { - s = xss.process(s); - if (s) { - s = `
${s}
`; - } - return s; - }; let replaceUI = s => { if (noReplaceUI) return s; @@ -90,13 +60,13 @@ module.exports = { if (!keys) { if (!obj || !obj.trim()) resolve(""); else markdownRenderer(obj, s => { - resolve(replaceUI(replaceXSS(s))); + resolve(replaceUI(s)); }); } else { let res = obj, cnt = keys.length; for (let key of keys) { markdownRenderer(res[key], (s) => { - res[key] = replaceUI(replaceXSS(s)); + res[key] = replaceUI(s); if (!--cnt) resolve(res); }); }