mirror of
https://github.com/zadam/trilium.git
synced 2025-11-11 17:08:58 +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 { TypeWidgetProps } from "../type_widget";
|
||||||
import { jsPlumbInstance, OnConnectionBindInfo } from "jsplumb";
|
import { jsPlumbInstance, OnConnectionBindInfo } from "jsplumb";
|
||||||
import { useEditorSpacedUpdate, useTriliumEvent, useTriliumEvents } from "../../react/hooks";
|
import { useEditorSpacedUpdate, useTriliumEvent, useTriliumEvents } from "../../react/hooks";
|
||||||
@ -19,6 +19,7 @@ import { NoteBox } from "./NoteBox";
|
|||||||
import utils from "../../../services/utils";
|
import utils from "../../../services/utils";
|
||||||
import attribute_autocomplete from "../../../services/attribute_autocomplete";
|
import attribute_autocomplete from "../../../services/attribute_autocomplete";
|
||||||
import { buildRelationContextMenuHandler } from "./context_menu";
|
import { buildRelationContextMenuHandler } from "./context_menu";
|
||||||
|
import { HTMLProps } from "preact/compat";
|
||||||
|
|
||||||
interface Clipboard {
|
interface Clipboard {
|
||||||
noteId: string;
|
noteId: string;
|
||||||
@ -90,6 +91,7 @@ export default function RelationMap({ note, ntxId }: TypeWidgetProps) {
|
|||||||
ntxId,
|
ntxId,
|
||||||
mapApiRef
|
mapApiRef
|
||||||
});
|
});
|
||||||
|
const dragProps = useNoteDragging({ containerRef, mapApiRef });
|
||||||
|
|
||||||
const connectionCallback = useRelationCreation({ mapApiRef, jsPlumbApiRef: pbApiRef });
|
const connectionCallback = useRelationCreation({ mapApiRef, jsPlumbApiRef: pbApiRef });
|
||||||
|
|
||||||
@ -115,7 +117,11 @@ export default function RelationMap({ note, ntxId }: TypeWidgetProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="note-detail-relation-map note-detail-printable">
|
<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
|
<JsPlumb
|
||||||
apiRef={pbApiRef}
|
apiRef={pbApiRef}
|
||||||
containerRef={containerRef}
|
containerRef={containerRef}
|
||||||
@ -305,6 +311,46 @@ function useNoteCreation({ ntxId, note, containerRef, mapApiRef }: {
|
|||||||
return onClickHandler;
|
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> }) {
|
function useRelationCreation({ mapApiRef, jsPlumbApiRef }: { mapApiRef: RefObject<RelationMapApi>, jsPlumbApiRef: RefObject<jsPlumbInstance> }) {
|
||||||
const connectionCallback = useCallback(async (info: OnConnectionBindInfo, originalEvent: Event) => {
|
const connectionCallback = useCallback(async (info: OnConnectionBindInfo, originalEvent: Event) => {
|
||||||
const connection = info.connection;
|
const connection = info.connection;
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { t } from "../../../services/i18n";
|
|||||||
import server from "../../../services/server";
|
import server from "../../../services/server";
|
||||||
import utils from "../../../services/utils";
|
import utils from "../../../services/utils";
|
||||||
import { RelationMapRelation } from "@triliumnext/commons";
|
import { RelationMapRelation } from "@triliumnext/commons";
|
||||||
|
import toast from "../../../services/toast";
|
||||||
|
|
||||||
export interface MapDataNoteEntry {
|
export interface MapDataNoteEntry {
|
||||||
noteId: string;
|
noteId: string;
|
||||||
@ -103,6 +104,23 @@ export default class RelationMapApi {
|
|||||||
this.onDataChange(false);
|
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) {
|
async connect(name: string, sourceNoteId: string, targetNoteId: string) {
|
||||||
name = utils.filterAttributeName(name);
|
name = utils.filterAttributeName(name);
|
||||||
const relationExists = this.relations?.some((rel) => rel.targetNoteId === targetNoteId && rel.sourceNoteId === sourceNoteId && rel.name === 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.clipboard = null;
|
||||||
|
|
||||||
this.$widget.on("drop", (ev) => this.dropNoteOntoRelationMapHandler(ev));
|
this.$widget.on("drop", (ev) => this.dropNoteOntoRelationMapHandler(ev));
|
||||||
this.$widget.on("dragover", (ev) => ev.preventDefault());
|
|
||||||
|
|
||||||
this.initialized = new Promise(async (res) => {
|
this.initialized = new Promise(async (res) => {
|
||||||
// Weird typecast is needed probably due to bad typings in the module itself.
|
// 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();
|
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