Skip to content

Commit b91dc14

Browse files
committed
Fixed TEI XPath reviving bug
1 parent 69be7ea commit b91dc14

File tree

4 files changed

+46
-31
lines changed

4 files changed

+46
-31
lines changed

packages/extension-tei/src/crosswalk/forward.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { rangeToSelector, reviveTarget as reviveTextOffsetTarget } from '@recogito/text-annotator';
2+
import type { TEIAnnotation, TEIAnnotationTarget, TEIRangeSelector } from '../TEIAnnotation';
3+
import { reanchor } from './utils';
24
import type {
35
TextAnnotation,
46
TextAnnotationTarget,
57
TextSelector
68
} from '@recogito/text-annotator';
7-
import type { TEIAnnotation, TEIAnnotationTarget, TEIRangeSelector } from '../TEIAnnotation';
89

910
/**
1011
* Helper: Returns the given XPath for a DOM node, in the form of
@@ -145,8 +146,21 @@ export const reviveTarget = (t: TextAnnotationTarget, container: HTMLElement) =>
145146
const [endNode, endOffset] = evaluateSelector(endExpression);
146147

147148
const range = document.createRange();
148-
range.setStart(startNode.firstChild, startOffset);
149-
range.setEnd(endNode.firstChild, endOffset);
149+
150+
// Helper
151+
const reanchorIfNeeded = (parent: Node, offset: number) => {
152+
if (parent.firstChild.toString().length >= offset) {
153+
return { node: parent.firstChild, offset };
154+
} else {
155+
return reanchor(parent.firstChild, parent, offset);
156+
}
157+
}
158+
159+
const reanchoredStart = reanchorIfNeeded(startNode, startOffset);
160+
const reanchoredEnd = reanchorIfNeeded(endNode, endOffset);
161+
162+
range.setStart(reanchoredStart.node, reanchoredStart.offset);
163+
range.setEnd(reanchoredEnd.node, reanchoredEnd.offset);
150164

151165
const textSelector = rangeToSelector(range, container);
152166

packages/extension-tei/src/crosswalk/reverse.ts

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { TextAnnotation, TextAnnotationTarget } from '@recogito/text-annotator';
22
import type { TEIAnnotation, TEIAnnotationTarget, TEIRangeSelector } from '../TEIAnnotation';
3+
import { reanchor } from './utils';
34

45
/**
56
* Helper: converts the given XPath string and DOM container element
@@ -24,35 +25,8 @@ const xpathToDOMPosition = (path: string, container: Element) => {
2425

2526
const offset = parseInt(path.substring(offsetIdx + 2));
2627

27-
const reanchor = (originalNode: Node, originalOffset: number) => {
28-
let node = originalNode;
29-
30-
let offset = originalOffset;
31-
32-
const it = document.createNodeIterator(parentNode, NodeFilter.SHOW_TEXT);
33-
34-
let currentNode = it.nextNode();
35-
36-
let run = true;
37-
38-
do {
39-
if (currentNode instanceof Text) {
40-
if (currentNode.length < offset) {
41-
offset -= currentNode.length;
42-
} else {
43-
node = currentNode;
44-
run = false;
45-
}
46-
}
47-
48-
currentNode = it.nextNode();
49-
} while (currentNode && run);
50-
51-
return { node, offset };
52-
};
53-
5428
if (!(node instanceof Text) || offset > node.length) {
55-
return reanchor(node, offset);
29+
return reanchor(node, parentNode, offset);
5630
} else {
5731
return { node, offset };
5832
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './reanchor';
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
export const reanchor = (originalNode: Node, parentNode: Node, originalOffset: number) => {
2+
let node = originalNode;
3+
4+
let offset = originalOffset;
5+
6+
const it = document.createNodeIterator(parentNode, NodeFilter.SHOW_TEXT);
7+
8+
let currentNode = it.nextNode();
9+
10+
let run = true;
11+
12+
do {
13+
if (currentNode instanceof Text) {
14+
if (currentNode.length < offset) {
15+
offset -= currentNode.length;
16+
} else {
17+
node = currentNode;
18+
run = false;
19+
}
20+
}
21+
22+
currentNode = it.nextNode();
23+
} while (currentNode && run);
24+
25+
return { node, offset };
26+
};

0 commit comments

Comments
 (0)