From 41334fda90d79fea5512784e5a1ea493997b381b Mon Sep 17 00:00:00 2001 From: TomNUSDS <74203452+TomNUSDS@users.noreply.github.com> Date: Fri, 15 Mar 2024 08:14:05 -0700 Subject: [PATCH] Clean-up, fixes and comments --- .../clearFormatting/ClearFormatting.tsx | 56 +++++++++++++------ src/pages/BlogEditorPage.tsx | 2 +- src/pages/HomePage.tsx | 13 +++-- 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/src/mdxcomponents/clearFormatting/ClearFormatting.tsx b/src/mdxcomponents/clearFormatting/ClearFormatting.tsx index 08fb314..ddd41b4 100644 --- a/src/mdxcomponents/clearFormatting/ClearFormatting.tsx +++ b/src/mdxcomponents/clearFormatting/ClearFormatting.tsx @@ -6,13 +6,18 @@ import {useCellValues} from "@mdxeditor/gurx"; import ClearFormatSVG from "../../../public/img/clear-format-icon.svg?react"; import { $getSelection, - $setSelection, + $getTextContent, $isRangeSelection, + $setSelection, LexicalEditor, - $getTextContent, + KEY_DELETE_COMMAND, + SELECTION_CHANGE_COMMAND } from "lexical"; import {moveNativeSelection} from "../frontmatterUtils.ts"; +// Reselected cleared text is a hack right now. It reselects one-character-at-a-time +// which gets really slow for large text blocks. Work-around is to limit it. +const MAX_SELECTION_LENGTH = 2000; /** * A toolbar button that allows the user to insert a thematic break (rendered as an HR HTML element). @@ -25,7 +30,6 @@ export const ClearFormatting: React.FC = () => { const clearFormatting = (editor: LexicalEditor | null) => { editor?.update(() => { const selection = $getSelection(); - if (!$isRangeSelection(selection)) { return; } @@ -36,21 +40,34 @@ export const ClearFormatting: React.FC = () => { return; } - { - const nativeSelection = window.getSelection(); - const rootElement = editor.getRootElement(); - const selectedText = $getTextContent(); + const nativeSelection = window.getSelection(); + const rootElement = editor.getRootElement(); + const selectedText = $getTextContent(); - if ( - nativeSelection !== null && - rootElement !== null && - rootElement.contains(nativeSelection.anchorNode) && - editor.isEditable() - ) { + if ( + nativeSelection === null || + rootElement === null || + !rootElement.contains(nativeSelection.anchorNode) || + !editor.isEditable() + ) { + return; + } + + // For 95% of the time, `selection.insertRawText` just works. + // But sometimes it causes the lexiI don't understand the failure scenario + // Quickfix is deleting, then inserting. + // Unfortunately the Delete is in the undo buffer. :facepalm: + editor.dispatchCommand(KEY_DELETE_COMMAND, new KeyboardEvent("keypress")); + + setTimeout(() => { + editor?.update(() => { // this replaces the elements with plaintext correctly // things like lists are NOT collapsed into a single line, which is what we want selection.insertRawText(selectedText); + // this will cause a throw if something got broken by the insert + editor.dispatchCommand(SELECTION_CHANGE_COMMAND, undefined); + // we need to let the lexical state process those changes before we can do // the next step setTimeout(() => { @@ -61,8 +78,12 @@ export const ClearFormatting: React.FC = () => { if (!newNativeSelection) { return; } - for (const _eachChar of selectedText) { + // because of the "select back one space" approach, limit max size + const selectionSize = Math.min(selectedText.length, MAX_SELECTION_LENGTH); + + for (let ii = 0; ii < selectionSize; ii++) { // this is literally like pressing shift + arrow left repeatedly. + // Not sure how slow it is for really large text moveNativeSelection(newNativeSelection, 'extend', 'backward', 'character'); } @@ -81,9 +102,10 @@ export const ClearFormatting: React.FC = () => { } } }); // editor.update - }, 100); // setTimeout - } - } + }, 1); // setTimeout + });// editor.update + }, 1);// setTimeout + }); }; diff --git a/src/pages/BlogEditorPage.tsx b/src/pages/BlogEditorPage.tsx index b4c436b..a5fa2a1 100644 --- a/src/pages/BlogEditorPage.tsx +++ b/src/pages/BlogEditorPage.tsx @@ -107,7 +107,7 @@ export const BlogEditorPage = () => { }), frontmatterCustomPlugin(), diffSourcePlugin({diffMarkdown: oldMarkdown, viewMode: 'rich-text'}), - headingsPlugin({allowedHeadingLevels: [2, 3, 4]}), + headingsPlugin({allowedHeadingLevels: [1, 2, 3, 4, 5]}), imagePlugin({imageUploadHandler, disableImageResize: true, ImageDialog: ImageDialogCustom}), linkDialogPlugin(), linkPlugin(), diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 05f991d..e3836ba 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -21,7 +21,7 @@ export const HomePage = () => { the most handy.