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

Commit 269e97b

Browse files
authored
Merge pull request #353 from ckeditor/t/311a
Other: The `closeDropdownOnBlur()` helper should use `clickOutsideHandler()`. Decorated the `View#render()` method. Closes #311.
2 parents ca6c636 + 01d0230 commit 269e97b

File tree

5 files changed

+40
-31
lines changed

5 files changed

+40
-31
lines changed

src/dropdown/utils.js

+10-23
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @module ui/dropdown/utils
88
*/
99

10-
/* global document */
10+
import clickOutsideHandler from '../bindings/clickoutsidehandler';
1111

1212
/**
1313
* Adds a behavior to a dropdownView that focuses dropdown panel view contents on keystrokes.
@@ -57,27 +57,14 @@ export function closeDropdownOnExecute( dropdownView, viewCollection ) {
5757
* @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
5858
*/
5959
export function closeDropdownOnBlur( dropdownView ) {
60-
dropdownView.on( 'change:isOpen', ( evt, name, value ) => {
61-
if ( value ) {
62-
attachDocumentClickListener( document, dropdownView );
63-
} else {
64-
dropdownView.stopListening( document );
65-
}
66-
} );
67-
}
68-
69-
// Attaches a "click" listener in DOM to check if any element outside
70-
// the dropdown has been clicked.
71-
//
72-
// @private
73-
// @param {module:ui/dropdown/listdropdownview~ListDropdownView} dropdownView
74-
function attachDocumentClickListener( document, dropdownView ) {
75-
// TODO: It will probably be focus/blur-based rather than click. It should be bound
76-
// to focusmanager of some sort.
77-
dropdownView.listenTo( document, 'click', ( evtInfo, { target: domEvtTarget } ) => {
78-
// Collapse the dropdown when the webpage outside of the component is clicked.
79-
if ( dropdownView.element != domEvtTarget && !dropdownView.element.contains( domEvtTarget ) ) {
80-
dropdownView.isOpen = false;
81-
}
60+
dropdownView.on( 'render', () => {
61+
clickOutsideHandler( {
62+
emitter: dropdownView,
63+
activator: () => dropdownView.isOpen,
64+
callback: () => {
65+
dropdownView.isOpen = false;
66+
},
67+
contextElements: [ dropdownView.element ]
68+
} );
8269
} );
8370
}

src/view.js

+11
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ export default class View {
190190
* @private
191191
* @member {Object} #_bindTemplate
192192
*/
193+
194+
this.decorate( 'render' );
193195
}
194196

195197
/**
@@ -492,6 +494,15 @@ export default class View {
492494

493495
this._viewCollections.map( c => c.destroy() );
494496
}
497+
498+
/**
499+
* Event fired by the {@link #render} method. Actual rendering is executed as a listener to
500+
* this event with the default priority.
501+
*
502+
* See {@link module:utils/observablemixin~ObservableMixin.decorate} for more information and samples.
503+
*
504+
* @event render
505+
*/
495506
}
496507

497508
mix( View, DomEmitterMixin );

tests/dropdown/button/createbuttondropdown.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ describe( 'createButtonDropdown', () => {
9595
view.isOpen = true;
9696

9797
// Fire event from outside of the dropdown.
98-
document.body.dispatchEvent( new Event( 'click', {
98+
document.body.dispatchEvent( new Event( 'mousedown', {
9999
bubbles: true
100100
} ) );
101101

102102
// Closed the dropdown.
103103
expect( view.isOpen ).to.be.false;
104104

105105
// Fire event from outside of the dropdown.
106-
document.body.dispatchEvent( new Event( 'click', {
106+
document.body.dispatchEvent( new Event( 'mousedown', {
107107
bubbles: true
108108
} ) );
109109

@@ -116,7 +116,7 @@ describe( 'createButtonDropdown', () => {
116116
view.isOpen = true;
117117

118118
// Event from view.element should be discarded.
119-
view.element.dispatchEvent( new Event( 'click', {
119+
view.element.dispatchEvent( new Event( 'mousedown', {
120120
bubbles: true
121121
} ) );
122122

@@ -127,7 +127,7 @@ describe( 'createButtonDropdown', () => {
127127
const child = document.createElement( 'div' );
128128
view.element.appendChild( child );
129129

130-
child.dispatchEvent( new Event( 'click', {
130+
child.dispatchEvent( new Event( 'mousedown', {
131131
bubbles: true
132132
} ) );
133133

tests/dropdown/list/createlistdropdown.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,15 @@ describe( 'createListDropdown', () => {
106106
view.isOpen = true;
107107

108108
// Fire event from outside of the dropdown.
109-
document.body.dispatchEvent( new Event( 'click', {
109+
document.body.dispatchEvent( new Event( 'mousedown', {
110110
bubbles: true
111111
} ) );
112112

113113
// Closed the dropdown.
114114
expect( view.isOpen ).to.be.false;
115115

116116
// Fire event from outside of the dropdown.
117-
document.body.dispatchEvent( new Event( 'click', {
117+
document.body.dispatchEvent( new Event( 'mousedown', {
118118
bubbles: true
119119
} ) );
120120

@@ -127,7 +127,7 @@ describe( 'createListDropdown', () => {
127127
view.isOpen = true;
128128

129129
// Event from view.element should be discarded.
130-
view.element.dispatchEvent( new Event( 'click', {
130+
view.element.dispatchEvent( new Event( 'mousedown', {
131131
bubbles: true
132132
} ) );
133133

@@ -138,7 +138,7 @@ describe( 'createListDropdown', () => {
138138
const child = document.createElement( 'div' );
139139
view.element.appendChild( child );
140140

141-
child.dispatchEvent( new Event( 'click', {
141+
child.dispatchEvent( new Event( 'mousedown', {
142142
bubbles: true
143143
} ) );
144144

tests/view.js

+11
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,17 @@ describe( 'View', () => {
195195
} );
196196

197197
describe( 'render()', () => {
198+
it( 'is decorated', done => {
199+
const view = new View();
200+
201+
view.on( 'render', () => {
202+
expect( view.isRendered ).to.be.true;
203+
done();
204+
} );
205+
206+
view.render();
207+
} );
208+
198209
it( 'should throw if already rendered', () => {
199210
const view = new View();
200211

0 commit comments

Comments
 (0)