Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Feature: Ctrl+A in a nested editable should select nested editable's …
Browse files Browse the repository at this point in the history
…content. Closes #13.
  • Loading branch information
oleq committed Aug 21, 2017
1 parent 0bd3d66 commit e9fd0e8
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 5 deletions.
48 changes: 43 additions & 5 deletions src/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
import ViewEditableElement from '@ckeditor/ckeditor5-engine/src/view/editableelement';
import RootEditableElement from '@ckeditor/ckeditor5-engine/src/view/rooteditableelement';
import { isWidget, WIDGET_SELECTED_CLASS_NAME, getLabel } from './utils';
import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
import { keyCodes, getCode, parseKeystroke } from '@ckeditor/ckeditor5-utils/src/keyboard';

import '../theme/theme.scss';

const selectAllKeystrokeCode = parseKeystroke( 'Ctrl+A' );

/**
* The widget plugin.
* Registers model to view selection converter for editing pipeline. It is hooked after default selection conversion.
Expand Down Expand Up @@ -126,10 +128,13 @@ export default class Widget extends Plugin {
const keyCode = domEventData.keyCode;
const isForward = keyCode == keyCodes.delete || keyCode == keyCodes.arrowdown || keyCode == keyCodes.arrowright;

// Checks if delete/backspace or arrow keys were handled and then prevents default event behaviour and stops
// event propagation.
if ( ( isDeleteKeyCode( keyCode ) && this._handleDelete( isForward ) ) ||
( isArrowKeyCode( keyCode ) && this._handleArrowKeys( isForward ) ) ) {
// Checks if the keys were handled and then prevents the default event behaviour and stops
// the propagation.
if (
( isDeleteKeyCode( keyCode ) && this._handleDelete( isForward ) ) ||
( isArrowKeyCode( keyCode ) && this._handleArrowKeys( isForward ) ) ||
( isSelectAllKeyCode( domEventData ) && this._selectAllNestedEditableContent() )
) {
domEventData.preventDefault();
eventInfo.stop();
}
Expand Down Expand Up @@ -213,6 +218,31 @@ export default class Widget extends Plugin {
}
}

/**
* 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.
*
* See: {@link module:engine/model/schema~Schema#getLimitElement}.
*
* @private
*/
_selectAllNestedEditableContent() {
const modelDocument = this.editor.document;
const modelSelection = modelDocument.selection;
const schema = modelDocument.schema;
const limitElement = schema.getLimitElement( modelSelection );

if ( modelSelection.getFirstRange().root == limitElement ) {
return false;
}

modelDocument.enqueueChanges( () => {
modelSelection.setIn( limitElement );
} );

return true;
}

/**
* Sets {@link module:engine/model/selection~Selection document's selection} over given element.
*
Expand Down Expand Up @@ -271,6 +301,14 @@ function isDeleteKeyCode( keyCode ) {
return keyCode == keyCodes.delete || keyCode == keyCodes.backspace;
}

// Returns 'true' if provided (DOM) key event data corresponds with the Ctrl+A keystroke.
//
// @param {module:engine/view/observer/keyobserver~KeyEventData} domEventData
// @returns {Boolean}
function isSelectAllKeyCode( domEventData ) {
return getCode( domEventData ) == selectAllKeystrokeCode;
}

// Returns `true` when element is a nested editable or is placed inside one.
//
// @param {module:engine/view/element~Element}
Expand Down
17 changes: 17 additions & 0 deletions tests/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe( 'Widget', () => {
doc.schema.registerItem( 'inline', '$inline' );
doc.schema.objects.add( 'inline' );
doc.schema.registerItem( 'nested' );
doc.schema.limits.add( 'nested' );
doc.schema.allow( { name: '$inline', inside: 'nested' } );
doc.schema.allow( { name: 'nested', inside: 'widget' } );
doc.schema.registerItem( 'editable' );
Expand Down Expand Up @@ -744,6 +745,22 @@ describe( 'Widget', () => {
);
} );

describe( 'Ctrl+A', () => {
test(
'should select the entire content of the nested editable',
'<widget><nested>foo[]</nested></widget><paragraph>bar</paragraph>',
{ keyCode: keyCodes.a, ctrlKey: true },
'<widget><nested>[foo]</nested></widget><paragraph>bar</paragraph>'
);

test(
'should not change the selection if outside of the nested editable',
'<widget><nested>foo</nested></widget><paragraph>[]bar</paragraph>',
{ keyCode: keyCodes.a, ctrlKey: true },
'<widget><nested>foo</nested></widget><paragraph>[]bar</paragraph>'
);
} );

function test( name, data, keyCodeOrMock, expected ) {
it( name, () => {
const domEventDataMock = ( typeof keyCodeOrMock == 'object' ) ? keyCodeOrMock : {
Expand Down

0 comments on commit e9fd0e8

Please sign in to comment.