This commit is contained in:
+28
-5
@@ -126,6 +126,26 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
return text(poi?.id ?? poi?.poiId);
|
||||
}
|
||||
|
||||
function numericPoiId(value) {
|
||||
const raw = text(value).trim();
|
||||
if (!raw) return null;
|
||||
const parsed = Number(raw);
|
||||
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : null;
|
||||
}
|
||||
|
||||
function nextLocalPoiId() {
|
||||
let highest = -1;
|
||||
for (const poi of state.pois) {
|
||||
const identifier = numericPoiId(poi?.id ?? poi?.poiId);
|
||||
if (identifier != null && identifier > highest) highest = identifier;
|
||||
}
|
||||
const next = highest + 1;
|
||||
if (!Number.isSafeInteger(next)) {
|
||||
throw new Error('Für diese lokale Strecke kann keine weitere Streckenpunkt-ID vergeben werden.');
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
function routeName(route) {
|
||||
return text(route?.name || route?.title || 'Unbenannte Strecke');
|
||||
}
|
||||
@@ -479,7 +499,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
byId(ids.routeName).value = routeName(route) === 'Unbenannte Strecke' ? '' : routeName(route);
|
||||
byId(ids.routeDescription).value = text(route?.description);
|
||||
byId(ids.routeGpx).value = '';
|
||||
setHidden(byId(ids.routeGpxGroup), !routeId(route));
|
||||
setHidden(byId(ids.routeGpxGroup), state.currentSource !== 'server');
|
||||
|
||||
const uploadButton = byId(ids.routeUpload);
|
||||
if (state.currentSource === 'local') {
|
||||
@@ -983,7 +1003,9 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
|
||||
const accuracy = Number(position?.accuracy);
|
||||
state.currentPoi = null;
|
||||
const identifier = state.currentSource === 'local' ? nextLocalPoiId() : null;
|
||||
fillPoiForm({
|
||||
...(identifier == null ? {} : { id: identifier }),
|
||||
lat,
|
||||
lon,
|
||||
triggerRadiusM: Number.isFinite(accuracy) && accuracy > 0 ? accuracy : 25
|
||||
@@ -1062,9 +1084,10 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
if (!Number.isFinite(values.lat) || !Number.isFinite(values.lon)) {
|
||||
throw new TypeError('Für einen Streckenpunkt 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 currentId = numericPoiId(byId(ids.poiId).value);
|
||||
const identifier = currentId ?? nextLocalPoiId();
|
||||
byId(ids.poiId).value = String(identifier);
|
||||
const existing = state.pois.find(poi => numericPoiId(poi?.id ?? poi?.poiId) === identifier) || state.currentPoi;
|
||||
const media = await mediaFromLocalForm(existing, identifier);
|
||||
const savedPoi = {
|
||||
...existing,
|
||||
@@ -1074,7 +1097,7 @@ globalThis.Wegwichtel = globalThis.Wegwichtel || {};
|
||||
id: identifier,
|
||||
sequence: existing?.sequence ?? state.pois.length
|
||||
};
|
||||
const index = state.pois.findIndex(poi => Number(poi.id) === identifier);
|
||||
const index = state.pois.findIndex(poi => numericPoiId(poi?.id ?? poi?.poiId) === identifier);
|
||||
if (index >= 0) state.pois[index] = savedPoi;
|
||||
else state.pois.push(savedPoi);
|
||||
|
||||
|
||||
+40
-3
@@ -78,7 +78,7 @@ test('editor markup and source describe local draft creation instead of immediat
|
||||
assert.match(ui, /sendForm\('\/routes',\s*'POST'/);
|
||||
assert.match(ui, /serverRouteId/);
|
||||
assert.match(ui, /position\?\.accuracy/);
|
||||
assert.match(ui, /setHidden\(byId\(ids\.routeGpxGroup\), !routeId\(route\)\)/);
|
||||
assert.match(ui, /setHidden\(byId\(ids\.routeGpxGroup\), state\.currentSource !== 'server'\)/);
|
||||
});
|
||||
|
||||
class FakeElement extends EventTarget {
|
||||
@@ -386,7 +386,7 @@ test('public editor workflow saves new route and GPX Streckenpunkt locally witho
|
||||
assert.equal(elements.get('editor-status').textContent, 'Speichern erfolgreich.');
|
||||
assert.equal(elements.get('editor-route-upload').hidden, false);
|
||||
assert.equal(elements.get('editor-route-upload').disabled, false);
|
||||
assert.equal(elements.get('editor-route-gpx-group').hidden, false);
|
||||
assert.equal(elements.get('editor-route-gpx-group').hidden, true);
|
||||
|
||||
elements.get('editor-add-poi').dispatchEvent(pointerEvent());
|
||||
assert.equal(elements.get('editor-poi-audio').clickCount, 0);
|
||||
@@ -399,7 +399,7 @@ test('public editor workflow saves new route and GPX Streckenpunkt locally witho
|
||||
assert.equal(elements.get('editor-poi-lon').value, '10.987654321');
|
||||
assert.equal(elements.get('editor-poi-radius').value, '4.321');
|
||||
elements.get('editor-poi-title').value = 'Aussicht';
|
||||
elements.get('editor-poi-description').value = 'Text zur Station';
|
||||
elements.get('editor-poi-description').value = 'Text zum Streckenpunkt';
|
||||
elements.get('editor-poi-audio').files = [{ name: 'aussicht.mp3', size: 5, type: 'audio/mpeg' }];
|
||||
elements.get('editor-poi-audio').dispatchEvent(new Event('change'));
|
||||
elements.get('editor-poi-images').files = [{ name: 'aussicht.jpg', size: 7, type: 'image/jpeg' }];
|
||||
@@ -488,6 +488,42 @@ test('public editor workflow saves new route and GPX Streckenpunkt locally witho
|
||||
assert.equal(elements.get('editor-button').attributes.get('aria-expanded'), 'false');
|
||||
});
|
||||
|
||||
test('local Streckenpunkt ids start at zero and increment from the highest existing id', async () => {
|
||||
const sourcePath = path.join(root, 'public/js/editor-ui.js');
|
||||
const source = await fs.readFile(sourcePath, 'utf8');
|
||||
const { context, elements, packages } = buildEditorContext();
|
||||
|
||||
vm.runInNewContext(source, context, { filename: sourcePath });
|
||||
await context.Wegwichtel.EditorUi.openNewLocalRoute();
|
||||
elements.get('editor-route-name').value = 'ID-Test';
|
||||
elements.get('editor-route-form').dispatchEvent(submitEvent());
|
||||
await tick();
|
||||
await tick();
|
||||
|
||||
elements.get('editor-add-poi').dispatchEvent(pointerEvent());
|
||||
assert.equal(elements.get('editor-poi-id').value, '0');
|
||||
elements.get('editor-poi-title').value = 'Erster Streckenpunkt';
|
||||
elements.get('editor-poi-form').dispatchEvent(submitEvent());
|
||||
await tick();
|
||||
await tick();
|
||||
|
||||
elements.get('editor-add-poi').dispatchEvent(pointerEvent());
|
||||
assert.equal(elements.get('editor-poi-id').value, '1');
|
||||
elements.get('editor-poi-title').value = 'Zweiter Streckenpunkt';
|
||||
elements.get('editor-poi-form').dispatchEvent(submitEvent());
|
||||
await tick();
|
||||
await tick();
|
||||
|
||||
const saved = packages.get('local-new');
|
||||
assert.equal(saved.pois.length, 2);
|
||||
assert.deepEqual(Array.from(saved.pois, poi => poi.id), [0, 1]);
|
||||
assert.deepEqual(Array.from(saved.pois, poi => poi.title), ['Erster Streckenpunkt', 'Zweiter Streckenpunkt']);
|
||||
|
||||
const pointItems = elements.get('editor-poi-list').children.filter(child => child.dataset.poiId);
|
||||
assert.equal(pointItems.length, 2);
|
||||
});
|
||||
|
||||
|
||||
test('route and Streckenpunkt list expose red delete actions and remove local data', async () => {
|
||||
const sourcePath = path.join(root, 'public/js/editor-ui.js');
|
||||
const source = await fs.readFile(sourcePath, 'utf8');
|
||||
@@ -560,6 +596,7 @@ test('editing an activated server route uses PUT and never writes activation sta
|
||||
await tick();
|
||||
|
||||
assert.equal(elements.get('editor-route-id').value, '1');
|
||||
assert.equal(elements.get('editor-route-gpx-group').hidden, false);
|
||||
assert.match(elements.get('editor-route-activated').textContent, /Veröffentlicht am/);
|
||||
assert.equal(elements.get('editor-route-upload').hidden, true);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user