8
0
Pārlūkot izejas kodu

Merge pull request #277 from ckeditor/t/273

Implemented FocusObserver.
Piotrek Koszuliński 9 gadi atpakaļ
vecāks
revīzija
809100ce74

+ 9 - 7
packages/ckeditor5-engine/src/treeview/observer/domeventobserver.js

@@ -37,9 +37,11 @@ export default class DomEventObserver extends Observer {
 		super( treeView );
 
 		/**
-		 * Type of the DOM event the observer should listen on.
+		 * Type of the DOM event the observer should listen on. Array of types can be defined
+		 * if the obsever should listen to multiple DOM events.
 		 *
-		 * @member {String} core.treeView.observer.DomEventObserver#domEventType
+		 * @readonly
+		 * @member {String|Array.<String>} core.treeView.observer.DomEventObserver#domEventType
 		 */
 	}
 
@@ -56,10 +58,10 @@ export default class DomEventObserver extends Observer {
 	 * @inheritDoc
 	 */
 	observe( domElement ) {
-		domElement.addEventListener( this.domEventType, domEvent => {
-			if ( this.isEnabled ) {
-				this.onDomEvent( domEvent );
-			}
+		const types = typeof this.domEventType == 'string' ? [ this.domEventType ] : this.domEventType;
+
+		types.forEach( type => {
+			domElement.addEventListener( type, domEvent => this.isEnabled && this.onDomEvent( domEvent ) );
 		} );
 	}
 
@@ -72,7 +74,7 @@ export default class DomEventObserver extends Observer {
 	 */
 	fire( ...args ) {
 		if ( this.isEnabled ) {
-			this.treeView.fire.apply( this.treeView, args );
+			this.treeView.fire( ...args );
 		}
 	}
 }

+ 50 - 0
packages/ckeditor5-engine/src/treeview/observer/focusobserver.js

@@ -0,0 +1,50 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import DomEventObserver from './domeventobserver.js';
+
+/**
+ * {@link core.treeView.TreeView#focus Focus} and {@link core.treeView.TreeView#blur blur} events observer.
+ *
+ * @memberOf core.treeView.observer
+ * @extends core.treeView.observer.DomEventObserver
+ */
+export default class FocusObserver extends DomEventObserver {
+	constructor( treeView ) {
+		super( treeView );
+
+		this.domEventType = [ 'focus', 'blur' ];
+	}
+
+	onDomEvent( domEvt ) {
+		const treeView = this.treeView;
+
+		this.fire( domEvt.type, {
+			get target() {
+				return treeView.domConverter.getCorrespondingViewElement( domEvt.target );
+			},
+
+			domTarget: domEvt.target
+		} );
+	}
+}
+
+/**
+ * Fired when one of the editables gets focus.
+ *
+ * @event core.treeView.TreeView#focus
+ * @param {core.treeView.Element} data.target The event view target (editable element that was focused).
+ * @param {HTMLElement} data.domTarget The event DOM target (editable element that was focused).
+ */
+
+/**
+ * Fired when one of the editables loses focus.
+ *
+ * @event core.treeView.TreeView#blur
+ * @param {core.treeView.Element} data.target The event view target (editable element that was blurred).
+ * @param {HTMLElement} data.domTarget The event DOM target (editable element that was blurred).
+ */

+ 6 - 0
packages/ckeditor5-engine/tests/treeview/manual/focusobserver.html

@@ -0,0 +1,6 @@
+<div contenteditable="true" id="editable1" style="border: solid 1px blue">
+	<p>First editable.</p>
+</div>
+<div contenteditable="true" id="editable2" style="border: solid 1px blue">
+	<p>Second editable.</p>
+</div>

+ 21 - 0
packages/ckeditor5-engine/tests/treeview/manual/focusobserver.js

@@ -0,0 +1,21 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global console:false */
+
+'use strict';
+
+import TreeView from '/ckeditor5/core/treeview/treeview.js';
+import FocusObserver from '/ckeditor5/core/treeview/observer/focusobserver.js';
+
+const treeView = new TreeView();
+
+treeView.on( 'focus', ( evt, data ) => console.log( 'focus', data.domTarget ) );
+treeView.on( 'blur', ( evt, data ) => console.log( 'blur', data.domTarget ) );
+
+treeView.addObserver( FocusObserver );
+
+treeView.createRoot( document.getElementById( 'editable1' ), 'editable1' );
+treeView.createRoot( document.getElementById( 'editable2' ), 'editable2' );

+ 9 - 0
packages/ckeditor5-engine/tests/treeview/manual/focusobserver.md

@@ -0,0 +1,9 @@
+@bender-ui: collapsed
+@bender-tags: treeview
+
+* Open console.
+* Focus the first editable.
+  * Focus in the 1st editable should be logged.
+* Focus the second editable.
+  * Blur in the 1st editable should be logged.
+  * Focus in the 2nd editable should be logged.

+ 36 - 5
packages/ckeditor5-engine/tests/treeview/observer/domeventobserver.js

@@ -11,7 +11,7 @@ import DomEventObserver from '/ckeditor5/core/treeview/observer/domeventobserver
 import Observer from '/ckeditor5/core/treeview/observer/observer.js';
 import TreeView from '/ckeditor5/core/treeview/treeview.js';
 
-class TestObserver extends DomEventObserver {
+class ClickObserver extends DomEventObserver {
 	constructor( treeView ) {
 		super( treeView );
 
@@ -23,6 +23,18 @@ class TestObserver extends DomEventObserver {
 	}
 }
 
+class MultiObserver extends DomEventObserver {
+	constructor( treeView ) {
+		super( treeView );
+
+		this.domEventType = [ 'evt1', 'evt2' ];
+	}
+
+	onDomEvent( domEvt ) {
+		this.fire( domEvt.type );
+	}
+}
+
 describe( 'DomEventObserver', () => {
 	let treeView;
 
@@ -44,7 +56,7 @@ describe( 'DomEventObserver', () => {
 		const evtSpy = sinon.spy();
 
 		treeView.createRoot( domElement, 'root' );
-		treeView.addObserver( TestObserver );
+		treeView.addObserver( ClickObserver );
 		treeView.on( 'click', evtSpy );
 
 		domElement.dispatchEvent( domEvent );
@@ -54,13 +66,32 @@ describe( 'DomEventObserver', () => {
 		expect( evtSpy.args[ 0 ][ 2 ] ).to.equal( domEvent );
 	} );
 
+	it( 'should add multiple event listeners', () => {
+		const domElement = document.createElement( 'p' );
+		const domEvent1 = new MouseEvent( 'evt1' );
+		const domEvent2 = new MouseEvent( 'evt2' );
+		const evtSpy1 = sinon.spy();
+		const evtSpy2 = sinon.spy();
+
+		treeView.createRoot( domElement, 'root' );
+		treeView.addObserver( MultiObserver );
+		treeView.on( 'evt1', evtSpy1 );
+		treeView.on( 'evt2', evtSpy2 );
+
+		domElement.dispatchEvent( domEvent1 );
+		expect( evtSpy1.calledOnce ).to.be.true;
+
+		domElement.dispatchEvent( domEvent2 );
+		expect( evtSpy2.calledOnce ).to.be.true;
+	} );
+
 	it( 'should not fire event if observer is disabled', () => {
 		const domElement = document.createElement( 'p' );
 		const domEvent = new MouseEvent( 'click' );
 		const evtSpy = sinon.spy();
 
 		treeView.createRoot( domElement, 'root' );
-		treeView.addObserver( TestObserver );
+		treeView.addObserver( ClickObserver );
 		treeView.on( 'click', evtSpy );
 
 		const testObserver = Array.from( treeView._observers )[ 0 ];
@@ -78,7 +109,7 @@ describe( 'DomEventObserver', () => {
 		const evtSpy = sinon.spy();
 
 		treeView.createRoot( domElement, 'root' );
-		treeView.addObserver( TestObserver );
+		treeView.addObserver( ClickObserver );
 		treeView.on( 'click', evtSpy );
 
 		const testObserver = Array.from( treeView._observers )[ 0 ];
@@ -98,7 +129,7 @@ describe( 'DomEventObserver', () => {
 
 	describe( 'fire', () => {
 		it( 'should do nothing if observer is disabled', () => {
-			const testObserver = new TestObserver( treeView );
+			const testObserver = new ClickObserver( treeView );
 			const fireSpy = sinon.spy( treeView, 'fire' );
 
 			testObserver.disable();

+ 58 - 0
packages/ckeditor5-engine/tests/treeview/observer/focusobserver.js

@@ -0,0 +1,58 @@
+/**
+ * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: treeview */
+
+'use strict';
+
+import FocusObserver from '/ckeditor5/core/treeview/observer/focusobserver.js';
+import TreeView from '/ckeditor5/core/treeview/treeview.js';
+
+describe( 'FocusObserver', () => {
+	let treeView, viewBody, observer;
+
+	beforeEach( () => {
+		treeView = new TreeView();
+		treeView.addObserver( FocusObserver );
+
+		viewBody = treeView.domConverter.domToView( document.body, { bind: true } );
+
+		observer = Array.from( treeView._observers )[ 0 ];
+	} );
+
+	it( 'should define domEventType', () => {
+		expect( observer.domEventType ).to.deep.equal( [ 'focus', 'blur' ] );
+	} );
+
+	describe( 'onDomEvent', () => {
+		it( 'should fire focus with the target', () => {
+			const spy = sinon.spy();
+
+			treeView.on( 'focus', spy );
+
+			observer.onDomEvent( { type: 'focus', target: document.body } );
+
+			expect( spy.calledOnce ).to.be.true;
+
+			const data = spy.args[ 0 ][ 1 ];
+			expect( data.target ).to.equal( viewBody );
+			expect( data.domTarget ).to.equal( document.body );
+		} );
+
+		it( 'should fire blur with the target', () => {
+			const spy = sinon.spy();
+
+			treeView.on( 'blur', spy );
+
+			observer.onDomEvent( { type: 'blur', target: document.body } );
+
+			expect( spy.calledOnce ).to.be.true;
+
+			const data = spy.args[ 0 ][ 1 ];
+			expect( data.target ).to.equal( viewBody );
+			expect( data.domTarget ).to.equal( document.body );
+		} );
+	} );
+} );