UNPKG

@wordpress/block-editor

Version:
84 lines (76 loc) 2.29 kB
/** * WordPress dependencies */ import { useRefEffect } from '@wordpress/compose'; const nodesByDocument = new Map(); function add( doc, node ) { let set = nodesByDocument.get( doc ); if ( ! set ) { set = new Set(); nodesByDocument.set( doc, set ); doc.addEventListener( 'pointerdown', down ); } set.add( node ); } function remove( doc, node ) { const set = nodesByDocument.get( doc ); if ( set ) { set.delete( node ); restore( node ); if ( set.size === 0 ) { nodesByDocument.delete( doc ); doc.removeEventListener( 'pointerdown', down ); } } } function restore( node ) { const prevDraggable = node.getAttribute( 'data-draggable' ); if ( prevDraggable ) { node.removeAttribute( 'data-draggable' ); // Only restore if `draggable` is still removed. It could have been // changed by React in the meantime. if ( prevDraggable === 'true' && ! node.getAttribute( 'draggable' ) ) { node.setAttribute( 'draggable', 'true' ); } } } function down( event ) { const { target } = event; const { ownerDocument, isContentEditable } = target; const nodes = nodesByDocument.get( ownerDocument ); if ( isContentEditable ) { // Whenever an editable element is clicked, check which draggable // blocks contain this element, and temporarily disable draggability. for ( const node of nodes ) { if ( node.getAttribute( 'draggable' ) === 'true' && node.contains( target ) ) { node.removeAttribute( 'draggable' ); node.setAttribute( 'data-draggable', 'true' ); } } } else { // Whenever a non-editable element is clicked, re-enable draggability // for any blocks that were previously disabled. for ( const node of nodes ) { restore( node ); } } } /** * In Firefox, the `draggable` and `contenteditable` attributes don't play well * together. When `contenteditable` is within a `draggable` element, selection * doesn't get set in the right place. The only solution is to temporarily * remove the `draggable` attribute clicking inside `contenteditable` elements. * * @return {Function} Cleanup function. */ export function useFirefoxDraggableCompatibility() { return useRefEffect( ( node ) => { add( node.ownerDocument, node ); return () => { remove( node.ownerDocument, node ); }; }, [] ); }