11import { Direction } from '../../core/src/VSelection' ;
22import { MutationNormalizer } from './MutationNormalizer' ;
3- import { caretPositionFromPoint } from '../../utils/polyfill' ;
3+ import { caretPositionFromPoint , elementFromPoint } from '../../utils/src /polyfill' ;
44import { targetDeepest } from '../../utils/src/Dom' ;
5- import { nodeName } from '../../utils/src/utils' ;
5+ import { nodeName , getDocument } from '../../utils/src/utils' ;
66
77const navigationKey = new Set ( [
88 'ArrowUp' ,
@@ -221,7 +221,7 @@ interface DataTransferDetails {
221221type EventToProcess = Event | DataTransferDetails ;
222222
223223interface EventListenerDeclaration {
224- readonly target : EventTarget ;
224+ readonly target : Document | ShadowRoot ;
225225 readonly type : string ;
226226 readonly listener : EventListener ;
227227}
@@ -457,6 +457,12 @@ export class EventNormalizer {
457457 * manually fire its execution when a navigation key is pressed.
458458 */
459459 _stackTimeout : Timeout < EventBatch > ;
460+ /**
461+ * Map of the shadow dom event normalizer.
462+ * If an event is triggered inside a shadow dom, we instanciate a new
463+ * EventNormalizer in the shadow dom.
464+ */
465+ private _shadowNormalizers = new Map < ShadowRoot , EventNormalizer > ( ) ;
460466
461467 /**
462468 *
@@ -466,32 +472,35 @@ export class EventNormalizer {
466472 constructor (
467473 private _isInEditable : ( node : Node ) => boolean ,
468474 private _triggerEventBatch : TriggerEventBatchCallback ,
475+ root : Document | ShadowRoot = document ,
469476 ) {
470477 this . initNextObservation ( ) ;
471478
472479 // const document = this.editable.ownerDocument;
473- this . _bindEventInEditable ( document , 'compositionstart' , this . _registerEvent ) ;
474- this . _bindEventInEditable ( document , 'compositionupdate' , this . _registerEvent ) ;
475- this . _bindEventInEditable ( document , 'compositionend' , this . _registerEvent ) ;
476- this . _bindEventInEditable ( document , 'beforeinput' , this . _registerEvent ) ;
477- this . _bindEventInEditable ( document , 'input' , this . _registerEvent ) ;
480+ this . _bindEventInEditable ( root , 'compositionstart' , this . _registerEvent ) ;
481+ this . _bindEventInEditable ( root , 'compositionupdate' , this . _registerEvent ) ;
482+ this . _bindEventInEditable ( root , 'compositionend' , this . _registerEvent ) ;
483+ this . _bindEventInEditable ( root , 'beforeinput' , this . _registerEvent ) ;
484+ this . _bindEventInEditable ( root , 'input' , this . _registerEvent ) ;
478485
479486 this . _bindEvent ( document , 'selectionchange' , this . _onSelectionChange ) ;
480- this . _bindEventInEditable ( document , 'contextmenu' , this . _onContextMenu ) ;
481- this . _bindEvent ( document , 'mousedown' , this . _onPointerDown ) ;
482- this . _bindEvent ( document , 'touchstart' , this . _onPointerDown ) ;
483- this . _bindEvent ( document , 'mouseup' , this . _onPointerUp ) ;
484- this . _bindEvent ( document , 'touchend' , this . _onPointerUp ) ;
485- this . _bindEventInEditable ( document , 'keydown' , this . _onKeyDownOrKeyPress ) ;
486- this . _bindEventInEditable ( document , 'keypress' , this . _onKeyDownOrKeyPress ) ;
487- this . _bindEvent ( document , 'onkeyup' , this . _updateModifiersKeys ) ;
488-
489- this . _bindEventInEditable ( document , 'cut' , this . _onClipboard ) ;
490- this . _bindEventInEditable ( document , 'paste' , this . _onClipboard ) ;
491- this . _bindEventInEditable ( document , 'dragstart' , this . _onDragStart ) ;
492- this . _bindEventInEditable ( document , 'drop' , this . _onDrop ) ;
493-
494- this . _mutationNormalizer = new MutationNormalizer ( ) ;
487+ this . _bindEventInEditable ( root , 'contextmenu' , this . _onContextMenu ) ;
488+ this . _bindEvent ( root , 'mousedown' , this . _onPointerDown ) ;
489+ this . _bindEvent ( root , 'touchstart' , this . _onPointerDown ) ;
490+ this . _bindEvent ( root , 'mouseup' , this . _onPointerUp ) ;
491+ this . _bindEvent ( root , 'touchend' , this . _onPointerUp ) ;
492+ this . _bindEventInEditable ( root , 'keydown' , this . _onKeyDownOrKeyPress ) ;
493+ this . _bindEventInEditable ( root , 'keypress' , this . _onKeyDownOrKeyPress ) ;
494+ this . _bindEvent ( root , 'onkeyup' , this . _updateModifiersKeys ) ;
495+
496+ this . _bindEventInEditable ( root , 'cut' , this . _onClipboard ) ;
497+ this . _bindEventInEditable ( root , 'paste' , this . _onClipboard ) ;
498+ this . _bindEventInEditable ( root , 'dragstart' , this . _onDragStart ) ;
499+ this . _bindEventInEditable ( root , 'drop' , this . _onDrop ) ;
500+
501+ this . _mutationNormalizer = new MutationNormalizer (
502+ root instanceof Document ? root . body : root . lastElementChild ,
503+ ) ;
495504 }
496505 /**
497506 * Called when destroy the event normalizer.
@@ -501,6 +510,7 @@ export class EventNormalizer {
501510 destroy ( ) : void {
502511 this . _mutationNormalizer . destroy ( ) ;
503512 this . _unbindEvents ( ) ;
513+ this . _shadowNormalizers . forEach ( eventNormalizer => eventNormalizer . destroy ( ) ) ;
504514 }
505515
506516 //--------------------------------------------------------------------------
@@ -516,14 +526,14 @@ export class EventNormalizer {
516526 * @param type of the event to listen
517527 * @param listener to call when the even occurs on the target
518528 */
519- _bindEvent ( target : EventTarget , type : string , listener : Function ) : void {
529+ _bindEvent ( target : Document | ShadowRoot , type : string , listener : Function ) : void {
520530 const boundListener = listener . bind ( this ) ;
521531 this . _eventListeners . push ( {
522532 target : target ,
523533 type : type ,
524534 listener : boundListener ,
525535 } ) ;
526- target . addEventListener ( type , boundListener , false ) ;
536+ target . addEventListener ( type , boundListener , true ) ;
527537 }
528538 /**
529539 * Filter event from editable.
@@ -534,9 +544,20 @@ export class EventNormalizer {
534544 * @param type of the event to listen
535545 * @param listener to call when the even occurs on the target
536546 */
537- _bindEventInEditable ( target : EventTarget , type : string , listener : Function ) : void {
547+ _bindEventInEditable ( target : Document | ShadowRoot , type : string , listener : Function ) : void {
538548 const boundListener = ( ev : EventToProcess ) : void => {
539- if ( ! ( 'target' in ev ) || this . _isInEditable ( ev . target as Node ) ) {
549+ const eventTarget = 'target' in ev && ( ev . target as Element ) ;
550+ const shadowRoot = eventTarget instanceof Element && eventTarget . shadowRoot ;
551+ if ( shadowRoot ) {
552+ if ( ! this . _shadowNormalizers . get ( shadowRoot ) ) {
553+ const eventNormalizer = new EventNormalizer (
554+ this . _isInEditable ,
555+ this . _triggerEventBatch ,
556+ shadowRoot ,
557+ ) ;
558+ this . _shadowNormalizers . set ( shadowRoot , eventNormalizer ) ;
559+ }
560+ } else if ( ! eventTarget || this . _isInEditable ( eventTarget ) ) {
540561 listener . call ( this , ev ) ;
541562 }
542563 } ;
@@ -1306,7 +1327,18 @@ export class EventNormalizer {
13061327 */
13071328 _getSelection ( ev ?: MouseEvent | TouchEvent ) : DomSelectionDescription {
13081329 let selectionDescription : DomSelectionDescription ;
1309- const selection = document . getSelection ( ) ;
1330+ let target : Node ;
1331+ let root : Document | ShadowRoot ;
1332+ if ( ev ) {
1333+ target = this . _getEventTarget ( ev ) ;
1334+ root = getDocument ( target ) ;
1335+ } else if ( this . _initialCaretPosition ?. offsetNode ) {
1336+ root = getDocument ( this . _initialCaretPosition . offsetNode ) ;
1337+ } else {
1338+ root = document ;
1339+ }
1340+
1341+ const selection = root . getSelection ( ) ;
13101342
13111343 let forward : boolean ;
13121344 if ( ! selection || selection . rangeCount === 0 ) {
@@ -1339,8 +1371,7 @@ export class EventNormalizer {
13391371 // contained in the target of the event, otherwise it means it took no
13401372 // part in it. In this case, consider the caret position instead.
13411373 // This can happen when target is an input or a contenteditable=false.
1342- if ( ev && ev . target instanceof Node ) {
1343- const target = ev . target ;
1374+ if ( target instanceof Node ) {
13441375 if (
13451376 ! target . contains ( selectionDescription . anchorNode ) &&
13461377 ! target . contains ( selectionDescription . focusNode )
@@ -1369,14 +1400,35 @@ export class EventNormalizer {
13691400 if ( selection . direction === Direction . BACKWARD ) {
13701401 return false ;
13711402 }
1403+
13721404 let startContainer = selection . anchorNode ;
13731405 let startOffset = selection . anchorOffset ;
13741406 let endContainer = selection . focusNode ;
13751407 let endOffset = selection . focusOffset ;
1376- const body = document . body ;
1408+
13771409 // The selection might still be on a node which has since been removed.
1378- const invalidStart = ! startContainer || ! body . contains ( startContainer ) ;
1379- const invalidEnd = ! endContainer || ! body . contains ( endContainer ) ;
1410+ let invalidStart = true ;
1411+ let domNode = startContainer ;
1412+ while ( domNode && invalidStart ) {
1413+ if ( domNode instanceof ShadowRoot ) {
1414+ domNode = domNode . host ;
1415+ } else if ( document . body . contains ( domNode ) ) {
1416+ invalidStart = false ;
1417+ } else {
1418+ domNode = domNode . parentNode ;
1419+ }
1420+ }
1421+ let invalidEnd = true ;
1422+ domNode = endContainer ;
1423+ while ( domNode && invalidEnd ) {
1424+ if ( domNode instanceof ShadowRoot ) {
1425+ domNode = domNode . host ;
1426+ } else if ( document . body . contains ( domNode ) ) {
1427+ invalidEnd = false ;
1428+ } else {
1429+ domNode = domNode . parentNode ;
1430+ }
1431+ }
13801432 const invalidSelection = invalidStart || invalidEnd ;
13811433
13821434 // The selection might be collapsed in which case there is no selection.
@@ -1473,15 +1525,32 @@ export class EventNormalizer {
14731525 }
14741526 return this . _isVisible ( el . parentNode , editable ) ;
14751527 }
1528+ /**
1529+ * Return the node and offset targeted by a event, including if the target
1530+ * is inside a shadow element
1531+ *
1532+ * @param ev
1533+ */
14761534 _getEventCaretPosition ( ev : MouseEvent | TouchEvent ) : CaretPosition {
14771535 const x = ev instanceof MouseEvent ? ev . clientX : ev . touches [ 0 ] . clientX ;
14781536 const y = ev instanceof MouseEvent ? ev . clientY : ev . touches [ 0 ] . clientY ;
14791537 let caretPosition = caretPositionFromPoint ( x , y ) ;
1480- if ( ! this . _isInEditable ( caretPosition . offsetNode ) ) {
1538+ if ( ! caretPosition || ! this . _isInEditable ( caretPosition . offsetNode ) ) {
14811539 caretPosition = { offsetNode : ev . target as Node , offset : 0 } ;
14821540 }
14831541 return caretPosition ;
14841542 }
1543+ /**
1544+ * Use the position to get the target from the event (including the target
1545+ * in shadow element)
1546+ *
1547+ * @param ev
1548+ */
1549+ _getEventTarget ( ev : MouseEvent | TouchEvent ) : Node {
1550+ const x = ev instanceof MouseEvent ? ev . clientX : ev . touches [ 0 ] . clientX ;
1551+ const y = ev instanceof MouseEvent ? ev . clientY : ev . touches [ 0 ] . clientY ;
1552+ return elementFromPoint ( x , y ) || ( ev . target as Node ) ;
1553+ }
14851554
14861555 //--------------------------------------------------------------------------
14871556 // Handlers
@@ -1539,7 +1608,8 @@ export class EventNormalizer {
15391608 _onPointerDown ( ev : MouseEvent | TouchEvent ) : void {
15401609 // Don't trigger events on the editable if the click was done outside of
15411610 // the editable itself or on something else than an element.
1542- if ( ev . target instanceof Element && this . _isInEditable ( ev . target ) ) {
1611+ const target = this . _getEventTarget ( ev ) ;
1612+ if ( target && this . _isInEditable ( target ) ) {
15431613 this . _mousedownInEditable = true ;
15441614 this . _initialCaretPosition = this . _getEventCaretPosition ( ev ) ;
15451615 this . _selectionHasChanged = false ;
@@ -1563,7 +1633,6 @@ export class EventNormalizer {
15631633 // to the next tick as well. Store the data we have now before it
15641634 // gets invalidated by the redrawing of the DOM.
15651635 this . _initialCaretPosition = this . _getEventCaretPosition ( ev ) ;
1566-
15671636 this . _pointerSelectionTimeout = new Timeout < EventBatch > ( ( ) => {
15681637 return this . _analyzeSelectionChange ( ev ) ;
15691638 } ) ;
@@ -1700,10 +1769,8 @@ export class EventNormalizer {
17001769 */
17011770 _onSelectionChange ( ) : void {
17021771 if ( ! this . _initialCaretPosition ) {
1703- // TODO: Remove this once the renderer only re-renders what has
1704- // changed rather than re-rendering everything. Right now it is
1705- // needed to avoid an infinite loop when selectAll triggers a new
1706- // setRange, which triggers a new selection, which loops infinitely.
1772+ // Filter the events because we can have some Shadow root and each
1773+ // normaliser bind event on document.
17071774 return ;
17081775 }
17091776 const keydownEvent = this . currentStackObservation . _eventsMap . keydown ;
@@ -1730,7 +1797,6 @@ export class EventNormalizer {
17301797 const modifiedKeyEvent = this . _modifierKeys . ctrlKey || this . _modifierKeys . metaKey ;
17311798 const heuristic = modifiedKeyEvent || this . _followsPointerAction ;
17321799 const isSelectAll = heuristic && this . _isSelectAll ( this . _getSelection ( ) ) ;
1733-
17341800 if ( isSelectAll && ! this . _currentlySelectingAll ) {
17351801 if ( modifiedKeyEvent ) {
17361802 // This select all was triggered from the keyboard. Add a
0 commit comments