| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- /**
- * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
- */
- /* global document, Event */
- import clickOutsideHandler from '../../src/bindings/clickoutsidehandler';
- import DomEmitterMixin from '@ckeditor/ckeditor5-utils/src/dom/emittermixin';
- import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
- describe( 'clickOutsideHandler', () => {
- let activator, actionSpy, contextElement1, contextElement2;
- let shadowRootContainer, shadowContextElement1, shadowContextElement2;
- testUtils.createSinonSandbox();
- beforeEach( () => {
- activator = testUtils.sinon.stub().returns( false );
- contextElement1 = document.createElement( 'div' );
- contextElement2 = document.createElement( 'div' );
- shadowRootContainer = document.createElement( 'div' );
- shadowRootContainer.attachShadow( { mode: 'open' } );
- shadowContextElement1 = document.createElement( 'div' );
- shadowContextElement2 = document.createElement( 'div' );
- actionSpy = testUtils.sinon.spy();
- document.body.appendChild( contextElement1 );
- document.body.appendChild( contextElement2 );
- shadowRootContainer.shadowRoot.appendChild( shadowContextElement1 );
- shadowRootContainer.shadowRoot.appendChild( shadowContextElement2 );
- document.body.appendChild( shadowRootContainer );
- clickOutsideHandler( {
- emitter: Object.create( DomEmitterMixin ),
- activator,
- contextElements: [ contextElement1, contextElement2, shadowContextElement1, shadowContextElement2 ],
- callback: actionSpy
- } );
- } );
- afterEach( () => {
- document.body.removeChild( contextElement1 );
- document.body.removeChild( contextElement2 );
- document.body.removeChild( shadowRootContainer );
- } );
- it( 'should execute upon #mousedown outside of the contextElements (activator is active)', () => {
- activator.returns( true );
- document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.calledOnce( actionSpy );
- } );
- it( 'should execute upon #mousedown outside of the contextElements (activator is active, unsupported shadow DOM)', () => {
- activator.returns( true );
- const event = new Event( 'mousedown', { bubbles: true } );
- event.composedPath = undefined;
- document.body.dispatchEvent( event );
- sinon.assert.calledOnce( actionSpy );
- } );
- it( 'should execute upon #mousedown in the shadow root but outside the contextElements (activator is active)', () => {
- activator.returns( true );
- shadowRootContainer.shadowRoot.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- } );
- it( 'should not execute upon #mousedown outside of the contextElements (activator is inactive)', () => {
- activator.returns( false );
- document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- } );
- it( 'should not execute upon #mousedown outside of the contextElements (activator is inactive, unsupported shadow DOM)', () => {
- activator.returns( false );
- const event = new Event( 'mousedown', { bubbles: true } );
- event.composedPath = undefined;
- document.body.dispatchEvent( event );
- sinon.assert.notCalled( actionSpy );
- } );
- it( 'should not execute upon #mousedown in the shadow root but outside of the contextElements (activator is inactive)', () => {
- activator.returns( false );
- shadowRootContainer.shadowRoot.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- } );
- it( 'should not execute upon #mousedown from one of the contextElements (activator is active)', () => {
- activator.returns( true );
- contextElement1.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- contextElement2.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- shadowContextElement1.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- shadowContextElement2.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- } );
- it( 'should not execute upon #mousedown from one of the contextElements (activator is inactive)', () => {
- activator.returns( false );
- contextElement1.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- contextElement2.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- shadowContextElement1.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- shadowContextElement2.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- } );
- it( 'should execute if the activator function returns `true`', () => {
- const spy = testUtils.sinon.spy();
- activator.returns( true );
- clickOutsideHandler( {
- emitter: Object.create( DomEmitterMixin ),
- activator,
- contextElements: [ contextElement1 ],
- callback: spy
- } );
- document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.calledOnce( spy );
- } );
- it( 'should not execute if the activator function returns `false`', () => {
- const spy = testUtils.sinon.spy();
- activator.returns( false );
- clickOutsideHandler( {
- emitter: Object.create( DomEmitterMixin ),
- activator,
- contextElements: [ contextElement1 ],
- callback: spy
- } );
- document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.notCalled( spy );
- } );
- it( 'should react to the activator\'s return value change', () => {
- activator.returns( true );
- document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.calledOnce( actionSpy );
- activator.returns( false );
- document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- // Still called once, was not called second time.
- sinon.assert.calledOnce( actionSpy );
- activator.returns( true );
- document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- // Called one more time.
- sinon.assert.calledTwice( actionSpy );
- } );
- it( 'should not execute if one of contextElements contains the DOM event target', () => {
- const target = document.createElement( 'div' );
- activator.returns( true );
- contextElement2.appendChild( target );
- target.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- } );
- it( 'should not execute if one of contextElements in the shadow root contains the DOM event target', () => {
- const target = document.createElement( 'div' );
- activator.returns( true );
- shadowContextElement1.appendChild( target );
- target.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- } );
- it( 'should not execute if one of contextElements in the shadow root is the DOM event target', () => {
- const target = document.createElement( 'div' );
- activator.returns( true );
- shadowRootContainer.shadowRoot.appendChild( target );
- target.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
- sinon.assert.notCalled( actionSpy );
- } );
- } );
|