Skip to content

Commit 4fe0f07

Browse files
authored
Merge pull request #1506 from hackmdio/feature/csvpreview
2 parents a569881 + 731cec6 commit 4fe0f07

File tree

6 files changed

+96
-0
lines changed

6 files changed

+96
-0
lines changed

package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@
169169
"mock-require": "~3.0.3",
170170
"nyc": "~14.0.0",
171171
"optimize-css-assets-webpack-plugin": "~5.0.0",
172+
"papaparse": "^5.2.0",
172173
"pdfobject": "~2.1.1",
173174
"plantuml-encoder": "^1.2.5",
174175
"power-assert": "~1.6.1",

public/docs/features.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,30 @@ When you’re a carpenter making a beautiful chest of drawers, you’re not goin
208208
> > Even support the nest blockquotes!
209209
> > [name=ChengHan Wu] [time=Sun, Jun 28, 2015 10:00 PM] [color=red]
210210
211+
### Render CSV as table
212+
213+
You can use write csv in the codeblock:
214+
215+
~~~md
216+
```csvpreview {header="true"}
217+
firstName,lastName,email,phoneNumber
218+
John,Doe,john@doe.com,0123456789
219+
Jane,Doe,jane@doe.com,9876543210
220+
James,Bond,james.bond@mi6.co.uk,0612345678
221+
```
222+
~~~
223+
224+
which rendered to:
225+
226+
```csvpreview {header="true"}
227+
firstName,lastName,email,phoneNumber
228+
John,Doe,john@doe.com,0123456789
229+
Jane,Doe,jane@doe.com,9876543210
230+
James,Bond,james.bond@mi6.co.uk,0612345678
231+
```
232+
233+
We use [Papa Parse](https://www.papaparse.com/) for parsing csv. The parsing option is given in braces: `{}`, and multiple options are seperated by a space. e.g. `{header="true" delimiter="."}`. Please read [their documentation](https://www.papaparse.com/docs#config) as reference.
234+
211235
## Externals
212236

213237
### YouTube

public/js/extra.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
} from './lib/markdown/utils'
2626
import { renderFretBoard } from './lib/renderer/fretboard/fretboard'
2727
import './lib/renderer/lightbox'
28+
import { renderCSVPreview } from './lib/renderer/csvpreview'
2829

2930
import markdownit from 'markdown-it'
3031
import markdownitContainer from 'markdown-it-container'
@@ -1211,6 +1212,12 @@ md.renderer.rules.fence = (tokens, idx, options, env, self) => {
12111212

12121213
if (info) {
12131214
langName = info.split(/\s+/g)[0]
1215+
1216+
if (langName === 'csvpreview') {
1217+
const params = parseFenceCodeParams(info)
1218+
return renderCSVPreview(token.content, params)
1219+
}
1220+
12141221
if (/!$/.test(info)) token.attrJoin('class', 'wrap')
12151222
token.attrJoin('class', options.langPrefix + langName.replace(/=$|=\d+$|=\+$|!$|=!$/, ''))
12161223
token.attrJoin('class', 'hljs')

public/js/lib/renderer/csvpreview.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import Papa from 'papaparse'
2+
import escapeHTML from 'lodash/escape'
3+
4+
const safeParse = d => {
5+
try {
6+
return JSON.parse(d)
7+
} catch (err) {
8+
return d
9+
}
10+
}
11+
12+
export function renderCSVPreview (csv, options = {}, attr = '') {
13+
const opt = Object.keys(options).reduce((acc, key) => {
14+
return Object.assign(acc, {
15+
[key]: safeParse(options[key])
16+
})
17+
}, {})
18+
19+
const results = Papa.parse(csv.trim(), opt)
20+
21+
if (opt.header) {
22+
const fields = results.meta.fields
23+
return `<table ${attr}>
24+
<thead>
25+
<tr>
26+
${fields.map(f => `<th>${escapeHTML(f)}</th>`).join('')}
27+
</tr>
28+
</thead>
29+
<tbody>
30+
${results.data.map(d => `<tr>
31+
${fields.map(f => `<td>${escapeHTML(d[f])}</td>`).join('')}
32+
</tr>`).join('')}
33+
</tbody>
34+
</table>`
35+
} else {
36+
return `<table ${attr}>
37+
<tbody>
38+
${results.data.map(d => `<tr>
39+
${d.map(f => `<td>${escapeHTML(f)}</td>`).join('')}
40+
</tr>`).join('')}
41+
</tbody>
42+
</table>`
43+
}
44+
}

public/js/lib/syncscroll.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import markdownitContainer from 'markdown-it-container'
77
import { md } from '../extra'
88
import modeType from './modeType'
99
import appState from './appState'
10+
import { renderCSVPreview } from './renderer/csvpreview'
11+
import { parseFenceCodeParams } from './markdown/utils'
1012

1113
function addPart (tokens, idx) {
1214
if (tokens[idx].map && tokens[idx].level === 0) {
@@ -71,6 +73,18 @@ md.renderer.rules.fence = (tokens, idx, options, env, self) => {
7173

7274
if (info) {
7375
langName = info.split(/\s+/g)[0]
76+
77+
if (langName === 'csvpreview') {
78+
const params = parseFenceCodeParams(info)
79+
let attr = ''
80+
if (tokens[idx].map && tokens[idx].level === 0) {
81+
const startline = tokens[idx].map[0] + 1
82+
const endline = tokens[idx].map[1]
83+
attr = `class="part" data-startline="${startline}" data-endline="${endline}"`
84+
}
85+
return renderCSVPreview(token.content, params, attr)
86+
}
87+
7488
if (/!$/.test(info)) token.attrJoin('class', 'wrap')
7589
token.attrJoin('class', options.langPrefix + langName.replace(/=$|=\d+$|=\+$|!$|=!/, ''))
7690
token.attrJoin('class', 'hljs')

0 commit comments

Comments
 (0)