Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit 6b980b6

Browse files
authored
Merge pull request #282 from ckeditor/t/281
Fix: The `clickOutsideHandler` helper should use `mousedown` instead of `mouseup` event. Closes #281.
2 parents 1588c82 + 3e423fc commit 6b980b6

File tree

2 files changed

+25
-15
lines changed

2 files changed

+25
-15
lines changed

src/bindings/clickoutsidehandler.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* @param {Function} options.callback Function fired after clicking outside of specified elements.
2323
*/
2424
export default function clickOutsideHandler( { emitter, activator, callback, contextElements } ) {
25-
emitter.listenTo( document, 'mouseup', ( evt, { target } ) => {
25+
emitter.listenTo( document, 'mousedown', ( evt, { target } ) => {
2626
if ( !activator() ) {
2727
return;
2828
}

tests/bindings/clickoutsidehandler.js

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,23 +38,23 @@ describe( 'clickOutsideHandler', () => {
3838
document.body.removeChild( contextElement2 );
3939
} );
4040

41-
it( 'should fired callback after clicking out of context element when listener is active', () => {
41+
it( 'should execute upon #mousedown outside of the contextElements (activator is active)', () => {
4242
activator.returns( true );
4343

44-
document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
44+
document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
4545

4646
sinon.assert.calledOnce( actionSpy );
4747
} );
4848

49-
it( 'should not fired callback after clicking out of context element when listener is not active', () => {
49+
it( 'should not execute upon #mousedown outside of the contextElements (activator is inactive)', () => {
5050
activator.returns( false );
5151

52-
document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
52+
document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
5353

5454
sinon.assert.notCalled( actionSpy );
5555
} );
5656

57-
it( 'should not fired callback after clicking on context element when listener is active', () => {
57+
it( 'should not execute upon #mousedown from one of the contextElements (activator is active)', () => {
5858
activator.returns( true );
5959

6060
contextElement1.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
@@ -64,7 +64,7 @@ describe( 'clickOutsideHandler', () => {
6464
sinon.assert.notCalled( actionSpy );
6565
} );
6666

67-
it( 'should not fired callback after clicking on context element when listener is not active', () => {
67+
it( 'should not execute upon #mousedown from one of the contextElements (activator is inactive)', () => {
6868
activator.returns( false );
6969

7070
contextElement1.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
@@ -74,7 +74,7 @@ describe( 'clickOutsideHandler', () => {
7474
sinon.assert.notCalled( actionSpy );
7575
} );
7676

77-
it( 'should listen when model initial `ifActive` value was `true`', () => {
77+
it( 'should execute if the activator function returns `true`', () => {
7878
const spy = testUtils.sinon.spy();
7979

8080
activator.returns( true );
@@ -86,12 +86,12 @@ describe( 'clickOutsideHandler', () => {
8686
callback: spy
8787
} );
8888

89-
document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
89+
document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
9090

9191
sinon.assert.calledOnce( spy );
9292
} );
9393

94-
it( 'should not listen when model initial `ifActive` value was `false`', () => {
94+
it( 'should not execute if the activator function returns `false`', () => {
9595
const spy = testUtils.sinon.spy();
9696

9797
activator.returns( false );
@@ -103,30 +103,40 @@ describe( 'clickOutsideHandler', () => {
103103
callback: spy
104104
} );
105105

106-
document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
106+
document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
107107

108108
sinon.assert.notCalled( spy );
109109
} );
110110

111-
it( 'should react on model `ifActive` property change', () => {
111+
it( 'should react to the activator\'s return value change', () => {
112112
activator.returns( true );
113113

114-
document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
114+
document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
115115

116116
sinon.assert.calledOnce( actionSpy );
117117

118118
activator.returns( false );
119119

120-
document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
120+
document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
121121

122122
// Still called once, was not called second time.
123123
sinon.assert.calledOnce( actionSpy );
124124

125125
activator.returns( true );
126126

127-
document.body.dispatchEvent( new Event( 'mouseup', { bubbles: true } ) );
127+
document.body.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
128128

129129
// Called one more time.
130130
sinon.assert.calledTwice( actionSpy );
131131
} );
132+
133+
it( 'should not execute if one of contextElements contains the DOM event target', () => {
134+
const target = document.createElement( 'div' );
135+
activator.returns( true );
136+
137+
contextElement2.appendChild( target );
138+
target.dispatchEvent( new Event( 'mousedown', { bubbles: true } ) );
139+
140+
sinon.assert.notCalled( actionSpy );
141+
} );
132142
} );

0 commit comments

Comments
 (0)