mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-29 19:12:27 +08:00
Merge branch 'develop' of https://github.com/TriliumNext/Notes into develop
This commit is contained in:
commit
c84737b90e
18
package-lock.json
generated
18
package-lock.json
generated
@ -69,6 +69,7 @@
|
|||||||
"katex": "0.16.21",
|
"katex": "0.16.21",
|
||||||
"knockout": "3.5.1",
|
"knockout": "3.5.1",
|
||||||
"leaflet": "1.9.4",
|
"leaflet": "1.9.4",
|
||||||
|
"leaflet-gpx": "2.1.2",
|
||||||
"mark.js": "8.11.1",
|
"mark.js": "8.11.1",
|
||||||
"marked": "15.0.6",
|
"marked": "15.0.6",
|
||||||
"mermaid": "11.4.1",
|
"mermaid": "11.4.1",
|
||||||
@ -132,6 +133,7 @@
|
|||||||
"@types/jasmine": "5.1.5",
|
"@types/jasmine": "5.1.5",
|
||||||
"@types/jquery": "3.5.32",
|
"@types/jquery": "3.5.32",
|
||||||
"@types/jsdom": "21.1.7",
|
"@types/jsdom": "21.1.7",
|
||||||
|
"@types/leaflet-gpx": "1.3.7",
|
||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "2.1.4",
|
||||||
"@types/multer": "1.4.12",
|
"@types/multer": "1.4.12",
|
||||||
"@types/node": "22.12.0",
|
"@types/node": "22.12.0",
|
||||||
@ -3839,6 +3841,16 @@
|
|||||||
"@types/geojson": "*"
|
"@types/geojson": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/leaflet-gpx": {
|
||||||
|
"version": "1.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/leaflet-gpx/-/leaflet-gpx-1.3.7.tgz",
|
||||||
|
"integrity": "sha512-IDshIOLZ7dUUjRiCE3DuJcAGavgUCw0xQ93dc/3YvsA6jrFc+nx8eXr0tqZIf2SaWMgqiDj/n7N24WWNh/898g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/leaflet": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/linkify-it": {
|
"node_modules/@types/linkify-it": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||||
@ -11431,6 +11443,12 @@
|
|||||||
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
|
"integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
|
||||||
"license": "BSD-2-Clause"
|
"license": "BSD-2-Clause"
|
||||||
},
|
},
|
||||||
|
"node_modules/leaflet-gpx": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/leaflet-gpx/-/leaflet-gpx-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-lKoEPlAWel9KXn9keg6Dmyt7gmj5IYyD8CKuxivN+77GpZr2bpKliwFvZJxLUHmNu4fICmCySyxhm5qjZuvvQg==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
"node_modules/limiter": {
|
"node_modules/limiter": {
|
||||||
"version": "1.1.5",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz",
|
||||||
|
@ -114,6 +114,7 @@
|
|||||||
"katex": "0.16.21",
|
"katex": "0.16.21",
|
||||||
"knockout": "3.5.1",
|
"knockout": "3.5.1",
|
||||||
"leaflet": "1.9.4",
|
"leaflet": "1.9.4",
|
||||||
|
"leaflet-gpx": "2.1.2",
|
||||||
"mark.js": "8.11.1",
|
"mark.js": "8.11.1",
|
||||||
"marked": "15.0.6",
|
"marked": "15.0.6",
|
||||||
"mermaid": "11.4.1",
|
"mermaid": "11.4.1",
|
||||||
@ -174,6 +175,7 @@
|
|||||||
"@types/jasmine": "5.1.5",
|
"@types/jasmine": "5.1.5",
|
||||||
"@types/jquery": "3.5.32",
|
"@types/jquery": "3.5.32",
|
||||||
"@types/jsdom": "21.1.7",
|
"@types/jsdom": "21.1.7",
|
||||||
|
"@types/leaflet-gpx": "1.3.7",
|
||||||
"@types/mime-types": "2.1.4",
|
"@types/mime-types": "2.1.4",
|
||||||
"@types/multer": "1.4.12",
|
"@types/multer": "1.4.12",
|
||||||
"@types/node": "22.12.0",
|
"@types/node": "22.12.0",
|
||||||
|
@ -104,6 +104,7 @@ export default class GeoMapTypeWidget extends TypeWidget {
|
|||||||
private _state: State;
|
private _state: State;
|
||||||
private L!: Leaflet;
|
private L!: Leaflet;
|
||||||
private currentMarkerData: MarkerData;
|
private currentMarkerData: MarkerData;
|
||||||
|
private gpxLoaded?: boolean;
|
||||||
|
|
||||||
static getType() {
|
static getType() {
|
||||||
return "geoMap";
|
return "geoMap";
|
||||||
@ -159,9 +160,7 @@ export default class GeoMapTypeWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async #reloadMarkers() {
|
async #reloadMarkers() {
|
||||||
const map = this.geoMapWidget.map;
|
if (!this.note) {
|
||||||
|
|
||||||
if (!this.note || !map) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,48 +172,80 @@ export default class GeoMapTypeWidget extends TypeWidget {
|
|||||||
// Add the new markers.
|
// Add the new markers.
|
||||||
this.currentMarkerData = {};
|
this.currentMarkerData = {};
|
||||||
const childNotes = await this.note.getChildNotes();
|
const childNotes = await this.note.getChildNotes();
|
||||||
const L = this.L;
|
|
||||||
for (const childNote of childNotes) {
|
for (const childNote of childNotes) {
|
||||||
const latLng = childNote.getAttributeValue("label", LOCATION_ATTRIBUTE);
|
if (childNote.mime === "application/gpx+xml") {
|
||||||
if (!latLng) {
|
this.#processNoteWithGpxTrack(childNote);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [ lat, lng ] = latLng.split(",", 2).map((el) => parseFloat(el));
|
const latLng = childNote.getAttributeValue("label", LOCATION_ATTRIBUTE);
|
||||||
const icon = L.divIcon({
|
if (latLng) {
|
||||||
html: `\
|
this.#processNoteWithMarker(childNote, latLng);
|
||||||
<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), {
|
async #processNoteWithGpxTrack(note: FNote) {
|
||||||
icon,
|
if (!this.L || !this.geoMapWidget.map) {
|
||||||
draggable: true,
|
return;
|
||||||
autoPan: true,
|
}
|
||||||
autoPanSpeed: 5,
|
|
||||||
})
|
|
||||||
.addTo(map)
|
|
||||||
.on("moveend", e => {
|
|
||||||
this.moveMarker(childNote.noteId, (e.target as Marker).getLatLng());
|
|
||||||
});
|
|
||||||
|
|
||||||
marker.on("contextmenu", (e) => {
|
if (!this.gpxLoaded) {
|
||||||
openContextMenu(childNote.noteId, e.originalEvent);
|
await import("leaflet-gpx");
|
||||||
|
this.gpxLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This is not very efficient as it's probably a string response that is parsed and then converted back to string and parsed again.
|
||||||
|
const xmlResponse = await server.get<XMLDocument>(`notes/${note.noteId}/open`);
|
||||||
|
const stringResponse = new XMLSerializer().serializeToString(xmlResponse);
|
||||||
|
|
||||||
|
const track = new this.L.GPX(stringResponse, {
|
||||||
|
|
||||||
|
});
|
||||||
|
track.addTo(this.geoMapWidget.map);
|
||||||
|
}
|
||||||
|
|
||||||
|
#processNoteWithMarker(note: FNote, latLng: string) {
|
||||||
|
const map = this.geoMapWidget.map;
|
||||||
|
if (!map) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ lat, lng ] = latLng.split(",", 2).map((el) => parseFloat(el));
|
||||||
|
const L = this.L;
|
||||||
|
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 ${note.getIcon()}"></span>
|
||||||
|
<span class="title-label">${note.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(note.noteId, (e.target as Marker).getLatLng());
|
||||||
});
|
});
|
||||||
|
|
||||||
const el = marker.getElement();
|
marker.on("contextmenu", (e) => {
|
||||||
if (el) {
|
openContextMenu(note.noteId, e.originalEvent);
|
||||||
const $el = $(el);
|
});
|
||||||
$el.attr("data-href", `#${childNote.noteId}`);
|
|
||||||
note_tooltip.setupElementTooltip($($el));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.currentMarkerData[childNote.noteId] = marker;
|
const el = marker.getElement();
|
||||||
|
if (el) {
|
||||||
|
const $el = $(el);
|
||||||
|
$el.attr("data-href", `#${note.noteId}`);
|
||||||
|
note_tooltip.setupElementTooltip($($el));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.currentMarkerData[note.noteId] = marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
#changeState(newState: State) {
|
#changeState(newState: State) {
|
||||||
@ -299,6 +330,14 @@ export default class GeoMapTypeWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
||||||
|
// If any of the children branches are altered.
|
||||||
|
if (loadResults.getBranchRows().find((branch) => branch.parentNoteId === this.noteId)) {
|
||||||
|
this.#reloadMarkers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If any of note has its location attribute changed.
|
||||||
|
// TODO: Should probably filter by parent here as well.
|
||||||
const attributeRows = loadResults.getAttributeRows();
|
const attributeRows = loadResults.getAttributeRows();
|
||||||
if (attributeRows.find((at) => at.name === LOCATION_ATTRIBUTE)) {
|
if (attributeRows.find((at) => at.name === LOCATION_ATTRIBUTE)) {
|
||||||
this.#reloadMarkers();
|
this.#reloadMarkers();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user