mirror of https://github.com/TriliumNext/Notes
commit
16b5eef650
@ -1,36 +1,44 @@
|
|||||||
import { t } from "../services/i18n.js";
|
import { t } from "../services/i18n.js";
|
||||||
import contextMenu from "./context_menu.js";
|
import contextMenu, { type ContextMenuEvent, type MenuItem } from "./context_menu.js";
|
||||||
import appContext from "../components/app_context.js";
|
import appContext, { type CommandNames } from "../components/app_context.js";
|
||||||
import type { ViewScope } from "../services/link.js";
|
import type { ViewScope } from "../services/link.js";
|
||||||
|
|
||||||
function openContextMenu(notePath: string, e: PointerEvent | MouseEvent | JQuery.ContextMenuEvent, viewScope: ViewScope = {}, hoistedNoteId: string | null = null) {
|
function openContextMenu(notePath: string, e: ContextMenuEvent, viewScope: ViewScope = {}, hoistedNoteId: string | null = null) {
|
||||||
contextMenu.show({
|
contextMenu.show({
|
||||||
x: e.pageX,
|
x: e.pageX,
|
||||||
y: e.pageY,
|
y: e.pageY,
|
||||||
items: [
|
items: getItems(),
|
||||||
{ title: t("link_context_menu.open_note_in_new_tab"), command: "openNoteInNewTab", uiIcon: "bx bx-link-external" },
|
selectMenuItemHandler: ({ command }) => handleLinkContextMenuItem(command, notePath, viewScope, hoistedNoteId)
|
||||||
{ title: t("link_context_menu.open_note_in_new_split"), command: "openNoteInNewSplit", uiIcon: "bx bx-dock-right" },
|
});
|
||||||
{ title: t("link_context_menu.open_note_in_new_window"), command: "openNoteInNewWindow", uiIcon: "bx bx-window-open" }
|
}
|
||||||
],
|
|
||||||
selectMenuItemHandler: ({ command }) => {
|
function getItems(): MenuItem<CommandNames>[] {
|
||||||
if (!hoistedNoteId) {
|
return [
|
||||||
hoistedNoteId = appContext.tabManager.getActiveContext().hoistedNoteId;
|
{ title: t("link_context_menu.open_note_in_new_tab"), command: "openNoteInNewTab", uiIcon: "bx bx-link-external" },
|
||||||
}
|
{ title: t("link_context_menu.open_note_in_new_split"), command: "openNoteInNewSplit", uiIcon: "bx bx-dock-right" },
|
||||||
|
{ title: t("link_context_menu.open_note_in_new_window"), command: "openNoteInNewWindow", uiIcon: "bx bx-window-open" }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
if (command === "openNoteInNewTab") {
|
function handleLinkContextMenuItem(command: string | undefined, notePath: string, viewScope = {}, hoistedNoteId: string | null = null) {
|
||||||
appContext.tabManager.openContextWithNote(notePath, { hoistedNoteId, viewScope });
|
if (!hoistedNoteId) {
|
||||||
} else if (command === "openNoteInNewSplit") {
|
hoistedNoteId = appContext.tabManager.getActiveContext().hoistedNoteId;
|
||||||
const subContexts = appContext.tabManager.getActiveContext().getSubContexts();
|
}
|
||||||
const { ntxId } = subContexts[subContexts.length - 1];
|
|
||||||
|
|
||||||
appContext.triggerCommand("openNewNoteSplit", { ntxId, notePath, hoistedNoteId, viewScope });
|
if (command === "openNoteInNewTab") {
|
||||||
} else if (command === "openNoteInNewWindow") {
|
appContext.tabManager.openContextWithNote(notePath, { hoistedNoteId, viewScope });
|
||||||
appContext.triggerCommand("openInWindow", { notePath, hoistedNoteId, viewScope });
|
} else if (command === "openNoteInNewSplit") {
|
||||||
}
|
const subContexts = appContext.tabManager.getActiveContext().getSubContexts();
|
||||||
}
|
const { ntxId } = subContexts[subContexts.length - 1];
|
||||||
});
|
|
||||||
|
appContext.triggerCommand("openNewNoteSplit", { ntxId, notePath, hoistedNoteId, viewScope });
|
||||||
|
} else if (command === "openNoteInNewWindow") {
|
||||||
|
appContext.triggerCommand("openInWindow", { notePath, hoistedNoteId, viewScope });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
getItems,
|
||||||
|
handleLinkContextMenuItem,
|
||||||
openContextMenu
|
openContextMenu
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,42 @@
|
|||||||
|
import { t } from "../../services/i18n.js";
|
||||||
|
import NoteContextAwareWidget from "../note_context_aware_widget.js"
|
||||||
|
|
||||||
|
const TPL = `\
|
||||||
|
<div class="geo-map-buttons">
|
||||||
|
<style>
|
||||||
|
.geo-map-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-pane {
|
||||||
|
z-index: 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-map-buttons {
|
||||||
|
contain: none;
|
||||||
|
background: var(--main-background-color);
|
||||||
|
box-shadow: 0px 10px 20px rgba(0, 0, 0, var(--dropdown-shadow-opacity));
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<button type="button"
|
||||||
|
class="geo-map-create-child-note floating-button btn bx bx-folder-plus"
|
||||||
|
title="${t("geo-map.create-child-note-title")}" />
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
export default class GeoMapButtons extends NoteContextAwareWidget {
|
||||||
|
|
||||||
|
isEnabled() {
|
||||||
|
return super.isEnabled() && this.note?.type === "geoMap";
|
||||||
|
}
|
||||||
|
|
||||||
|
doRender() {
|
||||||
|
super.doRender();
|
||||||
|
|
||||||
|
this.$widget = $(TPL);
|
||||||
|
this.$widget.find(".geo-map-create-child-note").on("click", () => this.triggerEvent("geoMapCreateChildNote", { ntxId: this.ntxId }));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
import type { Map } from "leaflet";
|
||||||
|
import library_loader from "../services/library_loader.js";
|
||||||
|
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
||||||
|
|
||||||
|
const TPL = `\
|
||||||
|
<div class="geo-map-widget">
|
||||||
|
<style>
|
||||||
|
.note-detail-geo-map,
|
||||||
|
.geo-map-widget,
|
||||||
|
.geo-map-container {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="geo-map-container"></div>
|
||||||
|
</div>`
|
||||||
|
|
||||||
|
export type Leaflet = typeof import("leaflet");
|
||||||
|
export type InitCallback = ((L: Leaflet) => void);
|
||||||
|
|
||||||
|
export default class GeoMapWidget extends NoteContextAwareWidget {
|
||||||
|
|
||||||
|
map?: Map;
|
||||||
|
$container!: JQuery<HTMLElement>;
|
||||||
|
private initCallback?: InitCallback;
|
||||||
|
|
||||||
|
constructor(widgetMode: "type", initCallback?: InitCallback) {
|
||||||
|
super();
|
||||||
|
this.initCallback = initCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
doRender() {
|
||||||
|
this.$widget = $(TPL);
|
||||||
|
|
||||||
|
this.$container = this.$widget.find(".geo-map-container");
|
||||||
|
|
||||||
|
library_loader.requireLibrary(library_loader.LEAFLET)
|
||||||
|
.then(async () => {
|
||||||
|
const L = (await import("leaflet")).default;
|
||||||
|
|
||||||
|
const map = L.map(this.$container[0], {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
this.map = map;
|
||||||
|
if (this.initCallback) {
|
||||||
|
this.initCallback(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,323 @@
|
|||||||
|
import { Marker, type LatLng, type LeafletMouseEvent } from "leaflet";
|
||||||
|
import type FNote from "../../entities/fnote.js";
|
||||||
|
import GeoMapWidget, { type InitCallback, type Leaflet } from "../geo_map.js";
|
||||||
|
import TypeWidget from "./type_widget.js"
|
||||||
|
import server from "../../services/server.js";
|
||||||
|
import toastService from "../../services/toast.js";
|
||||||
|
import dialogService from "../../services/dialog.js";
|
||||||
|
import type { EventData } from "../../components/app_context.js";
|
||||||
|
import { t } from "../../services/i18n.js";
|
||||||
|
import attributes from "../../services/attributes.js";
|
||||||
|
import asset_path from "../../../../services/asset_path.js";
|
||||||
|
import openContextMenu from "./geo_map_context_menu.js";
|
||||||
|
import link from "../../services/link.js";
|
||||||
|
import note_tooltip from "../../services/note_tooltip.js";
|
||||||
|
|
||||||
|
const TPL = `\
|
||||||
|
<div class="note-detail-geo-map note-detail-printable">
|
||||||
|
<style>
|
||||||
|
.leaflet-pane {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-map-container.placing-note {
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-map-container .marker-pin {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-map-container .leaflet-div-icon {
|
||||||
|
position: relative;
|
||||||
|
background: transparent;
|
||||||
|
border: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-map-container .leaflet-div-icon .icon-shadow {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-map-container .leaflet-div-icon .bx {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
left: 2px;
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
padding: 2px;
|
||||||
|
border-radius: 50%;
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.geo-map-container .leaflet-div-icon .title-label {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
height: 1rem;
|
||||||
|
color: black;
|
||||||
|
width: 100px;
|
||||||
|
text-align: center;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;
|
||||||
|
white-space: no-wrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
const LOCATION_ATTRIBUTE = "geolocation";
|
||||||
|
const CHILD_NOTE_ICON = "bx bx-pin";
|
||||||
|
const DEFAULT_COORDINATES: [ number, number ] = [ 3.878638227135724, 446.6630455551659 ];
|
||||||
|
const DEFAULT_ZOOM = 2;
|
||||||
|
|
||||||
|
interface MapData {
|
||||||
|
view?: {
|
||||||
|
center?: LatLng | [ number, number ];
|
||||||
|
zoom?: number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Deduplicate
|
||||||
|
interface CreateChildResponse {
|
||||||
|
note: {
|
||||||
|
noteId: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MarkerData = Record<string, Marker>;
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
Normal,
|
||||||
|
NewNote
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class GeoMapTypeWidget extends TypeWidget {
|
||||||
|
|
||||||
|
private geoMapWidget: GeoMapWidget;
|
||||||
|
private _state: State;
|
||||||
|
private L!: Leaflet;
|
||||||
|
private currentMarkerData: MarkerData;
|
||||||
|
|
||||||
|
static getType() {
|
||||||
|
return "geoMap";
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.geoMapWidget = new GeoMapWidget("type", (L: Leaflet) => this.#onMapInitialized(L));
|
||||||
|
this.currentMarkerData = {};
|
||||||
|
this._state = State.Normal;
|
||||||
|
|
||||||
|
this.child(this.geoMapWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
doRender() {
|
||||||
|
this.$widget = $(TPL);
|
||||||
|
this.$widget.append(this.geoMapWidget.render());
|
||||||
|
|
||||||
|
super.doRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
async #onMapInitialized(L: Leaflet) {
|
||||||
|
this.L = L;
|
||||||
|
const map = this.geoMapWidget.map;
|
||||||
|
if (!map) {
|
||||||
|
throw new Error(t("geo-map.unable-to-load-map"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.note) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = await this.note.getBlob();
|
||||||
|
|
||||||
|
let parsedContent: MapData = {};
|
||||||
|
if (blob && blob.content) {
|
||||||
|
parsedContent = JSON.parse(blob.content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore viewport position & zoom
|
||||||
|
const center = parsedContent.view?.center ?? DEFAULT_COORDINATES;
|
||||||
|
const zoom = parsedContent.view?.zoom ?? DEFAULT_ZOOM;
|
||||||
|
map.setView(center, zoom);
|
||||||
|
|
||||||
|
// Restore markers.
|
||||||
|
await this.#reloadMarkers();
|
||||||
|
|
||||||
|
const updateFn = () => this.spacedUpdate.scheduleUpdate();
|
||||||
|
map.on("moveend", updateFn);
|
||||||
|
map.on("zoomend", updateFn);
|
||||||
|
map.on("click", (e) => this.#onMapClicked(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
async #reloadMarkers() {
|
||||||
|
const map = this.geoMapWidget.map;
|
||||||
|
|
||||||
|
if (!this.note || !map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all existing markers
|
||||||
|
for (const marker of Object.values(this.currentMarkerData)) {
|
||||||
|
marker.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the new markers.
|
||||||
|
this.currentMarkerData = {};
|
||||||
|
const childNotes = await this.note.getChildNotes();
|
||||||
|
const L = this.L;
|
||||||
|
for (const childNote of childNotes) {
|
||||||
|
const latLng = childNote.getAttributeValue("label", LOCATION_ATTRIBUTE);
|
||||||
|
if (!latLng) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ lat, lng ] = latLng.split(",", 2).map((el) => parseFloat(el));
|
||||||
|
const icon = L.divIcon({
|
||||||
|
html: `\
|
||||||
|
<img class="icon" src="${asset_path}/node_modules/leaflet/dist/images/marker-icon.png" />
|
||||||
|
<img class="icon-shadow" src="${asset_path}/node_modules/leaflet/dist/images/marker-shadow.png" />
|
||||||
|
<span class="bx ${childNote.getIcon()}"></span>
|
||||||
|
<span class="title-label">${childNote.title}</span>`,
|
||||||
|
iconSize: [ 25, 41 ],
|
||||||
|
iconAnchor: [ 12, 41 ]
|
||||||
|
})
|
||||||
|
|
||||||
|
const marker = L.marker(L.latLng(lat, lng), {
|
||||||
|
icon,
|
||||||
|
draggable: true,
|
||||||
|
autoPan: true,
|
||||||
|
autoPanSpeed: 5,
|
||||||
|
})
|
||||||
|
.addTo(map)
|
||||||
|
.on("moveend", e => {
|
||||||
|
this.moveMarker(childNote.noteId, (e.target as Marker).getLatLng());
|
||||||
|
});
|
||||||
|
|
||||||
|
marker.on("contextmenu", (e) => {
|
||||||
|
openContextMenu(childNote.noteId, e.originalEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
const el = marker.getElement();
|
||||||
|
if (el) {
|
||||||
|
const $el = $(el);
|
||||||
|
$el.attr("data-href", `#${childNote.noteId}`);
|
||||||
|
note_tooltip.setupElementTooltip($($el));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentMarkerData[childNote.noteId] = marker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#changeState(newState: State) {
|
||||||
|
this._state = newState;
|
||||||
|
this.geoMapWidget.$container.toggleClass("placing-note", newState === State.NewNote);
|
||||||
|
}
|
||||||
|
|
||||||
|
async #onMapClicked(e: LeafletMouseEvent) {
|
||||||
|
if (this._state !== State.NewNote) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toastService.closePersistent("geo-new-note");
|
||||||
|
const title = await dialogService.prompt({ message: t("relation_map.enter_title_of_new_note"), defaultValue: t("relation_map.default_new_note_title") });
|
||||||
|
|
||||||
|
if (title?.trim()) {
|
||||||
|
const { note } = await server.post<CreateChildResponse>(`notes/${this.noteId}/children?target=into`, {
|
||||||
|
title,
|
||||||
|
content: "",
|
||||||
|
type: "text"
|
||||||
|
});
|
||||||
|
attributes.setLabel(note.noteId, "iconClass", CHILD_NOTE_ICON);
|
||||||
|
this.moveMarker(note.noteId, e.latlng);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#changeState(State.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
async moveMarker(noteId: string, latLng: LatLng | null) {
|
||||||
|
const value = (latLng ? [latLng.lat, latLng.lng].join(",") : "");
|
||||||
|
await attributes.setLabel(noteId, LOCATION_ATTRIBUTE, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
getData(): any {
|
||||||
|
const map = this.geoMapWidget.map;
|
||||||
|
if (!map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: MapData = {
|
||||||
|
view: {
|
||||||
|
center: map.getBounds().getCenter(),
|
||||||
|
zoom: map.getZoom()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
content: JSON.stringify(data)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async geoMapCreateChildNoteEvent({ ntxId }: EventData<"geoMapCreateChildNote">) {
|
||||||
|
if (!this.isNoteContext(ntxId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toastService.showPersistent({
|
||||||
|
icon: "plus",
|
||||||
|
id: "geo-new-note",
|
||||||
|
title: "New note",
|
||||||
|
message: t("geo-map.create-child-note-instruction")
|
||||||
|
});
|
||||||
|
|
||||||
|
this.#changeState(State.NewNote);
|
||||||
|
|
||||||
|
const globalKeyListener: (this: Window, ev: KeyboardEvent) => any = (e) => {
|
||||||
|
if (e.key !== "Escape") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#changeState(State.Normal);
|
||||||
|
|
||||||
|
window.removeEventListener("keydown", globalKeyListener);
|
||||||
|
toastService.closePersistent("geo-new-note");
|
||||||
|
};
|
||||||
|
window.addEventListener("keydown", globalKeyListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
async doRefresh(note: FNote) {
|
||||||
|
await this.geoMapWidget.refresh();
|
||||||
|
await this.#reloadMarkers();
|
||||||
|
}
|
||||||
|
|
||||||
|
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
||||||
|
const attributeRows = loadResults.getAttributeRows();
|
||||||
|
if (attributeRows.find((at) => at.name === LOCATION_ATTRIBUTE)) {
|
||||||
|
this.#reloadMarkers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openGeoLocationEvent({ noteId, event }: EventData<"openGeoLocation">) {
|
||||||
|
const marker = this.currentMarkerData[noteId];
|
||||||
|
if (!marker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const latLng = this.currentMarkerData[noteId].getLatLng();
|
||||||
|
const url = `geo:${latLng.lat},${latLng.lng}`;
|
||||||
|
link.goToLinkExt(event, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteFromMapEvent({ noteId }: EventData<"deleteFromMap">) {
|
||||||
|
this.moveMarker(noteId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
import appContext from "../../components/app_context.js";
|
||||||
|
import type { ContextMenuEvent } from "../../menus/context_menu.js";
|
||||||
|
import contextMenu from "../../menus/context_menu.js";
|
||||||
|
import linkContextMenu from "../../menus/link_context_menu.js";
|
||||||
|
import { t } from "../../services/i18n.js";
|
||||||
|
|
||||||
|
export default function openContextMenu(noteId: string, e: ContextMenuEvent) {
|
||||||
|
contextMenu.show({
|
||||||
|
x: e.pageX,
|
||||||
|
y: e.pageY,
|
||||||
|
items: [
|
||||||
|
...linkContextMenu.getItems(),
|
||||||
|
{ title: t("geo-map-context.open-location"), command: "openGeoLocation", uiIcon: "bx bx-map-alt" },
|
||||||
|
{ title: "----" },
|
||||||
|
{ title: t("geo-map-context.remove-from-map"), command: "deleteFromMap", uiIcon: "bx bx-trash" }
|
||||||
|
],
|
||||||
|
selectMenuItemHandler: ({ command }, e) => {
|
||||||
|
if (command === "deleteFromMap") {
|
||||||
|
appContext.triggerCommand(command, { noteId });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command === "openGeoLocation") {
|
||||||
|
appContext.triggerCommand(command, { noteId, event: e });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass the events to the link context menu
|
||||||
|
linkContextMenu.handleLinkContextMenuItem(command, noteId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue