mirror of
https://github.com/zadam/trilium.git
synced 2025-10-21 15:49:00 +02:00
chore(react/collections/table): integrate relation editor
This commit is contained in:
parent
cb959e93f2
commit
7777cd5238
@ -1,12 +1,11 @@
|
|||||||
import { NoteTitleFormatter, RowNumberFormatter } from "./formatters.js";
|
import type { CellComponent, ColumnDefinition, EmptyCallback, FormatterParams, ValueBooleanCallback, ValueVoidCallback } from "tabulator-tables";
|
||||||
import type { CellComponent, ColumnDefinition, EmptyCallback, FormatterParams } from "tabulator-tables";
|
|
||||||
import { LabelType } from "../../../services/promoted_attribute_definition_parser.js";
|
import { LabelType } from "../../../services/promoted_attribute_definition_parser.js";
|
||||||
import { RelationEditor } from "./relation_editor.js";
|
|
||||||
import { JSX } from "preact";
|
import { JSX } from "preact";
|
||||||
import { renderReactWidget } from "../../react/react_utils.jsx";
|
import { renderReactWidget } from "../../react/react_utils.jsx";
|
||||||
import Icon from "../../react/Icon.jsx";
|
import Icon from "../../react/Icon.jsx";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
import froca from "../../../services/froca.js";
|
import froca from "../../../services/froca.js";
|
||||||
|
import NoteAutocomplete from "../../react/NoteAutocomplete.jsx";
|
||||||
|
|
||||||
type ColumnType = LabelType | "relation";
|
type ColumnType = LabelType | "relation";
|
||||||
|
|
||||||
@ -50,7 +49,7 @@ const labelTypeMappings: Record<ColumnType, Partial<ColumnDefinition>> = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
relation: {
|
relation: {
|
||||||
editor: RelationEditor,
|
editor: wrapEditor(RelationEditor),
|
||||||
formatter: wrapFormatter(NoteFormatter)
|
formatter: wrapFormatter(NoteFormatter)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -178,6 +177,14 @@ interface FormatterOpts {
|
|||||||
formatterParams: FormatterParams;
|
formatterParams: FormatterParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface EditorOpts {
|
||||||
|
cell: CellComponent,
|
||||||
|
onRendered: EmptyCallback,
|
||||||
|
success: ValueBooleanCallback,
|
||||||
|
cancel: ValueVoidCallback,
|
||||||
|
editorParams: {}
|
||||||
|
}
|
||||||
|
|
||||||
function wrapFormatter(Component: (opts: FormatterOpts) => JSX.Element): ((cell: CellComponent, formatterParams: {}, onRendered: EmptyCallback) => string | HTMLElement) {
|
function wrapFormatter(Component: (opts: FormatterOpts) => JSX.Element): ((cell: CellComponent, formatterParams: {}, onRendered: EmptyCallback) => string | HTMLElement) {
|
||||||
return (cell, formatterParams, onRendered) => {
|
return (cell, formatterParams, onRendered) => {
|
||||||
const elWithParams = <Component cell={cell} formatterParams={formatterParams} />;
|
const elWithParams = <Component cell={cell} formatterParams={formatterParams} />;
|
||||||
@ -185,6 +192,18 @@ function wrapFormatter(Component: (opts: FormatterOpts) => JSX.Element): ((cell:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wrapEditor(Component: (opts: EditorOpts) => JSX.Element): ((
|
||||||
|
cell: CellComponent,
|
||||||
|
success: ValueBooleanCallback,
|
||||||
|
cancel: ValueVoidCallback,
|
||||||
|
editorParams: {},
|
||||||
|
) => HTMLElement | false) {
|
||||||
|
return (cell, _, success, cancel, editorParams) => {
|
||||||
|
const elWithParams = <Component cell={cell} success={success} cancel={cancel} editorParams={editorParams} />
|
||||||
|
return renderReactWidget(null, elWithParams)[0];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function NoteFormatter({ cell }: FormatterOpts) {
|
function NoteFormatter({ cell }: FormatterOpts) {
|
||||||
const noteId = cell.getValue();
|
const noteId = cell.getValue();
|
||||||
const [ note, setNote ] = useState(noteId ? froca.getNoteFromCache(noteId) : null)
|
const [ note, setNote ] = useState(noteId ? froca.getNoteFromCache(noteId) : null)
|
||||||
@ -199,3 +218,17 @@ function NoteFormatter({ cell }: FormatterOpts) {
|
|||||||
</span>;
|
</span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function RelationEditor({ cell, success }: EditorOpts) {
|
||||||
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
useEffect(() => inputRef.current?.focus());
|
||||||
|
|
||||||
|
return <NoteAutocomplete
|
||||||
|
inputRef={inputRef}
|
||||||
|
noteId={cell.getValue()}
|
||||||
|
opts={{
|
||||||
|
allowCreatingNotes: true,
|
||||||
|
hideAllButtons: true
|
||||||
|
}}
|
||||||
|
noteIdChanged={success}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
import { CellComponent } from "tabulator-tables";
|
|
||||||
import note_autocomplete from "../../../services/note_autocomplete";
|
|
||||||
import froca from "../../../services/froca";
|
|
||||||
|
|
||||||
export function RelationEditor(cell: CellComponent, onRendered, success, cancel, editorParams){
|
|
||||||
//cell - the cell component for the editable cell
|
|
||||||
//onRendered - function to call when the editor has been rendered
|
|
||||||
//success - function to call to pass thesuccessfully updated value to Tabulator
|
|
||||||
//cancel - function to call to abort the edit and return to a normal cell
|
|
||||||
//editorParams - params object passed into the editorParams column definition property
|
|
||||||
|
|
||||||
//create and style editor
|
|
||||||
const editor = document.createElement("input");
|
|
||||||
|
|
||||||
const $editor = $(editor);
|
|
||||||
editor.classList.add("form-control");
|
|
||||||
|
|
||||||
//create and style input
|
|
||||||
editor.style.padding = "3px";
|
|
||||||
editor.style.width = "100%";
|
|
||||||
editor.style.boxSizing = "border-box";
|
|
||||||
|
|
||||||
//Set value of editor to the current value of the cell
|
|
||||||
const originalNoteId = cell.getValue();
|
|
||||||
if (originalNoteId) {
|
|
||||||
const note = froca.getNoteFromCache(originalNoteId);
|
|
||||||
editor.value = note.title;
|
|
||||||
} else {
|
|
||||||
editor.value = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
//set focus on the select box when the editor is selected
|
|
||||||
onRendered(function(){
|
|
||||||
let newNoteId = originalNoteId;
|
|
||||||
|
|
||||||
note_autocomplete.initNoteAutocomplete($editor, {
|
|
||||||
allowCreatingNotes: true,
|
|
||||||
hideAllButtons: true
|
|
||||||
}).on("autocomplete:noteselected", (event, suggestion, dataset) => {
|
|
||||||
const notePath = suggestion.notePath;
|
|
||||||
newNoteId = (notePath ?? "").split("/").at(-1);
|
|
||||||
}).on("blur", () => {
|
|
||||||
if (!editor.value) {
|
|
||||||
newNoteId = "";
|
|
||||||
}
|
|
||||||
success(newNoteId);
|
|
||||||
});
|
|
||||||
editor.focus();
|
|
||||||
});
|
|
||||||
|
|
||||||
const container = document.createElement("div");
|
|
||||||
container.classList.add("input-group");
|
|
||||||
container.classList.add("autocomplete");
|
|
||||||
container.appendChild(editor);
|
|
||||||
return container;
|
|
||||||
};
|
|
Loading…
x
Reference in New Issue
Block a user