feat(views/geomap): allow disabling editing

This commit is contained in:
Elian Doran 2025-07-07 19:04:47 +03:00
parent 5c6bb99d78
commit c1a5808f37
No known key found for this signature in database
6 changed files with 70 additions and 31 deletions

View File

@ -23,7 +23,9 @@ const TPL = /*html*/`\
export default class GeoMapButtons extends NoteContextAwareWidget { export default class GeoMapButtons extends NoteContextAwareWidget {
isEnabled() { isEnabled() {
return super.isEnabled() && this.note?.getLabelValue("viewType") === "geoMap"; return super.isEnabled()
&& this.note?.getLabelValue("viewType") === "geoMap"
&& !this.note.hasLabel("readOnly");
} }
doRender() { doRender() {

View File

@ -39,10 +39,20 @@ export default class ToggleReadOnlyButton extends OnClickButtonWidget {
} }
isEnabled() { isEnabled() {
return super.isEnabled() if (!super.isEnabled()) {
&& this.note?.type === "mermaid" return false;
&& this.note?.isContentAvailable() }
&& this.noteContext?.viewScope?.viewMode === "default";
if (!this?.note?.isContentAvailable()) {
return false;
}
if (this.noteContext?.viewScope?.viewMode !== "default") {
return false;
}
return this.note.type === "mermaid" ||
(this.note.getLabelValue("viewType") === "geoMap");
} }
} }

View File

@ -1,22 +1,31 @@
import type { LatLng, LeafletMouseEvent } from "leaflet"; import type { LatLng, LeafletMouseEvent } from "leaflet";
import appContext from "../../../components/app_context.js"; import appContext, { type CommandMappings } from "../../../components/app_context.js";
import contextMenu from "../../../menus/context_menu.js"; import contextMenu, { type MenuItem } from "../../../menus/context_menu.js";
import linkContextMenu from "../../../menus/link_context_menu.js"; import linkContextMenu from "../../../menus/link_context_menu.js";
import { t } from "../../../services/i18n.js"; import { t } from "../../../services/i18n.js";
import { createNewNote } from "./editing.js"; import { createNewNote } from "./editing.js";
import { copyTextWithToast } from "../../../services/clipboard_ext.js"; import { copyTextWithToast } from "../../../services/clipboard_ext.js";
import link from "../../../services/link.js"; import link from "../../../services/link.js";
export default function openContextMenu(noteId: string, e: LeafletMouseEvent) { export default function openContextMenu(noteId: string, e: LeafletMouseEvent, isEditable: boolean) {
let items: MenuItem<keyof CommandMappings>[] = [
...buildGeoLocationItem(e),
{ title: "----" },
...linkContextMenu.getItems(),
];
if (isEditable) {
items = [
...items,
{ title: "----" },
{ title: t("geo-map-context.remove-from-map"), command: "deleteFromMap", uiIcon: "bx bx-trash" }
];
}
contextMenu.show({ contextMenu.show({
x: e.originalEvent.pageX, x: e.originalEvent.pageX,
y: e.originalEvent.pageY, y: e.originalEvent.pageY,
items: [ items,
...buildGeoLocationItem(e),
...linkContextMenu.getItems(),
{ title: "----" },
{ title: t("geo-map-context.remove-from-map"), command: "deleteFromMap", uiIcon: "bx bx-trash" }
],
selectMenuItemHandler: ({ command }, e) => { selectMenuItemHandler: ({ command }, e) => {
if (command === "deleteFromMap") { if (command === "deleteFromMap") {
appContext.triggerCommand(command, { noteId }); appContext.triggerCommand(command, { noteId });
@ -29,14 +38,23 @@ export default function openContextMenu(noteId: string, e: LeafletMouseEvent) {
}); });
} }
export function openMapContextMenu(noteId: string, e: LeafletMouseEvent) { export function openMapContextMenu(noteId: string, e: LeafletMouseEvent, isEditable: boolean) {
let items: MenuItem<keyof CommandMappings>[] = [
...buildGeoLocationItem(e)
];
if (isEditable) {
items = [
...items,
{ title: "----" },
{ title: t("geo-map-context.add-note"), command: "addNoteToMap", uiIcon: "bx bx-plus" }
]
}
contextMenu.show({ contextMenu.show({
x: e.originalEvent.pageX, x: e.originalEvent.pageX,
y: e.originalEvent.pageY, y: e.originalEvent.pageY,
items: [ items,
...buildGeoLocationItem(e),
{ title: t("geo-map-context.add-note"), command: "addNoteToMap", uiIcon: "bx bx-plus" }
],
selectMenuItemHandler: ({ command }) => { selectMenuItemHandler: ({ command }) => {
switch (command) { switch (command) {
case "addNoteToMap": case "addNoteToMap":
@ -64,9 +82,6 @@ function buildGeoLocationItem(e: LeafletMouseEvent) {
title: t("geo-map-context.open-location"), title: t("geo-map-context.open-location"),
uiIcon: "bx bx-map-alt", uiIcon: "bx bx-map-alt",
handler: () => link.goToLinkExt(null, `geo:${e.latlng.lat},${e.latlng.lng}`) handler: () => link.goToLinkExt(null, `geo:${e.latlng.lat},${e.latlng.lng}`)
},
{
title: "----"
} }
]; ];
} }

View File

@ -152,12 +152,16 @@ export default class GeoView extends ViewMode<MapData> {
this.#restoreViewportAndZoom(); this.#restoreViewportAndZoom();
const isEditable = !this.isReadOnly;
const updateFn = () => this.spacedUpdate.scheduleUpdate(); const updateFn = () => this.spacedUpdate.scheduleUpdate();
map.on("moveend", updateFn); map.on("moveend", updateFn);
map.on("zoomend", updateFn); map.on("zoomend", updateFn);
map.on("click", (e) => this.#onMapClicked(e)) map.on("click", (e) => this.#onMapClicked(e))
map.on("contextmenu", (e) => openMapContextMenu(this.parentNote.noteId, e)); map.on("contextmenu", (e) => openMapContextMenu(this.parentNote.noteId, e, isEditable));
setupDragging(this.$container, map, this.parentNote.noteId);
if (isEditable) {
setupDragging(this.$container, map, this.parentNote.noteId);
}
this.#reloadMarkers(); this.#reloadMarkers();
@ -219,6 +223,7 @@ export default class GeoView extends ViewMode<MapData> {
// Add the new markers. // Add the new markers.
this.currentMarkerData = {}; this.currentMarkerData = {};
const notes = await this.parentNote.getChildNotes(); const notes = await this.parentNote.getChildNotes();
const draggable = !this.isReadOnly;
for (const childNote of notes) { for (const childNote of notes) {
if (childNote.mime === "application/gpx+xml") { if (childNote.mime === "application/gpx+xml") {
const track = await processNoteWithGpxTrack(this.map, childNote); const track = await processNoteWithGpxTrack(this.map, childNote);
@ -228,7 +233,7 @@ export default class GeoView extends ViewMode<MapData> {
const latLng = childNote.getAttributeValue("label", LOCATION_ATTRIBUTE); const latLng = childNote.getAttributeValue("label", LOCATION_ATTRIBUTE);
if (latLng) { if (latLng) {
const marker = processNoteWithMarker(this.map, childNote, latLng); const marker = processNoteWithMarker(this.map, childNote, latLng, draggable);
this.currentMarkerData[childNote.noteId] = marker; this.currentMarkerData[childNote.noteId] = marker;
} }
} }

View File

@ -9,20 +9,23 @@ import { moveMarker } from "./editing.js";
let gpxLoaded = false; let gpxLoaded = false;
export default function processNoteWithMarker(map: Map, note: FNote, location: string) { export default function processNoteWithMarker(map: Map, note: FNote, location: string, isEditable: boolean) {
const [lat, lng] = location.split(",", 2).map((el) => parseFloat(el)); const [lat, lng] = location.split(",", 2).map((el) => parseFloat(el));
const icon = buildIcon(note.getIcon(), note.getColorClass(), note.title); const icon = buildIcon(note.getIcon(), note.getColorClass(), note.title);
const newMarker = marker(latLng(lat, lng), { const newMarker = marker(latLng(lat, lng), {
icon, icon,
draggable: true, draggable: isEditable,
autoPan: true, autoPan: true,
autoPanSpeed: 5 autoPanSpeed: 5
}) }).addTo(map);
.addTo(map)
.on("moveend", (e) => { if (isEditable) {
newMarker.on("moveend", (e) => {
moveMarker(note.noteId, (e.target as Marker).getLatLng()); moveMarker(note.noteId, (e.target as Marker).getLatLng());
}); });
}
newMarker.on("mousedown", ({ originalEvent }) => { newMarker.on("mousedown", ({ originalEvent }) => {
// Middle click to open in new tab // Middle click to open in new tab
if (originalEvent.button === 1) { if (originalEvent.button === 1) {
@ -33,7 +36,7 @@ export default function processNoteWithMarker(map: Map, note: FNote, location: s
} }
}); });
newMarker.on("contextmenu", (e) => { newMarker.on("contextmenu", (e) => {
openContextMenu(note.noteId, e); openContextMenu(note.noteId, e, isEditable);
}); });
const el = newMarker.getElement(); const el = newMarker.getElement();

View File

@ -44,6 +44,10 @@ export default abstract class ViewMode<T extends object> extends Component {
return false; return false;
} }
get isReadOnly() {
return this.parentNote.hasLabel("readOnly");
}
get viewStorage() { get viewStorage() {
if (this._viewStorage) { if (this._viewStorage) {
return this._viewStorage; return this._viewStorage;