Format the structured lines in park4night waypoint popups
CI / check (push) Successful in 41s
CI / deploy (push) Successful in 16s

A park4night <desc> packs a free-text narrative and several lines of
structured data (address, rating, services, activities, the listing URL)
into one field, separated only by newlines. Rendered as a single paragraph
it read as a wall of run-together text — no visual hierarchy between the
actual description and what's really key-value metadata.

formatDescription now recognizes "Label: value" lines (Rating/Services/
Activities) and bare-URL lines, and gives each its own row instead of
burying them in the narrative paragraph: a bordered meta block with bold
labels, and an isolated link line. Anything that doesn't match — the real
narrative text, or a plain GPX file's <desc> with no such structure — stays
exactly as it rendered before, so this only adds structure, never removes
or reorders text.
This commit is contained in:
randy committed 2026-09-07 17:03:36 +02:00
1 parent 6f7d332993
commit 3759f7a5c9
3 files changed
+88 -2

No files matched your search

+47 -1
View File
@@ -757,7 +757,7 @@ function popupHtml({ name, description, time, category }) {
const parts = [];
if (name) parts.push(`<strong>${escapeHtml(name)}</strong>`);
if (category) parts.push(`<p class="gpx-popup__category">${escapeHtml(category)}</p>`);
if (description) parts.push(`<p>${linkify(description).replace(/\n/g, "<br>")}</p>`);
if (description) parts.push(formatDescription(description));
if (time) {
const parsed = new Date(time);
if (!Number.isNaN(parsed.getTime())) {
@@ -795,6 +795,52 @@ function escapeHtml(text) {
return div.innerHTML;
}
// park4night exports pack a free-text description and several lines of
// structured data (address, rating, services, activities, the listing URL)
// into one <desc> blob, separated only by newlines — rendered as one plain
// paragraph, it read as a wall of run-together text. Lines matching a
// recognizable "Label: value" or bare-URL shape get pulled out and rendered
// as their own visually distinct rows instead; anything else (the actual
// narrative, or a plain GPX file's <desc> with no such structure at all)
// stays exactly as before, one paragraph with line breaks — so this only
// ever adds structure, never loses any text.
const DESCRIPTION_META_LINE = /^(Rating|Services|Activities):\s*(.+)$/i;
const DESCRIPTION_LINK_LINE = /^https?:\/\/\S+$/;
function formatDescription(description) {
const body = [];
const meta = [];
const links = [];
for (const line of description.split("\n")) {
const trimmed = line.trim();
const metaMatch = trimmed.match(DESCRIPTION_META_LINE);
if (DESCRIPTION_LINK_LINE.test(trimmed)) {
links.push(trimmed);
} else if (metaMatch) {
meta.push(metaMatch);
} else {
body.push(line);
}
}
const parts = [];
const bodyText = body.join("\n").trim();
if (bodyText) parts.push(`<p class="gpx-popup__description">${linkify(bodyText).replace(/\n/g, "<br>")}</p>`);
if (meta.length > 0) {
const rows = meta
.map(
([, label, value]) =>
`<div class="gpx-popup__meta-row"><span class="gpx-popup__meta-label">${escapeHtml(label)}</span> ${escapeHtml(value)}</div>`,
)
.join("");
parts.push(`<div class="gpx-popup__meta">${rows}</div>`);
}
links.forEach((url) => parts.push(`<p class="gpx-popup__link">${urlToLink(url)}</p>`));
return parts.join("");
}
// Turns bare URLs in untrusted text into safe <a> links: the string is
// split on the URL pattern and every piece is escaped — including the URL
// itself, both as href and as link text — before any HTML is assembled, so