mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 00:49:00 +01:00
chore(react/type_widgets): reintroduce relation note dragging
This commit is contained in:
parent
1eca9f6541
commit
67d9154795
@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "preact/hooks";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks";
|
||||
import { TypeWidgetProps } from "../type_widget";
|
||||
import { jsPlumbInstance, OnConnectionBindInfo } from "jsplumb";
|
||||
import { useEditorSpacedUpdate, useTriliumEvent, useTriliumEvents } from "../../react/hooks";
|
||||
@ -19,6 +19,7 @@ import { NoteBox } from "./NoteBox";
|
||||
import utils from "../../../services/utils";
|
||||
import attribute_autocomplete from "../../../services/attribute_autocomplete";
|
||||
import { buildRelationContextMenuHandler } from "./context_menu";
|
||||
import { HTMLProps } from "preact/compat";
|
||||
|
||||
interface Clipboard {
|
||||
noteId: string;
|
||||
@ -90,6 +91,7 @@ export default function RelationMap({ note, ntxId }: TypeWidgetProps) {
|
||||
ntxId,
|
||||
mapApiRef
|
||||
});
|
||||
const dragProps = useNoteDragging({ containerRef, mapApiRef });
|
||||
|
||||
const connectionCallback = useRelationCreation({ mapApiRef, jsPlumbApiRef: pbApiRef });
|
||||
|
||||
@ -115,7 +117,11 @@ export default function RelationMap({ note, ntxId }: TypeWidgetProps) {
|
||||
|
||||
return (
|
||||
<div className="note-detail-relation-map note-detail-printable">
|
||||
<div className="relation-map-wrapper" onClick={clickCallback}>
|
||||
<div
|
||||
className="relation-map-wrapper"
|
||||
onClick={clickCallback}
|
||||
{...dragProps}
|
||||
>
|
||||
<JsPlumb
|
||||
apiRef={pbApiRef}
|
||||
containerRef={containerRef}
|
||||
@ -305,6 +311,46 @@ function useNoteCreation({ ntxId, note, containerRef, mapApiRef }: {
|
||||
return onClickHandler;
|
||||
}
|
||||
|
||||
function useNoteDragging({ containerRef, mapApiRef }: {
|
||||
containerRef: RefObject<HTMLDivElement>;
|
||||
mapApiRef: RefObject<RelationMapApi>;
|
||||
}): Pick<HTMLProps<HTMLDivElement>, "onDrop" | "onDragOver"> {
|
||||
const dragProps = useMemo(() => ({
|
||||
onDrop(ev: DragEvent) {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
|
||||
const dragData = ev.dataTransfer?.getData("text");
|
||||
if (!dragData) return;
|
||||
const notes = JSON.parse(dragData);
|
||||
|
||||
let { x, y } = getMousePosition(ev, container, getZoom(container));
|
||||
const entries: (MapDataNoteEntry & { title: string })[] = [];
|
||||
|
||||
for (const note of notes) {
|
||||
entries.push({
|
||||
...note,
|
||||
x, y
|
||||
});
|
||||
|
||||
if (x > 1000) {
|
||||
y += 100;
|
||||
x = 0;
|
||||
} else {
|
||||
x += 200;
|
||||
}
|
||||
}
|
||||
|
||||
mapApiRef.current?.addMultipleNotes(entries);
|
||||
},
|
||||
onDragOver(ev) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
}), [ containerRef, mapApiRef ]);
|
||||
|
||||
return dragProps;
|
||||
}
|
||||
|
||||
function useRelationCreation({ mapApiRef, jsPlumbApiRef }: { mapApiRef: RefObject<RelationMapApi>, jsPlumbApiRef: RefObject<jsPlumbInstance> }) {
|
||||
const connectionCallback = useCallback(async (info: OnConnectionBindInfo, originalEvent: Event) => {
|
||||
const connection = info.connection;
|
||||
|
||||
@ -4,6 +4,7 @@ import { t } from "../../../services/i18n";
|
||||
import server from "../../../services/server";
|
||||
import utils from "../../../services/utils";
|
||||
import { RelationMapRelation } from "@triliumnext/commons";
|
||||
import toast from "../../../services/toast";
|
||||
|
||||
export interface MapDataNoteEntry {
|
||||
noteId: string;
|
||||
@ -103,6 +104,23 @@ export default class RelationMapApi {
|
||||
this.onDataChange(false);
|
||||
}
|
||||
|
||||
addMultipleNotes(entries: (MapDataNoteEntry & { title: string })[]) {
|
||||
if (!entries.length) return;
|
||||
|
||||
for (const entry of entries) {
|
||||
const exists = this.data.notes.some((n) => n.noteId === entry.noteId);
|
||||
|
||||
if (exists) {
|
||||
toast.showError(t("relation_map.note_already_in_diagram", { title: entry.title }));
|
||||
continue;
|
||||
}
|
||||
|
||||
this.data.notes.push(entry);
|
||||
}
|
||||
|
||||
this.onDataChange(true);
|
||||
}
|
||||
|
||||
async connect(name: string, sourceNoteId: string, targetNoteId: string) {
|
||||
name = utils.filterAttributeName(name);
|
||||
const relationExists = this.relations?.some((rel) => rel.targetNoteId === targetNoteId && rel.sourceNoteId === sourceNoteId && rel.name === name);
|
||||
|
||||
@ -70,7 +70,6 @@ export default class RelationMapTypeWidget extends TypeWidget {
|
||||
this.clipboard = null;
|
||||
|
||||
this.$widget.on("drop", (ev) => this.dropNoteOntoRelationMapHandler(ev));
|
||||
this.$widget.on("dragover", (ev) => ev.preventDefault());
|
||||
|
||||
this.initialized = new Promise(async (res) => {
|
||||
// Weird typecast is needed probably due to bad typings in the module itself.
|
||||
@ -122,38 +121,4 @@ export default class RelationMapTypeWidget extends TypeWidget {
|
||||
this.spacedUpdate.scheduleUpdate();
|
||||
}
|
||||
|
||||
async dropNoteOntoRelationMapHandler(ev: JQuery.DropEvent) {
|
||||
ev.preventDefault();
|
||||
|
||||
const dragData = ev.originalEvent?.dataTransfer?.getData("text");
|
||||
if (!dragData) {
|
||||
return;
|
||||
}
|
||||
const notes = JSON.parse(dragData);
|
||||
|
||||
let { x, y } = this.getMousePosition(ev);
|
||||
|
||||
for (const note of notes) {
|
||||
const exists = this.mapData?.notes.some((n) => n.noteId === note.noteId);
|
||||
|
||||
if (exists) {
|
||||
toastService.showError(t("relation_map.note_already_in_diagram", { title: note.title }));
|
||||
continue;
|
||||
}
|
||||
|
||||
this.mapData?.notes.push({ noteId: note.noteId, x, y });
|
||||
|
||||
if (x > 1000) {
|
||||
y += 100;
|
||||
x = 0;
|
||||
} else {
|
||||
x += 200;
|
||||
}
|
||||
}
|
||||
|
||||
this.saveData();
|
||||
|
||||
this.loadNotesAndRelations();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user