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() {
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -17,11 +15,9 @@
 | 
			
		|||
- 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)
 | 
			
		||||
- Content not properly saving on new pages
 | 
			
		||||
| 
						 | 
				
			
			@ -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 = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue