diff --git a/core/emitter.js b/core/emitter.js index 0f9ba4f06a..76fd97e5ea 100644 --- a/core/emitter.js +++ b/core/emitter.js @@ -4,14 +4,12 @@ import logger from './logger'; const debug = logger('quill:events'); const EVENTS = ['selectionchange', 'mousedown', 'mouseup', 'click']; +const EMITTERS = []; EVENTS.forEach(eventName => { document.addEventListener(eventName, (...args) => { - Array.from(document.querySelectorAll('.ql-container')).forEach(node => { - const quill = instances.get(node); - if (quill && quill.emitter) { - quill.emitter.handleDOM(...args); - } + EMITTERS.forEach(emitter => { + emitter.handleDOM(...args); }); }); }); @@ -20,6 +18,7 @@ class Emitter extends EventEmitter { constructor() { super(); this.listeners = {}; + EMITTERS.push(this); this.on('error', debug.error); } @@ -29,8 +28,24 @@ class Emitter extends EventEmitter { } handleDOM(event, ...args) { + const target = (event.composedPath ? event.composedPath()[0] : event.target); + const containsNode = (node, target) => { + if (!('getRootNode' in document) || target.getRootNode() === document) { + return node.contains(target); + } + + while (!node.contains(target)) { + const root = target.getRootNode(); + if (!root || !root.host) { + return false; + } + target = root.host; + } + + return true; + }; (this.listeners[event.type] || []).forEach(({ node, handler }) => { - if (event.target === node || node.contains(event.target)) { + if (target === node || containsNode(node, target)) { handler(event, ...args); } }); diff --git a/core/selection.js b/core/selection.js index b181b088f8..3761ebaa75 100644 --- a/core/selection.js +++ b/core/selection.js @@ -20,13 +20,14 @@ class Selection { this.composing = false; this.mouseDown = false; this.root = this.scroll.domNode; + this.rootDocument = (this.root.getRootNode ? this.root.getRootNode() : document); this.cursor = this.scroll.create('cursor', this); // savedRange is last non-null range this.savedRange = new Range(0, 0); this.lastRange = this.savedRange; this.handleComposition(); this.handleDragging(); - this.emitter.listenDOM('selectionchange', document, () => { + this.emitter.listenDOM('selectionchange', this.rootDocument, () => { if (!this.mouseDown && !this.composing) { setTimeout(this.update.bind(this, Emitter.sources.USER), 1); } @@ -175,7 +176,7 @@ class Selection { } getNativeRange() { - const selection = document.getSelection(); + const selection = this.rootDocument.getSelection(); if (selection == null || selection.rangeCount <= 0) return null; const nativeRange = selection.getRangeAt(0); if (nativeRange == null) return null; @@ -193,8 +194,8 @@ class Selection { hasFocus() { return ( - document.activeElement === this.root || - contains(this.root, document.activeElement) + this.rootDocument.activeElement === this.root || + contains(this.root, this.rootDocument.activeElement) ); } @@ -316,7 +317,7 @@ class Selection { ) { return; } - const selection = document.getSelection(); + const selection = this.rootDocument.getSelection(); if (selection == null) return; if (startNode != null) { if (!this.hasFocus()) this.root.focus(); diff --git a/modules/toolbar.js b/modules/toolbar.js index a16923ec0a..d73a15c7c1 100644 --- a/modules/toolbar.js +++ b/modules/toolbar.js @@ -15,7 +15,8 @@ class Toolbar extends Module { quill.container.parentNode.insertBefore(container, quill.container); this.container = container; } else if (typeof this.options.container === 'string') { - this.container = document.querySelector(this.options.container); + const rootDocument = ('getRootNode' in document ? quill.container.getRootNode() : document); + this.container = rootDocument.querySelector(this.options.container); } else { this.container = this.options.container; }