Skip to content

Commit 8acacda

Browse files
Extracted range -> quote transform into a separate function
1 parent 25a3485 commit 8acacda

File tree

2 files changed

+41
-32
lines changed

2 files changed

+41
-32
lines changed

packages/text-annotator/src/SelectionHandler.ts

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,42 @@
11
import { Origin, type User } from '@annotorious/core';
22
import { v4 as uuidv4 } from 'uuid';
33
import type { TextAnnotatorState } from './state';
4-
import type { TextSelector, TextAnnotationTarget } from './model';
4+
import type { TextSelector, TextAnnotationTarget, TextSelectorQuote } from './model';
55
import { trimRange } from './utils';
66

7-
export const rangeToSelector = (range: Range, container: HTMLElement, offsetReferenceSelector?: string): TextSelector => {
8-
const offsetReference: HTMLElement = offsetReferenceSelector ?
9-
(range.startContainer.parentElement as HTMLElement).closest(offsetReferenceSelector) : container;
10-
11-
// Helper range from the start of the contentNode to the start of the selection
12-
const rangeBefore = document.createRange();
13-
rangeBefore.setStart(offsetReference, 0);
14-
rangeBefore.setEnd(range.startContainer, range.startOffset);
15-
7+
const rangeToQuote = (range: Range): TextSelectorQuote => {
168
/**
17-
* Capture the prefix and suffix of the selection to match the `Text Quote Selector` spec from the W3C Annotation Data Model
9+
* Captures the prefix and suffix snippets of the selection to match the `Text Quote Selector` spec
1810
* @see https://www.w3.org/TR/annotation-model/#text-quote-selector
1911
*/
2012
const snippetLength = 10;
2113

2214
const rangePrefix = document.createRange();
23-
const rangePrefixStartOffset = range.startOffset < snippetLength ? 0 : range.startOffset - snippetLength;
24-
rangePrefix.setStart(range.startContainer, rangePrefixStartOffset);
15+
rangePrefix.setStart(range.startContainer, Math.max(range.startOffset - snippetLength, 0));
2516
rangePrefix.setEnd(range.startContainer, range.startOffset);
2617

2718
const rangeSuffix = document.createRange();
28-
const rangeSuffixEndOffset = range.endOffset + snippetLength > range.endContainer.textContent.length ? range.endContainer.textContent.length : range.endOffset + snippetLength;
2919
rangeSuffix.setStart(range.endContainer, range.endOffset);
30-
rangeSuffix.setEnd(range.endContainer, rangeSuffixEndOffset);
20+
rangeSuffix.setEnd(range.endContainer, Math.min(range.endOffset + snippetLength, range.endContainer.textContent.length));
3121

32-
const quote = {
22+
return {
3323
exact: range.toString(),
3424
prefix: rangePrefix.toString(),
3525
suffix: rangeSuffix.toString()
3626
}
27+
}
28+
29+
export const rangeToSelector = (range: Range, container: HTMLElement, offsetReferenceSelector?: string): TextSelector => {
30+
const offsetReference: HTMLElement = offsetReferenceSelector
31+
? (range.startContainer.parentElement as HTMLElement).closest(offsetReferenceSelector)
32+
: container;
33+
34+
// Helper range from the start of the contentNode to the start of the selection
35+
const rangeBefore = document.createRange();
36+
rangeBefore.setStart(offsetReference, 0);
37+
rangeBefore.setEnd(range.startContainer, range.startOffset);
38+
39+
const quote = rangeToQuote(range);
3740
const start = rangeBefore.toString().length;
3841
const end = start + quote.exact.length;
3942

@@ -43,7 +46,7 @@ export const rangeToSelector = (range: Range, container: HTMLElement, offsetRefe
4346
}
4447

4548
export const SelectionHandler = (
46-
container: HTMLElement,
49+
container: HTMLElement,
4750
state: TextAnnotatorState,
4851
// Experimental
4952
offsetReferenceSelector?: string
@@ -66,7 +69,7 @@ export const SelectionHandler = (
6669
return;
6770

6871
// Make sure we don't listen to selection changes that
69-
// were not started on the container, or which are not supposed to
72+
// were not started on the container, or which are not supposed to
7073
// be annotatable (like the popup)
7174
const annotatable = !(evt.target as Node).parentElement.closest('.not-annotatable');
7275
if (annotatable) {
@@ -91,7 +94,7 @@ export const SelectionHandler = (
9194
debounceTimer = setTimeout(() => onSelectionChange(), 50);
9295
});
9396

94-
const onSelectionChange = () => {
97+
const onSelectionChange = () => {
9598
const sel = document.getSelection();
9699

97100
if (!sel.isCollapsed && isLeftClick && currentTarget) {
@@ -108,7 +111,7 @@ export const SelectionHandler = (
108111
...currentTarget,
109112
selector: rangeToSelector(ranges[0], container, offsetReferenceSelector)
110113
};
111-
114+
112115
if (store.getAnnotation(currentTarget.annotation)) {
113116
store.updateTarget(currentTarget, Origin.LOCAL);
114117
} else {
@@ -148,13 +151,13 @@ export const SelectionHandler = (
148151

149152
currentTarget = null;
150153
lastPointerEvent = undefined;
151-
} else {
154+
} else {
152155
const { x, y } = container.getBoundingClientRect();
153-
156+
154157
const hovered = store.getAt(evt.clientX - x, evt.clientY - y);
155158
if (hovered) {
156159
const { selected } = selection;
157-
160+
158161
if (selected.length !== 1 || selected[0].id !== hovered.id) {
159162
selection.clickSelect(hovered.id, evt);
160163
lastPointerEvent = undefined;

packages/text-annotator/src/model/TextAnnotation.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,7 @@ export interface TextAnnotationTarget extends AnnotationTarget {
1414

1515
export interface TextSelector {
1616

17-
/**
18-
* Matches the `Text Quote Selector` spec from the W3C Annotation Data Model
19-
* @see https://www.w3.org/TR/annotation-model/#text-quote-selector
20-
*/
21-
quote: {
22-
exact: string;
23-
prefix: string;
24-
suffix: string;
25-
}
17+
quote: TextSelectorQuote
2618

2719
start: number;
2820

@@ -33,3 +25,17 @@ export interface TextSelector {
3325
offsetReference?: HTMLElement
3426

3527
}
28+
29+
/**
30+
* Matches the `Text Quote Selector` spec from the W3C Annotation Data Model
31+
* @see https://www.w3.org/TR/annotation-model/#text-quote-selector
32+
*/
33+
export interface TextSelectorQuote {
34+
35+
exact: string;
36+
37+
prefix: string;
38+
39+
suffix: string;
40+
41+
}

0 commit comments

Comments
 (0)