fix: image refs in description and broken gallery URLs

- EditDrawer: stop auto-inserting ![filename](...) into description on
  upload — images are tracked via custom.images; the refs only cluttered
  the textarea. Strip any pre-existing refs on load so old sidecars are
  also cleaned up when the drawer is opened.
- ActivityDetail: imageBase now treats detail_url that starts with '/'
  as already-absolute (same fix pattern as track_url / detail_url);
  was prepending ${base}data/ on top of /data/... → double path.
This commit is contained in:
Davide Scaini
2026-04-16 10:19:32 +02:00
parent 395182649b
commit cfdd8d2744
2 changed files with 5 additions and 9 deletions
+3 -2
View File
@@ -82,10 +82,11 @@
})(); })();
// Derive image dir from detail_url so multi-user paths resolve correctly. // Derive image dir from detail_url so multi-user paths resolve correctly.
// "dave/_merged/activities/foo.json" → "/data/dave/_merged/activities/images/{id}/" // Relative: "dave/_merged/activities/foo.json" → "/data/dave/_merged/activities/images/{id}/"
// Absolute: "/data/dave/_merged/activities/foo.json" → "/data/dave/_merged/activities/images/{id}/"
$: imageBase = (() => { $: imageBase = (() => {
const du = activity.detail_url ?? ''; const du = activity.detail_url ?? '';
const dir = du.startsWith('http') const dir = du.startsWith('http') || du.startsWith('/')
? du.substring(0, du.lastIndexOf('/') + 1) ? du.substring(0, du.lastIndexOf('/') + 1)
: du.includes('/') : du.includes('/')
? `${base}data/${du.substring(0, du.lastIndexOf('/') + 1)}` ? `${base}data/${du.substring(0, du.lastIndexOf('/') + 1)}`
+2 -7
View File
@@ -51,7 +51,8 @@
title = d.title ?? ''; title = d.title ?? '';
sport = d.sport ?? 'cycling'; sport = d.sport ?? 'cycling';
gear = d.gear ?? ''; gear = d.gear ?? '';
description = d.description ?? ''; // Strip any auto-inserted image markdown refs — images are tracked via custom.images
description = (d.description ?? '').replace(/!\[[^\]]*\]\([^)]+\)\n?/g, '').trim();
highlight = d.highlight ?? false; highlight = d.highlight ?? false;
isPrivate = d.private ?? false; isPrivate = d.private ?? false;
hideStats = d.hide_stats ?? []; hideStats = d.hide_stats ?? [];
@@ -95,9 +96,6 @@
if (res.ok) { if (res.ok) {
const d = await res.json(); const d = await res.json();
if (!images.includes(d.filename)) images = [...images, d.filename]; if (!images.includes(d.filename)) images = [...images, d.filename];
// Insert markdown reference at cursor or end
const ref = `\n![${d.filename.replace(/\.[^.]+$/, '')}](${d.filename})`;
description = description.trimEnd() + ref;
} }
} }
} catch (e: any) { } catch (e: any) {
@@ -111,9 +109,6 @@
async function deleteImage(filename: string) { async function deleteImage(filename: string) {
await fetch(`${api}/images/${encodeURIComponent(filename)}`, { method: 'DELETE' }); await fetch(`${api}/images/${encodeURIComponent(filename)}`, { method: 'DELETE' });
images = images.filter(f => f !== filename); images = images.filter(f => f !== filename);
// Remove the markdown reference — escape filename before using in regex
const escaped = filename.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
description = description.replace(new RegExp(`!\\[[^\\]]*\\]\\(${escaped}\\)`, 'g'), '').trim();
} }
function toggleStat(key: string) { function toggleStat(key: string) {