UNPKG

@ckeditor/ckeditor5-typing

Version:

Typing feature for CKEditor 5.

104 lines (103 loc) 4.44 kB
/** * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ import { Plugin } from '@ckeditor/ckeditor5-core'; import { keyCodes } from '@ckeditor/ckeditor5-utils'; import DeleteCommand from './deletecommand.js'; import DeleteObserver from './deleteobserver.js'; /** * The delete and backspace feature. Handles keys such as <kbd>Delete</kbd> and <kbd>Backspace</kbd>, other * keystrokes and user actions that result in deleting content in the editor. */ export default class Delete extends Plugin { /** * Whether pressing backspace should trigger undo action */ _undoOnBackspace; /** * @inheritDoc */ static get pluginName() { return 'Delete'; } /** * @inheritDoc */ static get isOfficialPlugin() { return true; } /** * @inheritDoc */ init() { const editor = this.editor; const view = editor.editing.view; const viewDocument = view.document; const modelDocument = editor.model.document; view.addObserver(DeleteObserver); this._undoOnBackspace = false; const deleteForwardCommand = new DeleteCommand(editor, 'forward'); // Register `deleteForward` command and add `forwardDelete` command as an alias for backward compatibility. editor.commands.add('deleteForward', deleteForwardCommand); editor.commands.add('forwardDelete', deleteForwardCommand); editor.commands.add('delete', new DeleteCommand(editor, 'backward')); this.listenTo(viewDocument, 'delete', (evt, data) => { // When not in composition, we handle the action, so prevent the default one. // When in composition, it's the browser who modify the DOM (renderer is disabled). if (!viewDocument.isComposing) { data.preventDefault(); } const { direction, sequence, selectionToRemove, unit } = data; const commandName = direction === 'forward' ? 'deleteForward' : 'delete'; const commandData = { sequence }; if (unit == 'selection') { const modelRanges = Array.from(selectionToRemove.getRanges()).map(viewRange => { return editor.editing.mapper.toModelRange(viewRange); }); commandData.selection = editor.model.createSelection(modelRanges); } else { commandData.unit = unit; } editor.execute(commandName, commandData); view.scrollToTheSelection(); }, { priority: 'low' }); // Handle the Backspace key while at the beginning of a nested editable. See https://github.com/ckeditor/ckeditor5/issues/17383. this.listenTo(viewDocument, 'keydown', (evt, data) => { if (viewDocument.isComposing || data.keyCode != keyCodes.backspace || !modelDocument.selection.isCollapsed) { return; } const ancestorLimit = editor.model.schema.getLimitElement(modelDocument.selection); const limitStartPosition = editor.model.createPositionAt(ancestorLimit, 0); if (limitStartPosition.isTouching(modelDocument.selection.getFirstPosition())) { data.preventDefault(); } }); if (this.editor.plugins.has('UndoEditing')) { this.listenTo(viewDocument, 'delete', (evt, data) => { if (this._undoOnBackspace && data.direction == 'backward' && data.sequence == 1 && data.unit == 'codePoint') { this._undoOnBackspace = false; editor.execute('undo'); data.preventDefault(); evt.stop(); } }, { context: '$capture' }); this.listenTo(modelDocument, 'change', () => { this._undoOnBackspace = false; }); } } /** * If the next user action after calling this method is pressing backspace, it would undo the last change. * * Requires {@link module:undo/undoediting~UndoEditing} plugin. If not loaded, does nothing. */ requestUndoOnBackspace() { if (this.editor.plugins.has('UndoEditing')) { this._undoOnBackspace = true; } } }