Split combined trade-fair bookmark links and add shared-ticket notes

This commit is contained in:
2026-02-21 20:02:43 +01:00
parent 758ffd158f
commit 4b1e935000
2 changed files with 79 additions and 26 deletions

View File

@@ -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;
}

View File

@@ -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;
}