Explorar el Código

Merge pull request #353 from ckeditor/t/311a

Other: The `closeDropdownOnBlur()` helper should use `clickOutsideHandler()`. Decorated the `View#render()` method. Closes #311.
Piotrek Koszuliński hace 8 años
padre
commit
4607ba1329

+ 10 - 23
packages/ckeditor5-ui/src/dropdown/utils.js

@@ -7,7 +7,7 @@
  * @module ui/dropdown/utils
  * @module ui/dropdown/utils
  */
  */
 
 
-/* global document */
+import clickOutsideHandler from '../bindings/clickoutsidehandler';
 
 
 /**
 /**
  * Adds a behavior to a dropdownView that focuses dropdown panel view contents on keystrokes.
  * Adds a behavior to a dropdownView that focuses dropdown panel view contents on keystrokes.
@@ -57,27 +57,14 @@ export function closeDropdownOnExecute( dropdownView, viewCollection ) {
  * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
  * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
  */
  */
 export function closeDropdownOnBlur( dropdownView ) {
 export function closeDropdownOnBlur( dropdownView ) {
-	dropdownView.on( 'change:isOpen', ( evt, name, value ) => {
-		if ( value ) {
-			attachDocumentClickListener( document, dropdownView );
-		} else {
-			dropdownView.stopListening( document );
-		}
-	} );
-}
-
-// Attaches a "click" listener in DOM to check if any element outside
-// the dropdown has been clicked.
-//
-// @private
-// @param {module:ui/dropdown/listdropdownview~ListDropdownView} dropdownView
-function attachDocumentClickListener( document, dropdownView ) {
-	// TODO: It will probably be focus/blur-based rather than click. It should be bound
-	// to focusmanager of some sort.
-	dropdownView.listenTo( document, 'click', ( evtInfo, { target: domEvtTarget } ) => {
-		// Collapse the dropdown when the webpage outside of the component is clicked.
-		if ( dropdownView.element != domEvtTarget && !dropdownView.element.contains( domEvtTarget ) ) {
-			dropdownView.isOpen = false;
-		}
+	dropdownView.on( 'render', () => {
+		clickOutsideHandler( {
+			emitter: dropdownView,
+			activator: () => dropdownView.isOpen,
+			callback: () => {
+				dropdownView.isOpen = false;
+			},
+			contextElements: [ dropdownView.element ]
+		} );
 	} );
 	} );
 }
 }

+ 11 - 0
packages/ckeditor5-ui/src/view.js

@@ -190,6 +190,8 @@ export default class View {
 		 * @private
 		 * @private
 		 * @member {Object} #_bindTemplate
 		 * @member {Object} #_bindTemplate
 		 */
 		 */
+
+		this.decorate( 'render' );
 	}
 	}
 
 
 	/**
 	/**
@@ -492,6 +494,15 @@ export default class View {
 
 
 		this._viewCollections.map( c => c.destroy() );
 		this._viewCollections.map( c => c.destroy() );
 	}
 	}
+
+	/**
+	 * Event fired by the {@link #render} method. Actual rendering is executed as a listener to
+	 * this event with the default priority.
+	 *
+	 * See {@link module:utils/observablemixin~ObservableMixin.decorate} for more information and samples.
+	 *
+	 * @event render
+	 */
 }
 }
 
 
 mix( View, DomEmitterMixin );
 mix( View, DomEmitterMixin );

+ 4 - 4
packages/ckeditor5-ui/tests/dropdown/button/createbuttondropdown.js

