Multiple improvements
This commit is contained in:
+73
-24
@@ -202,7 +202,17 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
return ns.I18n.t("editor.view-route");
|
||||
}
|
||||
|
||||
let poiMediaGeneration = 0;
|
||||
let previewPoi = null;
|
||||
|
||||
function releasePoiPreview() {
|
||||
poiMediaGeneration += 1;
|
||||
ns.LocalRoutes?.releasePoiMedia?.(previewPoi);
|
||||
previewPoi = null;
|
||||
}
|
||||
|
||||
function showListView() {
|
||||
releasePoiPreview();
|
||||
ns.RouteRecorder?.endEditing();
|
||||
setDialogTitle('Streckenverwaltung');
|
||||
setHidden(byId(ids.routeListView), false);
|
||||
@@ -211,6 +221,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function showRouteView() {
|
||||
releasePoiPreview();
|
||||
setDialogTitle(routeDialogTitle());
|
||||
setHidden(byId(ids.routeListView), true);
|
||||
setHidden(byId(ids.routeDetailView), false);
|
||||
@@ -411,8 +422,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
list.textContent = '';
|
||||
const serverRoutes = state.routes.filter(route => routeSource(route) === 'server');
|
||||
const localRoutes = state.routes.filter(route => routeSource(route) === 'local');
|
||||
renderRouteGroup(list, ns.I18n.t("editor.public-routes"), serverRoutes, ns.I18n.t("app.no-public-route"));
|
||||
renderRouteGroup(list, ns.I18n.t("editor.drafts"), localRoutes, ns.I18n.t("editor.no-draft"));
|
||||
renderRouteGroup(list, ns.I18n.t("editor.public-routes"), serverRoutes, ns.I18n.t("app.no-public-route"));
|
||||
}
|
||||
|
||||
function renderPoiList() {
|
||||
@@ -438,19 +449,30 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}));
|
||||
}
|
||||
|
||||
let routeListGeneration = 0;
|
||||
|
||||
async function loadRoutes() {
|
||||
setStatus(ns.I18n.t("editor.loading-routes"));
|
||||
const payload = await readJson('/routes?activatedOnly=true');
|
||||
const serverRoutes = routeArray(payload).map(route => ({ ...route, _source: 'server' }));
|
||||
let localRoutes = [];
|
||||
try {
|
||||
localRoutes = localRouteSummaries();
|
||||
} catch (error) {
|
||||
setStatus(error.message, true);
|
||||
}
|
||||
state.routes = [...serverRoutes, ...localRoutes];
|
||||
const requestGeneration = ++routeListGeneration;
|
||||
state.routes = [...localRouteSummaries(), ...state.routes.filter(route => routeSource(route) === 'server')];
|
||||
renderRouteList();
|
||||
if (!byId(ids.status)?.dataset.kind || byId(ids.status).dataset.kind !== 'error') setStatus('');
|
||||
setStatus('');
|
||||
// Local drafts are usable even while this request is waiting for a connection.
|
||||
void refreshPublicRoutes(requestGeneration);
|
||||
}
|
||||
|
||||
async function refreshPublicRoutes(requestGeneration) {
|
||||
const listIsVisible = () => byId(ids.dialog)?.open && !byId(ids.routeListView)?.hidden;
|
||||
try {
|
||||
const payload = await readJson('/routes?activatedOnly=true');
|
||||
if (requestGeneration !== routeListGeneration) return;
|
||||
const serverRoutes = routeArray(payload).map(route => ({ ...route, _source: 'server' }));
|
||||
state.routes = [...localRouteSummaries(), ...serverRoutes];
|
||||
renderRouteList();
|
||||
} catch {
|
||||
if (requestGeneration === routeListGeneration && listIsVisible()) {
|
||||
setStatus(ns.I18n.t('editor.public-unavailable'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function openEditor() {
|
||||
@@ -471,6 +493,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function closeEditor() {
|
||||
releasePoiPreview();
|
||||
ns.RouteRecorder?.endEditing();
|
||||
const dialog = byId(ids.dialog);
|
||||
if (dialog?.open && typeof dialog.close === 'function') dialog.close();
|
||||
@@ -499,6 +522,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
function fillRouteForm(route) {
|
||||
setHidden(byId('editor-path-positions'), state.currentSource !== 'local');
|
||||
setHidden(byId('editor-recording-options'), state.currentSource !== 'local');
|
||||
if (state.currentSource === 'local') ns.RouteRecorder?.renderPoints(route.gpx || ns.LocalRoutes.emptyGpx(route.name));
|
||||
byId(ids.routeId).value = routeId(route);
|
||||
byId(ids.routeName).value = routeName(route) === ns.I18n.t("editor.untitled-route") ? '' : routeName(route);
|
||||
@@ -764,14 +788,14 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
async function loadRoute(route) {
|
||||
const id = routeId(route);
|
||||
if (!id) return;
|
||||
if (ns.RouteRecorder?.routeId && (routeSource(route) !== 'local' || ns.RouteRecorder.routeId !== id)) {
|
||||
ns.RouteRecorder.endEditing();
|
||||
if (state.currentRoute && (routeSource(route) !== state.currentSource || routeId(state.currentRoute) !== id)) {
|
||||
ns.RouteRecorder?.endEditing();
|
||||
}
|
||||
setStatus(ns.I18n.t("editor.route.loading"));
|
||||
state.currentSource = routeSource(route);
|
||||
|
||||
if (state.currentSource === 'local') {
|
||||
const routePackage = await ns.LocalRoutes.getWithMedia(id, { requestPermission: true });
|
||||
const routePackage = ns.LocalRoutes.get(id);
|
||||
if (!routePackage) throw new Error(ns.I18n.t("editor.error.draft-missing"));
|
||||
state.currentRoute = {
|
||||
...routePackage.route,
|
||||
@@ -1048,6 +1072,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function newPoi() {
|
||||
releasePoiPreview();
|
||||
const position = currentPosition();
|
||||
const lat = position?.lat ?? null;
|
||||
const lon = position?.lon ?? null;
|
||||
@@ -1065,11 +1090,26 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
showPoiView();
|
||||
}
|
||||
|
||||
function editPoi(poi) {
|
||||
async function editPoi(poi) {
|
||||
if (!poi) return;
|
||||
releasePoiPreview();
|
||||
state.currentPoi = poi;
|
||||
fillPoiForm(poi);
|
||||
byId(ids.poiFormTitle).textContent = ns.I18n.t("editor.edit-station");
|
||||
showPoiView();
|
||||
if (state.currentSource !== 'local') return;
|
||||
const requestGeneration = poiMediaGeneration;
|
||||
const hydrated = await ns.LocalRoutes.getPoiWithMedia(routeId(state.currentRoute), poi.id, { requestPermission: true });
|
||||
if (requestGeneration !== poiMediaGeneration || state.currentPoi !== poi) {
|
||||
ns.LocalRoutes.releasePoiMedia(hydrated);
|
||||
return;
|
||||
}
|
||||
if (!hydrated) return;
|
||||
previewPoi = hydrated;
|
||||
state.currentPoi = hydrated;
|
||||
// Preserve any text edits and newly selected files while existing previews load.
|
||||
renderPoiMediaPreview();
|
||||
updatePoiMediaStatus();
|
||||
}
|
||||
|
||||
async function mediaFromLocalForm(existingPoi, poiIdentifier) {
|
||||
@@ -1122,13 +1162,16 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
route: state.currentRoute,
|
||||
pois: state.pois
|
||||
});
|
||||
const hydrated = await ns.LocalRoutes.getWithMedia(id) || saved;
|
||||
state.currentRoute = { ...hydrated.route, id: hydrated.id, gpx: hydrated.gpx, _source: 'local' };
|
||||
state.pois = hydrated.pois;
|
||||
const previousPoi = state.currentPoi;
|
||||
state.currentRoute = { ...saved.route, id: saved.id, gpx: saved.gpx, _source: 'local' };
|
||||
state.pois = saved.pois;
|
||||
state.currentPoi = currentPoiId
|
||||
? state.pois.find(poi => poiId(poi) === currentPoiId) || null
|
||||
: null;
|
||||
return hydrated;
|
||||
if (state.currentPoi && previousPoi) {
|
||||
state.currentPoi = { ...state.currentPoi, audio: previousPoi.audio, images: previousPoi.images };
|
||||
}
|
||||
return saved;
|
||||
}
|
||||
|
||||
async function saveLocalPoi(values) {
|
||||
@@ -1241,7 +1284,10 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
updateCurrentPoi(updated);
|
||||
await persistLocalCurrentRoute();
|
||||
if (removedMedia) await ns.LocalRoutes.removeMedia(removedMedia);
|
||||
if (removedMedia) {
|
||||
ns.LocalRoutes.releasePoiMedia({ audio: removedMedia });
|
||||
await ns.LocalRoutes.removeMedia(removedMedia);
|
||||
}
|
||||
state.selectedMediaKey = null;
|
||||
renderPoiMediaPreview();
|
||||
updatePoiMediaStatus();
|
||||
@@ -1416,7 +1462,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
async function poiListAction(event) {
|
||||
const action = event.target.closest('[data-editor-action]')?.dataset.editorAction;
|
||||
if (action === 'edit-poi') {
|
||||
editPoi(poiForItem(event.target));
|
||||
await editPoi(poiForItem(event.target));
|
||||
return;
|
||||
}
|
||||
if (action === 'delete-poi') {
|
||||
@@ -1442,12 +1488,15 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
function bind() {
|
||||
for (const eventName of ['cancel', 'close']) {
|
||||
byId(ids.dialog)?.addEventListener(eventName, () => ns.RouteRecorder?.endEditing());
|
||||
byId(ids.dialog)?.addEventListener(eventName, () => {
|
||||
releasePoiPreview();
|
||||
ns.RouteRecorder?.endEditing();
|
||||
});
|
||||
}
|
||||
activate(byId(ids.button), () => guarded(openEditor));
|
||||
activate(byId(ids.close), closeEditor);
|
||||
activate(byId(ids.newRoute), newRoute);
|
||||
activate(byId(ids.routeBack), () => guarded(loadRoutes).then(showListView));
|
||||
activate(byId(ids.routeBack), () => { showListView(); void guarded(loadRoutes); });
|
||||
activate(byId(ids.routeUpload), () => guarded(uploadLocalRoute));
|
||||
activate(byId(ids.rightsOpen), () => ns.LegalUi?.open('terms'));
|
||||
activate(byId(ids.addPoi), newPoi);
|
||||
|
||||
Reference in New Issue
Block a user