From 6cfd85bd8edc3d986765a9bbd266236dc144ea0a Mon Sep 17 00:00:00 2001 From: Neil Jenkins Date: Wed, 20 Dec 2023 14:17:12 +1100 Subject: [PATCH] Add undo point for automatic list creation If you do `*` then space or `1. ` then space at the beginning of a line, we automatically create a list. Now you can use undo to undo just the automatic list creation, reverting to the plain text you typed. --- source/Editor.ts | 26 ++++++++++++++++---------- source/keyboard/Space.ts | 9 ++++++--- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/source/Editor.ts b/source/Editor.ts index 4fe5582..67a1fae 100644 --- a/source/Editor.ts +++ b/source/Editor.ts @@ -267,8 +267,8 @@ class Squire { // stop it by preventing default. // 30-11-2023 Update: The fix for Grammarly bug prevents pasting // text directly from the keyboard on Android if the text to be - // inserted contains \n, as pasting from the keyboard does not - // fire a true paste event. The Grammarly bug seems to have been + // inserted contains \n, as pasting from the keyboard does not + // fire a true paste event. The Grammarly bug seems to have been // fixed in Samsung keyboard as of v5.6.10.4, but leaving the // fix in place for now, as the bug is particularly destructive. if (isAndroid && event.data && event.data.includes('\n')) { @@ -839,33 +839,39 @@ class Squire { * Leaves bookmark. */ _recordUndoState(range: Range, replace?: boolean): Squire { - // Don't record if we're already in an undo state - if (!this._isInUndoState || replace) { + const isInUndoState = this._isInUndoState; + if (!isInUndoState || replace) { // Advance pointer to new position - let undoIndex = this._undoIndex; + let undoIndex = this._undoIndex + 1; const undoStack = this._undoStack; const undoConfig = this._config.undo; const undoThreshold = undoConfig.documentSizeThreshold; const undoLimit = undoConfig.undoLimit; - if (!replace) { - undoIndex += 1; - } - // Truncate stack if longer (i.e. if has been previously undone) if (undoIndex < this._undoStackLength) { undoStack.length = this._undoStackLength = undoIndex; } - // Get data + // Add bookmark if (range) { this._saveRangeToBookmark(range); } + + // Don't record if we're already in an undo state + if (isInUndoState) { + return this; + } + + // Get data const html = this._getRawHTML(); // If this document is above the configured size threshold, // limit the number of saved undo states. // Threshold is in bytes, JS uses 2 bytes per character + if (replace) { + undoIndex -= 1; + } if (undoThreshold > -1 && html.length * 2 > undoThreshold) { if (undoLimit > -1 && undoIndex > undoLimit) { undoStack.splice(0, undoIndex - undoLimit); diff --git a/source/keyboard/Space.ts b/source/keyboard/Space.ts index 1ec8e31..8ce1a25 100644 --- a/source/keyboard/Space.ts +++ b/source/keyboard/Space.ts @@ -1,4 +1,4 @@ -import { getLength } from '../node/Node'; +import { detach, getLength } from '../node/Node'; import { moveRangeBoundariesDownTree } from '../range/Boundaries'; import { deleteContentsOfRange } from '../range/InsertDelete'; @@ -9,7 +9,7 @@ import { rangeDoesEndAtBlockBoundary, } from '../range/Block'; import { SHOW_TEXT, TreeIterator } from '../node/TreeIterator'; -import { ZWS, cantFocusEmptyTextNodes } from '../Constants'; +import { ZWS } from '../Constants'; // --- @@ -31,10 +31,13 @@ const Space = (self: Squire, event: KeyboardEvent, range: Range): void => { const text = block.textContent?.trimEnd().replace(ZWS, ''); if (text === '*' || text === '1.') { event.preventDefault(); + self.insertPlainText(' ', false); + self._docWasChanged(); + self.saveUndoState(range); const walker = new TreeIterator(block, SHOW_TEXT); let textNode: Text | null; while ((textNode = walker.nextNode())) { - textNode.data = cantFocusEmptyTextNodes ? ZWS : ''; + detach(textNode); } if (text === '*') { self.makeUnorderedList();