Commit f276b34
feat(pm-adapter): synthesize internal link for PAGEREF with \h switch (#2899)
* feat(super-editor): render imported heading/bookmark cross-references (SD-2495)
Wire the sd:crossReference v3 translator into the v2 importer entity list so
REF / NOTEREF / STYLEREF fields imported from DOCX actually produce PM
crossReference nodes instead of being silently dropped by the dispatch loop.
Walk nested run wrappers when extracting the field's cached display text, and
render the cross-reference as an internal hyperlink when the instruction
carries the \\h switch. Route clicks on internal #bookmark anchors through
goToAnchor so rendered cross-references navigate to their target in the
document.
Fixes IT-949 — Word cross-references (e.g. "Section 15") now appear in the
viewer and are searchable, matching Word's output.
* fix(presentation-editor): anchor nav writes scrollTop to the real scroll container
#scrollPageIntoView wrote scrollTop to #visibleHost, which is typically
overflow: visible and therefore not the actual scroll target. Anchor
navigation (TOC clicks and SD-2495 cross-reference click-to-navigate)
silently did nothing whenever the bookmark target was outside the
current viewport — the PM selection moved but the viewport never
scrolled.
Write to #scrollContainer (the resolved scrollable ancestor) as the
primary target, plus #visibleHost for backward compatibility with
legacy layouts and the existing test harness that mocks scrollTop on
the host element.
This unblocks SD-2495's cross-reference click-to-navigate on docs
where cross-references and their targets live on different pages.
* feat(layout): show-bookmarks bracket indicators (SD-2454)
Opt-in visual indicators for bookmark positions — mirrors Word's "Show
bookmarks" (File > Options > Advanced). Off by default.
- Pm-adapter bookmark-start and new bookmark-end converters emit gray `[`
and `]` marker TextRuns when `layoutEngineOptions.showBookmarks` is
true. Markers flow through pagination and line breaking as real
characters, matching Word's own visual model.
- Auto-generated bookmarks (`_Toc…`, `_Ref…`, `_GoBack`) are hidden even
when the feature is on — matching Word. A `renderedBookmarkIds` set on
the converter context pairs suppression so closing brackets don't
orphan open ones.
- PresentationEditor.setShowBookmarks toggles at runtime: clears the
flow-block cache and schedules a re-render.
- SuperDoc.setShowBookmarks is the public API passthrough.
- Dev app gets a Show/Hide bookmarks toggle button in the header.
- CSS: subtle gray, non-selectable so users don't include brackets in
copied text. Bookmark name surfaces via the native title tooltip on
the opening bracket.
* test: close regression gaps for SD-2495 / SD-2454 / anchor-nav fix
Fills the test gaps surfaced by the testing-excellence review of this PR:
- crossReferenceImporter.integration.test.js (new, 4 tests): exercises the
full v2 body pipeline (preprocessor -> dispatcher -> entity handler ->
v3 translator). Asserts crossReferenceEntity is a member of the
defaultNodeListHandler entities list, so the exact root cause that
produced IT-949 ("Section 15" vanishing) fails loudly if a future
refactor drops the wire-up. Unit tests of the translator alone cannot
catch this — they bypass the dispatcher.
- EditorInputManager.anchorClick.test.ts (new, 4 tests): pins the
SD-2537 click-to-navigate routing. Clicking #bookmark hrefs routes
through goToAnchor (was TOC-only before). External and empty-fragment
hrefs are explicitly NOT routed.
- cross-reference.test.ts: added marks-propagation test (node.marks flow
into the emitted TextRun so italic/textStyle on xref text survives —
SD-2537 "preserve surrounding run styling" AC).
- bookmark-markers.test.ts: converted the `for` loop over auto-generated
bookmark names into `it.each`. Each input now reports per-case on
failure, complies with testing-excellence's "no control flow inside
test bodies" guideline.
- PresentationEditor.test.ts: documents why the scrollContainer-vs-
visibleHost branch of the SD-2495 scrollPageIntoView fix isn't unit-
testable here (happy-dom doesn't propagate inline overflow through
getComputedStyle, which is what findScrollableAncestor uses).
* feat(pm-adapter): synthesize internal link for PAGEREF with \h switch
Mirrors the pattern added for crossReference in #2882. When a PAGEREF
field instruction carries the `\h` switch, attach a FlowRunLink via
`buildFlowRunLink({ anchor: bookmarkId })` so clicks on the rendered
page number navigate to the referenced bookmark through the existing
anchor-link routing (`EditorInputManager.#handleLinkClick` → `goToAnchor`).
Previously the PAGEREF inline converter emitted the `pageReference`
token run with `pageRefMetadata.bookmarkId` but no `link`, so the DOM
layer never produced a clickable element for PAGEREFs. TOC entries and
other hyperlinked page references imported from Word therefore failed
to navigate on click, even though Word honored the `\h` switch.
Depends on #2882 for `buildFlowRunLink` export and the generalized
anchor-click routing.
* fix(pm-adapter): match PAGEREF \h switch case-insensitively
Word field switches are case-insensitive per the field-code grammar, so
`\H` should produce the hyperlink the same as `\h`. Reviewer
(codex-connector) flagged that the original `/\\h\b/` regex skipped the
link synthesis for instructions like `PAGEREF _Toc123 \H`, leaving them
non-navigable even though the author had requested hyperlink behavior.
Adds the `i` flag and a regression test with an uppercase switch.
* test: add coverage for standalone PAGEREF \h + REF-family preprocessors
Behavior test (tests/behavior/tests/navigation/pageref-standalone-click.spec.ts):
Covers the PR's load-bearing case - a PAGEREF \h field NOT wrapped in a
<w:hyperlink>. The existing toc-anchor-scroll.spec.ts only exercises the
wrapped-in-hyperlink shape, where the outer link mark already propagates
via marksAsAttrs and the PR is a no-op. Fixtures exercise both \h and \H
(case-insensitivity per ECMA-376 17.16.1).
Preprocessor unit tests (ref/noteref/styleref):
These three importer modules were added in #2882 without tests. Each
verifies the preprocessor produces a sd:crossReference node with the
right fieldType and preserves the instruction text verbatim.
* test(superdoc): cover setShowBookmarks propagation and no-op guard
Closes the Codecov patch-coverage gap on SuperDoc.js flagged on PR #2899.
The uncovered setShowBookmarks method came in via the SD-2454 merge and
had no test for its config mutation, no-op short-circuit, or Boolean()
coercion. Models the existing setDisableContextMenu test pattern.
* refactor(pm-adapter): drop TextRun casts + case-insensitive \h in cross-reference
Addresses review feedback on #2899:
- page-reference.ts: remove redundant `as TextRun` casts — textNodeToRun
already returns TextRun, so the casts are noise (cross-reference.ts:34
already does this cleanly). Shorten the \h comment.
- cross-reference.ts: add the `i` flag to the \h switch regex to match
ECMA-376 §17.16.1, same fix as 7f19358 for page-reference. Add a
regression test covering `\H`.
* test: add unit coverage for scroll fan-out when ancestor != host
Stubs window.getComputedStyle to mark a wrapper element as scrollable so
#findScrollableAncestor returns the wrapper, then asserts both the wrapper
and the visibleHost receive scrollTop. This pins the SD-2495 fix: a revert
to the pre-fix one-liner (writing only to the visibleHost) now fails.
---------
Co-authored-by: Tadeu Tupinamba <tadeu.tupiz@gmail.com>
Co-authored-by: Caio Pizzol <97641911+caio-pizzol@users.noreply.github.com>
Co-authored-by: Caio Pizzol <caio@superdoc.dev>1 parent da38a24 commit f276b34
32 files changed
Lines changed: 1352 additions & 32 deletions
File tree
- packages
- layout-engine
- painters/dom/src
- pm-adapter/src
- converters
- inline-converters
- super-editor/src/editors/v1/core
- presentation-editor
- pointer-events
- tests
- super-converter
- field-references/fld-preprocessors
- v2/importer
- v3/handlers/sd/crossReference
- superdoc/src
- core
- dev/components
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5383 | 5383 | | |
5384 | 5384 | | |
5385 | 5385 | | |
| 5386 | + | |
| 5387 | + | |
| 5388 | + | |
| 5389 | + | |
| 5390 | + | |
| 5391 | + | |
| 5392 | + | |
| 5393 | + | |
5386 | 5394 | | |
5387 | 5395 | | |
5388 | 5396 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
197 | 197 | | |
198 | 198 | | |
199 | 199 | | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
200 | 215 | | |
201 | 216 | | |
202 | 217 | | |
| |||
Lines changed: 17 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
54 | 54 | | |
55 | 55 | | |
56 | 56 | | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
57 | 74 | | |
58 | 75 | | |
59 | 76 | | |
| |||
Lines changed: 44 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
Lines changed: 113 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
Lines changed: 54 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
2 | 5 | | |
3 | | - | |
4 | | - | |
5 | | - | |
6 | | - | |
7 | | - | |
8 | | - | |
9 | | - | |
10 | | - | |
11 | | - | |
12 | | - | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
13 | 25 | | |
14 | 26 | | |
15 | 27 | | |
| 28 | + | |
16 | 29 | | |
17 | 30 | | |
18 | 31 | | |
19 | 32 | | |
20 | 33 | | |
21 | 34 | | |
22 | | - | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
23 | 63 | | |
24 | 64 | | |
25 | 65 | | |
| 66 | + | |
| 67 | + | |
26 | 68 | | |
0 commit comments