Format the structured lines in park4night waypoint popups
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:
1 parent
6f7d332993
commit
3759f7a5c9
3 files changed
+88
-2
No files matched your search
@@ -450,6 +450,32 @@ html, body {
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.gpx-popup__description {
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.gpx-popup__meta {
|
||||
margin-top: 8px;
|
||||
padding-top: 6px;
|
||||
border-top: 1px solid #eee;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.gpx-popup__meta-row + .gpx-popup__meta-row {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.gpx-popup__meta-label {
|
||||
font-weight: 600;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.gpx-popup__link {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.gnss-control__status {
|
||||
color: #888;
|
||||
white-space: nowrap;
|
||||
|
||||
+47
-1
@@ -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
|
||||
|
||||
Reference in new issue
Block a user