feat(docx): write a page reference as a PAGEREF field Word keeps current - #729
Merged
Merged
Conversation
| } else { | ||
| CTSimpleField field = para.getCTP().addNewFldSimple(); | ||
| field.setInstr(" PAGEREF " + bookmark + " \\h "); | ||
| run = new XWPFRun(field.addNewR(), para); |
The DOCX export dropped every PageReferenceNode, so a table of contents reached Word with its entries and no page numbers. Each is now a PAGEREF field to the anchor's bookmark, as a hyperlink, storing the page the layout resolved; the editor recomputes it as the document changes. A reference to an anchor with no bookmark is written as its placeholder text instead of a field Word would turn into an error. w:updateFields is not set. The recipe states which field each page number is and what updates it.
DemchaAV
force-pushed
the
feature/docx-page-references
branch
from
September 23, 2026 15:04
458e349 to
dd5f371
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
addTableOfContents(...)andaddPageReference(...)print the page an anchor lands on. The layout resolves that page and lays it out as text (PageReferenceDefinition). The DOCX backend had no case forPageReferenceNodeand dropped it: a table of contents reached Word with its entries and no page numbers, and a "see page N" wrote nothing.A number written as plain text would be right only until the reader edits the document. So a page reference has to be a field the editor recomputes. For that field it also has to be decided when fields update, and what the file shows before they do.
What changed
DocxSemanticBackend.writePageReferencewrites the node as a paragraph with aPAGEREF <bookmark> \hfield.DocxLayoutMetrics.laidOutText), so the file opens reading the PDF's numbers.bookmarkedAnchorsIn: paragraph anchors plus the block anchors from fix(docx): make a block's anchor a bookmark Word can link to #728). Otherwise it is the placeholder text the page prints. Word turns aPAGEREFto a missing bookmark into "Error! Bookmark not defined." the first time the field updates.PAGE,NUMPAGESandSECTIONPAGESin zones are updated by the editor on every layout. LibreOffice is the exception: it does not updateSECTIONPAGES.PAGEREFis updated by LibreOffice on layout, and by Word on a field update (F9, or printing with field updates on).w:updateFieldsis deliberately not set. It would make Word ask on every open to recompute numbers that already read correctly.Verification
In an editor, including after the numbers go stale. A 5-page document with a three-entry table of contents: one paragraph anchor and two section anchors.
PAGEREFresult rewritten to99, LibreOffice still shows 2 / 3 / 5. It recomputes the field rather than trusting the stored number.Gate. Full reactor gate (
clean verifyover core, render-pdf/docx/pptx, templates, testing, qa, coverage) → BUILD SUCCESS. Examples after install: 93 green. No committed preview moved.New
DocxPageReferenceTest(4):PAGEREF … \hper entry, storing pages 2 / 3 / 4, and every name is a bookmark the document has, section anchors included;addPageReferenceis a field too;settings.xmlhas noupdateFields.Forcing the field for a missing anchor fails the missing-anchor test.
Known limit, separate. A table-of-contents entry is a row with auto-width label columns, and in LibreOffice the labels wrap mid-word. The editor's substitute font is wider than the engine's measurement, and rows do not get the 1pt editor slack that table auto columns have. This predates this change and is tracked as its own task.
Lane: shared-engine (render-docx). No public API change.