diff --git a/shared/naturalcrit/markdown.js b/shared/naturalcrit/markdown.js index 9ae71214a..3a341f379 100644 --- a/shared/naturalcrit/markdown.js +++ b/shared/naturalcrit/markdown.js @@ -234,7 +234,188 @@ const definitionLists = { } }; -Markdown.use({ extensions: [mustacheSpans, mustacheDivs, mustacheInjectInline, definitionLists] }); +const spanTable = { + name : 'spanTable', + level : 'block', // Is this a block-level or inline-level tokenizer? + start(src) { return src.match(/^\n *([^\n ].*\|.*)\n/)?.index; }, // Hint to Marked.js to stop and check for a match + tokenizer(src, tokens) { + //const regex = this.tokenizer.rules.block.table; + const regex = new RegExp('^ *([^\\n ].*\\|.*\\n(?:.*?[^\\s].*\\n)*?)' // Header + + ' {0,3}(?:\\| *)?(:?-+:? *(?:\\| *:?-+:? *)*)\\|?' // Align + + '(?:\\n *((?:(?!\\n| {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})' // Cells + + '(?:\\n+|$)| {0,3}#{1,6} | {0,3}>| {4}[^\\n]| {0,3}(?:`{3,}' + + '(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n| {0,3}(?:[*+-]|1[.)]) |' + + '<\\/?(?:address|article|aside|base|basefont|blockquote|body|' + + 'caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul)(?: +|\\n|\\/?>)|<(?:script|pre|style|textarea|!--)).*(?:\\n|$))*)\\n*|$)'); // Cells + const cap = regex.exec(src); + + if(cap) { + const item = { + type : 'spanTable', + header : cap[1].replace(/\n$/, '').split('\n'), + align : cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + rows : cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [] + }; + + // Get first header row to determine how many columns + item.header[0] = splitCells(item.header[0]); + + const colCount = item.header[0].reduce((length, header)=>{ + return length + header.colspan; + }, 0); + + if(colCount === item.align.length) { + item.raw = cap[0]; + + let i, j, k, row; + + // Get alignment row (:---:) + let l = item.align.length; + + for (i = 0; i < l; i++) { + if(/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if(/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if(/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + // Get any remaining header rows + l = item.header.length; + for (i = 1; i < l; i++) { + item.header[i] = splitCells(item.header[i], colCount); + } + + // Get main table cells + l = item.rows.length; + for (i = 0; i < l; i++) { + item.rows[i] = splitCells(item.rows[i], colCount); + } + + // header child tokens + l = item.header.length; + for (j = 0; j < l; j++) { + row = item.header[j]; + for (k = 0; k < row.length; k++) { + row[k].tokens = []; + this.inlineTokens(row[k].text, row[k].tokens); + } + } + + // cell child tokens + l = item.rows.length; + for (j = 0; j < l; j++) { + row = item.rows[j]; + for (k = 0; k < row.length; k++) { + row[k].tokens = []; + this.inlineTokens(row[k].text, row[k].tokens); + } + } + return item; + } + } + }, + renderer(token) { + let i, j, row, cell, col, text; + let output = `