diff --git a/apps/client/src/widgets/attribute_widgets/attribute_editor.ts b/apps/client/src/widgets/attribute_widgets/attribute_editor.ts index 016bd8776..4baecd691 100644 --- a/apps/client/src/widgets/attribute_widgets/attribute_editor.ts +++ b/apps/client/src/widgets/attribute_widgets/attribute_editor.ts @@ -16,12 +16,7 @@ import type { default as FAttribute, AttributeType } from "../../entities/fattri import type FNote from "../../entities/fnote.js"; import { escapeQuotes } from "../../services/utils.js"; -const HELP_TEXT = ` -

${t("attribute_editor.help_text_body1")}

-

${t("attribute_editor.help_text_body2")}

- -

${t("attribute_editor.help_text_body3")}

`; const TPL = /*html*/` @@ -229,9 +224,7 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem } async handleEditorClick(e: JQuery.ClickEvent) { - const pos = this.textEditor.model.document.selection.getFirstPosition(); - - if (pos && pos.textNode && pos.textNode.data) { + if () { const clickIndex = this.getClickIndex(pos); let parsedAttrs; @@ -267,25 +260,9 @@ export default class AttributeEditorWidget extends NoteContextAwareWidget implem this.showHelpTooltip(); } }, 100); - } else { - this.showHelpTooltip(); } } - showHelpTooltip() { - this.attributeDetailWidget.hide(); - - this.$editor.tooltip({ - trigger: "focus", - html: true, - title: HELP_TEXT, - placement: "bottom", - offset: "0,30" - }); - - this.$editor.tooltip("show"); - } - getClickIndex(pos: ModelPosition) { let clickIndex = pos.offset - (pos.textNode?.startOffset ?? 0); diff --git a/apps/client/src/widgets/react/CKEditor.tsx b/apps/client/src/widgets/react/CKEditor.tsx index 7b28c30cf..8f521a827 100644 --- a/apps/client/src/widgets/react/CKEditor.tsx +++ b/apps/client/src/widgets/react/CKEditor.tsx @@ -1,4 +1,4 @@ -import type { AttributeEditor, EditorConfig } from "@triliumnext/ckeditor5"; +import { CKTextEditor, type AttributeEditor, type EditorConfig, type ModelPosition } from "@triliumnext/ckeditor5"; import { useEffect, useRef } from "preact/compat"; interface CKEditorOpts { @@ -9,15 +9,19 @@ interface CKEditorOpts { disableNewlines?: boolean; disableSpellcheck?: boolean; onChange?: () => void; + onClick?: (pos?: ModelPosition | null) => void; } -export default function CKEditor({ className, tabIndex, editor, config, disableNewlines, disableSpellcheck, onChange }: CKEditorOpts) { +export default function CKEditor({ className, tabIndex, editor, config, disableNewlines, disableSpellcheck, onChange, onClick }: CKEditorOpts) { const editorContainerRef = useRef(null); + const textEditorRef = useRef(null); useEffect(() => { if (!editorContainerRef.current) return; editor.create(editorContainerRef.current, config).then((textEditor) => { + textEditorRef.current = textEditor; + if (disableNewlines) { textEditor.editing.view.document.on( "enter", @@ -48,6 +52,12 @@ export default function CKEditor({ className, tabIndex, editor, config, disableN ref={editorContainerRef} className={className} tabIndex={tabIndex} + onClick={() => { + if (onClick) { + const pos = textEditorRef.current?.model.document.selection.getFirstPosition(); + onClick(pos); + } + }} /> ) } \ No newline at end of file diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index af74c6873..6436b1734 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -12,7 +12,8 @@ import FNote from "../../entities/fnote"; import attributes from "../../services/attributes"; import FBlob from "../../entities/fblob"; import NoteContextAwareWidget from "../note_context_aware_widget"; -import { RefObject, VNode } from "preact"; +import { Ref, RefObject, VNode } from "preact"; +import { Tooltip } from "bootstrap"; type TriliumEventHandler = (data: EventData) => void; const registeredHandlers: Map[]>> = new Map(); @@ -510,4 +511,29 @@ export function useWindowSize() { }); return size; +} + +export function useTooltip(elRef: RefObject, config: Partial) { + useEffect(() => { + if (!elRef?.current) return; + + const $el = $(elRef.current); + $el.tooltip(config); + }, [ elRef, config ]); + + const showTooltip = useCallback(() => { + if (!elRef?.current) return; + + const $el = $(elRef.current); + $el.tooltip("show"); + }, [ elRef ]); + + const hideTooltip = useCallback(() => { + if (!elRef?.current) return; + + const $el = $(elRef.current); + $el.tooltip("hide"); + }, [ elRef ]); + + return { showTooltip, hideTooltip }; } \ No newline at end of file diff --git a/apps/client/src/widgets/ribbon/components/AttributeEditor.tsx b/apps/client/src/widgets/ribbon/components/AttributeEditor.tsx index 9ae3f2372..d8071f7b9 100644 --- a/apps/client/src/widgets/ribbon/components/AttributeEditor.tsx +++ b/apps/client/src/widgets/ribbon/components/AttributeEditor.tsx @@ -1,9 +1,17 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks" -import { AttributeEditor as CKEditorAttributeEditor, EditorConfig, MentionFeed } from "@triliumnext/ckeditor5"; +import { useEffect, useRef, useState } from "preact/hooks" +import { AttributeEditor as CKEditorAttributeEditor, MentionFeed } from "@triliumnext/ckeditor5"; import { t } from "../../../services/i18n"; import server from "../../../services/server"; import note_autocomplete, { Suggestion } from "../../../services/note_autocomplete"; import CKEditor from "../../react/CKEditor"; +import { useTooltip } from "../../react/hooks"; + +const HELP_TEXT = ` +

${t("attribute_editor.help_text_body1")}

+ +

${t("attribute_editor.help_text_body2")}

+ +

${t("attribute_editor.help_text_body3")}

`; const mentionSetup: MentionFeed[] = [ { @@ -51,11 +59,27 @@ const mentionSetup: MentionFeed[] = [ export default function AttributeEditor() { - - const [ attributeDetailVisible, setAttributeDetailVisible ] = useState(false); + const [ state, setState ] = useState<"normal" | "showHelpTooltip" | "showAttributeDetail">(); + const wrapperRef = useRef(null); + const { showTooltip, hideTooltip } = useTooltip(wrapperRef, { + trigger: "focus", + html: true, + title: HELP_TEXT, + placement: "bottom", + offset: "0,30" + }); + + useEffect(() => { + if (state === "showHelpTooltip") { + showTooltip(); + } else { + hideTooltip(); + } + }, [ state ]); + return ( -
+
{ console.log("Data changed!"); }} + onClick={(pos) => { + if (pos && pos.textNode && pos.textNode.data) { + setState("showAttributeDetail") + } else { + setState("showHelpTooltip"); + } + }} disableNewlines disableSpellcheck />