From 4b1e935000cf6359acf0007d3ae2b57d30f05c42 Mon Sep 17 00:00:00 2001 From: Meik Date: Sat, 21 Feb 2026 20:02:43 +0100 Subject: [PATCH] Split combined trade-fair bookmark links and add shared-ticket notes --- web/style.css | 12 ++++++ web/trade-fairs.js | 93 +++++++++++++++++++++++++++++++++------------- 2 files changed, 79 insertions(+), 26 deletions(-) diff --git a/web/style.css b/web/style.css index f119db0..7550de4 100644 --- a/web/style.css +++ b/web/style.css @@ -1944,6 +1944,18 @@ h1 { text-align: left; } +.bookmark-subpage__messe-links { + display: inline-flex; + flex-wrap: wrap; + align-items: center; + row-gap: 2px; +} + +.bookmark-subpage__messe-separator { + color: #6b7280; + margin: 0 2px; +} + .bookmark-subpage__messe-link:hover { color: #1d4ed8; } diff --git a/web/trade-fairs.js b/web/trade-fairs.js index 6cdf66b..569a0b0 100644 --- a/web/trade-fairs.js +++ b/web/trade-fairs.js @@ -222,6 +222,7 @@ { rang: 11, messe: 'Leipziger Buchmesse / Manga Comic Con', + bookmark_suchbegriffe: ['Leipziger Buchmesse', 'Manga Comic Con'], thema: 'Buchmarkt, Medien, Manga/Comic', stadt: 'Leipzig', bundesland: 'Sachsen', @@ -233,7 +234,7 @@ ausstellungsflaeche_m2: 20788, ticketpreis_we_eur: 35, ticketpreis_unterderwoche_eur: 28, - notiz: 'Ticketpreise laut offizieller Leipzig-Messe-Preisliste 2026 (Sa am hoechsten).', + notiz: 'Ein Ticket gilt fuer Leipziger Buchmesse und Manga Comic Con (parallel, inkl. Antiquariatsmesse).', quelle_homepage: 'https://www.leipziger-buchmesse.de' }, { @@ -391,7 +392,8 @@ }, { rang: 21, - messe: 'f.re.e München', + messe: 'f.re.e München / IMOT', + bookmark_suchbegriffe: ['f.re.e München', 'IMOT'], thema: 'Reisen, Freizeit, Caravaning, Outdoor', stadt: 'München', bundesland: 'Bayern', @@ -403,7 +405,7 @@ ausstellungsflaeche_m2: null, ticketpreis_we_eur: 17, ticketpreis_unterderwoche_eur: 14, - notiz: 'Preisniveau aus zuletzt veroeffentlichtem Ticketstand (Wochenende hoeher).', + notiz: 'Ein Ticket gilt fuer f.re.e und IMOT (sowie meist auch Muenchner Auto Tage) laut offiziellem Ticketshop.', quelle_homepage: 'https://free-muenchen.de' }, { @@ -459,7 +461,8 @@ }, { rang: 25, - messe: 'Heim+Handwerk', + messe: 'Heim+Handwerk / FOOD & LIFE', + bookmark_suchbegriffe: ['Heim+Handwerk', 'FOOD & LIFE'], thema: 'Wohnen, Handwerk, Lifestyle', stadt: 'München', bundesland: 'Bayern', @@ -471,7 +474,7 @@ ausstellungsflaeche_m2: null, ticketpreis_we_eur: 15, ticketpreis_unterderwoche_eur: 15, - notiz: 'Ticketpreis als zuletzt verfuegbares Preisniveau; finale 2026-Staffel folgt i.d.R. spaeter.', + notiz: 'Ein Ticket gilt fuer Heim+Handwerk und FOOD & LIFE (parallel in Muenchen).', quelle_homepage: 'https://www.heim-handwerk.de' }, { @@ -493,7 +496,8 @@ }, { rang: 27, - messe: 'Reise + Camping Essen', + messe: 'Reise + Camping Essen / Fahrrad Essen', + bookmark_suchbegriffe: ['Reise + Camping Essen', 'Fahrrad Essen'], thema: 'Reisen, Camping, Fahrrad, Outdoor', stadt: 'Essen', bundesland: 'Nordrhein-Westfalen', @@ -505,7 +509,7 @@ ausstellungsflaeche_m2: null, ticketpreis_we_eur: 12, ticketpreis_unterderwoche_eur: 12, - notiz: 'Online-Tagesticket laut Messe-Essen-Presse (EUR 12).', + notiz: 'Ein Ticket gilt fuer Reise + Camping und Fahrrad Essen (parallel in den Messehallen).', quelle_homepage: 'https://www.reise-camping.de' }, { @@ -1021,14 +1025,28 @@ return td; } - function buildTradeFairBaseQuery(row) { - const base = String(row.messe || '').trim(); - if (base) { - return base; + function getTradeFairBookmarkQueries(row) { + if (Array.isArray(row.bookmark_suchbegriffe) && row.bookmark_suchbegriffe.length) { + return [...new Set( + row.bookmark_suchbegriffe + .map((entry) => String(entry || '').trim()) + .filter(Boolean) + )]; } - const fallback = [row.messe, row.stadt].map((value) => String(value || '').trim()).filter(Boolean).join(' '); - return fallback.trim(); + const messe = String(row.messe || '').trim(); + if (!messe) { + return []; + } + + if (messe.includes(' / ')) { + const split = messe.split(' / ').map((part) => part.trim()).filter(Boolean); + if (split.length > 1) { + return [...new Set(split)]; + } + } + + return [messe]; } function openBookmarkLikeFallback(baseQuery) { @@ -1060,8 +1078,10 @@ return opened; } - function openTradeFairSearch(row) { - const baseQuery = buildTradeFairBaseQuery(row); + function openTradeFairSearch(row, explicitBaseQuery) { + const baseQuery = explicitBaseQuery + ? String(explicitBaseQuery).trim() + : getTradeFairBookmarkQueries(row)[0]; if (!baseQuery) { return 0; } @@ -1084,19 +1104,40 @@ function createMesseCell(row) { const td = document.createElement('td'); td.dataset.column = 'messe'; - const button = document.createElement('button'); - button.type = 'button'; - button.className = 'bookmark-subpage__messe-link'; - button.textContent = row.messe || 'k.A.'; - button.title = getTradeFairHoverTitle(row); - button.addEventListener('click', () => { - const opened = openTradeFairSearch(row); - if (opened > 0) { - button.title = getTradeFairHoverTitle(row); - render(); + + const bookmarkQueries = getTradeFairBookmarkQueries(row); + if (!bookmarkQueries.length) { + td.textContent = row.messe || 'k.A.'; + return td; + } + + const linksWrap = document.createElement('div'); + linksWrap.className = 'bookmark-subpage__messe-links'; + + bookmarkQueries.forEach((query, index) => { + const button = document.createElement('button'); + button.type = 'button'; + button.className = 'bookmark-subpage__messe-link'; + button.textContent = query; + button.title = getTradeFairHoverTitle(row); + button.addEventListener('click', () => { + const opened = openTradeFairSearch(row, query); + if (opened > 0) { + button.title = getTradeFairHoverTitle(row); + render(); + } + }); + linksWrap.appendChild(button); + + if (index < bookmarkQueries.length - 1) { + const separator = document.createElement('span'); + separator.className = 'bookmark-subpage__messe-separator'; + separator.textContent = ' / '; + linksWrap.appendChild(separator); } }); - td.appendChild(button); + + td.appendChild(linksWrap); return td; }