3
3
*/
4
4
import { useRefEffect } from '@wordpress/compose' ;
5
5
6
+ const nodesByDocument = new Map ( ) ;
7
+
8
+ function add ( doc , node ) {
9
+ let set = nodesByDocument . get ( doc ) ;
10
+ if ( ! set ) {
11
+ set = new Set ( ) ;
12
+ nodesByDocument . set ( doc , set ) ;
13
+ doc . addEventListener ( 'pointerdown' , down ) ;
14
+ }
15
+ set . add ( node ) ;
16
+ }
17
+
18
+ function remove ( doc , node ) {
19
+ const set = nodesByDocument . get ( doc ) ;
20
+ if ( set ) {
21
+ set . delete ( node ) ;
22
+ restore ( node ) ;
23
+ if ( set . size === 0 ) {
24
+ nodesByDocument . delete ( doc ) ;
25
+ doc . removeEventListener ( 'pointerdown' , down ) ;
26
+ }
27
+ }
28
+ }
29
+
30
+ function restore ( node ) {
31
+ const prevDraggable = node . getAttribute ( 'data-draggable' ) ;
32
+ if ( prevDraggable ) {
33
+ node . removeAttribute ( 'data-draggable' ) ;
34
+ // Only restore if `draggable` is still removed. It could have been
35
+ // changed by React in the meantime.
36
+ if ( prevDraggable === 'true' && ! node . getAttribute ( 'draggable' ) ) {
37
+ node . setAttribute ( 'draggable' , 'true' ) ;
38
+ }
39
+ }
40
+ }
41
+
42
+ function down ( event ) {
43
+ const { target } = event ;
44
+ const { ownerDocument, isContentEditable } = target ;
45
+ const nodes = nodesByDocument . get ( ownerDocument ) ;
46
+
47
+ if ( isContentEditable ) {
48
+ // Whenever an editable element is clicked, check which draggable
49
+ // blocks contain this element, and temporarily disable draggability.
50
+ for ( const node of nodes ) {
51
+ if (
52
+ node . getAttribute ( 'draggable' ) === 'true' &&
53
+ node . contains ( target )
54
+ ) {
55
+ node . removeAttribute ( 'draggable' ) ;
56
+ node . setAttribute ( 'data-draggable' , 'true' ) ;
57
+ }
58
+ }
59
+ } else {
60
+ // Whenever a non-editable element is clicked, re-enable draggability
61
+ // for any blocks that were previously disabled.
62
+ for ( const node of nodes ) {
63
+ restore ( node ) ;
64
+ }
65
+ }
66
+ }
67
+
6
68
/**
7
69
* In Firefox, the `draggable` and `contenteditable` attributes don't play well
8
70
* together. When `contenteditable` is within a `draggable` element, selection
@@ -13,13 +75,9 @@ import { useRefEffect } from '@wordpress/compose';
13
75
*/
14
76
export function useFirefoxDraggableCompatibility ( ) {
15
77
return useRefEffect ( ( node ) => {
16
- function onDown ( event ) {
17
- node . draggable = ! event . target . isContentEditable ;
18
- }
19
- const { ownerDocument } = node ;
20
- ownerDocument . addEventListener ( 'pointerdown' , onDown ) ;
78
+ add ( node . ownerDocument , node ) ;
21
79
return ( ) => {
22
- ownerDocument . removeEventListener ( 'pointerdown' , onDown ) ;
80
+ remove ( node . ownerDocument , node ) ;
23
81
} ;
24
82
} , [ ] ) ;
25
83
}
0 commit comments