Skip to content

fix(mdviewer): prevent Turndown from indenting image-only links on save#2937

Merged
abose merged 1 commit into
mainfrom
ai
May 22, 2026
Merged

fix(mdviewer): prevent Turndown from indenting image-only links on save#2937
abose merged 1 commit into
mainfrom
ai

Conversation

@abose
Copy link
Copy Markdown
Member

@abose abose commented May 22, 2026

An wrapping multiple children (e.g. badge rows) leaked the inter-image whitespace text nodes outside the link as flanking whitespace during the Turndown HTML->markdown roundtrip, producing N-1 leading spaces before the [ for N images. The phoenix README badge row (9 images) gained 8 leading spaces on every md editor save.

Fix in two parts:

Adds a regression test in test/spec/md-editor-integ-test.js that builds a 5-image badges-style line, forces an HTML->markdown roundtrip via __triggerContentSync, and asserts the CM source is byte-identical with no leading whitespace.

An <a href> wrapping multiple <img> children (e.g. badge rows) leaked
the inter-image whitespace text nodes outside the link as flanking
whitespace during the Turndown HTML->markdown roundtrip, producing N-1
leading spaces before the [ for N images. The phoenix README badge row
(9 images) gained 8 leading spaces on every md editor save.

Fix in two parts:
- convertToMarkdown preprocessing strips the whitespace text nodes
  between <img> siblings inside an <a href>, so the anchor's textContent
  is empty and Turndown's flanking-whitespace handler has nothing to
  bubble out.
- A new imageOnlyLink Turndown rule renders such anchors directly as
  [![alt](src) ![alt](src) ...](href), re-emitting the single joining
  space inside the brackets.

Adds a regression test in test/spec/md-editor-integ-test.js that builds
a 5-image badges-style line, forces an HTML->markdown roundtrip via
__triggerContentSync, and asserts the CM source is byte-identical with
no leading whitespace.
@sonarqubecloud
Copy link
Copy Markdown

replacement(content, node) {
const href = node.getAttribute("href") || "";
const title = node.getAttribute("title");
const titlePart = title ? ` "${title.replace(/"/g, '\\"')}"` : "";
const alt = child.getAttribute("alt") || "";
const src = child.getAttribute("src") || "";
const imgTitle = child.getAttribute("title");
const imgTitlePart = imgTitle ? ` "${imgTitle.replace(/"/g, '\\"')}"` : "";
@abose abose merged commit 0da2c61 into main May 22, 2026
11 of 21 checks passed
@abose abose deleted the ai branch May 22, 2026 05:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants