diff --git a/apps/client/src/widgets/collections/geomap/api.ts b/apps/client/src/widgets/collections/geomap/api.ts new file mode 100644 index 000000000..7c3b1dbbd --- /dev/null +++ b/apps/client/src/widgets/collections/geomap/api.ts @@ -0,0 +1,8 @@ +import { LatLng } from "leaflet"; +import { LOCATION_ATTRIBUTE } from "."; +import attributes from "../../../services/attributes"; + +export async function moveMarker(noteId: string, latLng: LatLng | null) { + const value = latLng ? [latLng.lat, latLng.lng].join(",") : ""; + await attributes.setLabel(noteId, LOCATION_ATTRIBUTE, value); +} diff --git a/apps/client/src/widgets/collections/geomap/index.tsx b/apps/client/src/widgets/collections/geomap/index.tsx index 63142b365..dae07753d 100644 --- a/apps/client/src/widgets/collections/geomap/index.tsx +++ b/apps/client/src/widgets/collections/geomap/index.tsx @@ -11,6 +11,7 @@ import FNote from "../../../entities/fnote"; import markerIcon from "leaflet/dist/images/marker-icon.png"; import markerIconShadow from "leaflet/dist/images/marker-shadow.png"; import appContext from "../../../components/app_context"; +import { moveMarker } from "./api"; const DEFAULT_COORDINATES: [number, number] = [3.878638227135724, 446.6630455551659]; const DEFAULT_ZOOM = 2; @@ -25,6 +26,7 @@ interface MapData { export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewModeProps) { const [ layerName ] = useNoteLabel(note, "map:style"); + const [ isReadOnly ] = useNoteLabel(note, "readOnly"); const [ notes, setNotes ] = useState([]); const spacedUpdate = useSpacedUpdate(() => { if (viewConfig) { @@ -46,13 +48,13 @@ export default function GeoView({ note, noteIds, viewConfig, saveConfig }: ViewM spacedUpdate.scheduleUpdate(); }} > - {notes.map(note => )} + {notes.map(note => )} ); } -function NoteMarker({ note }: { note: FNote }) { +function NoteMarker({ note, editable }: { note: FNote, editable: boolean }) { const [ location ] = useNoteLabel(note, LOCATION_ATTRIBUTE); // React to changes @@ -65,17 +67,25 @@ function NoteMarker({ note }: { note: FNote }) { const latLng = location?.split(",", 2).map((el) => parseFloat(el)) as [ number, number ] | undefined; const icon = useMemo(() => buildIcon(iconClass, colorClass ?? undefined, title, note.noteId), [ iconClass, colorClass, title, note.noteId]); + // Middle click to open in new tab + const onMouseDown = useCallback((e: MouseEvent) => { + if (e.button === 1) { + const hoistedNoteId = appContext.tabManager.getActiveContext()?.hoistedNoteId; + appContext.tabManager.openInNewTab(note.noteId, hoistedNoteId); + return true; + } + }, [ note.noteId ]); + + const onDragged = useCallback((newCoordinates: LatLng) => { + moveMarker(note.noteId, newCoordinates); + }, [ note.noteId ]); + return latLng && { - // Middle click to open in new tab - if (e.button === 1) { - const hoistedNoteId = appContext.tabManager.getActiveContext()?.hoistedNoteId; - appContext.tabManager.openInNewTab(note.noteId, hoistedNoteId); - return true; - } - }, [ note.noteId ])} + mouseDown={onMouseDown} + draggable={editable} + dragged={onDragged} /> } diff --git a/apps/client/src/widgets/collections/geomap/marker.tsx b/apps/client/src/widgets/collections/geomap/marker.tsx index 900ef8852..53ec84ab8 100644 --- a/apps/client/src/widgets/collections/geomap/marker.tsx +++ b/apps/client/src/widgets/collections/geomap/marker.tsx @@ -1,27 +1,41 @@ import { useContext, useEffect } from "preact/hooks"; import { ParentMap } from "./map"; -import { DivIcon, Icon, marker } from "leaflet"; +import { DivIcon, Icon, LatLng, Marker as LeafletMarker, marker, MarkerOptions } from "leaflet"; export interface MarkerProps { coordinates: [ number, number ]; icon?: Icon | DivIcon; mouseDown?: (e: MouseEvent) => void; + dragged: ((newCoordinates: LatLng) => void) + draggable?: boolean; } -export default function Marker({ coordinates, icon, mouseDown }: MarkerProps) { +export default function Marker({ coordinates, icon, draggable, dragged, mouseDown }: MarkerProps) { const parentMap = useContext(ParentMap); useEffect(() => { if (!parentMap) return; - const newMarker = marker(coordinates, { - icon - }); + const options: MarkerOptions = { icon }; + if (draggable) { + options.draggable = true; + options.autoPan = true; + options.autoPanSpeed = 5; + } + + const newMarker = marker(coordinates, options); if (mouseDown) { newMarker.on("mousedown", e => mouseDown(e.originalEvent)); } + if (dragged) { + newMarker.on("moveend", e => { + const coordinates = (e.target as LeafletMarker).getLatLng(); + dragged(coordinates); + }); + } + newMarker.addTo(parentMap); return () => newMarker.removeFrom(parentMap); 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 c9dd7368c..85753f38d 100644 --- a/apps/client/src/widgets/view_widgets/geo_view/editing.ts +++ b/apps/client/src/widgets/view_widgets/geo_view/editing.ts @@ -18,11 +18,6 @@ interface CreateChildResponse { }; } -export async function moveMarker(noteId: string, latLng: LatLng | null) { - const value = latLng ? [latLng.lat, latLng.lng].join(",") : ""; - await attributes.setLabel(noteId, LOCATION_ATTRIBUTE, value); -} - export async function createNewNote(noteId: string, e: LeafletMouseEvent) { const title = await dialog.prompt({ message: t("relation_map.enter_title_of_new_note"), defaultValue: t("relation_map.default_new_note_title") }); diff --git a/apps/client/src/widgets/view_widgets/geo_view/markers.ts b/apps/client/src/widgets/view_widgets/geo_view/markers.ts index 1a89d3c2f..8cfad222d 100644 --- a/apps/client/src/widgets/view_widgets/geo_view/markers.ts +++ b/apps/client/src/widgets/view_widgets/geo_view/markers.ts @@ -9,19 +9,6 @@ import L from "leaflet"; let gpxLoaded = false; export default function processNoteWithMarker(map: Map, note: FNote, location: string, isEditable: boolean) { - const newMarker = marker(latLng(lat, lng), { - icon, - draggable: isEditable, - autoPan: true, - autoPanSpeed: 5 - }).addTo(map); - - if (isEditable) { - newMarker.on("moveend", (e) => { - moveMarker(note.noteId, (e.target as Marker).getLatLng()); - }); - } - newMarker.on("contextmenu", (e) => { openContextMenu(note.noteId, e, isEditable); }); diff --git a/apps/client/src/widgets/view_widgets/view_mode.ts b/apps/client/src/widgets/view_widgets/view_mode.ts index 303eac985..1bce10499 100644 --- a/apps/client/src/widgets/view_widgets/view_mode.ts +++ b/apps/client/src/widgets/view_widgets/view_mode.ts @@ -53,8 +53,4 @@ export default abstract class ViewMode extends Component { } } - get isReadOnly() { - return this.parentNote.hasLabel("readOnly"); - } - }