Explorar el Código

Merge pull request #41 from ckeditor/t/ckeditor5/407

Feature: Creating a paragraph next to the selected widget is possible using the (<kbd>Shift</kbd>+)<kbd>Enter</kbd> key (see ckeditor/ckeditor5#407).
Piotrek Koszuliński hace 7 años
padre
commit
7da2e9342f

+ 31 - 0
packages/ckeditor5-widget/src/widget.js

@@ -154,6 +154,8 @@ export default class Widget extends Plugin {
 			wasHandled = this._handleArrowKeys( isForward );
 		} else if ( isSelectAllKeyCode( domEventData ) ) {
 			wasHandled = this._selectAllNestedEditableContent() || this._selectAllContent();
+		} else if ( keyCode === keyCodes.enter ) {
+			wasHandled = this._handleEnterKey( domEventData.shiftKey );
 		}
 
 		if ( wasHandled ) {
@@ -207,6 +209,7 @@ export default class Widget extends Plugin {
 	/**
 	 * Handles arrow keys.
 	 *
+	 * @private
 	 * @param {Boolean} isForward Set to true if arrow key should be handled in forward direction.
 	 * @returns {Boolean|undefined} Returns `true` if keys were handled correctly.
 	 */
@@ -247,6 +250,34 @@ export default class Widget extends Plugin {
 	}
 
 	/**
+	 * Handles the enter key, giving users and access to positions in the editable directly before
+	 * (<kbd>Shift</kbd>+<kbd>Enter</kbd>) or after (<kbd>Enter</kbd>) the selected widget.
+	 * It improves the UX, mainly when the widget is the first or last child of the root editable
+	 * and there's no other way to type after or before it.
+	 *
+	 * @private
+	 * @param {Boolean} isBackwards Set to true if the new paragraph is to be inserted before
+	 * the selected widget (<kbd>Shift</kbd>+<kbd>Enter</kbd>).
+	 * @returns {Boolean|undefined} Returns `true` if keys were handled correctly.
+	 */
+	_handleEnterKey( isBackwards ) {
+		const model = this.editor.model;
+		const modelSelection = model.document.selection;
+		const objectElement = modelSelection.getSelectedElement();
+
+		if ( objectElement && model.schema.isObject( objectElement ) ) {
+			model.change( writer => {
+				const paragraph = writer.createElement( 'paragraph' );
+
+				writer.insert( paragraph, objectElement, isBackwards ? 'before' : 'after' );
+				writer.setSelection( paragraph, 'in' );
+			} );
+
+			return true;
+		}
+	}
+
+	/**
 	 * Extends the {@link module:engine/model/selection~Selection document's selection} to span the entire
 	 * content of the nested editable if already anchored in one.
 	 *

+ 44 - 0
packages/ckeditor5-widget/tests/widget.js

@@ -681,6 +681,50 @@ describe( 'Widget', () => {
 			);
 		} );
 
+		describe( 'enter', () => {
+			test(
+				'should insert a paragraph after the selected widget upon Enter',
+				'[<widget></widget>]',
+				keyCodes.enter,
+				'<widget></widget><paragraph>[]</paragraph>'
+			);
+
+			test(
+				'should insert a paragraph before the selected widget upon Shift+Enter',
+				'[<widget></widget>]',
+				{ keyCode: keyCodes.enter, shiftKey: true },
+				'<paragraph>[]</paragraph><widget></widget>'
+			);
+
+			test(
+				'should insert a paragraph when not a first-child of the root',
+				'[<widget></widget>]<paragraph>foo</paragraph>',
+				keyCodes.enter,
+				'<widget></widget><paragraph>[]</paragraph><paragraph>foo</paragraph>'
+			);
+
+			test(
+				'should insert a paragraph when not a last-child of the root',
+				'<paragraph>foo</paragraph>[<widget></widget>]',
+				{ keyCode: keyCodes.enter, shiftKey: true },
+				'<paragraph>foo</paragraph><paragraph>[]</paragraph><widget></widget>'
+			);
+
+			test(
+				'should insert a paragraph only when an entire widget is selected (#1)',
+				'<widget><nested>[foo] bar</nested></widget>',
+				keyCodes.enter,
+				'<widget><nested>[] bar</nested></widget>'
+			);
+
+			test(
+				'should insert a paragraph only when an entire widget is selected (#2)',
+				'<paragraph>f[oo</paragraph><widget></widget><paragraph>b]ar</paragraph>',
+				keyCodes.enter,
+				'<paragraph>f[]ar</paragraph>'
+			);
+		} );
+
 		function test( name, data, keyCodeOrMock, expected, expectedView ) {
 			it( name, () => {
 				const domEventDataMock = ( typeof keyCodeOrMock == 'object' ) ? keyCodeOrMock : {