fix: restore highlights for cross-node and cross-paragraph selections#30
Merged
Conversation
…closes #29) - serializeRange: add endXpath field to anchor shape so the end container is serialised independently of the start container; restoreRange resolves both nodes separately with legacy fallback (endXpath || xpath) for backward compat with existing IDB/server data - highlightRange: catch HierarchyRequestError from surroundContents and fall back to _highlightRangeMulti, which collects text nodes via NodeIterator before any DOM mutation, then wraps each in its own <mark> - _allMarksOf(mark): helper returning mark._allMarks || [mark]; all downstream ops (unwrap, is-resolved class, click listeners, _threadId) iterate the full mark group atomically - Bump version to 0.5.14; rebuild annotate.min.js - Update README.md and CLAUDE.md with endXpath data model, Phase M, new manual test cases, and Key Implementation Notes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Summary
serializeRangeonly storedxpath(start container path); for any selection wherestartContainer ≠ endContainer,restoreRangeappliedendOffsetto the wrong node — producing a null range or a truncated highlight on every page reloadendXpath: _getXPath(range.endContainer)to the serialized anchor;restoreRangenow resolves start and end nodes independently withanchor.endXpath || anchor.xpathfallback for backward compat with existing IDB/server datarange.surroundContents()throwsHierarchyRequestErrorfor cross-element ranges;highlightRangenow catches this and falls back to_highlightRangeMulti, which collects all text nodes viaNodeIteratorbefore any DOM mutation (prevents iterator invalidation), then wraps each in its own<mark>_allMarksOf(mark): new helper returningmark._allMarks || [mark]; all downstream operations (unwrap,is-resolvedclass, click listeners,_threadIdassignment) iterate the full mark group atomically0.5.14; rebuiltannotate.min.jsType
Affected modes
All modes (offline, BroadcastChannel, server-sync, P2P) — anchor serialization and highlight rendering are shared across all sync modes.
Testing
<strong>) → multi-segment highlight; reload → fully restoredendXpathin IDB/server) →restoreRangefalls back toanchor.xpathfor both nodes; no regressionsis-resolvedclass applied/removed on all marks atomicallyBreaking changes
None. The
endXpathfield is additive;restoreRangeis fully backward compatible with anchors that lack it.Checklist
assets/js/annotate.jsannotate.min.jsrebuilt (npm run build)0.5.13→0.5.14)README.mdupdated (anchor data model, core checklist, Roadmap Shipped)CLAUDE.mdupdated (anchor shape, Highlight Re-anchoring section, Phase M, Key Implementation Notes)Closes #29
🤖 Generated with Claude Code