Comprehensive command system for all list operations including creation, indentation, merging, and splitting.
import { type ModelElement } from "ckeditor5/src/engine.js";Base command for list operations that handles converting paragraphs to lists and changing list types.
/**
* The list command. It is used by the numbered list and bulleted list features.
*/
class ListCommand extends Command {
/**
* The type of the list created by this command.
*/
readonly type: ListType;
/**
* @inheritDoc
*/
constructor(editor: Editor, type: ListType);
/**
* Executes the list command.
* @param options Command execution options
* @param options.forceValue If set, it will force the command behavior. If `true`, the command will try to convert the selected items and potentially the neighbor elements to the proper list items. If set to `false` it will convert selected elements to paragraphs. If not set, the command will toggle selected elements to list items or paragraphs, depending on the selection.
* @param options.additionalAttributes Additional attributes that are set for list items when the command is executed.
*/
execute(options?: { forceValue?: boolean; additionalAttributes?: Record<string, unknown> }): void;
/**
* Checks the command's value.
*/
value: boolean | null;
/**
* Checks whether the command can be enabled in the current context.
*/
isEnabled: boolean;
}Events:
interface ListCommandAfterExecuteEvent {
readonly name: 'afterExecute';
readonly args: [changedBlocks: Array<ModelElement>];
}Handles list item indentation (increasing nesting level).
/**
* The list indent command. It is used by the list indent feature.
*/
class ListIndentCommand extends Command {
/**
* Creates an instance of the command.
* @param editor The editor instance.
* @param indentDirection The direction of indent. If it is equal to `backward`, the command will outdent a list item.
*/
constructor(editor: Editor, indentDirection: 'forward' | 'backward');
/**
* Executes the list indent command.
*/
execute(): void;
/**
* Checks whether the command can be enabled in the current context.
*/
isEnabled: boolean;
}Events:
interface ListIndentCommandAfterExecuteEvent {
readonly name: 'afterExecute';
readonly args: [changedBlocks: Array<ModelElement>];
}Merges list items, typically used when combining adjacent list structures.
/**
* The list merge command. It merges the selected list item with the previous list item.
*/
class ListMergeCommand extends Command {
/**
* @inheritDoc
*/
constructor(editor: Editor);
/**
* Executes the list merge command.
* @param options Command execution options
* @param options.backward Whether to merge backward (with previous item) or forward (with next item)
*/
execute(options?: { backward?: boolean }): void;
/**
* Checks whether the command can be enabled in the current context.
*/
isEnabled: boolean;
}Events:
interface ListMergeCommandAfterExecuteEvent {
readonly name: 'afterExecute';
readonly args: [data: { backward?: boolean }];
}Splits list items, creating separate list items from a single item.
/**
* The list split command. It splits the selected list item.
*/
class ListSplitCommand extends Command {
/**
* @inheritDoc
*/
constructor(editor: Editor);
/**
* Executes the list split command.
*/
execute(): void;
/**
* Checks whether the command can be enabled in the current context.
*/
isEnabled: boolean;
}Events:
interface ListSplitCommandAfterExecuteEvent {
readonly name: 'afterExecute';
readonly args: [data: {}];
}import { ClassicEditor } from "@ckeditor/ckeditor5-editor-classic";
import { List } from "@ckeditor/ckeditor5-list";
ClassicEditor
.create(document.querySelector('#editor'), {
plugins: [List],
toolbar: ['numberedList', 'bulletedList', 'indent', 'outdent']
})
.then(editor => {
// Get commands
const numberedListCommand = editor.commands.get('numberedList');
const bulletedListCommand = editor.commands.get('bulletedList');
const indentCommand = editor.commands.get('indentList');
const outdentCommand = editor.commands.get('outdentList');
// Execute commands
numberedListCommand.execute(); // Create/toggle numbered list
bulletedListCommand.execute(); // Create/toggle bulleted list
indentCommand.execute(); // Indent current list items
outdentCommand.execute(); // Outdent current list items
});// Create a numbered list
const listCommand = editor.commands.get('numberedList');
if (listCommand.isEnabled) {
listCommand.execute({ type: 'numbered' });
}
// Check if current selection is in a list
if (listCommand.value) {
console.log('Selection is in a numbered list');
}
// Indent list items
const indentCommand = editor.commands.get('indentList');
if (indentCommand.isEnabled) {
indentCommand.execute();
}// Listen to command execution events
editor.commands.get('numberedList').on('afterExecute', (evt, data) => {
console.log('List command executed with type:', data.type);
});
editor.commands.get('indentList').on('afterExecute', (evt, data) => {
console.log('List items indented');
});
editor.commands.get('listMerge').on('afterExecute', (evt, data) => {
console.log('List items merged, backward:', data.backward);
});import { Plugin, Command } from 'ckeditor5/src/core';
class CustomListPlugin extends Plugin {
init() {
const editor = this.editor;
// Add custom command that works with lists
editor.commands.add('customListAction', new CustomListCommand(editor));
}
}
class CustomListCommand extends Command {
execute() {
const listCommand = this.editor.commands.get('numberedList');
const indentCommand = this.editor.commands.get('indentList');
if (listCommand.isEnabled && !listCommand.value) {
// Create list if not in list
listCommand.execute();
} else if (indentCommand.isEnabled) {
// Indent if already in list
indentCommand.execute();
}
}
get isEnabled() {
const listCommand = this.editor.commands.get('numberedList');
const indentCommand = this.editor.commands.get('indentList');
return listCommand.isEnabled || indentCommand.isEnabled;
}
}// Monitor command states for UI updates
const commands = ['numberedList', 'bulletedList', 'indentList', 'outdentList'];
commands.forEach(commandName => {
const command = editor.commands.get(commandName);
command.on('change:isEnabled', () => {
console.log(`${commandName} enabled:`, command.isEnabled);
});
command.on('change:value', () => {
console.log(`${commandName} value:`, command.value);
});
});
// Create reactive UI based on command states
function updateListToolbar() {
const numberedListCommand = editor.commands.get('numberedList');
const bulletedListCommand = editor.commands.get('bulletedList');
// Update button states
document.querySelector('#numbered-list-btn').disabled = !numberedListCommand.isEnabled;
document.querySelector('#bulleted-list-btn').disabled = !bulletedListCommand.isEnabled;
// Update active states
document.querySelector('#numbered-list-btn').classList.toggle('active', numberedListCommand.value);
document.querySelector('#bulleted-list-btn').classList.toggle('active', bulletedListCommand.value);
}
// Update on selection change
editor.model.document.selection.on('change', updateListToolbar);