8
0
Просмотр исходного кода

Implemented expandToolbarConfig() and enableToolbarKeyboardFocus() toolbar utils.

Aleksander Nowodzinski 9 лет назад
Родитель
Сommit
01ba1dba53

+ 68 - 0
packages/ckeditor5-ui/src/toolbar/utils.js

@@ -0,0 +1,68 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module ui/toolbar/utils
+ */
+
+/**
+ * An utility which expands a plain toolbar configuration into a collection
+ * of {@link module:ui/view~View views} using a given factory.
+ *
+ * @param {Object} config The toolbar config.
+ * @param {module:utils/collection~Collection} collection A collection into which the config
+ * is expanded.
+ * @param {module:ui/componentfactory~ComponentFactory} factory A factory producing toolbar items.
+ * @returns {Promise} A promise resolved when all toolbar items are initialized.
+ */
+export function expandToolbarConfig( config, collection, factory ) {
+	let promises = [];
+
+	if ( config ) {
+		promises = config.map( name => collection.add( factory.create( name ) ) );
+	}
+
+	return Promise.all( promises );
+}
+
+/**
+ * Enables focus/blur toolbar navigation using `Alt+F10` and `Esc` keystrokes.
+ *
+ * @param {Object} options Options of the utility.
+ * @param {*} options.origin A view to which the focus will return when `Esc` is pressed and
+ * `options.toolbar` is focused.
+ * @param {module:core/keystrokehandler~KeystrokeHandler} options.originKeystrokeHandler A keystroke
+ * handler to register `Alt+F10` keystroke.
+ * @param {module:utils/focustracker~FocusTracker} options.originFocusTracker A focus tracker
+ * for `options.origin`.
+ * @param {module:ui/toolbar/toolbarview~ToolbarView} options.toolbar A toolbar which is to gain
+ * focus when `Alt+F10` is pressed.
+ */
+export function enableToolbarKeyboardFocus( {
+	origin,
+	originKeystrokeHandler,
+	originFocusTracker,
+	toolbar
+} ) {
+	// Because toolbar items can get focus, the overall state of the toolbar must
+	// also be tracked.
+	originFocusTracker.add( toolbar.element );
+
+	// Focus the toolbar on the keystroke, if not already focused.
+	originKeystrokeHandler.set( 'Alt+F10', ( data, cancel ) => {
+		if ( originFocusTracker.isFocused && !toolbar.focusTracker.isFocused ) {
+			toolbar.focus();
+			cancel();
+		}
+	} );
+
+	// Blur the toolbar and bring the focus back to origin.
+	toolbar.keystrokes.set( 'Esc', ( data, cancel ) => {
+		if ( toolbar.focusTracker.isFocused ) {
+			origin.focus();
+			cancel();
+		}
+	} );
+}

+ 2 - 2
packages/ckeditor5-ui/tests/toolbar/floating/floatingtoolbarview.js

