Skip to content

Keep links and inline formatting in image captions - #405

Open
semsevens wants to merge 1 commit into
kepano:mainfrom
semsevens:keep-figcaption-links
Open

semsevens wants to merge 1 commit into
kepano:mainfrom
semsevens:keep-figcaption-links

Conversation

@semsevens

Copy link
Copy Markdown

Problem

When a figure is standardized (createFigureWithCaption in src/elements/images.ts), the caption goes through extractUniqueCaptionContent, which collects the caption's text nodes and joins them with spaces. Every element is dropped, so links in captions disappear:

<figcaption class="image-caption"><span>…You can find the source code </span><a href="https://…/notebook.ipynb">here</a><span>.</span></figcaption>

becomes …You can find the source code here. This is how Substack renders captions, so every Substack post with linked captions loses them (a real post I clipped lost 12). It also reaches Obsidian Web Clipper users.

A second, smaller issue in the same path: the joined text is passed back through parseHTML, so escaped markup in a caption (&lt;img src=x&gt;) is turned back into a real element. With the current code the new fixture's Figure 4 comes out as ![](https://www.example.com/article/x).

Fix

extractUniqueCaptionContent is replaced by appendUniqueCaptionContent, which copies the caption into the new <figcaption> as DOM nodes instead of building an HTML string:

  • repeated text is still skipped, which was the original purpose of the function;
  • links are kept, and their href is checked with isDangerousUrl. Inline formatting (em, i, strong, b, code, sub, sup) is kept as clean elements with no attributes;
  • other wrappers (spans, divs) are unwrapped, with a space at block boundaries so that <div>A</div><div>B</div> doesn't become AB;
  • text stays text, and there's no parseHTML/innerHTML round trip.

Tests

  • New fixture elements--figcaption-inline-formatting covers a Substack-style caption, emphasis + inline code + a relative link, a caption split across block elements, escaped markup, and a javascript: link that keeps its text but loses its href. It fails on main and passes with the fix.
  • issues--227-noscript-lazy-images expected output updated: its captions contain <a href="https://example.com/source1">Source One</a> and <a href="https://example.com/source2">Source Two</a>, which were flattened before and are now kept as links.
  • npm test and npm run test:jsdom: 773/773. lint:unused and lint:innerhtml pass, and npm run size is within budget.

🤖 Generated with Claude Code

When a figure is rebuilt by createFigureWithCaption, the caption went
through extractUniqueCaptionContent, which collected the text nodes and
joined them with spaces. Every element was dropped, so a caption like
"You can find the source code <a href="…">here</a>." lost its link.
This happens on Substack posts, where captions are spans around links.

The joined text was then re-parsed as HTML, so escaped markup in a
caption (&lt;img src=x&gt;) came back as a real element.

Replace it with appendUniqueCaptionContent, which copies the caption
into the new figcaption as DOM nodes: repeated text is still skipped,
links (href checked with isDangerousUrl) and inline formatting (em, i,
strong, b, code, sub, sup) are kept as clean shells, other wrappers are
unwrapped with a space at block boundaries, and text stays text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

1 participant