]> BookStack Code Mirror - bookstack/commitdiff
Lexical: Range of fixes
authorDan Brown <redacted>
Sun, 22 Sep 2024 15:15:02 +0000 (16:15 +0100)
committerDan Brown <redacted>
Sun, 22 Sep 2024 15:15:02 +0000 (16:15 +0100)
- Prevented ui shortcuts running in editor
- Added form modal closing on submit
- Fixed ability to escape lists via enter on empty last item

resources/js/components/shortcuts.js
resources/js/wysiwyg/lexical/list/LexicalListItemNode.ts
resources/js/wysiwyg/todo.md
resources/js/wysiwyg/ui/defaults/forms/objects.ts
resources/js/wysiwyg/ui/framework/forms.ts
resources/js/wysiwyg/ui/framework/modals.ts

index b22c467318e73f383259119d5b96126b8e39c98f..8bf26fbb51c1a680587eaf89f348f90853ea7ea6 100644 (file)
@@ -25,7 +25,7 @@ export class Shortcuts extends Component {
 
     setupListeners() {
         window.addEventListener('keydown', event => {
-            if (event.target.closest('input, select, textarea, .cm-editor')) {
+            if (event.target.closest('input, select, textarea, .cm-editor, .editor-container')) {
                 return;
             }
 
index 7d12b5bd38a9111ef01d20c09599b73ace7c250c..5026a01293ef26216b715a37a2b27160088a1f78 100644 (file)
@@ -259,9 +259,21 @@ export class ListItemNode extends ElementNode {
     _: RangeSelection,
     restoreSelection = true,
   ): ListItemNode | ParagraphNode {
+
+    if (this.getTextContent().trim() === '' && this.isLastChild()) {
+      const list = this.getParentOrThrow<ListNode>();
+      if (!$isListItemNode(list.getParent())) {
+        const paragraph = $createParagraphNode();
+        list.insertAfter(paragraph, restoreSelection);
+        this.remove();
+        return paragraph;
+      }
+    }
+
     const newElement = $createListItemNode(
       this.__checked == null ? undefined : false,
     );
+
     this.insertAfter(newElement, restoreSelection);
 
     return newElement;
index 66878f37db087b61ea5087a6d059b915a4dbda73..91e1a9678534616c16c89a0fad8a098cba06ba00 100644 (file)
@@ -7,8 +7,6 @@
 ## Main Todo
 
 - Mac: Shortcut support via command.
-- Translations
-- Form closing on submit
 - Update toolbar overflows to match existing editor, incl. direction dynamic controls
 
 ## Secondary Todo
 - Color picker for color controls
 - Table caption text support
 - Support media src conversions (https://github.com/tinymce/tinymce/blob/release/6.6/modules/tinymce/src/plugins/media/main/ts/core/UrlPatterns.ts)
-- Check translation coverage
+- Deep check of translation coverage
 
 ## Bugs
 
 - List selection can get lost on nesting/unnesting
-- Can't escape lists when bottom element
-- Content not properly saving on new pages
-- BookStack UI (non-editor) shortcuts can trigger in editor (`/` for example)
\ No newline at end of file
+- Content not properly saving on new pages
\ No newline at end of file
index f1575953b519db89c4cfd727e610c2a36b1074f1..228566d442e5ce8c609dc4d363b3b29550f26bf3 100644 (file)
@@ -100,13 +100,12 @@ export const image: EditorFormDefinition = {
 export function $showLinkForm(link: LinkNode|null, context: EditorUiContext) {
     const linkModal = context.manager.createModal('link');
 
-    let formDefaults = {};
     if (link) {
-        formDefaults = {
+        const formDefaults: Record<string, string> = {
             url: link.getURL(),
             text: link.getTextContent(),
-            title: link.getTitle(),
-            target: link.getTarget(),
+            title: link.getTitle() || '',
+            target: link.getTarget() || '',
         }
 
         context.editor.update(() => {
@@ -114,9 +113,16 @@ export function $showLinkForm(link: LinkNode|null, context: EditorUiContext) {
             selection.add(link.getKey());
             $setSelection(selection);
         });
-    }
 
-    linkModal.show(formDefaults);
+        linkModal.show(formDefaults);
+    } else {
+        context.editor.getEditorState().read(() => {
+            const selection = $getSelection();
+            const text = selection?.getTextContent() || '';
+            const formDefaults = {text};
+            linkModal.show(formDefaults);
+        });
+    }
 }
 
 export const link: EditorFormDefinition = {
index 615d5b4ded0362f7c5aace812916a89523158d8b..36371e30238d9c38061db80aae889812d6234588 100644 (file)
@@ -72,6 +72,7 @@ export class EditorFormField extends EditorUiElement {
 export class EditorForm extends EditorContainerUiElement {
     protected definition: EditorFormDefinition;
     protected onCancel: null|(() => void) = null;
+    protected onSuccessfulSubmit: null|(() => void) = null;
 
     constructor(definition: EditorFormDefinition) {
         let children: (EditorFormField|EditorUiElement)[] = definition.fields.map(fieldDefinition => {
@@ -98,6 +99,10 @@ export class EditorForm extends EditorContainerUiElement {
         this.onCancel = callback;
     }
 
+    setOnSuccessfulSubmit(callback: () => void) {
+        this.onSuccessfulSubmit = callback;
+    }
+
     protected getFieldByName(name: string): EditorFormField|null {
 
         const search = (children: EditorUiElement[]): EditorFormField|null => {
@@ -128,10 +133,13 @@ export class EditorForm extends EditorContainerUiElement {
             ])
         ]);
 
-        form.addEventListener('submit', (event) => {
+        form.addEventListener('submit', async (event) => {
             event.preventDefault();
             const formData = new FormData(form as HTMLFormElement);
-            this.definition.action(formData, this.getContext());
+            const result = await this.definition.action(formData, this.getContext());
+            if (result && this.onSuccessfulSubmit) {
+                this.onSuccessfulSubmit();
+            }
         });
 
         cancelButton.addEventListener('click', (event) => {
index ae69302f6d0613b411137de2eef99af22c8d1e63..3eea62ebb94d9cca2e1ab1ae9bfff7f1990467e0 100644 (file)
@@ -28,6 +28,7 @@ export class EditorFormModal extends EditorContainerUiElement {
         const form = this.getForm();
         form.setValues(defaultValues);
         form.setOnCancel(this.hide.bind(this));
+        form.setOnSuccessfulSubmit(this.hide.bind(this));
 
         this.getContext().manager.setModalActive(this.key, this);
     }