From c197d89ddc7b925c0b00f7e62db0c4ca82d720c8 Mon Sep 17 00:00:00 2001
From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
Date: Wed, 18 Dec 2024 03:51:03 -0800
Subject: [PATCH] Desktop: Fixes #11382: Rich Text Editor: Fix resized images
in lists break sub-list items (#11532)
---
.../image_preserve_size_in_lists.html | 33 +++++++++++++++++
.../image_preserve_size_in_lists.md | 11 ++++++
packages/turndown/src/commonmark-rules.js | 35 ++++++++++++++++++-
3 files changed, 78 insertions(+), 1 deletion(-)
create mode 100644 packages/app-cli/tests/html_to_md/image_preserve_size_in_lists.html
create mode 100644 packages/app-cli/tests/html_to_md/image_preserve_size_in_lists.md
diff --git a/packages/app-cli/tests/html_to_md/image_preserve_size_in_lists.html b/packages/app-cli/tests/html_to_md/image_preserve_size_in_lists.html
new file mode 100644
index 000000000..2050b05ba
--- /dev/null
+++ b/packages/app-cli/tests/html_to_md/image_preserve_size_in_lists.html
@@ -0,0 +1,33 @@
+
+ -
+
+
+ - HTML images just before a sublist should have a closing <img> tag added.
+ - Otherwise, when rendered to Markdown again, the subsequent list items will be rendered as HTML.
+
+
+ -
+
+
+ A closing tag is also necessary if the image is followed by content on a new line.
+
+ -
+
+
+ - Similar logic isn't necessary for images converted to Markdown.
+
+
+ -
+
+
+ - It also isn't necessary if the next item is at the same level as the image...
+ -
+ ...or if the image has text just before it.
+
+
+
+
\ No newline at end of file
diff --git a/packages/app-cli/tests/html_to_md/image_preserve_size_in_lists.md b/packages/app-cli/tests/html_to_md/image_preserve_size_in_lists.md
new file mode 100644
index 000000000..6ca842d2f
--- /dev/null
+++ b/packages/app-cli/tests/html_to_md/image_preserve_size_in_lists.md
@@ -0,0 +1,11 @@
+-
+ - HTML images just before a sublist should have a closing <img> tag added.
+ - Otherwise, when rendered to Markdown again, the subsequent list items will be rendered as HTML.
+-
+ **A closing tag is also necessary if the image is followed by content on a new line.**
+- ![](:/0123456789abcdef0123456789abcdef)
+ - Similar logic isn't necessary for images converted to Markdown.
+-
+- It also isn't necessary if the next item is at the same level as the image...
+- ...or if the image has text just before it.
+ - See [this issue](https://github.com/laurent22/joplin/issues/11382) for details.
\ No newline at end of file
diff --git a/packages/turndown/src/commonmark-rules.js b/packages/turndown/src/commonmark-rules.js
index b2a3249d2..7b94a38ad 100644
--- a/packages/turndown/src/commonmark-rules.js
+++ b/packages/turndown/src/commonmark-rules.js
@@ -561,7 +561,40 @@ function imageMarkdownFromNode(node, options = null) {
}, options);
if (options.preserveImageTagsWithSize && (node.getAttribute('width') || node.getAttribute('height'))) {
- return node.outerHTML;
+ let html = node.outerHTML;
+
+ // To prevent markup immediately after the image from being interpreted as HTML, a closing tag
+ // is sometimes necessary.
+ const needsClosingTag = () => {
+ const parent = node.parentElement;
+ if (!parent || parent.nodeName !== 'LI') return false;
+ const hasClosingTag = html.match(/<\/[a-z]+\/>$/ig);
+ if (hasClosingTag) {
+ return false;
+ }
+
+ const allChildren = [...parent.childNodes];
+ const nonEmptyChildren = allChildren.filter(item => {
+ // Even if surrounded by #text nodes that only contain whitespace, Markdown after
+ // an can still be incorrectly interpreted as HTML. Only non-empty #texts seem
+ // to prevent this.
+ return item.nodeName !== '#text' || item.textContent.trim() !== '';
+ });
+
+ const imageIndex = nonEmptyChildren.indexOf(node);
+ const hasNextSibling = imageIndex + 1 < nonEmptyChildren.length;
+ const nextSiblingName = hasNextSibling ? (
+ nonEmptyChildren[imageIndex + 1].nodeName
+ ) : null;
+
+ const nextSiblingIsNewLine = nextSiblingName === 'UL' || nextSiblingName === 'OL' || nextSiblingName === 'BR';
+ return imageIndex === 0 && nextSiblingIsNewLine;
+ };
+
+ if (needsClosingTag()) {
+ html = html.replace(/[/]?>$/, `>${node.nodeName.toLowerCase()}>`);
+ }
+ return html;
}
return imageMarkdownFromAttributes({