group editor implemented
This commit is contained in:
+209
-20
@@ -88,6 +88,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
const state = {
|
||||
currentPoi: null,
|
||||
groupDeletions: [],
|
||||
groupDeletePoint: false,
|
||||
currentRoute: null,
|
||||
currentSource: null,
|
||||
pendingAudioFile: null,
|
||||
@@ -212,6 +214,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function showListView() {
|
||||
void ns.GroupPoints?.release();
|
||||
releasePoiPreview();
|
||||
ns.RouteRecorder?.endEditing();
|
||||
setDialogTitle('Streckenverwaltung');
|
||||
@@ -221,6 +224,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function showRouteView() {
|
||||
void ns.GroupPoints?.release();
|
||||
releasePoiPreview();
|
||||
setDialogTitle(routeDialogTitle());
|
||||
setHidden(byId(ids.routeListView), true);
|
||||
@@ -276,7 +280,18 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
async function handleResponse(response) {
|
||||
if (response.ok) return parseJson(response);
|
||||
if ([401, 403].includes(response.status) && state.currentSource === 'group') {
|
||||
throw new Error(ns.I18n.t('groups.error.access'));
|
||||
}
|
||||
if (response.status === 423) throw new Error(ns.I18n.t('point-locks.lost'));
|
||||
if (response.status === 409 && response.headers?.get('X-Group-Route')) {
|
||||
throw new Error(ns.I18n.t('groups.error.conflict'));
|
||||
}
|
||||
if (response.ok) {
|
||||
ns.Groups?.observe?.(response);
|
||||
ns.GroupPoints?.observe?.(response);
|
||||
return parseJson(response);
|
||||
}
|
||||
const payload = await parseJson(response);
|
||||
const error = new Error(payload.message || ns.I18n.t("editor.error.action"));
|
||||
error.status = response.status;
|
||||
@@ -286,7 +301,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
async function readJson(path) {
|
||||
const response = await fetch(apiUrl(path), {
|
||||
credentials: 'same-origin',
|
||||
headers: { Accept: 'application/json' }
|
||||
headers: { ...ns.Groups?.headersFor?.(path), ...ns.GroupPoints?.headersFor?.(path), Accept: 'application/json' }
|
||||
});
|
||||
return handleResponse(response);
|
||||
}
|
||||
@@ -296,6 +311,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
body: JSON.stringify(body),
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
...ns.Groups?.headersFor?.(path), ...ns.GroupPoints?.headersFor?.(path),
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
@@ -308,7 +324,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const response = await fetch(apiUrl(path), {
|
||||
body: formData,
|
||||
credentials: 'same-origin',
|
||||
headers: { Accept: 'application/json' },
|
||||
headers: { ...ns.Groups?.headersFor?.(path), ...ns.GroupPoints?.headersFor?.(path), Accept: 'application/json' },
|
||||
method
|
||||
});
|
||||
return handleResponse(response);
|
||||
@@ -317,7 +333,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
async function sendDelete(path) {
|
||||
const response = await fetch(apiUrl(path), {
|
||||
credentials: 'same-origin',
|
||||
headers: { Accept: 'application/json' },
|
||||
headers: { ...ns.Groups?.headersFor?.(path), ...ns.GroupPoints?.headersFor?.(path), Accept: 'application/json' },
|
||||
method: 'DELETE'
|
||||
});
|
||||
return handleResponse(response);
|
||||
@@ -375,6 +391,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const actions = document.createElement('div');
|
||||
actions.className = classes.iconRow;
|
||||
actions.appendChild(iconButton(ns.I18n.t("editor.edit-route"), '✎', 'edit-route'));
|
||||
if (ns.Groups?.shareButton) actions.appendChild(ns.Groups.shareButton('share-route'));
|
||||
if (routeSource(route) === 'local') {
|
||||
actions.appendChild(iconButton(ns.I18n.t("editor.delete-route"), '×', 'delete-route', false, true));
|
||||
}
|
||||
@@ -453,6 +470,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
let routeListGeneration = 0;
|
||||
let shareInProgress = false;
|
||||
|
||||
async function loadRoutes() {
|
||||
const requestGeneration = ++routeListGeneration;
|
||||
@@ -518,6 +536,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
setDialogExpanded(true);
|
||||
showListView();
|
||||
await guarded(loadRoutes);
|
||||
void ns.Groups?.refresh?.();
|
||||
}
|
||||
|
||||
async function openNewLocalRoute() {
|
||||
@@ -526,6 +545,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function closeEditor() {
|
||||
if (pointSaveInProgress) return;
|
||||
void ns.GroupPoints?.release();
|
||||
releasePoiPreview();
|
||||
ns.RouteRecorder?.endEditing();
|
||||
const dialog = byId(ids.dialog);
|
||||
@@ -837,7 +858,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
} else {
|
||||
const payload = await readJson(`/routes/${encodeURIComponent(id)}`);
|
||||
const detail = payload.route || payload;
|
||||
state.currentRoute = { ...detail, _source: 'server' };
|
||||
state.currentRoute = { ...detail, _source: state.currentSource };
|
||||
state.pois = poiArray(detail);
|
||||
}
|
||||
|
||||
@@ -871,6 +892,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const file = byId(ids.routeGpx)?.files?.[0];
|
||||
data.append('name', values.name);
|
||||
data.append('description', values.description);
|
||||
data.append('creator_id', state.currentRoute.creator_id || ns.LocalRoutes.creatorId());
|
||||
if (file) data.append('gpx', file);
|
||||
return data;
|
||||
}
|
||||
@@ -911,21 +933,22 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const id = routeId(state.currentRoute);
|
||||
if (!id) throw new Error(ns.I18n.t("editor.error.create-locally"));
|
||||
const file = byId(ids.routeGpx)?.files?.[0];
|
||||
values = { ...values, creator_id: state.currentRoute.creator_id || ns.LocalRoutes.creatorId() };
|
||||
const path = `/routes/${encodeURIComponent(id)}`;
|
||||
const payload = file
|
||||
? await sendForm(path, 'PUT', formDataFromRoute(values))
|
||||
: await sendJson(path, 'PUT', values);
|
||||
const saved = payload.route || payload;
|
||||
state.currentRoute = { ...saved, _source: 'server' };
|
||||
state.currentRoute = { ...saved, _source: state.currentSource };
|
||||
await loadRoutes();
|
||||
await loadRoute({ id, _source: 'server' });
|
||||
await loadRoute({ id, _source: state.currentSource });
|
||||
setStatus(ns.I18n.t("editor.saved"));
|
||||
}
|
||||
|
||||
async function saveRoute() {
|
||||
const values = routeFromForm();
|
||||
if (!values.name) throw new Error(ns.I18n.t("editor.error.route-name"));
|
||||
if (state.currentSource === 'server') await saveServerRoute(values);
|
||||
if (state.currentSource !== 'local') await saveServerRoute(values);
|
||||
else await saveLocalRoute(values);
|
||||
}
|
||||
|
||||
@@ -1134,6 +1157,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
}
|
||||
|
||||
function newPoi() {
|
||||
void ns.GroupPoints?.release();
|
||||
releasePoiPreview();
|
||||
const position = currentPosition();
|
||||
const lat = position?.lat ?? null;
|
||||
@@ -1141,6 +1165,8 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
const accuracy = Number(position?.accuracy);
|
||||
state.currentPoi = null;
|
||||
state.groupDeletions = [];
|
||||
state.groupDeletePoint = false;
|
||||
const identifier = state.currentSource === 'local' ? nextLocalPoiId() : null;
|
||||
fillPoiForm({
|
||||
...(identifier == null ? {} : { id: identifier }),
|
||||
@@ -1155,11 +1181,30 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
async function editPoi(poi) {
|
||||
if (!poi) return;
|
||||
releasePoiPreview();
|
||||
let draft;
|
||||
if (state.currentSource === 'group' && ns.GroupPoints) {
|
||||
const opened = await ns.GroupPoints.begin(routeId(state.currentRoute), poi);
|
||||
if (!opened) return;
|
||||
poi = opened.poi;
|
||||
draft = opened.draft;
|
||||
}
|
||||
state.groupDeletions = draft?.media?.deletions || [];
|
||||
state.groupDeletePoint = Boolean(draft?.media?.deletePoint);
|
||||
state.currentPoi = poi;
|
||||
fillPoiForm(poi);
|
||||
fillPoiForm(draft ? { ...poi, ...draft.values } : poi);
|
||||
if (draft) {
|
||||
state.pendingAudioFile = draft.media?.audio || null;
|
||||
state.pendingImages = (draft.media?.images || []).map(file => ({ file, key: `pending-image-${ns.LocalRoutes.createPoiId()}`, previewUrl: objectUrlFor(file) }));
|
||||
const hiddenImages = state.groupDeletions.map(item => item.path);
|
||||
state.currentPoi = { ...poi, images: (poi.images || []).filter(image => !hiddenImages.includes(`pictures/${image.id}`)),
|
||||
...(hiddenImages.includes('audio') ? { audioUrl: null } : {}) };
|
||||
renderPoiMediaPreview();
|
||||
updatePoiMediaStatus();
|
||||
setStatus(ns.I18n.t(state.groupDeletePoint ? 'point-locks.delete-restored' : 'point-locks.restored'));
|
||||
}
|
||||
byId(ids.poiFormTitle).textContent = ns.I18n.t("editor.edit-station");
|
||||
showPoiView();
|
||||
if (state.currentSource !== 'local') return;
|
||||
if (state.currentSource !== 'local') return true;
|
||||
const requestGeneration = poiMediaGeneration;
|
||||
const hydrated = await ns.LocalRoutes.getPoiWithMedia(routeId(state.currentRoute), poi.id, { requestPermission: true });
|
||||
if (requestGeneration !== poiMediaGeneration || state.currentPoi !== poi) {
|
||||
@@ -1278,16 +1323,62 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
if (state.pendingAudioFile) {
|
||||
const method = existingAudioUrl(state.currentPoi) ? 'PUT' : 'POST';
|
||||
await uploadOne(`${basePath}/audio`, 'audio', state.pendingAudioFile, method);
|
||||
if (state.currentSource === 'group') { state.pendingAudioFile = null; await rememberGroupPoint(poiFromForm(), currentPoiId); }
|
||||
}
|
||||
for (const pending of state.pendingImages) {
|
||||
for (const pending of [...state.pendingImages]) {
|
||||
await uploadOne(`${basePath}/pictures`, 'picture', pending.file);
|
||||
if (state.currentSource === 'group') {
|
||||
state.pendingImages = state.pendingImages.filter(item => item !== pending);
|
||||
releasePendingPreview(pending);
|
||||
await rememberGroupPoint(poiFromForm(), currentPoiId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function rememberGroupPoint(values, identifier = byId(ids.poiId).value || 'new') {
|
||||
return ns.GroupPoints.remember(state.currentRoute, identifier, values, {
|
||||
audio: state.pendingAudioFile, images: state.pendingImages.map(item => item.file), deletions: state.groupDeletions, deletePoint: state.groupDeletePoint
|
||||
});
|
||||
}
|
||||
|
||||
async function prepareGroupPoint(values, currentPoiId) {
|
||||
const draft = await rememberGroupPoint(values);
|
||||
if (!currentPoiId) return true;
|
||||
try {
|
||||
const prepared = await ns.GroupPoints.prepare(draft);
|
||||
if (prepared) {
|
||||
state.groupDeletions = draft.media.deletions;
|
||||
state.currentPoi = prepared.poi;
|
||||
return true;
|
||||
}
|
||||
} catch { /* The complete intent was persisted before trying to acquire the point. */ }
|
||||
setStatus(ns.I18n.t('point-locks.saved-device'));
|
||||
return false;
|
||||
}
|
||||
|
||||
async function saveGroupPointActions(currentRouteId, currentPoiId, saved, values) {
|
||||
const savedPoiId = poiId(saved) || currentPoiId;
|
||||
if (!currentPoiId) {
|
||||
byId(ids.poiId).value = savedPoiId;
|
||||
state.currentPoi = saved;
|
||||
// Persist the acknowledged ID before any further network request.
|
||||
await rememberGroupPoint(values, savedPoiId);
|
||||
await ns.GroupPoints.remove(currentRouteId, 'new');
|
||||
await ns.GroupPoints.acceptNew(currentRouteId, saved);
|
||||
}
|
||||
for (const deletion of [...state.groupDeletions]) {
|
||||
await sendDelete(`/routes/${currentRouteId}/pois/${savedPoiId}/${deletion.path}`);
|
||||
state.groupDeletions = state.groupDeletions.filter(item => item !== deletion);
|
||||
await rememberGroupPoint(values, savedPoiId);
|
||||
}
|
||||
}
|
||||
|
||||
async function saveServerPoi(values) {
|
||||
if (state.currentSource === 'group' && state.groupDeletePoint) return deleteCurrentPoi();
|
||||
const currentRouteId = routeId(state.currentRoute);
|
||||
if (!currentRouteId) throw new Error(ns.I18n.t("editor.error.save-route-first"));
|
||||
const currentPoiId = byId(ids.poiId).value;
|
||||
if (state.currentSource === 'group' && ns.GroupPoints && !await prepareGroupPoint(values, currentPoiId)) return;
|
||||
const path = currentPoiId
|
||||
? `/routes/${encodeURIComponent(currentRouteId)}/pois/${encodeURIComponent(currentPoiId)}`
|
||||
: `/routes/${encodeURIComponent(currentRouteId)}/pois`;
|
||||
@@ -1295,16 +1386,34 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const payload = await sendJson(path, method, values);
|
||||
const saved = payload.poi || payload;
|
||||
const savedPoiId = poiId(saved) || currentPoiId;
|
||||
if (state.currentSource === 'group' && ns.GroupPoints) await saveGroupPointActions(currentRouteId, currentPoiId, saved, values);
|
||||
if (savedPoiId) await uploadPoiMedia(currentRouteId, savedPoiId);
|
||||
if (state.currentSource === 'group' && ns.GroupPoints) await ns.GroupPoints.remove(currentRouteId, savedPoiId);
|
||||
setStatus(ns.I18n.t("editor.station-saved"));
|
||||
await loadRoute({ id: currentRouteId, _source: 'server' });
|
||||
await loadRoute({ id: currentRouteId, _source: state.currentSource });
|
||||
}
|
||||
|
||||
let pointSaveInProgress = false;
|
||||
async function savePoi() {
|
||||
if (pointSaveInProgress) return;
|
||||
pointSaveInProgress = true;
|
||||
byId(ids.dialog).inert = true;
|
||||
try { await savePoiContents(); } finally { pointSaveInProgress = false; byId(ids.dialog).inert = false; }
|
||||
}
|
||||
|
||||
async function savePoiContents() {
|
||||
const values = poiFromForm();
|
||||
if (!values.title) throw new Error(ns.I18n.t("editor.error.station-name"));
|
||||
if (state.currentSource === 'local') await saveLocalPoi(values);
|
||||
else await saveServerPoi(values);
|
||||
else {
|
||||
try { await saveServerPoi(values); }
|
||||
catch (error) {
|
||||
if (state.currentSource !== 'group' || !ns.GroupPoints) throw error;
|
||||
// Retain all unacknowledged files and intents, even when the lock changed during upload.
|
||||
await rememberGroupPoint(values);
|
||||
setStatus(ns.I18n.t('point-locks.saved-device'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateCurrentPoi(updatedPoi) {
|
||||
@@ -1364,13 +1473,15 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const updated = { ...state.currentPoi };
|
||||
|
||||
if (kind === 'audio') {
|
||||
await sendDelete(`${basePath}/audio`);
|
||||
if (state.currentSource === 'group') state.groupDeletions.push({ path: 'audio' });
|
||||
else await sendDelete(`${basePath}/audio`);
|
||||
updated.audio = null;
|
||||
updated.audioUrl = null;
|
||||
updated.audio_path = null;
|
||||
} else {
|
||||
if (!mediaId) throw new Error(ns.I18n.t("editor.error.remove-image"));
|
||||
await sendDelete(`${basePath}/pictures/${encodeURIComponent(mediaId)}`);
|
||||
if (state.currentSource === 'group') state.groupDeletions.push({ path: `pictures/${encodeURIComponent(mediaId)}` });
|
||||
else await sendDelete(`${basePath}/pictures/${encodeURIComponent(mediaId)}`);
|
||||
updated.images = (state.currentPoi.images || []).filter(image => text(image.id) !== text(mediaId));
|
||||
}
|
||||
|
||||
@@ -1378,7 +1489,10 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
state.selectedMediaKey = null;
|
||||
renderPoiMediaPreview();
|
||||
updatePoiMediaStatus();
|
||||
setStatus(kind === 'audio' ? ns.I18n.t("editor.audio.removed") : ns.I18n.t("editor.image-removed"));
|
||||
if (state.currentSource === 'group') {
|
||||
await rememberGroupPoint(poiFromForm());
|
||||
setStatus(ns.I18n.t('point-locks.deletion-staged'));
|
||||
} else setStatus(kind === 'audio' ? ns.I18n.t("editor.audio.removed") : ns.I18n.t("editor.image-removed"));
|
||||
}
|
||||
|
||||
async function removeMedia(control) {
|
||||
@@ -1427,8 +1541,16 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
return;
|
||||
}
|
||||
|
||||
await sendDelete(`/routes/${encodeURIComponent(currentRouteId)}/pois/${encodeURIComponent(currentPoiId)}`);
|
||||
await loadRoute({ id: currentRouteId, _source: 'server' });
|
||||
if (state.currentSource === 'group' && ns.GroupPoints) {
|
||||
state.groupDeletePoint = true;
|
||||
const draft = await rememberGroupPoint(poiFromForm());
|
||||
try {
|
||||
if (!await ns.GroupPoints.prepare(draft)) { setStatus(ns.I18n.t('point-locks.saved-device')); return; }
|
||||
await sendDelete(`/routes/${currentRouteId}/pois/${currentPoiId}`);
|
||||
await ns.GroupPoints.remove(currentRouteId, currentPoiId);
|
||||
} catch { setStatus(ns.I18n.t('point-locks.saved-device')); return; }
|
||||
} else await sendDelete(`/routes/${encodeURIComponent(currentRouteId)}/pois/${encodeURIComponent(currentPoiId)}`);
|
||||
await loadRoute({ id: currentRouteId, _source: state.currentSource });
|
||||
setStatus(ns.I18n.t("editor.station-removed"));
|
||||
}
|
||||
|
||||
@@ -1447,6 +1569,25 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
guarded(savePoiOrder);
|
||||
}
|
||||
|
||||
async function saveGroupPoiOrder(currentRouteId) {
|
||||
let deferred = false;
|
||||
for (const [index, poi] of state.pois.entries()) {
|
||||
if (await ns.GroupPoints.read(currentRouteId, poi.id)) { deferred = true; continue; }
|
||||
const values = { ...poi, sequence: index };
|
||||
try {
|
||||
const opened = await ns.GroupPoints.begin(currentRouteId, poi);
|
||||
await ns.GroupPoints.remember(state.currentRoute, poi.id, { ...(opened?.poi || values), sequence: index }, { images: [], audio: null, deletions: [] });
|
||||
if (!opened) { deferred = true; continue; }
|
||||
await sendJson(`/routes/${currentRouteId}/pois/${poi.id}`, 'PUT', { sequence: index, sortOrder: index });
|
||||
await ns.GroupPoints.remove(currentRouteId, poi.id);
|
||||
} catch {
|
||||
await ns.GroupPoints.remember(state.currentRoute, poi.id, values, { images: [], audio: null, deletions: [] });
|
||||
deferred = true;
|
||||
} finally { await ns.GroupPoints.release(); }
|
||||
}
|
||||
setStatus(ns.I18n.t(deferred ? 'point-locks.saved-device' : 'editor.order.saved'));
|
||||
}
|
||||
|
||||
async function savePoiOrder() {
|
||||
const currentRouteId = routeId(state.currentRoute);
|
||||
if (!currentRouteId) return;
|
||||
@@ -1455,6 +1596,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
setStatus(ns.I18n.t("editor.station-order-saved"));
|
||||
return;
|
||||
}
|
||||
if (state.currentSource === 'group' && ns.GroupPoints) return saveGroupPoiOrder(currentRouteId);
|
||||
const jobs = state.pois.map((poi, index) => {
|
||||
const currentPoiId = poiId(poi);
|
||||
if (!currentPoiId) return null;
|
||||
@@ -1506,6 +1648,21 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
const route = routeForItem(event.target);
|
||||
if (!route) return;
|
||||
|
||||
if (action === 'share-route') {
|
||||
if (shareInProgress) return;
|
||||
shareInProgress = true;
|
||||
try {
|
||||
let sourceId = routeId(route);
|
||||
if (routeSource(route) === 'local') {
|
||||
if (!globalThis.confirm(ns.I18n.t('groups.upload-confirm'))) return;
|
||||
await loadRoute(route);
|
||||
await uploadLocalRoute();
|
||||
sourceId = state.currentRoute.serverRouteId;
|
||||
}
|
||||
await ns.Groups.share(sourceId);
|
||||
} finally { shareInProgress = false; }
|
||||
return;
|
||||
}
|
||||
if (action === 'edit-route') {
|
||||
await loadRoute(route);
|
||||
return;
|
||||
@@ -1517,6 +1674,12 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
async function deletePoiFromList(poi) {
|
||||
if (!poi) return;
|
||||
if (state.currentSource === 'group') {
|
||||
if (!await editPoi(poi)) return;
|
||||
state.groupDeletePoint = true;
|
||||
await savePoi();
|
||||
return;
|
||||
}
|
||||
state.currentPoi = poi;
|
||||
await deleteCurrentPoi();
|
||||
}
|
||||
@@ -1550,8 +1713,10 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
function bind() {
|
||||
for (const eventName of ['cancel', 'close']) {
|
||||
byId(ids.dialog)?.addEventListener(eventName, () => {
|
||||
byId(ids.dialog)?.addEventListener(eventName, event => {
|
||||
if (pointSaveInProgress && eventName === 'cancel') { event.preventDefault(); return; }
|
||||
releasePoiPreview();
|
||||
void ns.GroupPoints?.release();
|
||||
ns.RouteRecorder?.endEditing();
|
||||
});
|
||||
}
|
||||
@@ -1567,7 +1732,10 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
byId(ids.poiAudio)?.addEventListener('change', handleAudioSelection);
|
||||
byId(ids.poiImages)?.addEventListener('change', () => guarded(handleImageSelection));
|
||||
activate(byId(ids.poiMediaPreview), event => guarded(() => mediaPreviewAction(event)));
|
||||
activate(byId(ids.poiDelete), () => guarded(deleteCurrentPoi));
|
||||
activate(byId(ids.poiDelete), () => {
|
||||
if (state.currentSource === 'group') { state.groupDeletePoint = true; void guarded(savePoi); }
|
||||
else void guarded(deleteCurrentPoi);
|
||||
});
|
||||
activate(byId(ids.poiCancel), showRouteView);
|
||||
activate(byId(ids.routeList), event => guarded(() => routeListAction(event)));
|
||||
activate(byId(ids.poiList), event => guarded(() => poiListAction(event)));
|
||||
@@ -1580,6 +1748,27 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
close: closeEditor,
|
||||
open: openEditor,
|
||||
openNewLocalRoute,
|
||||
openGroup: async route => {
|
||||
await openEditor();
|
||||
await loadRoute({ ...route, _source: 'group' });
|
||||
},
|
||||
openPendingPoint: async draft => {
|
||||
await openEditor();
|
||||
try { await loadRoute({ ...draft.route, _source: 'group' }); }
|
||||
catch {
|
||||
state.currentSource = 'group';
|
||||
state.currentRoute = { ...draft.route, _source: 'group' };
|
||||
state.pois = draft.basePoi ? [draft.basePoi] : [];
|
||||
fillRouteForm(state.currentRoute); renderPoiList(); showRouteView();
|
||||
}
|
||||
if (draft.poiId === 'new') {
|
||||
newPoi();
|
||||
fillPoiForm(draft.values);
|
||||
state.pendingAudioFile = draft.media?.audio || null;
|
||||
state.pendingImages = (draft.media?.images || []).map(file => ({ file, key: `pending-image-${ns.LocalRoutes.createPoiId()}`, previewUrl: objectUrlFor(file) }));
|
||||
renderPoiMediaPreview(); updatePoiMediaStatus();
|
||||
} else await editPoi(draft.basePoi || { id: draft.poiId });
|
||||
},
|
||||
refresh: loadRoutes
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user