8
0
Quellcode durchsuchen

Merge pull request #7829 from ckeditor/i/201-page-editing

Feature (utils): Introduced the `passive` option support in the `DomEmitterMixin#listenTo()` method. Closes #7828.
Aleksander Nowodzinski vor 5 Jahren
Ursprung
Commit
a7ef65c824

+ 17 - 5
packages/ckeditor5-utils/src/dom/emittermixin.js

@@ -49,6 +49,8 @@ const DomEmitterMixin = extend( {}, EmitterMixin, {
 	 * order they were added.
 	 * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered
 	 * listener before being dispatched to any EventTarget beneath it in the DOM tree.
+	 * @param {Boolean} [options.usePassive=false] Indicates that the function specified by listener will never call preventDefault()
+	 * and prevents blocking browser's main thread by this event handler.
 	 */
 	listenTo( emitter, ...rest ) {
 		// Check if emitter is an instance of DOM Node. If so, replace the argument with
@@ -179,6 +181,8 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 	 * @param {Object} [options={}] Additional options.
 	 * @param {Boolean} [options.useCapture=false] Indicates that events of this type will be dispatched to the registered
 	 * listener before being dispatched to any EventTarget beneath it in the DOM tree.
+	 * @param {Boolean} [options.usePassive=false] Indicates that the function specified by listener will never call preventDefault()
+	 * and prevents blocking browser's main thread by this event handler.
 	 */
 	attach( event, callback, options = {} ) {
 		// If the DOM Listener for given event already exist it is pointless
@@ -187,10 +191,15 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 			return;
 		}
 
-		const domListener = this._createDomListener( event, !!options.useCapture );
+		const listenerOptions = {
+			capture: !!options.useCapture,
+			passive: !!options.usePassive
+		};
+
+		const domListener = this._createDomListener( event, listenerOptions );
 
 		// Attach the native DOM listener to DOM Node.
-		this._domNode.addEventListener( event, domListener, !!options.useCapture );
+		this._domNode.addEventListener( event, domListener, listenerOptions );
 
 		if ( !this._domListeners ) {
 			this._domListeners = {};
@@ -227,10 +236,13 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 	 * @private
 	 * @method module:utils/dom/emittermixin~ProxyEmitter#_createDomListener
 	 * @param {String} event The name of the event.
-	 * @param {Boolean} useCapture Indicates whether the listener was created for capturing event.
+	 * @param {Object} [options] Additional options.
+	 * @param {Boolean} [options.capture=false] Indicates whether the listener was created for capturing event.
+	 * @param {Boolean} [options.passive=false] Indicates that the function specified by listener will never call preventDefault()
+	 * and prevents blocking browser's main thread by this event handler.
 	 * @returns {Function} The DOM listener callback.
 	 */
-	_createDomListener( event, useCapture ) {
+	_createDomListener( event, options ) {
 		const domListener = domEvt => {
 			this.fire( event, domEvt );
 		};
@@ -239,7 +251,7 @@ extend( ProxyEmitter.prototype, EmitterMixin, {
 		// detach it from the DOM Node, when it is no longer necessary.
 		// See: {@link detach}.
 		domListener.removeListener = () => {
-			this._domNode.removeEventListener( event, domListener, useCapture );
+			this._domNode.removeEventListener( event, domListener, options );
 			delete this._domListeners[ event ];
 		};
 

+ 26 - 0
packages/ckeditor5-utils/tests/dom/emittermixin.js

@@ -113,6 +113,32 @@ describe( 'DomEmitterMixin', () => {
 				sinon.assert.calledOnce( spy );
 			} );
 		} );
+
+		describe( 'event passive handling', () => {
+			it( 'should not use passive mode by default', () => {
+				const spy = sinon.spy( node, 'addEventListener' );
+
+				domEmitter.listenTo( node, 'test', () => {} );
+
+				expect( spy.calledWith( 'test', sinon.match.func, sinon.match( { capture: false, passive: false } ) ) ).to.be.true;
+			} );
+
+			it( 'should optionally use passive mode', () => {
+				const spy = sinon.spy( node, 'addEventListener' );
+
+				domEmitter.listenTo( node, 'test', () => {}, { usePassive: true } );
+
+				expect( spy.calledWith( 'test', sinon.match.func, sinon.match( { capture: false, passive: true } ) ) ).to.be.true;
+			} );
+
+			it( 'should not get activated for event capturing (if not desired)', () => {
+				const spy = sinon.spy( node, 'addEventListener' );
+
+				domEmitter.listenTo( node, 'test', () => {}, { useCapture: true } );
+
+				expect( spy.calledWith( 'test', sinon.match.func, sinon.match( { capture: true, passive: false } ) ) ).to.be.true;
+			} );
+		} );
 	} );
 
 	describe( 'stopListening', () => {