Skip to content

fix(docx): make a block's anchor a bookmark Word can link to - #728

Merged
DemchaAV merged 1 commit into
2.5-devfrom
fix/docx-block-anchors
Sep 23, 2026
Merged

DemchaAV merged 1 commit into
2.5-devfrom
fix/docx-block-anchors

Conversation

@DemchaAV

@DemchaAV DemchaAV commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Why

anchor(...) sits on a paragraph, a section, a container, a table or an image, and linkTo(...) jumps to it. The DOCX export wrote a Word bookmark only for a paragraph's anchor. An anchor on any other block was dropped. The link to it was still written, with w:anchor naming a bookmark that did not exist, so in Word it went nowhere.

This is also the precondition for page references. A PAGEREF field to a block's anchor has to find a bookmark, or Word shows "Error! Bookmark not defined." when the field updates.

What changed

  • DocxSemanticBackend.writeNode now wraps a block's output in a bookmark named after its anchor (bookmarkAround). This covers a section, a container, a table and an image. It goes through the same DocxBookmarkNames as paragraph anchors, so the name a link uses is the name the bookmark carries. It sits alongside the existing keep-together pass.
    • The bookmark opens before the first word of the block's first paragraph. A block that starts with a table opens in the table's first cell.
      • addNewBookmarkStart appends after the runs, so the element is moved with an XmlCursor to just after the paragraph's w:pPr.
      • Left where it was appended, a link would land after the first line's text instead of on it.
    • It closes after the block's last paragraph, or in the last cell when the block ends with a table.
    • A block that wrote nothing gets no bookmark. That covers an empty section, and an anchor on a node this export drops, such as a shape.
  • A paragraph's own anchor is unchanged. The paragraph writer still wraps its own text.
  • Docs updated:

Verification

In an editor. A document with a link on page 1 to a section anchor on page 2, converted with LibreOffice: the link's destination is page 2, where the section starts.

Gate. Full reactor gate (clean verify over core, render-pdf/docx/pptx, templates, testing, qa, coverage) → BUILD SUCCESS. Examples after install: 93 green. No committed preview moved.

New DocxBlockAnchorTest (4):

  • a section's anchor opens before the first run of its first paragraph, and a link's w:anchor names it;
  • the bookmark closes on the section's last paragraph with the same id;
  • a table's anchor opens in its first cell and closes in its last;
  • an image's anchor marks the picture's paragraph;
  • an anchored section that writes nothing leaves no bookmark.

Removing the move to the paragraph start fails the section test.

Lane: shared-engine (render-docx). No public API change.

Only a paragraph's anchor(...) reached the file as a bookmark; an
anchor on a section, container, table or image was dropped, so an
internal link to one went nowhere in Word. Such a block's anchor now
wraps everything it wrote, opening before the first word of its first
paragraph (its first cell's, when it starts with a table) and closing
after its last.
@DemchaAV
DemchaAV merged commit 3a63a13 into 2.5-dev Sep 23, 2026
12 checks passed
@DemchaAV
DemchaAV deleted the fix/docx-block-anchors branch September 23, 2026 15:03
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