diff --git a/apps/client/src/widgets/collections/geomap/index.tsx b/apps/client/src/widgets/collections/geomap/index.tsx index 4651abddb..335a55825 100644 --- a/apps/client/src/widgets/collections/geomap/index.tsx +++ b/apps/client/src/widgets/collections/geomap/index.tsx @@ -1,10 +1,10 @@ import Map from "./map"; import "./index.css"; import { ViewModeProps } from "../interface"; -import { useNoteBlob, useNoteLabel, useNoteLabelBoolean, useNoteProperty, useSpacedUpdate, useTriliumEvent } from "../../react/hooks"; +import { useNoteBlob, useNoteLabel, useNoteLabelBoolean, useNoteProperty, useNoteTreeDrag, useSpacedUpdate, useTriliumEvent } from "../../react/hooks"; import { DEFAULT_MAP_LAYER_NAME } from "./map_layer"; import { divIcon, GPXOptions, LatLng, LeafletMouseEvent } from "leaflet"; -import { useCallback, useEffect, useMemo, useState } from "preact/hooks"; +import { useCallback, useEffect, useMemo, useRef, useState } from "preact/hooks"; import Marker, { GpxTrack } from "./marker"; import froca from "../../../services/froca"; import FNote from "../../../entities/fnote"; @@ -16,6 +16,7 @@ import openContextMenu, { openMapContextMenu } from "./context_menu"; import toast from "../../../services/toast"; import { t } from "../../../services/i18n"; import server from "../../../services/server"; +import branches from "../../../services/branches"; const DEFAULT_COORDINATES: [number, number] = [3.878638227135724, 446.6630455551659]; const DEFAULT_ZOOM = 2; @@ -85,9 +86,34 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM openMapContextMenu(note.noteId, e, !isReadOnly); }, [ note.noteId, isReadOnly ]); + // Dragging + const containerRef = useRef(null); + const apiRef = useRef(null); + useNoteTreeDrag(containerRef, async (treeData, e) => { + const api = apiRef.current; + if (!note || !api) return; + + const { noteId } = treeData[0]; + + const offset = containerRef.current?.getBoundingClientRect(); + const x = e.clientX - (offset?.left ?? 0); + const y = e.clientY - (offset?.top ?? 0); + const latlng = api.containerPointToLatLng([ x, y ]); + + const targetNote = await froca.getNote(noteId, true); + const parents = targetNote?.getParentNoteIds(); + if (parents?.includes(note.noteId)) { + await moveMarker(noteId, latlng); + } else { + await branches.cloneNoteToParentNote(noteId, noteId); + await moveMarker(noteId, latlng); + } + }); + return (
(null); interface MapProps { + apiRef?: RefObject; + containerRef?: RefObject; coordinates: LatLng | [number, number]; zoom: number; layerName: string; @@ -17,9 +20,9 @@ interface MapProps { scale: boolean; } -export default function Map({ coordinates, zoom, layerName, viewportChanged, children, onClick, onContextMenu, scale }: MapProps) { - const mapRef = useRef(null); - const containerRef = useRef(null); +export default function Map({ coordinates, zoom, layerName, viewportChanged, children, onClick, onContextMenu, scale, apiRef: _apiRef, containerRef: _containerRef }: MapProps) { + const mapRef = useSyncedRef(_apiRef); + const containerRef = useSyncedRef(_containerRef); useEffect(() => { if (!containerRef.current) return; diff --git a/apps/client/src/widgets/react/hooks.tsx b/apps/client/src/widgets/react/hooks.tsx index 6b1d7af68..cc4eb64fb 100644 --- a/apps/client/src/widgets/react/hooks.tsx +++ b/apps/client/src/widgets/react/hooks.tsx @@ -1,4 +1,4 @@ -import { useCallback, useContext, useDebugValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks"; +import { MutableRef, useCallback, useContext, useDebugValue, useEffect, useLayoutEffect, useMemo, useRef, useState } from "preact/hooks"; import { EventData, EventNames } from "../../components/app_context"; import { ParentComponent } from "./react_utils"; import SpacedUpdate from "../../services/spaced_update"; @@ -13,9 +13,10 @@ import FBlob from "../../entities/fblob"; import NoteContextAwareWidget from "../note_context_aware_widget"; import { RefObject, VNode } from "preact"; import { Tooltip } from "bootstrap"; -import { CSSProperties } from "preact/compat"; +import { CSSProperties, DragEventHandler } from "preact/compat"; import keyboard_actions from "../../services/keyboard_actions"; import Mark from "mark.js"; +import { DragData } from "../note_tree"; export function useTriliumEvent(eventName: T, handler: (data: EventData) => void) { const parentComponent = useContext(ParentComponent); @@ -576,3 +577,37 @@ export function useImperativeSearchHighlighlighting(highlightedTokens: string[] }); }; } + +export function useNoteTreeDrag(containerRef: MutableRef, callback: (data: DragData[], e: DragEvent) => void) { + useEffect(() => { + const container = containerRef.current; + if (!container) return; + + function onDragOver(e: DragEvent) { + // Allow drag. + e.preventDefault(); + } + + function onDrop(e: DragEvent) { + const data = e.dataTransfer?.getData('text'); + if (!data) { + return; + } + + const parsedData = JSON.parse(data) as DragData[]; + if (!parsedData.length) { + return; + } + + callback(parsedData, e); + } + + container.addEventListener("dragover", onDragOver); + container.addEventListener("drop", onDrop); + + return () => { + container.removeEventListener("dragover", onDragOver); + container.removeEventListener("drop", onDrop); + }; + }, [ containerRef, callback ]); +} diff --git a/apps/client/src/widgets/view_widgets/geo_view/editing.ts b/apps/client/src/widgets/view_widgets/geo_view/editing.ts index 71041b50a..16d3f435d 100644 --- a/apps/client/src/widgets/view_widgets/geo_view/editing.ts +++ b/apps/client/src/widgets/view_widgets/geo_view/editing.ts @@ -10,41 +10,9 @@ import froca from "../../../services/froca.js"; import branches from "../../../services/branches.js"; export function setupDragging($container: JQuery, map: Map, mapNoteId: string) { - $container.on("dragover", (e) => { - // Allow drag. - e.preventDefault(); - }); $container.on("drop", async (e) => { - if (!e.originalEvent) { - return; - } - - const data = e.originalEvent.dataTransfer?.getData('text'); - if (!data) { - return; - } - try { - const parsedData = JSON.parse(data) as DragData[]; - if (!parsedData.length) { - return; - } - const { noteId } = parsedData[0]; - - const offset = $container.offset(); - const x = e.originalEvent.clientX - (offset?.left ?? 0); - const y = e.originalEvent.clientY - (offset?.top ?? 0); - const latlng = map.containerPointToLatLng([ x, y ]); - - const note = await froca.getNote(noteId, true); - const parents = note?.getParentNoteIds(); - if (parents?.includes(mapNoteId)) { - await moveMarker(noteId, latlng); - } else { - await branches.cloneNoteToParentNote(noteId, mapNoteId); - await moveMarker(noteId, latlng); - } } catch (e) { console.warn(e); }