mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 21:19:01 +01:00 
			
		
		
		
	chore(react/ribbon): add focus to attribute editor
This commit is contained in:
		
							parent
							
								
									efd713dc61
								
							
						
					
					
						commit
						db687197de
					
				@ -18,14 +18,6 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async save() {
 | 
					 | 
				
			||||||
        if (this.lastUpdatedNoteId !== this.noteId) {
 | 
					 | 
				
			||||||
            // https://github.com/zadam/trilium/issues/3090
 | 
					 | 
				
			||||||
            console.warn("Ignoring blur event because a different note is loaded.");
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dataChanged() {
 | 
					    dataChanged() {
 | 
				
			||||||
        this.lastUpdatedNoteId = this.noteId;
 | 
					        this.lastUpdatedNoteId = this.noteId;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -49,20 +41,6 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem
 | 
				
			|||||||
    focus() {
 | 
					    focus() {
 | 
				
			||||||
        this.$editor.trigger("focus");
 | 
					        this.$editor.trigger("focus");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.textEditor.model.change((writer) => {
 | 
					 | 
				
			||||||
            const documentRoot = this.textEditor.editing.model.document.getRoot();
 | 
					 | 
				
			||||||
            if (!documentRoot) {
 | 
					 | 
				
			||||||
                return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const positionAt = writer.createPositionAt(documentRoot, "end");
 | 
					 | 
				
			||||||
            writer.setSelection(positionAt);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
 | 
					 | 
				
			||||||
        if (loadResults.getAttributeRows(this.componentId).find((attr) => attributeService.isAffecting(attr, this.note))) {
 | 
					 | 
				
			||||||
            this.refresh();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,13 @@
 | 
				
			|||||||
import { CKTextEditor, type AttributeEditor, type EditorConfig, type ModelPosition } from "@triliumnext/ckeditor5";
 | 
					import { CKTextEditor, type AttributeEditor, type EditorConfig, type ModelPosition } from "@triliumnext/ckeditor5";
 | 
				
			||||||
import { useEffect, useRef } from "preact/compat";
 | 
					import { useEffect, useImperativeHandle, useRef } from "preact/compat";
 | 
				
			||||||
 | 
					import { MutableRef } from "preact/hooks";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface CKEditorApi {
 | 
				
			||||||
 | 
					    focus: () => void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface CKEditorOpts {
 | 
					interface CKEditorOpts {
 | 
				
			||||||
 | 
					    apiRef: MutableRef<CKEditorApi | undefined>;
 | 
				
			||||||
    currentValue?: string;
 | 
					    currentValue?: string;
 | 
				
			||||||
    className: string;
 | 
					    className: string;
 | 
				
			||||||
    tabIndex?: number;
 | 
					    tabIndex?: number;
 | 
				
			||||||
@ -15,9 +21,22 @@ interface CKEditorOpts {
 | 
				
			|||||||
    onBlur?: () => void;
 | 
					    onBlur?: () => void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function CKEditor({ currentValue, editor, config, disableNewlines, disableSpellcheck, onChange, onClick, ...restProps }: CKEditorOpts) {
 | 
					export default function CKEditor({ apiRef, currentValue, editor, config, disableNewlines, disableSpellcheck, onChange, onClick, ...restProps }: CKEditorOpts) {
 | 
				
			||||||
    const editorContainerRef = useRef<HTMLDivElement>(null);    
 | 
					    const editorContainerRef = useRef<HTMLDivElement>(null);    
 | 
				
			||||||
    const textEditorRef = useRef<CKTextEditor>(null);
 | 
					    const textEditorRef = useRef<CKTextEditor>(null);
 | 
				
			||||||
 | 
					    useImperativeHandle(apiRef, () => {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            focus() {
 | 
				
			||||||
 | 
					                editorContainerRef.current?.focus();
 | 
				
			||||||
 | 
					                textEditorRef.current?.model.change((writer) => {
 | 
				
			||||||
 | 
					                    const documentRoot = textEditorRef.current?.editing.model.document.getRoot();
 | 
				
			||||||
 | 
					                    if (documentRoot) {
 | 
				
			||||||
 | 
					                        writer.setSelection(writer.createPositionAt(documentRoot, "end"));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }, [ editorContainerRef ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        if (!editorContainerRef.current) return;
 | 
					        if (!editorContainerRef.current) return;
 | 
				
			||||||
 | 
				
			|||||||
@ -148,7 +148,7 @@ const TAB_CONFIGURATION = numberObjectsInPlace<TabConfiguration>([
 | 
				
			|||||||
]);
 | 
					]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function Ribbon() {
 | 
					export default function Ribbon() {
 | 
				
			||||||
    const { note, ntxId, hoistedNoteId, notePath, noteContext } = useNoteContext();
 | 
					    const { note, ntxId, hoistedNoteId, notePath, noteContext, componentId } = useNoteContext();
 | 
				
			||||||
    const titleContext: TitleContext = { note };
 | 
					    const titleContext: TitleContext = { note };
 | 
				
			||||||
    const [ activeTabIndex, setActiveTabIndex ] = useState<number | undefined>();
 | 
					    const [ activeTabIndex, setActiveTabIndex ] = useState<number | undefined>();
 | 
				
			||||||
    const filteredTabs = useMemo(() => TAB_CONFIGURATION.filter(tab => typeof tab.show === "boolean" ? tab.show : tab.show?.(titleContext)), [ titleContext, note ]);
 | 
					    const filteredTabs = useMemo(() => TAB_CONFIGURATION.filter(tab => typeof tab.show === "boolean" ? tab.show : tab.show?.(titleContext)), [ titleContext, note ]);
 | 
				
			||||||
@ -190,7 +190,8 @@ export default function Ribbon() {
 | 
				
			|||||||
                            ntxId,
 | 
					                            ntxId,
 | 
				
			||||||
                            hoistedNoteId,
 | 
					                            hoistedNoteId,
 | 
				
			||||||
                            notePath,
 | 
					                            notePath,
 | 
				
			||||||
                            noteContext
 | 
					                            noteContext,
 | 
				
			||||||
 | 
					                            componentId
 | 
				
			||||||
                        });
 | 
					                        });
 | 
				
			||||||
                    })}
 | 
					                    })}
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,8 +3,8 @@ import { AttributeEditor as CKEditorAttributeEditor, MentionFeed, ModelElement,
 | 
				
			|||||||
import { t } from "../../../services/i18n";
 | 
					import { t } from "../../../services/i18n";
 | 
				
			||||||
import server from "../../../services/server";
 | 
					import server from "../../../services/server";
 | 
				
			||||||
import note_autocomplete, { Suggestion } from "../../../services/note_autocomplete";
 | 
					import note_autocomplete, { Suggestion } from "../../../services/note_autocomplete";
 | 
				
			||||||
import CKEditor from "../../react/CKEditor";
 | 
					import CKEditor, { CKEditorApi } from "../../react/CKEditor";
 | 
				
			||||||
import { useLegacyWidget, useTooltip } from "../../react/hooks";
 | 
					import { useLegacyWidget, useTooltip, useTriliumEventBeta } from "../../react/hooks";
 | 
				
			||||||
import FAttribute from "../../../entities/fattribute";
 | 
					import FAttribute from "../../../entities/fattribute";
 | 
				
			||||||
import attribute_renderer from "../../../services/attribute_renderer";
 | 
					import attribute_renderer from "../../../services/attribute_renderer";
 | 
				
			||||||
import FNote from "../../../entities/fnote";
 | 
					import FNote from "../../../entities/fnote";
 | 
				
			||||||
@ -19,6 +19,7 @@ import froca from "../../../services/froca";
 | 
				
			|||||||
import contextMenu from "../../../menus/context_menu";
 | 
					import contextMenu from "../../../menus/context_menu";
 | 
				
			||||||
import type { CommandData, FilteredCommandNames } from "../../../components/app_context";
 | 
					import type { CommandData, FilteredCommandNames } from "../../../components/app_context";
 | 
				
			||||||
import { AttributeType } from "@triliumnext/commons";
 | 
					import { AttributeType } from "@triliumnext/commons";
 | 
				
			||||||
 | 
					import attributes from "../../../services/attributes";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type AttributeCommandNames = FilteredCommandNames<CommandData>;
 | 
					type AttributeCommandNames = FilteredCommandNames<CommandData>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -86,6 +87,7 @@ export default function AttributeEditor({ note, componentId }: { note: FNote, co
 | 
				
			|||||||
    const lastSavedContent = useRef<string>();
 | 
					    const lastSavedContent = useRef<string>();
 | 
				
			||||||
    const currentValueRef = useRef(initialValue);
 | 
					    const currentValueRef = useRef(initialValue);
 | 
				
			||||||
    const wrapperRef = useRef<HTMLDivElement>(null);
 | 
					    const wrapperRef = useRef<HTMLDivElement>(null);
 | 
				
			||||||
 | 
					    const editorRef = useRef<CKEditorApi>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { showTooltip, hideTooltip } = useTooltip(wrapperRef, {
 | 
					    const { showTooltip, hideTooltip } = useTooltip(wrapperRef, {
 | 
				
			||||||
        trigger: "focus",
 | 
					        trigger: "focus",
 | 
				
			||||||
@ -207,9 +209,23 @@ export default function AttributeEditor({ note, componentId }: { note: FNote, co
 | 
				
			|||||||
        }, 100);
 | 
					        }, 100);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					    // Refresh with note
 | 
				
			||||||
 | 
					    function refresh() {
 | 
				
			||||||
        renderOwnedAttributes(note.getOwnedAttributes(), true);
 | 
					        renderOwnedAttributes(note.getOwnedAttributes(), true);
 | 
				
			||||||
    }, [ note ]);
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => refresh(), [ note ]);
 | 
				
			||||||
 | 
					    useTriliumEventBeta("entitiesReloaded", ({ loadResults }) => {
 | 
				
			||||||
 | 
					        if (loadResults.getAttributeRows(componentId).find((attr) => attributes.isAffecting(attr, note))) {
 | 
				
			||||||
 | 
					            console.log("Trigger due to entities reloaded");
 | 
				
			||||||
 | 
					            refresh();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Focus on show.
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        setTimeout(() => editorRef.current?.focus(), 0);
 | 
				
			||||||
 | 
					    }, []);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <>
 | 
					        <>
 | 
				
			||||||
@ -224,6 +240,7 @@ export default function AttributeEditor({ note, componentId }: { note: FNote, co
 | 
				
			|||||||
                }}
 | 
					                }}
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
                <CKEditor
 | 
					                <CKEditor
 | 
				
			||||||
 | 
					                    apiRef={editorRef}
 | 
				
			||||||
                    className="attribute-list-editor"
 | 
					                    className="attribute-list-editor"
 | 
				
			||||||
                    tabIndex={200}
 | 
					                    tabIndex={200}
 | 
				
			||||||
                    editor={CKEditorAttributeEditor}
 | 
					                    editor={CKEditorAttributeEditor}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,4 +8,5 @@ export interface TabContext {
 | 
				
			|||||||
    hoistedNoteId?: string;
 | 
					    hoistedNoteId?: string;
 | 
				
			||||||
    notePath?: string | null;
 | 
					    notePath?: string | null;
 | 
				
			||||||
    noteContext?: NoteContext;
 | 
					    noteContext?: NoteContext;
 | 
				
			||||||
 | 
					    componentId: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user