From 144ec1eea25519c2893f9b60ebc41c8aae8d20bb Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Fri, 22 Dec 2023 01:27:20 -0800 Subject: [PATCH 1/4] Desktop: Fixes #9543: Fix nested tables not preserved in rich text editor (#9579) --- .../tests/html_to_md/preserve_nested_tables.html | 6 +++--- .../app-cli/tests/html_to_md/preserve_nested_tables.md | 2 +- packages/turndown-plugin-gfm/src/tables.js | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/app-cli/tests/html_to_md/preserve_nested_tables.html b/packages/app-cli/tests/html_to_md/preserve_nested_tables.html index 3e0509f91b..335c6c13ac 100644 --- a/packages/app-cli/tests/html_to_md/preserve_nested_tables.html +++ b/packages/app-cli/tests/html_to_md/preserve_nested_tables.html @@ -1,10 +1,10 @@ - +
tag should only have
Left side of the main table - -

Nested Table

+
+Nested Table diff --git a/packages/app-cli/tests/html_to_md/preserve_nested_tables.md b/packages/app-cli/tests/html_to_md/preserve_nested_tables.md index f9c47f3bb4..4c3d10dde1 100644 --- a/packages/app-cli/tests/html_to_md/preserve_nested_tables.md +++ b/packages/app-cli/tests/html_to_md/preserve_nested_tables.md @@ -1 +1 @@ -
nested table C1 nested table C2
Left side of the main table

Nested Table

nested table C1nested table C2
nested tablenested table
\ No newline at end of file +
Left side of the main tableNested Table
nested table C1nested table C2
nested tablenested table
\ No newline at end of file diff --git a/packages/turndown-plugin-gfm/src/tables.js b/packages/turndown-plugin-gfm/src/tables.js index 9cdb10ff78..391a5fa24e 100644 --- a/packages/turndown-plugin-gfm/src/tables.js +++ b/packages/turndown-plugin-gfm/src/tables.js @@ -74,8 +74,8 @@ rules.tableRow = { rules.table = { // Only convert tables that can result in valid Markdown // Other tables are kept as HTML using `keep` (see below). - filter: function (node) { - return node.nodeName === 'TABLE' && !tableShouldBeHtml(node); + filter: function (node, options) { + return node.nodeName === 'TABLE' && !tableShouldBeHtml(node, options); }, replacement: function (content, node) { @@ -174,7 +174,7 @@ const nodeContains = (node, types) => { return false; } -const tableShouldBeHtml = (tableNode, preserveNestedTables) => { +const tableShouldBeHtml = (tableNode, options) => { const possibleTags = [ 'UL', 'OL', @@ -193,7 +193,7 @@ const tableShouldBeHtml = (tableNode, preserveNestedTables) => { // that's made of HTML tables. In that case we have this logic of removing the // outer table and keeping only the inner ones. For the Rich Text editor // however we always want to keep nested tables. - if (preserveNestedTables) possibleTags.push('TABLE'); + if (options.preserveNestedTables) possibleTags.push('TABLE'); return nodeContains(tableNode, 'code') || nodeContains(tableNode, possibleTags); @@ -249,7 +249,7 @@ export default function tables (turndownService) { isCodeBlock_ = turndownService.isCodeBlock; turndownService.keep(function (node) { - if (node.nodeName === 'TABLE' && tableShouldBeHtml(node, turndownService.options.preserveNestedTables)) return true; + if (node.nodeName === 'TABLE' && tableShouldBeHtml(node, turndownService.options)) return true; return false; }); for (var key in rules) turndownService.addRule(key, rules[key]) From d264bdd14d2832ddcb88a135fd713c28f8c8152e Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sat, 16 Dec 2023 12:01:37 +0000 Subject: [PATCH 2/4] Desktop, Cli: Fixed importing invalid tables from ENEX files --- .../app-cli/tests/enex_to_md/ImportTestCorrupt.enex | 2 +- .../tests/enex_to_md/table_with_invalid_content.html | 11 +++++++++++ .../tests/enex_to_md/table_with_invalid_content.md | 4 ++++ packages/lib/import-enex-md-gen.ts | 8 ++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 packages/app-cli/tests/enex_to_md/table_with_invalid_content.html create mode 100644 packages/app-cli/tests/enex_to_md/table_with_invalid_content.md diff --git a/packages/app-cli/tests/enex_to_md/ImportTestCorrupt.enex b/packages/app-cli/tests/enex_to_md/ImportTestCorrupt.enex index e605132663..6c256d14a1 100755 --- a/packages/app-cli/tests/enex_to_md/ImportTestCorrupt.enex +++ b/packages/app-cli/tests/enex_to_md/ImportTestCorrupt.enex @@ -7,7 +7,7 @@
Plain note
]]>20201223T163948Z20201223T163953Zlaurent22777@gmail.comdesktop.winevernote.win32Note 2 -

test
test

bl
bla
bla


]]>
20201223T164010Z20201223T164023Zlaurent22777@gmail.comdesktop.winevernote.win32
plain note 2 +

test
test

