Skip to content

Commit c5ffd36

Browse files
authored
Merge pull request #157 from oleksandr-danylchenko/fix-not-annotatable-elements-check
⚠️ Fixed false-negative `.not-annotatable` presence check ⚠️
2 parents 775f612 + ecd49de commit c5ffd36

File tree

4 files changed

+21
-30
lines changed

4 files changed

+21
-30
lines changed

packages/text-annotator/src/SelectionHandler.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
isMac,
1414
isWhitespaceOrEmpty,
1515
trimRangeToContainer,
16-
NOT_ANNOTATABLE_SELECTOR
16+
isNotAnnotatable
1717
} from './utils';
1818

1919
const CLICK_TIMEOUT = 300;
@@ -64,13 +64,14 @@ export const SelectionHandler = (
6464
* be annotatable (like a component popup).
6565
* Note that Chrome/iOS will sometimes return the root doc as target!
6666
*/
67-
const annotatable = !(evt.target as Node).parentElement?.closest(NOT_ANNOTATABLE_SELECTOR);
68-
currentTarget = annotatable ? {
69-
annotation: uuidv4(),
70-
selector: [],
71-
creator: currentUser,
72-
created: new Date()
73-
} : undefined;
67+
currentTarget = isNotAnnotatable(evt.target as Node)
68+
? undefined
69+
: {
70+
annotation: uuidv4(),
71+
selector: [],
72+
creator: currentUser,
73+
created: new Date()
74+
};
7475
};
7576

7677
const onSelectionChange = debounce((evt: Event) => {
@@ -79,8 +80,7 @@ export const SelectionHandler = (
7980
// This is to handle cases where the selection is "hijacked" by another element
8081
// in a not-annotatable area. A rare case in theory. But rich text editors
8182
// will like Quill do it...
82-
const annotatable = !sel.anchorNode?.parentElement?.closest(NOT_ANNOTATABLE_SELECTOR);
83-
if (!annotatable) {
83+
if (isNotAnnotatable(sel.anchorNode)) {
8484
currentTarget = undefined;
8585
return;
8686
}
@@ -163,8 +163,7 @@ export const SelectionHandler = (
163163
const onPointerDown = (evt: PointerEvent) => {
164164
if (isContextMenuOpen) return;
165165

166-
const annotatable = !(evt.target as Node).parentElement?.closest(NOT_ANNOTATABLE_SELECTOR);
167-
if (!annotatable) return;
166+
if (isNotAnnotatable(evt.target as Node)) return;
168167

169168
/**
170169
* Cloning the event to prevent it from accidentally being `undefined`
@@ -191,8 +190,7 @@ export const SelectionHandler = (
191190
const onPointerUp = (evt: PointerEvent) => {
192191
if (isContextMenuOpen) return;
193192

194-
const annotatable = !(evt.target as Node).parentElement?.closest(NOT_ANNOTATABLE_SELECTOR);
195-
if (!annotatable || !isLeftClick) return;
193+
if (isNotAnnotatable(evt.target as Node) || !isLeftClick) return;
196194

197195
// Logic for selecting an existing annotation
198196
const clickSelect = () => {

packages/text-annotator/src/utils/getAnnotatableFragment.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

packages/text-annotator/src/utils/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ export * from './cancelSingleClickEvents';
22
export * from './device';
33
export * from './programmaticallyFocusable';
44
export * from './debounce';
5-
export * from './getAnnotatableFragment';
65
export * from './getQuoteContext';
76
export * from './isWhitespaceOrEmpty';
87
export * from './isRevived';

packages/text-annotator/src/utils/splitAnnotatableRanges.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@ export const NOT_ANNOTATABLE_CLASS = 'not-annotatable';
22

33
export const NOT_ANNOTATABLE_SELECTOR = `.${NOT_ANNOTATABLE_CLASS}`;
44

5-
const isRangeAnnotatable = (range: Range): boolean => {
5+
export const isNotAnnotatable = (node: Node): boolean => {
6+
const closestNotAnnotatable = node instanceof HTMLElement
7+
? node.closest(NOT_ANNOTATABLE_SELECTOR)
8+
: node.parentElement?.closest(NOT_ANNOTATABLE_SELECTOR);
9+
return Boolean(closestNotAnnotatable);
10+
}
11+
12+
export const isRangeAnnotatable = (range: Range): boolean => {
613
const ancestor = range.commonAncestorContainer;
7-
return ancestor instanceof HTMLElement
8-
? !ancestor.closest(NOT_ANNOTATABLE_SELECTOR)
9-
: !ancestor.parentElement?.closest(NOT_ANNOTATABLE_SELECTOR);
14+
return !isNotAnnotatable(ancestor);
1015
}
1116

1217
const iterateNotAnnotatableElements = function*(range: Range): Generator<HTMLElement> {

0 commit comments

Comments
 (0)