Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved enter handling in document lists #11103

Merged
merged 2 commits into from
Jan 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions packages/ckeditor5-list/src/documentlist/documentlistediting.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,37 +93,49 @@ export default class DocumentListEditing extends Plugin {
editor.commands.add( 'indentList', new DocumentListIndentCommand( editor, 'forward' ) );
editor.commands.add( 'outdentList', new DocumentListIndentCommand( editor, 'backward' ) );

editor.commands.add( 'splitListItem', new DocumentListSplitCommand( editor ) );
editor.commands.add( 'splitListItemBefore', new DocumentListSplitCommand( editor, 'before' ) );
editor.commands.add( 'splitListItemAfter', new DocumentListSplitCommand( editor, 'after' ) );

// Overwrite the default Enter key behavior: outdent or split the list in certain cases.
this.listenTo( editor.editing.view.document, 'enter', ( evt, data ) => {
const doc = model.document;
const positionParent = doc.selection.getFirstPosition().parent;

if ( doc.selection.isCollapsed && positionParent.hasAttribute( 'listItemId' ) && positionParent.isEmpty ) {
const isFirstBlock = isFirstBlockOfListItem( positionParent );
const isLastBlock = isLastBlockOfListItem( positionParent );

// * a → * a
// * [] → []
if ( isFirstBlockOfListItem( positionParent ) ) {
if ( isFirstBlock && isLastBlock ) {
editor.execute( 'outdentList' );

data.preventDefault();
evt.stop();
}
// * [] → * []
// a → * a
else if ( isFirstBlock && !isLastBlock ) {
editor.execute( 'splitListItemAfter' );

data.preventDefault();
evt.stop();
}
// * a → * a
// [] → * []
else if ( isLastBlockOfListItem( positionParent ) ) {
editor.execute( 'splitListItem' );
else if ( isLastBlock ) {
editor.execute( 'splitListItemBefore' );

data.preventDefault();
evt.stop();
}
}
}, { context: 'li' } );

// In some cases, after the default block splitting, we want to modify the new block to become a new list item
// In some cases, after the default block splitting, we want to modify the new block to become a new list item
// instead of an additional block in the same list item.
this.listenTo( enterCommand, 'afterExecute', () => {
const splitCommand = commands.get( 'splitListItem' );
const splitCommand = commands.get( 'splitListItemBefore' );

// The command has not refreshed because the change block related to EnterCommand#execute() is not over yet.
// Let's keep it up to date and take advantage of DocumentListSplitCommand#isEnabled.
Expand All @@ -144,7 +156,7 @@ export default class DocumentListEditing extends Plugin {
// │ * a[] │ * a │ * a │
// │ │ [] │ * [] │
if ( listItemBlocks.length === 2 ) {
editor.execute( 'splitListItem' );
splitCommand.execute();
}
} );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export default class DocumentListIndentCommand extends Command {
*
* @readonly
* @private
* @member {Number}
* @member {'forward'|'backward'}
*/
this._direction = indentDirection;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ import {
* @extends module:core/command~Command
*/
export default class DocumentListSplitCommand extends Command {
/**
* Creates an instance of the command.
*
* @param {module:core/editor/editor~Editor} editor The editor instance.
* @param {'before'|'after'} direction Whether list item should be split before or after the selected block.
*/
constructor( editor, direction ) {
super( editor );

/**
* Whether list item should be split before or after the selected block.
*
* @readonly
* @private
* @member {'before'|'after'}
*/
this._direction = direction;
}

/**
* @inheritDoc
*/
Expand All @@ -39,8 +58,7 @@ export default class DocumentListSplitCommand extends Command {
const editor = this.editor;

editor.model.change( writer => {
const positionParent = editor.model.document.selection.getFirstPosition().parent;
const changedBlocks = splitListItemBefore( positionParent, writer );
const changedBlocks = splitListItemBefore( this._getStartBlock(), writer );

this._fireAfterExecute( changedBlocks );
} );
Expand Down Expand Up @@ -72,11 +90,24 @@ export default class DocumentListSplitCommand extends Command {
* @returns {Boolean} Whether the command should be enabled.
*/
_checkEnabled() {
const selection = this.editor.model.document.selection;
const block = this._getStartBlock();

return selection.isCollapsed &&
!!block && block.hasAttribute( 'listItemId' ) &&
!isFirstBlockOfListItem( block );
}

/**
* Returns the model element that is the main focus of the command (according to the current selection and command direction).
*
* @private
* @returns {module:engine/model/element~Element}
*/
_getStartBlock() {
const doc = this.editor.model.document;
const positionParent = doc.selection.getFirstPosition().parent;

return doc.selection.isCollapsed &&
positionParent.hasAttribute( 'listItemId' ) &&
!isFirstBlockOfListItem( positionParent );
return this._direction == 'before' ? positionParent : positionParent.nextSibling;
}
}
Loading