bl
bla
bla


]]>
20201223T164010Z20201223T164023Zlaurent22777@gmail.comdesktop.winevernote.win32
plain note 2

]]>
20201223T164236Zlaurent22777@gmail.comdesktop.winevernote.win32
diff --git a/packages/app-cli/tests/enex_to_md/table_with_invalid_content.html b/packages/app-cli/tests/enex_to_md/table_with_invalid_content.html new file mode 100644 index 0000000000..f74f7fb2c9 --- /dev/null +++ b/packages/app-cli/tests/enex_to_md/table_with_invalid_content.html @@ -0,0 +1,11 @@ + + + + + + +
+ + + +
onetwo
threefour
\ No newline at end of file diff --git a/packages/app-cli/tests/enex_to_md/table_with_invalid_content.md b/packages/app-cli/tests/enex_to_md/table_with_invalid_content.md new file mode 100644 index 0000000000..953d1f3a89 --- /dev/null +++ b/packages/app-cli/tests/enex_to_md/table_with_invalid_content.md @@ -0,0 +1,4 @@ +| | | +| --- | --- | +| one | two | +| three | four | \ No newline at end of file diff --git a/packages/lib/import-enex-md-gen.ts b/packages/lib/import-enex-md-gen.ts index a8a459a5d0..5440e568e6 100644 --- a/packages/lib/import-enex-md-gen.ts +++ b/packages/lib/import-enex-md-gen.ts @@ -1246,6 +1246,14 @@ function drawTable(table: Section) { for (let tdIndex = 0; tdIndex < tr.lines.length; tdIndex++) { const td = tr.lines[tdIndex]; + if (typeof td === 'string') { + // A
tags as direct children. + // However certain Evernote notes can contain other random tags + // such as empty DIVs. In that case we just skip the content. + // See test "table_with_invalid_content.html". + continue; + } + if (flatRender) { line.push(BLOCK_OPEN); From 495f08832057afb744384db14f9c914bbcefc243 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Sun, 17 Dec 2023 12:00:05 +0000 Subject: [PATCH 3/4] Desktop, Cli: Remove unnecessary warning when importing ENEX file --- packages/lib/import-enex.ts | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/packages/lib/import-enex.ts b/packages/lib/import-enex.ts index d3048890e1..bd04eec792 100644 --- a/packages/lib/import-enex.ts +++ b/packages/lib/import-enex.ts @@ -151,18 +151,22 @@ interface ExtractedNote extends NoteEntity { tags?: string[]; title?: string; bodyXml?: string; - // is_todo?: boolean; } -// At this point we have the resource has it's been parsed from the XML, but additional -// processing needs to be done to get the final resource file, its size, MD5, etc. +// At this point we have the resource as it's been parsed from the XML, but +// additional processing needs to be done to get the final resource file, its +// size, MD5, etc. async function processNoteResource(resource: ExtractedResource) { - if (!resource.hasData) { - // Some resources have no data, go figure, so we need a special case for this. - resource.id = md5(Date.now() + Math.random()); + const handleNoDataResource = async (resource: ExtractedResource, setId: boolean) => { + if (setId) resource.id = md5(Date.now() + Math.random()); resource.size = 0; resource.dataFilePath = `${Setting.value('tempDir')}/${resource.id}.empty`; await fs.writeFile(resource.dataFilePath, ''); + }; + + if (!resource.hasData) { + // Some resources have no data, go figure, so we need a special case for this. + await handleNoDataResource(resource, true); } else { if (resource.dataEncoding === 'base64') { const decodedFilePath = `${resource.dataFilePath}.decoded`; @@ -176,16 +180,19 @@ async function processNoteResource(resource: ExtractedResource) { resource.size = stats.size; if (!resource.id) { - // If no resource ID is present, the resource ID is actually the MD5 of the data. - // This ID will match the "hash" attribute of the corresponding tag. - // resourceId = md5(decodedData); + // If no resource ID is present, the resource ID is actually the MD5 + // of the data. This ID will match the "hash" attribute of the + // corresponding tag. resourceId = md5(decodedData); resource.id = await md5File(resource.dataFilePath); } if (!resource.id || !resource.size) { - const debugTemp = { ...resource }; - debugTemp.data = debugTemp.data ? `${debugTemp.data.substr(0, 32)}...` : debugTemp.data; - throw new Error(`This resource was not added because it has no ID or no content: ${JSON.stringify(debugTemp)}`); + // Don't throw an error because it happens semi-frequently, + // especially on notes that comes from the Evernote Web Clipper and + // we can't do anything about it. Previously we would throw the + // error "This resource was not added because it has no ID or no + // content". + await handleNoDataResource(resource, !resource.id); } } From 973193623a42ba6f54e1c8fec2b3ce67e7cc76aa Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 22 Dec 2023 09:30:38 +0000 Subject: [PATCH 4/4] Desktop release v2.13.10 --- packages/app-desktop/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app-desktop/package.json b/packages/app-desktop/package.json index fcd3e016dc..3064f41526 100644 --- a/packages/app-desktop/package.json +++ b/packages/app-desktop/package.json @@ -1,6 +1,6 @@ { "name": "@joplin/app-desktop", - "version": "2.13.9", + "version": "2.13.10", "description": "Joplin for Desktop", "main": "main.js", "private": true,