Lexical: Range of fixes
- Prevented ui shortcuts running in editor - Added form modal closing on submit - Fixed ability to escape lists via enter on empty last item
This commit is contained in:
		
							parent
							
								
									ef3de1050f
								
							
						
					
					
						commit
						c8ccb2bac7
					
				| 
						 | 
					@ -25,7 +25,7 @@ export class Shortcuts extends Component {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setupListeners() {
 | 
					    setupListeners() {
 | 
				
			||||||
        window.addEventListener('keydown', event => {
 | 
					        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;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -259,9 +259,21 @@ export class ListItemNode extends ElementNode {
 | 
				
			||||||
    _: RangeSelection,
 | 
					    _: RangeSelection,
 | 
				
			||||||
    restoreSelection = true,
 | 
					    restoreSelection = true,
 | 
				
			||||||
  ): ListItemNode | ParagraphNode {
 | 
					  ): 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(
 | 
					    const newElement = $createListItemNode(
 | 
				
			||||||
      this.__checked == null ? undefined : false,
 | 
					      this.__checked == null ? undefined : false,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.insertAfter(newElement, restoreSelection);
 | 
					    this.insertAfter(newElement, restoreSelection);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return newElement;
 | 
					    return newElement;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,8 +7,6 @@
 | 
				
			||||||
## Main Todo
 | 
					## Main Todo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Mac: Shortcut support via command.
 | 
					- Mac: Shortcut support via command.
 | 
				
			||||||
- Translations
 | 
					 | 
				
			||||||
- Form closing on submit
 | 
					 | 
				
			||||||
- Update toolbar overflows to match existing editor, incl. direction dynamic controls
 | 
					- Update toolbar overflows to match existing editor, incl. direction dynamic controls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Secondary Todo
 | 
					## Secondary Todo
 | 
				
			||||||
| 
						 | 
					@ -17,11 +15,9 @@
 | 
				
			||||||
- Color picker for color controls
 | 
					- Color picker for color controls
 | 
				
			||||||
- Table caption text support
 | 
					- 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)
 | 
					- 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
 | 
					## Bugs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- List selection can get lost on nesting/unnesting
 | 
					- List selection can get lost on nesting/unnesting
 | 
				
			||||||
- Can't escape lists when bottom element
 | 
					- Content not properly saving on new pages
 | 
				
			||||||
- Content not properly saving on new pages
 | 
					 | 
				
			||||||
- BookStack UI (non-editor) shortcuts can trigger in editor (`/` for example)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -100,13 +100,12 @@ export const image: EditorFormDefinition = {
 | 
				
			||||||
export function $showLinkForm(link: LinkNode|null, context: EditorUiContext) {
 | 
					export function $showLinkForm(link: LinkNode|null, context: EditorUiContext) {
 | 
				
			||||||
    const linkModal = context.manager.createModal('link');
 | 
					    const linkModal = context.manager.createModal('link');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let formDefaults = {};
 | 
					 | 
				
			||||||
    if (link) {
 | 
					    if (link) {
 | 
				
			||||||
        formDefaults = {
 | 
					        const formDefaults: Record<string, string> = {
 | 
				
			||||||
            url: link.getURL(),
 | 
					            url: link.getURL(),
 | 
				
			||||||
            text: link.getTextContent(),
 | 
					            text: link.getTextContent(),
 | 
				
			||||||
            title: link.getTitle(),
 | 
					            title: link.getTitle() || '',
 | 
				
			||||||
            target: link.getTarget(),
 | 
					            target: link.getTarget() || '',
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        context.editor.update(() => {
 | 
					        context.editor.update(() => {
 | 
				
			||||||
| 
						 | 
					@ -114,9 +113,16 @@ export function $showLinkForm(link: LinkNode|null, context: EditorUiContext) {
 | 
				
			||||||
            selection.add(link.getKey());
 | 
					            selection.add(link.getKey());
 | 
				
			||||||
            $setSelection(selection);
 | 
					            $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 = {
 | 
					export const link: EditorFormDefinition = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,6 +72,7 @@ export class EditorFormField extends EditorUiElement {
 | 
				
			||||||
export class EditorForm extends EditorContainerUiElement {
 | 
					export class EditorForm extends EditorContainerUiElement {
 | 
				
			||||||
    protected definition: EditorFormDefinition;
 | 
					    protected definition: EditorFormDefinition;
 | 
				
			||||||
    protected onCancel: null|(() => void) = null;
 | 
					    protected onCancel: null|(() => void) = null;
 | 
				
			||||||
 | 
					    protected onSuccessfulSubmit: null|(() => void) = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(definition: EditorFormDefinition) {
 | 
					    constructor(definition: EditorFormDefinition) {
 | 
				
			||||||
        let children: (EditorFormField|EditorUiElement)[] = definition.fields.map(fieldDefinition => {
 | 
					        let children: (EditorFormField|EditorUiElement)[] = definition.fields.map(fieldDefinition => {
 | 
				
			||||||
| 
						 | 
					@ -98,6 +99,10 @@ export class EditorForm extends EditorContainerUiElement {
 | 
				
			||||||
        this.onCancel = callback;
 | 
					        this.onCancel = callback;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setOnSuccessfulSubmit(callback: () => void) {
 | 
				
			||||||
 | 
					        this.onSuccessfulSubmit = callback;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected getFieldByName(name: string): EditorFormField|null {
 | 
					    protected getFieldByName(name: string): EditorFormField|null {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const search = (children: EditorUiElement[]): 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();
 | 
					            event.preventDefault();
 | 
				
			||||||
            const formData = new FormData(form as HTMLFormElement);
 | 
					            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) => {
 | 
					        cancelButton.addEventListener('click', (event) => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,7 @@ export class EditorFormModal extends EditorContainerUiElement {
 | 
				
			||||||
        const form = this.getForm();
 | 
					        const form = this.getForm();
 | 
				
			||||||
        form.setValues(defaultValues);
 | 
					        form.setValues(defaultValues);
 | 
				
			||||||
        form.setOnCancel(this.hide.bind(this));
 | 
					        form.setOnCancel(this.hide.bind(this));
 | 
				
			||||||
 | 
					        form.setOnSuccessfulSubmit(this.hide.bind(this));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.getContext().manager.setModalActive(this.key, this);
 | 
					        this.getContext().manager.setModalActive(this.key, this);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue