You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-13 22:12:50 +02:00
All: Improved rendering of imported ENEX tables
This commit is contained in:
@@ -320,15 +320,6 @@ function enexXmlToMdArray(stream, resources) {
|
|||||||
type: 'table',
|
type: 'table',
|
||||||
lines: [],
|
lines: [],
|
||||||
parent: section,
|
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.lines.push(newSection);
|
||||||
section = newSection;
|
section = newSection;
|
||||||
@@ -345,17 +336,6 @@ function enexXmlToMdArray(stream, resources) {
|
|||||||
lines: [],
|
lines: [],
|
||||||
parent: section,
|
parent: section,
|
||||||
isHeader: false,
|
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);
|
section.lines.push(newSection);
|
||||||
@@ -372,9 +352,6 @@ function enexXmlToMdArray(stream, resources) {
|
|||||||
type: 'td',
|
type: 'td',
|
||||||
lines: [],
|
lines: [],
|
||||||
parent: section,
|
parent: section,
|
||||||
toString: function() {
|
|
||||||
return processMdArrayNewLines(this.lines);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
section.lines.push(newSection);
|
section.lines.push(newSection);
|
||||||
@@ -577,6 +554,18 @@ function enexXmlToMdArray(stream, resources) {
|
|||||||
section.lines.pop();
|
section.lines.pop();
|
||||||
section.lines.push(url);
|
section.lines.push(url);
|
||||||
} else {
|
} 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 + ')');
|
section.lines.push('](' + url + ')');
|
||||||
}
|
}
|
||||||
} else if (isListTag(n)) {
|
} else if (isListTag(n)) {
|
||||||
@@ -607,50 +596,28 @@ function enexXmlToMdArray(stream, resources) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTableCellContent(table) {
|
function removeTableCellNewLines(cellText) {
|
||||||
if (!table.type == 'table') throw new Error('Only for tables');
|
return cellText.replace(/\n+/g, " ");
|
||||||
|
|
||||||
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 tableHasSubTables(table) {
|
||||||
}
|
|
||||||
|
|
||||||
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 = [];
|
|
||||||
for (let trIndex = 0; trIndex < table.lines.length; trIndex++) {
|
for (let trIndex = 0; trIndex < table.lines.length; trIndex++) {
|
||||||
const tr = table.lines[trIndex];
|
const tr = table.lines[trIndex];
|
||||||
for (let tdIndex = 0; tdIndex < tr.lines.length; tdIndex++) {
|
for (let tdIndex = 0; tdIndex < tr.lines.length; tdIndex++) {
|
||||||
const td = tr.lines[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)
|
for (let i = 0; i < td.lines.length; i++) {
|
||||||
if (output.length <= tdIndex) output.push(0);
|
if (typeof td.lines[i] === 'object') return true;
|
||||||
if (w > output[tdIndex]) output[tdIndex] = w;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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 <table>, <tr> and <td>
|
||||||
|
// elements by <div>) 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 |
|
// | First Header | Second Header |
|
||||||
// | ------------- | ------------- |
|
// | ------------- | ------------- |
|
||||||
// | Content Cell | Content Cell |
|
// | Content Cell | Content Cell |
|
||||||
@@ -658,8 +625,11 @@ function drawTable(table, colWidths) {
|
|||||||
|
|
||||||
// There must be at least 3 dashes separating each header cell.
|
// There must be at least 3 dashes separating each header cell.
|
||||||
// https://gist.github.com/IanWang/28965e13cdafdef4e11dc91f578d160d#tables
|
// https://gist.github.com/IanWang/28965e13cdafdef4e11dc91f578d160d#tables
|
||||||
|
|
||||||
|
const flatRender = tableHasSubTables(table); // Render the table has regular text
|
||||||
const minColWidth = 3;
|
const minColWidth = 3;
|
||||||
let lines = [];
|
let lines = [];
|
||||||
|
lines.push(BLOCK_OPEN);
|
||||||
let headerDone = false;
|
let headerDone = false;
|
||||||
for (let trIndex = 0; trIndex < table.lines.length; trIndex++) {
|
for (let trIndex = 0; trIndex < table.lines.length; trIndex++) {
|
||||||
const tr = table.lines[trIndex];
|
const tr = table.lines[trIndex];
|
||||||
@@ -667,22 +637,61 @@ function drawTable(table, colWidths) {
|
|||||||
let line = [];
|
let line = [];
|
||||||
let headerLine = [];
|
let headerLine = [];
|
||||||
let emptyHeader = null;
|
let emptyHeader = null;
|
||||||
for (let tdIndex = 0; tdIndex < colWidths.length; tdIndex++) {
|
for (let tdIndex = 0; tdIndex < tr.lines.length; tdIndex++) {
|
||||||
const width = Math.max(minColWidth, colWidths[tdIndex]);
|
const td = tr.lines[tdIndex];
|
||||||
const cell = tr.lines[tdIndex] ? tr.lines[tdIndex].content : '';
|
|
||||||
line.push(stringPadding(cell, width, ' ', stringPadding.RIGHT));
|
if (flatRender) {
|
||||||
|
line.push(BLOCK_OPEN);
|
||||||
|
|
||||||
|
let currentCells = [];
|
||||||
|
|
||||||
|
const renderCurrentCells = () => {
|
||||||
|
if (!currentCells.length) return;
|
||||||
|
const cellText = processMdArrayNewLines(currentCells);
|
||||||
|
line.push(cellText);
|
||||||
|
currentCells = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (!headerDone) {
|
||||||
if (!isHeader) {
|
if (!isHeader) {
|
||||||
if (!emptyHeader) emptyHeader = [];
|
if (!emptyHeader) emptyHeader = [];
|
||||||
let h = stringPadding(' ', width, ' ', stringPadding.RIGHT);
|
let h = stringPadding(' ', width, ' ', stringPadding.RIGHT);
|
||||||
if (!width) h = '';
|
|
||||||
emptyHeader.push(h);
|
emptyHeader.push(h);
|
||||||
}
|
}
|
||||||
headerLine.push('-'.repeat(width));
|
headerLine.push('-'.repeat(width));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (flatRender) {
|
||||||
|
headerDone = true;
|
||||||
|
lines.push(BLOCK_OPEN);
|
||||||
|
lines = lines.concat(line);
|
||||||
|
lines.push(BLOCK_CLOSE);
|
||||||
|
} else {
|
||||||
if (emptyHeader) {
|
if (emptyHeader) {
|
||||||
lines.push('| ' + emptyHeader.join(' | ') + ' |');
|
lines.push('| ' + emptyHeader.join(' | ') + ' |');
|
||||||
lines.push('| ' + headerLine.join(' | ') + ' |');
|
lines.push('| ' + headerLine.join(' | ') + ' |');
|
||||||
@@ -696,8 +705,11 @@ function drawTable(table, colWidths) {
|
|||||||
headerDone = true;
|
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) {
|
async function enexXmlToMd(stream, resources) {
|
||||||
@@ -708,13 +720,9 @@ async function enexXmlToMd(stream, resources) {
|
|||||||
for (let i = 0; i < result.content.lines.length; i++) {
|
for (let i = 0; i < result.content.lines.length; i++) {
|
||||||
let line = result.content.lines[i];
|
let line = result.content.lines[i];
|
||||||
if (typeof line === 'object') { // A table
|
if (typeof line === 'object') { // A table
|
||||||
let table = setTableCellContent(line);
|
const table = line;
|
||||||
//console.log(require('util').inspect(table, false, null))
|
const tableLines = drawTable(table);
|
||||||
const cw = colWidths(table);
|
|
||||||
const tableLines = drawTable(table, cw);
|
|
||||||
mdLines.push(BLOCK_OPEN);
|
|
||||||
mdLines = mdLines.concat(tableLines);
|
mdLines = mdLines.concat(tableLines);
|
||||||
mdLines.push(BLOCK_CLOSE);
|
|
||||||
} else { // an actual line
|
} else { // an actual line
|
||||||
mdLines.push(line);
|
mdLines.push(line);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user