diff --git a/browser/main/lib/dataApi/formatHTML.js b/browser/main/lib/dataApi/formatHTML.js index eb44e9ce..c879f4cd 100644 --- a/browser/main/lib/dataApi/formatHTML.js +++ b/browser/main/lib/dataApi/formatHTML.js @@ -102,6 +102,33 @@ export default function formatHTML (props) { let inlineScripts = '' let scripts = '' + let decodeEntities = false + function addDecodeEntities () { + if (decodeEntities) { + return + } + + decodeEntities = true + + inlineScripts += ` +function decodeEntities (text) { + var entities = [ + ['apos', '\\''], + ['amp', '&'], + ['lt', '<'], + ['gt', '>'], + ['#63', '\\?'], + ['#36', '\\$'] + ] + + for (var i = 0, max = entities.length; i < max; ++i) { + text = text.replace(new RegExp(\`&\${entities[i][0]};\`, 'g'), entities[i][1]) + } + + return text +}` + } + let lodash = false function addLodash () { if (lodash) { @@ -118,6 +145,87 @@ export default function formatHTML (props) { scripts += `` } + let raphael = false + function addRaphael () { + if (raphael) { + return + } + + raphael = true + + exportTasks.push({ + src: unprefix(`${appPath}/node_modules/raphael/raphael.min.js`), + dst: 'js' + }) + + scripts += `` + } + + let yaml = false + function addYAML () { + if (yaml) { + return + } + + yaml = true + + exportTasks.push({ + src: unprefix(`${appPath}/node_modules/js-yaml/dist/js-yaml.min.js`), + dst: 'js' + }) + + scripts += `` + } + + let chart = false + function addChart () { + if (chart) { + return + } + + chart = true + + addLodash() + + exportTasks.push({ + src: unprefix(`${appPath}/node_modules/chart.js/dist/Chart.min.js`), + dst: 'js' + }) + + scripts += `` + + inlineScripts += ` +function displayCharts () { + _.forEach( + document.querySelectorAll('.chart'), + el => { + try { + const format = el.attributes.getNamedItem('data-format').value + const chartConfig = format === 'yaml' ? jsyaml.load(el.innerHTML) : JSON.parse(el.innerHTML) + el.innerHTML = '' + + const canvas = document.createElement('canvas') + el.appendChild(canvas) + + const height = el.attributes.getNamedItem('data-height') + if (height && height.value !== 'undefined') { + el.style.height = height.value + 'vh' + canvas.height = height.value + 'vh' + } + + const chart = new Chart(canvas, chartConfig) + } catch (e) { + el.className = 'chart-error' + el.innerHTML = 'chartjs diagram parse error: ' + e.message + } + } + ) +} + +document.addEventListener('DOMContentLoaded', displayCharts); +` + } + let codemirror = false function addCodeMirror () { if (codemirror) { @@ -126,6 +234,7 @@ export default function formatHTML (props) { codemirror = true + addDecodeEntities() addLodash() exportTasks.push({ @@ -158,23 +267,6 @@ export default function formatHTML (props) { inlineScripts += ` CodeMirror.modeURL = 'js/codemirror/mode/%N/%N.js'; -function decodeEntities (text) { - var entities = [ - ['apos', '\\''], - ['amp', '&'], - ['lt', '<'], - ['gt', '>'], - ['#63', '\\?'], - ['#36', '\\$'] - ] - - for (var i = 0, max = entities.length; i < max; ++i) { - text = text.replace(new RegExp(\`&\${entities[i][0]};\`, 'g'), entities[i][1]) - } - - return text -} - function displayCodeBlocks () { _.forEach( document.querySelectorAll('.code code'), @@ -197,13 +289,140 @@ document.addEventListener('DOMContentLoaded', displayCodeBlocks); ` } + let flowchart = false + function addFlowchart () { + if (flowchart) { + return + } + + flowchart = true + + addDecodeEntities() + addLodash() + addRaphael() + + exportTasks.push({ + src: unprefix(`${appPath}/node_modules/flowchart.js/release/flowchart.min.js`), + dst: 'js' + }) + + scripts += `` + + inlineScripts += ` +function displayFlowcharts () { + _.forEach( + document.querySelectorAll('.flowchart'), + el => { + try { + const diagram = flowchart.parse( + decodeEntities(el.innerHTML) + ) + el.innerHTML = '' + diagram.drawSVG(el) + } catch (e) { + el.className = 'flowchart-error' + el.innerHTML = 'Flowchart parse error: ' + e.message + } + } + ) +} + +document.addEventListener('DOMContentLoaded', displayFlowcharts); +` + } + + let mermaid = false + function addMermaid () { + if (mermaid) { + return + } + + mermaid = true + + addLodash() + + exportTasks.push({ + src: unprefix(`${appPath}/node_modules/mermaid/dist/mermaid.min.js`), + dst: 'js' + }) + + scripts += `` + + const isDarkTheme = theme === 'dark' || theme === 'solarized-dark' || theme === 'monokai' || theme === 'dracula' + + inlineScripts += ` +function displayMermaids () { + _.forEach( + document.querySelectorAll('.mermaid'), + el => { + const height = el.attributes.getNamedItem('data-height') + if (height && height.value !== 'undefined') { + el.style.height = height.value + 'vh' + } + } + ) +} + +document.addEventListener('DOMContentLoaded', displayMermaids); +` + } + + let sequence = false + function addSequence () { + if (sequence) { + return + } + + sequence = true + + addDecodeEntities() + addLodash() + addRaphael() + + exportTasks.push({ + src: unprefix(`${appPath}/node_modules/js-sequence-diagrams/fucknpm/sequence-diagram-min.js`), + dst: 'js' + }) + + scripts += `` + + inlineScripts += ` +function displaySequences () { + _.forEach( + document.querySelectorAll('.sequence'), + el => { + try { + const diagram = Diagram.parse( + decodeEntities(el.innerHTML) + ) + el.innerHTML = '' + diagram.drawSVG(el, { theme: 'simple' }) + } catch (e) { + el.className = 'sequence-error' + el.innerHTML = 'Sequence diagram parse error: ' + e.message + } + } + ) +} + +document.addEventListener('DOMContentLoaded', displaySequences); +` + } + const modes = {} const markdown = new Markdown({ typographer: smartQuotes, sanitize, breaks, onFence (type, mode) { - if (type === 'code') { + if (type === 'chart') { + addChart() + + if (mode === 'yaml') { + addYAML() + } + } + else if (type === 'code') { addCodeMirror() if (mode && modes[mode] !== true) { @@ -218,6 +437,12 @@ document.addEventListener('DOMContentLoaded', displayCodeBlocks); modes[mode] = true } } + } else if (type === 'flowchart') { + addFlowchart() + } else if (type === 'mermaid') { + addMermaid() + } else if (type === 'sequence') { + addSequence() } } })