This commit is contained in:
+1
-1
@@ -712,7 +712,7 @@
|
||||
}
|
||||
|
||||
function refreshCurrentLocalRoute(id) {
|
||||
if (!state.route || state.route.source !== 'local' || String(state.route.id) !== String(id)) return;
|
||||
if (state.route?.source !== 'local' || String(state.route.id) !== String(id)) return;
|
||||
persistRouteProgress();
|
||||
try {
|
||||
state.route = ns.LocalRoutes.getAppRoute(id);
|
||||
|
||||
@@ -530,7 +530,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
id,
|
||||
gpx,
|
||||
route: {
|
||||
...(state.currentRoute || {}),
|
||||
...state.currentRoute,
|
||||
id,
|
||||
name: values.name,
|
||||
description: values.description
|
||||
@@ -622,14 +622,14 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
async function saveLocalPoi(values) {
|
||||
if (!Number.isFinite(values.lat) || !Number.isFinite(values.lon)) {
|
||||
throw new Error('Für einen GPX-POI sind gültige Breiten- und Längengrade erforderlich.');
|
||||
throw new TypeError('Für einen GPX-POI sind gültige Breiten- und Längengrade erforderlich.');
|
||||
}
|
||||
const currentId = Number(byId(ids.poiId).value);
|
||||
const identifier = Number.isSafeInteger(currentId) ? currentId : ns.LocalRoutes.createPoiId();
|
||||
const existing = state.pois.find(poi => Number(poi.id) === identifier) || state.currentPoi;
|
||||
const media = await mediaFromLocalForm(existing, identifier);
|
||||
const savedPoi = {
|
||||
...(existing || {}),
|
||||
...existing,
|
||||
...values,
|
||||
...media,
|
||||
id: identifier,
|
||||
|
||||
+46
-18
@@ -34,9 +34,32 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
storage().setItem(INDEX_KEY, JSON.stringify([...new Set(ids.map(String))]));
|
||||
}
|
||||
|
||||
function uuidFromRandomValues(cryptoApi) {
|
||||
const bytes = new Uint8Array(16);
|
||||
cryptoApi.getRandomValues(bytes);
|
||||
|
||||
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
||||
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
||||
|
||||
const hex = Array.from(bytes, byte => byte.toString(16).padStart(2, '0'));
|
||||
return [
|
||||
hex.slice(0, 4).join(''),
|
||||
hex.slice(4, 6).join(''),
|
||||
hex.slice(6, 8).join(''),
|
||||
hex.slice(8, 10).join(''),
|
||||
hex.slice(10, 16).join('')
|
||||
].join('-');
|
||||
}
|
||||
|
||||
function createRouteId() {
|
||||
if (globalThis.crypto?.randomUUID) return `local-${globalThis.crypto.randomUUID()}`;
|
||||
return `local-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
||||
const cryptoApi = globalThis.crypto;
|
||||
if (typeof cryptoApi?.randomUUID === 'function') {
|
||||
return `local-${cryptoApi.randomUUID()}`;
|
||||
}
|
||||
if (typeof cryptoApi?.getRandomValues === 'function') {
|
||||
return `local-${uuidFromRandomValues(cryptoApi)}`;
|
||||
}
|
||||
throw new Error('Keine sichere Zufallsquelle für eine lokale Strecken-ID verfügbar.');
|
||||
}
|
||||
|
||||
function createPoiId() {
|
||||
@@ -138,13 +161,14 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
const orderedPois = [...(pois || [])].sort((left, right) => Number(left.sequence) - Number(right.sequence));
|
||||
orderedPois.forEach((poi, index) => {
|
||||
const title = poi.title || `Station ${index + 1}`;
|
||||
if (!Number.isFinite(Number(poi.lat)) || !Number.isFinite(Number(poi.lon))) {
|
||||
throw new Error(`Für ${poi.title || `Station ${index + 1}`} fehlen gültige Koordinaten.`);
|
||||
throw new TypeError(`Für ${title} fehlen gültige Koordinaten.`);
|
||||
}
|
||||
const waypoint = createElement(document, 'wpt');
|
||||
waypoint.setAttribute('lat', String(Number(poi.lat)));
|
||||
waypoint.setAttribute('lon', String(Number(poi.lon)));
|
||||
waypoint.appendChild(createElement(document, 'name', poi.title || `Station ${index + 1}`));
|
||||
waypoint.appendChild(createElement(document, 'name', title));
|
||||
if (poi.description) waypoint.appendChild(createElement(document, 'desc', poi.description));
|
||||
const extensions = createElement(document, 'extensions');
|
||||
const poiId = document.createElementNS(POI_NAMESPACE, 'wegwichtel:poiId');
|
||||
@@ -154,7 +178,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const routeOrTrack = directChildrenByLocalName(root, 'rte')[0]
|
||||
|| directChildrenByLocalName(root, 'trk')[0]
|
||||
|| null;
|
||||
root.insertBefore(waypoint, routeOrTrack);
|
||||
if (routeOrTrack) routeOrTrack.before(waypoint);
|
||||
else root.appendChild(waypoint);
|
||||
});
|
||||
|
||||
return new XMLSerializer().serializeToString(document);
|
||||
@@ -375,25 +400,28 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
function readFileAsText(file) {
|
||||
if (!file) return Promise.resolve('');
|
||||
if (typeof file.text === 'function') return file.text();
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => resolve(String(reader.result || '')), { once: true });
|
||||
reader.addEventListener('error', () => reject(reader.error || new Error('Datei konnte nicht gelesen werden.')), { once: true });
|
||||
reader.readAsText(file);
|
||||
});
|
||||
if (typeof file.text !== 'function') {
|
||||
return Promise.reject(new TypeError('Die ausgewählte Datei unterstützt Blob.text() nicht.'));
|
||||
}
|
||||
return file.text();
|
||||
}
|
||||
|
||||
function fileToDataUrl(file) {
|
||||
if (!file) return Promise.resolve(null);
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => resolve({
|
||||
dataUrl: String(reader.result || ''),
|
||||
name: file.name || 'Datei',
|
||||
size: Number(file.size) || 0,
|
||||
type: file.type || 'application/octet-stream'
|
||||
}), { once: true });
|
||||
reader.addEventListener('load', () => {
|
||||
if (typeof reader.result !== 'string') {
|
||||
reject(new TypeError('Die Datei konnte nicht als Data-URL gelesen werden.'));
|
||||
return;
|
||||
}
|
||||
resolve({
|
||||
dataUrl: reader.result,
|
||||
name: file.name || 'Datei',
|
||||
size: Number(file.size) || 0,
|
||||
type: file.type || 'application/octet-stream'
|
||||
});
|
||||
}, { once: true });
|
||||
reader.addEventListener('error', () => reject(reader.error || new Error('Datei konnte nicht gelesen werden.')), { once: true });
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user