diff --git a/ReactNativeClient/lib/import-enex-md-gen.js b/ReactNativeClient/lib/import-enex-md-gen.js index e11afa5a62..fa862050b6 100644 --- a/ReactNativeClient/lib/import-enex-md-gen.js +++ b/ReactNativeClient/lib/import-enex-md-gen.js @@ -320,15 +320,6 @@ function enexXmlToMdArray(stream, resources) { type: 'table', lines: [], parent: section, - toString: function() { - let output = []; - output.push(BLOCK_OPEN); - for (let i = 0; i < this.lines.length; i++) { - output = output.concat(this.lines[i].toMdLines()); - } - output.push(BLOCK_CLOSE); - return processMdArrayNewLines(output); - }, }; section.lines.push(newSection); section = newSection; @@ -345,17 +336,6 @@ function enexXmlToMdArray(stream, resources) { lines: [], parent: section, isHeader: false, - // Normally tables are rendered properly as markdown, but for table within table within table... we cannot - // handle this in Markdown so simply render it as one cell per line. - toMdLines: function() { - let output = []; - output.push(BLOCK_OPEN); - for (let i = 0; i < this.lines.length; i++) { - output.push(this.lines[i].toString()); - } - output.push(BLOCK_CLOSE); - return output; - }, } section.lines.push(newSection); @@ -372,9 +352,6 @@ function enexXmlToMdArray(stream, resources) { type: 'td', lines: [], parent: section, - toString: function() { - return processMdArrayNewLines(this.lines); - }, }; section.lines.push(newSection); @@ -577,6 +554,18 @@ function enexXmlToMdArray(stream, resources) { section.lines.pop(); section.lines.push(url); } else { + // Need to remove any new line character between the current ']' and the previous '[' + // otherwise it won't render properly. + for (let i = section.lines.length - 1; i >= 0; i--) { + const c = section.lines[i]; + if (c === '[') { + break; + } else { + if (c === BLOCK_CLOSE || c === BLOCK_OPEN || c === NEWLINE) { + section.lines[i] = SPACE; + } + } + } section.lines.push('](' + url + ')'); } } else if (isListTag(n)) { @@ -607,50 +596,28 @@ function enexXmlToMdArray(stream, resources) { }); } -function setTableCellContent(table) { - if (!table.type == 'table') throw new Error('Only for tables'); - - for (let trIndex = 0; trIndex < table.lines.length; trIndex++) { - const tr = table.lines[trIndex]; - for (let tdIndex = 0; tdIndex < tr.lines.length; tdIndex++) { - let td = tr.lines[tdIndex]; - td.content = processMdArrayNewLines(td.lines); - td.content = td.content.replace(/\n\n\n\n\n/g, ' '); - td.content = td.content.replace(/\n\n\n\n/g, ' '); - td.content = td.content.replace(/\n\n\n/g, ' '); - td.content = td.content.replace(/\n\n/g, ' '); - td.content = td.content.replace(/\n/g, ' '); - } - } - - return table; +function removeTableCellNewLines(cellText) { + return cellText.replace(/\n+/g, " "); } -function cellWidth(cellText) { - const lines = cellText.split("\n"); - let maxWidth = 0; - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - if (line.length > maxWidth) maxWidth = line.length; - } - return maxWidth; -} - -function colWidths(table) { - let output = []; +function tableHasSubTables(table) { for (let trIndex = 0; trIndex < table.lines.length; trIndex++) { const tr = table.lines[trIndex]; for (let tdIndex = 0; tdIndex < tr.lines.length; tdIndex++) { const td = tr.lines[tdIndex]; - const w = Math.min(cellWidth(td.content), 20); // Have to set a max width otherwise it can be extremely long for notes that import entire web pages (eg. Hacker News comment pages) - if (output.length <= tdIndex) output.push(0); - if (w > output[tdIndex]) output[tdIndex] = w; + for (let i = 0; i < td.lines.length; i++) { + if (typeof td.lines[i] === 'object') return true; + } } } - return output; + return false; } -function drawTable(table, colWidths) { +// Markdown tables don't support tables within tables, which is common in notes that are complete web pages, for example when imported +// via Web Clipper. So to handle this, we render all the outer tables as regular text (as if replacing all the
+// elements by ) and only the inner ones, those that don't contain any other tables, are rendered as actual tables. This is generally
+// the required behaviour since the outer tables are usually for layout and the inner ones are the content.
+function drawTable(table) {
// | First Header | Second Header |
// | ------------- | ------------- |
// | Content Cell | Content Cell |
@@ -658,8 +625,11 @@ function drawTable(table, colWidths) {
// There must be at least 3 dashes separating each header cell.
// https://gist.github.com/IanWang/28965e13cdafdef4e11dc91f578d160d#tables
+
+ const flatRender = tableHasSubTables(table); // Render the table has regular text
const minColWidth = 3;
let lines = [];
+ lines.push(BLOCK_OPEN);
let headerDone = false;
for (let trIndex = 0; trIndex < table.lines.length; trIndex++) {
const tr = table.lines[trIndex];
@@ -667,37 +637,79 @@ function drawTable(table, colWidths) {
let line = [];
let headerLine = [];
let emptyHeader = null;
- for (let tdIndex = 0; tdIndex < colWidths.length; tdIndex++) {
- const width = Math.max(minColWidth, colWidths[tdIndex]);
- const cell = tr.lines[tdIndex] ? tr.lines[tdIndex].content : '';
- line.push(stringPadding(cell, width, ' ', stringPadding.RIGHT));
+ for (let tdIndex = 0; tdIndex < tr.lines.length; tdIndex++) {
+ const td = tr.lines[tdIndex];
- if (!headerDone) {
- if (!isHeader) {
- if (!emptyHeader) emptyHeader = [];
- let h = stringPadding(' ', width, ' ', stringPadding.RIGHT);
- if (!width) h = '';
- emptyHeader.push(h);
+ if (flatRender) {
+ line.push(BLOCK_OPEN);
+
+ let currentCells = [];
+
+ const renderCurrentCells = () => {
+ if (!currentCells.length) return;
+ const cellText = processMdArrayNewLines(currentCells);
+ line.push(cellText);
+ currentCells = [];
}
- headerLine.push('-'.repeat(width));
+
+ // In here, recursively render the tables
+ for (let i = 0; i < td.lines.length; i++) {
+ const c = td.lines[i];
+ if (typeof c === 'object') { // This is a table
+ renderCurrentCells();
+ currentCells = currentCells.concat(drawTable(c));
+ } else { // This is plain text
+ currentCells.push(c);
+ }
+ }
+
+ renderCurrentCells();
+
+ line.push(BLOCK_CLOSE);
+ } else { // Regular table rendering
+
+ // A cell in a Markdown table cannot have new lines so remove them
+ const cellText = removeTableCellNewLines(processMdArrayNewLines(td.lines));
+
+ const width = Math.max(cellText.length, 3);
+ line.push(stringPadding(cellText, width, ' ', stringPadding.RIGHT));
+
+ if (!headerDone) {
+ if (!isHeader) {
+ if (!emptyHeader) emptyHeader = [];
+ let h = stringPadding(' ', width, ' ', stringPadding.RIGHT);
+ emptyHeader.push(h);
+ }
+ headerLine.push('-'.repeat(width));
+ }
+
}
}
- if (emptyHeader) {
- lines.push('| ' + emptyHeader.join(' | ') + ' |');
- lines.push('| ' + headerLine.join(' | ') + ' |');
+ if (flatRender) {
headerDone = true;
- }
+ lines.push(BLOCK_OPEN);
+ lines = lines.concat(line);
+ lines.push(BLOCK_CLOSE);
+ } else {
+ if (emptyHeader) {
+ lines.push('| ' + emptyHeader.join(' | ') + ' |');
+ lines.push('| ' + headerLine.join(' | ') + ' |');
+ headerDone = true;
+ }
- lines.push('| ' + line.join(' | ') + ' |');
+ lines.push('| ' + line.join(' | ') + ' |');
- if (!headerDone) {
- lines.push('| ' + headerLine.join(' | ') + ' |');
- headerDone = true;
+ if (!headerDone) {
+ lines.push('| ' + headerLine.join(' | ') + ' |');
+ headerDone = true;
+ }
}
}
- return lines.join('<<<<:D>>>>' + NEWLINE + '<<<<:D>>>>').split('<<<<:D>>>>');
+ lines.push(BLOCK_CLOSE);
+
+ return flatRender ? lines : lines.join('<<<<:D>>>>' + NEWLINE + '<<<<:D>>>>').split('<<<<:D>>>>');
}
async function enexXmlToMd(stream, resources) {
@@ -708,13 +720,9 @@ async function enexXmlToMd(stream, resources) {
for (let i = 0; i < result.content.lines.length; i++) {
let line = result.content.lines[i];
if (typeof line === 'object') { // A table
- let table = setTableCellContent(line);
- //console.log(require('util').inspect(table, false, null))
- const cw = colWidths(table);
- const tableLines = drawTable(table, cw);
- mdLines.push(BLOCK_OPEN);
+ const table = line;
+ const tableLines = drawTable(table);
mdLines = mdLines.concat(tableLines);
- mdLines.push(BLOCK_CLOSE);
} else { // an actual line
mdLines.push(line);
}
|