2025-08-23 12:31:54 +03:00
|
|
|
import { useEffect, useRef, useState } from "preact/hooks"
|
|
|
|
|
import { AttributeEditor as CKEditorAttributeEditor, MentionFeed } from "@triliumnext/ckeditor5";
|
2025-08-23 11:44:51 +03:00
|
|
|
import { t } from "../../../services/i18n";
|
|
|
|
|
import server from "../../../services/server";
|
|
|
|
|
import note_autocomplete, { Suggestion } from "../../../services/note_autocomplete";
|
2025-08-23 12:05:03 +03:00
|
|
|
import CKEditor from "../../react/CKEditor";
|
2025-08-23 12:31:54 +03:00
|
|
|
import { useTooltip } from "../../react/hooks";
|
|
|
|
|
|
|
|
|
|
const HELP_TEXT = `
|
|
|
|
|
<p>${t("attribute_editor.help_text_body1")}</p>
|
|
|
|
|
|
|
|
|
|
<p>${t("attribute_editor.help_text_body2")}</p>
|
|
|
|
|
|
|
|
|
|
<p>${t("attribute_editor.help_text_body3")}</p>`;
|
2025-08-23 11:44:51 +03:00
|
|
|
|
|
|
|
|
const mentionSetup: MentionFeed[] = [
|
|
|
|
|
{
|
|
|
|
|
marker: "@",
|
|
|
|
|
feed: (queryText) => note_autocomplete.autocompleteSourceForCKEditor(queryText),
|
|
|
|
|
itemRenderer: (_item) => {
|
|
|
|
|
const item = _item as Suggestion;
|
|
|
|
|
const itemElement = document.createElement("button");
|
|
|
|
|
|
|
|
|
|
itemElement.innerHTML = `${item.highlightedNotePathTitle} `;
|
|
|
|
|
|
|
|
|
|
return itemElement;
|
|
|
|
|
},
|
|
|
|
|
minimumCharacters: 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
marker: "#",
|
|
|
|
|
feed: async (queryText) => {
|
|
|
|
|
const names = await server.get<string[]>(`attribute-names/?type=label&query=${encodeURIComponent(queryText)}`);
|
|
|
|
|
|
|
|
|
|
return names.map((name) => {
|
|
|
|
|
return {
|
|
|
|
|
id: `#${name}`,
|
|
|
|
|
name: name
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
minimumCharacters: 0
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
marker: "~",
|
|
|
|
|
feed: async (queryText) => {
|
|
|
|
|
const names = await server.get<string[]>(`attribute-names/?type=relation&query=${encodeURIComponent(queryText)}`);
|
|
|
|
|
|
|
|
|
|
return names.map((name) => {
|
|
|
|
|
return {
|
|
|
|
|
id: `~${name}`,
|
|
|
|
|
name: name
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
minimumCharacters: 0
|
|
|
|
|
}
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default function AttributeEditor() {
|
2025-08-23 11:52:40 +03:00
|
|
|
|
2025-08-23 12:31:54 +03:00
|
|
|
const [ state, setState ] = useState<"normal" | "showHelpTooltip" | "showAttributeDetail">();
|
|
|
|
|
const wrapperRef = useRef<HTMLDivElement>(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 ]);
|
|
|
|
|
|
2025-08-23 11:44:51 +03:00
|
|
|
return (
|
2025-08-23 12:31:54 +03:00
|
|
|
<div ref={wrapperRef} style="position: relative; padding-top: 10px; padding-bottom: 10px">
|
2025-08-23 12:05:03 +03:00
|
|
|
<CKEditor
|
|
|
|
|
className="attribute-list-editor"
|
|
|
|
|
tabIndex={200}
|
|
|
|
|
editor={CKEditorAttributeEditor}
|
|
|
|
|
config={{
|
|
|
|
|
toolbar: { items: [] },
|
|
|
|
|
placeholder: t("attribute_editor.placeholder"),
|
|
|
|
|
mention: { feeds: mentionSetup },
|
|
|
|
|
licenseKey: "GPL"
|
|
|
|
|
}}
|
|
|
|
|
onChange={() => {
|
|
|
|
|
console.log("Data changed!");
|
|
|
|
|
}}
|
2025-08-23 12:31:54 +03:00
|
|
|
onClick={(pos) => {
|
|
|
|
|
if (pos && pos.textNode && pos.textNode.data) {
|
|
|
|
|
setState("showAttributeDetail")
|
|
|
|
|
} else {
|
|
|
|
|
setState("showHelpTooltip");
|
|
|
|
|
}
|
|
|
|
|
}}
|
2025-08-23 12:05:03 +03:00
|
|
|
disableNewlines disableSpellcheck
|
|
|
|
|
/>
|
2025-08-23 11:44:51 +03:00
|
|
|
</div>
|
|
|
|
|
)
|
|
|
|
|
}
|