From b29d2c0a311b1ebca10b71e55e61fede6388dbdd Mon Sep 17 00:00:00 2001 From: Yukai Huang Date: Fri, 1 May 2020 12:14:59 +0800 Subject: [PATCH] Implement cspreview renderer Signed-off-by: Yukai Huang --- package-lock.json | 6 ++++ package.json | 1 + public/js/extra.js | 7 +++++ public/js/index.js | 4 ++- public/js/lib/renderer/csvpreview.js | 43 ++++++++++++++++++++++++++++ public/js/lib/syncscroll.js | 14 +++++++++ 6 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 public/js/lib/renderer/csvpreview.js diff --git a/package-lock.json b/package-lock.json index 2b8efafe..59bce698 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12024,6 +12024,12 @@ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, + "papaparse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.2.0.tgz", + "integrity": "sha512-ylq1wgUSnagU+MKQtNeVqrPhZuMYBvOSL00DHycFTCxownF95gpLAk1HiHdUW77N8yxRq1qHXLdlIPyBSG9NSA==", + "dev": true + }, "parallel-transform": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", diff --git a/package.json b/package.json index cbdcdd50..0e38cb59 100644 --- a/package.json +++ b/package.json @@ -169,6 +169,7 @@ "mock-require": "~3.0.3", "nyc": "~14.0.0", "optimize-css-assets-webpack-plugin": "~5.0.0", + "papaparse": "^5.2.0", "pdfobject": "~2.1.1", "plantuml-encoder": "^1.2.5", "power-assert": "~1.6.1", diff --git a/public/js/extra.js b/public/js/extra.js index b3ea2409..10e163d2 100644 --- a/public/js/extra.js +++ b/public/js/extra.js @@ -25,6 +25,7 @@ import { } from './lib/markdown/utils' import { renderFretBoard } from './lib/renderer/fretboard/fretboard' import './lib/renderer/lightbox' +import { renderCSVPreview } from './lib/renderer/csvpreview' import markdownit from 'markdown-it' import markdownitContainer from 'markdown-it-container' @@ -1211,6 +1212,12 @@ md.renderer.rules.fence = (tokens, idx, options, env, self) => { if (info) { langName = info.split(/\s+/g)[0] + + if (langName === 'csvpreview') { + const params = parseFenceCodeParams(info) + return renderCSVPreview(token.content, params) + } + if (/!$/.test(info)) token.attrJoin('class', 'wrap') token.attrJoin('class', options.langPrefix + langName.replace(/=$|=\d+$|=\+$|!$|=!$/, '')) token.attrJoin('class', 'hljs') diff --git a/public/js/index.js b/public/js/index.js index f5010960..47203a55 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -2786,7 +2786,9 @@ function updateViewInner () { var lastMeta = md.meta md.meta = {} delete md.metaError - var rendered = md.render(value) + const mdEnv = {} + window.mdTokens = md.parse(value, mdEnv) + let rendered = md.renderer.render(window.mdTokens, md.options, mdEnv) if (md.meta.type && md.meta.type === 'slide') { var slideOptions = { separator: '^(\r\n?|\n)---(\r\n?|\n)$', diff --git a/public/js/lib/renderer/csvpreview.js b/public/js/lib/renderer/csvpreview.js new file mode 100644 index 00000000..da12d720 --- /dev/null +++ b/public/js/lib/renderer/csvpreview.js @@ -0,0 +1,43 @@ +import Papa from 'papaparse' + +const safeParse = d => { + try { + return JSON.parse(d) + } catch (err) { + return d + } +} + +export function renderCSVPreview (csv, options = {}, attr = '') { + const opt = Object.keys(options).reduce((acc, key) => { + return Object.assign(acc, { + [key]: safeParse(options[key]) + }) + }, {}) + + const results = Papa.parse(csv.trim(), opt) + + if (opt.header) { + const fields = results.meta.fields + return ` + + + ${fields.map(f => ``).join('')} + + + + ${results.data.map(d => ` + ${fields.map(f => ``).join('')} + `).join('')} + +
${f}
${d[f]}
` + } else { + return ` + + ${results.data.map(d => ` + ${d.map(f => ``).join('')} + `).join('')} + +
${f}
` + } +} diff --git a/public/js/lib/syncscroll.js b/public/js/lib/syncscroll.js index df771c8e..41f0af1f 100644 --- a/public/js/lib/syncscroll.js +++ b/public/js/lib/syncscroll.js @@ -7,6 +7,8 @@ import markdownitContainer from 'markdown-it-container' import { md } from '../extra' import modeType from './modeType' import appState from './appState' +import { renderCSVPreview } from './renderer/csvpreview' +import { parseFenceCodeParams } from './markdown/utils' function addPart (tokens, idx) { if (tokens[idx].map && tokens[idx].level === 0) { @@ -71,6 +73,18 @@ md.renderer.rules.fence = (tokens, idx, options, env, self) => { if (info) { langName = info.split(/\s+/g)[0] + + if (langName === 'csvpreview') { + const params = parseFenceCodeParams(info) + let attr = '' + if (tokens[idx].map && tokens[idx].level === 0) { + const startline = tokens[idx].map[0] + 1 + const endline = tokens[idx].map[1] + attr = `class="part" data-startline="${startline}" data-endline="${endline}"` + } + return renderCSVPreview(token.content, params, attr) + } + if (/!$/.test(info)) token.attrJoin('class', 'wrap') token.attrJoin('class', options.langPrefix + langName.replace(/=$|=\d+$|=\+$|!$|=!/, '')) token.attrJoin('class', 'hljs')