瀏覽代碼

Implemented EditingKeystrokeHandler class with the support for editor commands.

Aleksander Nowodzinski 9 年之前
父節點
當前提交
9567e3db04

+ 80 - 0
packages/ckeditor5-core/src/editingkeystrokehandler.js

@@ -0,0 +1,80 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module core/editingkeystrokehandler
+ */
+
+import KeystrokeHandler from 'ckeditor5-utils/src/keystrokehandler';
+
+/**
+ * A keystroke handler for editor editing. Its instance is available
+ * in {@link module:core/editor/standardeditor~StandardEditor#keystrokes} so plugins
+ * can register their keystrokes.
+ *
+ * E.g. an undo plugin would do this:
+ *
+ *		editor.keystrokes.set( 'ctrl + Z', 'undo' );
+ *		editor.keystrokes.set( 'ctrl + shift + Z', 'redo' );
+ *		editor.keystrokes.set( 'ctrl + Y', 'redo' );
+ *
+ * @extends utils/keystrokehandler~KeystrokeHandler
+ */
+export default class EditingKeystrokeHandler extends KeystrokeHandler {
+	/**
+	 * Creates an instance of the keystroke handler.
+	 *
+	 * @param {module:core/editor/editor~Editor} editor
+	 */
+	constructor( editor ) {
+		super();
+
+		/**
+		 * The editor instance.
+		 *
+		 * @readonly
+		 * @member {module:core/editor/editor~Editor}
+		 */
+		this.editor = editor;
+	}
+
+	/**
+	 * Registers a handler for the specified keystroke.
+	 *
+	 * * The handler can be specified as a command name or a callback.
+	 *
+	 * @param {String|Array.<String|Number>} keystroke Keystroke defined in a format accepted by
+	 * the {@link module:utils/keyboard~parseKeystroke} function.
+	 * @param {Function} callback If a string is passed, then the keystroke will
+	 * {@link module:core/editor/editor~Editor#execute execute a command}.
+	 * If a function, then it will be called with the
+	 * {@link module:engine/view/observer/keyobserver~KeyEventData key event data} object and
+	 * a helper to both `preventDefault` and `stopPropagation` of the event.
+	 */
+	set( keystroke, callback ) {
+		if ( typeof callback == 'string' ) {
+			const commandName = callback;
+
+			callback = () => {
+				this.editor.execute( commandName );
+			};
+		}
+
+		super.set( keystroke, callback );
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	listenTo( emitter ) {
+		this._listener.listenTo( emitter, 'keydown', ( evt, data ) => {
+			const handled = this.press( data );
+
+			if ( handled ) {
+				data.preventDefault();
+			}
+		} );
+	}
+}

+ 53 - 0
packages/ckeditor5-core/tests/editingkeystrokehandler.js

@@ -0,0 +1,53 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import VirtualTestEditor from 'ckeditor5-core/tests/_utils/virtualtesteditor';
+import EditingKeystrokeHandler from 'ckeditor5-core/src/editingkeystrokehandler';
+import testUtils from 'ckeditor5-core/tests/_utils/utils';
+import { keyCodes } from 'ckeditor5-utils/src/keyboard';
+
+testUtils.createSinonSandbox();
+
+describe( 'EditingKeystrokeHandler', () => {
+	let editor;
+
+	beforeEach( () => {
+		return VirtualTestEditor.create()
+			.then( newEditor => {
+				editor = newEditor;
+				editor.keystrokes = new EditingKeystrokeHandler( editor );
+			} );
+	} );
+
+	describe( 'listenTo()', () => {
+		it( 'prevents default when keystroke was handled', () => {
+			const keyEvtData = { keyCode: 1, preventDefault: testUtils.sinon.spy() };
+
+			testUtils.sinon.stub( EditingKeystrokeHandler.prototype, 'press' ).returns( true );
+
+			editor.editing.view.fire( 'keydown', keyEvtData );
+
+			sinon.assert.calledOnce( keyEvtData.preventDefault );
+		} );
+	} );
+
+	describe( 'press()', () => {
+		it( 'executes a command', () => {
+			const spy = testUtils.sinon.stub( editor, 'execute' );
+
+			editor.keystrokes.set( 'ctrl + A', 'foo' );
+
+			const wasHandled = editor.keystrokes.press( getCtrlA() );
+
+			sinon.assert.calledOnce( spy );
+			sinon.assert.calledWithExactly( spy, 'foo' );
+			expect( wasHandled ).to.be.true;
+		} );
+	} );
+} );
+
+function getCtrlA() {
+	return { keyCode: keyCodes.a, ctrlKey: true };
+}