@@ -144,13 +144,13 @@ describe( 'FloatingToolbarView', () => {
 
 
 			view._updatePosition();
 			view._updatePosition();
 
 
-			sinon.assert.calledWithMatch( spy, sinon.match( {
+			sinon.assert.calledWithExactly( spy, {
 				element: view.element,
 				element: view.element,
 				target: target,
 				target: target,
 				positions: [ nw, sw, ne, se ],
 				positions: [ nw, sw, ne, se ],
 				limiter: global.document.body,
 				limiter: global.document.body,
 				fitInViewport: true
 				fitInViewport: true
-			} ) );
+			} );
 
 
 			expect( view.top ).to.equal( 5 );
 			expect( view.top ).to.equal( 5 );
 			expect( view.left ).to.equal( 10 );
 			expect( view.left ).to.equal( 10 );

+ 133 - 0
packages/ckeditor5-ui/tests/toolbar/utils.js

@@ -0,0 +1,133 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global document */
+
+import View from '../../src/view';
+import ComponentFactory from '../../src/componentfactory';
+import ToolbarView from '../../src/toolbar/toolbarview';
+import Editor from '@ckeditor/ckeditor5-core/src/editor/editor';
+import Collection from '@ckeditor/ckeditor5-utils/src/collection';
+import FocusTracker from '@ckeditor/ckeditor5-utils/src/focustracker';
+import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
+import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
+import {
+	expandToolbarConfig,
+	enableToolbarKeyboardFocus
+} from '../../src/toolbar/utils';
+
+describe( 'utils', () => {
+	describe( 'expandToolbarConfig()', () => {
+		let factory;
+
+		beforeEach( () => {
+			factory = new ComponentFactory( new Editor() );
+
+			factory.add( 'foo', viewCreator( 'foo' ) );
+			factory.add( 'bar', viewCreator( 'bar' ) );
+		} );
+
+		it( 'returns a promise', () => {
+			expect( expandToolbarConfig() ).to.be.instanceOf( Promise );
+		} );
+
+		it( 'expands the config into collection', () => {
+			const collection = new Collection();
+
+			return expandToolbarConfig( [ 'foo', 'bar', 'foo' ], collection, factory )
+				.then( () => {
+					expect( collection ).to.have.length( 3 );
+					expect( collection.get( 0 ).name ).to.equal( 'foo' );
+					expect( collection.get( 1 ).name ).to.equal( 'bar' );
+					expect( collection.get( 2 ).name ).to.equal( 'foo' );
+				} );
+		} );
+	} );
+
+	describe( 'enableToolbarKeyboardFocus()', () => {
+		let origin, originFocusTracker, originKeystrokeHandler, toolbar;
+
+		beforeEach( () => {
+			origin = viewCreator();
+			originFocusTracker = new FocusTracker();
+			originKeystrokeHandler = new KeystrokeHandler();
+			toolbar = new ToolbarView();
+
+			enableToolbarKeyboardFocus( {
+				origin: origin,
+				originFocusTracker: originFocusTracker,
+				originKeystrokeHandler: originKeystrokeHandler,
+				toolbar: toolbar
+			} );
+
+			return toolbar.init();
+		} );
+
+		it( 'focuses the toolbar on Alt+F10', () => {
+			const spy = sinon.spy( toolbar, 'focus' );
+			const toolbarFocusTracker = toolbar.focusTracker;
+			const keyEvtData = {
+				keyCode: keyCodes.f10,
+				altKey: true,
+				preventDefault: sinon.spy(),
+				stopPropagation: sinon.spy()
+			};
+
+			toolbarFocusTracker.isFocused = false;
+			originFocusTracker.isFocused = false;
+
+			originKeystrokeHandler.press( keyEvtData );
+			sinon.assert.notCalled( spy );
+
+			toolbarFocusTracker.isFocused = true;
+			originFocusTracker.isFocused = true;
+
+			originKeystrokeHandler.press( keyEvtData );
+			sinon.assert.notCalled( spy );
+
+			toolbarFocusTracker.isFocused = false;
+			originFocusTracker.isFocused = true;
+
+			originKeystrokeHandler.press( keyEvtData );
+			sinon.assert.calledOnce( spy );
+
+			sinon.assert.calledOnce( keyEvtData.preventDefault );
+			sinon.assert.calledOnce( keyEvtData.stopPropagation );
+		} );
+
+		it( 're–foucuses origin on Esc', () => {
+			const spy = origin.focus = sinon.spy();
+			const toolbarFocusTracker = toolbar.focusTracker;
+			const keyEvtData = { keyCode: keyCodes.esc,
+				preventDefault: sinon.spy(),
+				stopPropagation: sinon.spy()
+			};
+
+			toolbarFocusTracker.isFocused = false;
+
+			toolbar.keystrokes.press( keyEvtData );
+			sinon.assert.notCalled( spy );
+
+			toolbarFocusTracker.isFocused = true;
+
+			toolbar.keystrokes.press( keyEvtData );
+
+			sinon.assert.calledOnce( spy );
+			sinon.assert.calledOnce( keyEvtData.preventDefault );
+			sinon.assert.calledOnce( keyEvtData.stopPropagation );
+		} );
+	} );
+} );
+
+function viewCreator( name ) {
+	return ( locale ) => {
+		const view = new View( locale );
+
+		view.name = name;
+		view.element = document.createElement( 'a' );
+
+		return view;
+	};
+}