@@ -95,7 +95,7 @@ describe( 'createButtonDropdown', () => {
 			view.isOpen = true;
 			view.isOpen = true;
 
 
 			// Fire event from outside of the dropdown.
 			// Fire event from outside of the dropdown.
-			document.body.dispatchEvent( new Event( 'click', {
+			document.body.dispatchEvent( new Event( 'mousedown', {
 				bubbles: true
 				bubbles: true
 			} ) );
 			} ) );
 
 
@@ -103,7 +103,7 @@ describe( 'createButtonDropdown', () => {
 			expect( view.isOpen ).to.be.false;
 			expect( view.isOpen ).to.be.false;
 
 
 			// Fire event from outside of the dropdown.
 			// Fire event from outside of the dropdown.
-			document.body.dispatchEvent( new Event( 'click', {
+			document.body.dispatchEvent( new Event( 'mousedown', {
 				bubbles: true
 				bubbles: true
 			} ) );
 			} ) );
 
 
@@ -116,7 +116,7 @@ describe( 'createButtonDropdown', () => {
 			view.isOpen = true;
 			view.isOpen = true;
 
 
 			// Event from view.element should be discarded.
 			// Event from view.element should be discarded.
-			view.element.dispatchEvent( new Event( 'click', {
+			view.element.dispatchEvent( new Event( 'mousedown', {
 				bubbles: true
 				bubbles: true
 			} ) );
 			} ) );
 
 
@@ -127,7 +127,7 @@ describe( 'createButtonDropdown', () => {
 			const child = document.createElement( 'div' );
 			const child = document.createElement( 'div' );
 			view.element.appendChild( child );
 			view.element.appendChild( child );
 
 
-			child.dispatchEvent( new Event( 'click', {
+			child.dispatchEvent( new Event( 'mousedown', {
 				bubbles: true
 				bubbles: true
 			} ) );
 			} ) );
 
 

+ 4 - 4
packages/ckeditor5-ui/tests/dropdown/list/createlistdropdown.js

@@ -106,7 +106,7 @@ describe( 'createListDropdown', () => {
 			view.isOpen = true;
 			view.isOpen = true;
 
 
 			// Fire event from outside of the dropdown.
 			// Fire event from outside of the dropdown.
-			document.body.dispatchEvent( new Event( 'click', {
+			document.body.dispatchEvent( new Event( 'mousedown', {
 				bubbles: true
 				bubbles: true
 			} ) );
 			} ) );
 
 
@@ -114,7 +114,7 @@ describe( 'createListDropdown', () => {
 			expect( view.isOpen ).to.be.false;
 			expect( view.isOpen ).to.be.false;
 
 
 			// Fire event from outside of the dropdown.
 			// Fire event from outside of the dropdown.
-			document.body.dispatchEvent( new Event( 'click', {
+			document.body.dispatchEvent( new Event( 'mousedown', {
 				bubbles: true
 				bubbles: true
 			} ) );
 			} ) );
 
 
@@ -127,7 +127,7 @@ describe( 'createListDropdown', () => {
 			view.isOpen = true;
 			view.isOpen = true;
 
 
 			// Event from view.element should be discarded.
 			// Event from view.element should be discarded.
-			view.element.dispatchEvent( new Event( 'click', {
+			view.element.dispatchEvent( new Event( 'mousedown', {
 				bubbles: true
 				bubbles: true
 			} ) );
 			} ) );
 
 
@@ -138,7 +138,7 @@ describe( 'createListDropdown', () => {
 			const child = document.createElement( 'div' );
 			const child = document.createElement( 'div' );
 			view.element.appendChild( child );
 			view.element.appendChild( child );
 
 
-			child.dispatchEvent( new Event( 'click', {
+			child.dispatchEvent( new Event( 'mousedown', {
 				bubbles: true
 				bubbles: true
 			} ) );
 			} ) );
 
 

+ 11 - 0
packages/ckeditor5-ui/tests/view.js

@@ -195,6 +195,17 @@ describe( 'View', () => {
 	} );
 	} );
 
 
 	describe( 'render()', () => {
 	describe( 'render()', () => {
+		it( 'is decorated', done => {
+			const view = new View();
+
+			view.on( 'render', () => {
+				expect( view.isRendered ).to.be.true;
+				done();
+			} );
+
+			view.render();
+		} );
+
 		it( 'should throw if already rendered', () => {
 		it( 'should throw if already rendered', () => {
 			const view = new View();
 			const view = new View();