(function initTradeFairsSubpage() { const tableBody = document.getElementById('tradeFairTableBody'); const searchInput = document.getElementById('tradeFairSearchInput'); const meta = document.getElementById('tradeFairMeta'); const sortButtons = Array.from(document.querySelectorAll('.bookmark-subpage__sort[data-trade-sort]')); if (!tableBody || !searchInput || !meta || !sortButtons.length) { return; } const TRADE_FAIRS = [ { rang: 1, messe: 'bauma', thema: 'Baumaschinen, Baustoffmaschinen, Bergbau, Baufahrzeuge', stadt: 'München', bundesland: 'Bayern', termin_start: '2028-04-03', termin_ende: '2028-04-09', besucher: 605974, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 420107, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://bauma.de' }, { rang: 2, messe: 'AGRITECHNICA', thema: 'Landtechnik und Agrartechnologie', stadt: 'Hannover', bundesland: 'Niedersachsen', termin_start: '2027-11-14', termin_ende: '2027-11-20', besucher: 477055, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 229886, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.agritechnica.com' }, { rang: 3, messe: 'gamescom', thema: 'Games, digitale Unterhaltung, Hardware/Software', stadt: 'Köln', bundesland: 'Nordrhein-Westfalen', termin_start: '2026-08-26', termin_ende: '2026-08-30', besucher: 357416, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 73515, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.gamescom.global/en' }, { rang: 4, messe: 'Grüne Woche', thema: 'Ernährung, Landwirtschaft, Garten, Genuss', stadt: 'Berlin', bundesland: 'Berlin', termin_start: '2027-01-15', termin_ende: '2027-01-24', besucher: 307530, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 42500, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.gruenewoche.de' }, { rang: 5, messe: 'CARAVAN SALON DÜSSELDORF', thema: 'Reisemobile, Caravans, Camping, Touristik', stadt: 'Düsseldorf', bundesland: 'Nordrhein-Westfalen', termin_start: '2026-08-28', termin_ende: '2026-09-06', besucher: 270421, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 121439, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.caravan-salon.de' }, { rang: 6, messe: 'Maimarkt Mannheim', thema: 'Publikums-Mehrbranchenmesse', stadt: 'Mannheim', bundesland: 'Baden-Württemberg', termin_start: '2026-04-25', termin_ende: '2026-05-05', besucher: 268613, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 52769, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.maimarkt.de' }, { rang: 7, messe: 'CMT - Die Urlaubsmesse', thema: 'Tourismus, Caravaning, Freizeit', stadt: 'Stuttgart', bundesland: 'Baden-Württemberg', termin_start: '2027-01-16', termin_ende: '2027-01-24', besucher: 261004, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 75587, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.messe-stuttgart.de/cmt' }, { rang: 8, messe: 'Leipziger Buchmesse / Manga Comic Con', thema: 'Buchmarkt, Medien, Manga/Comic', stadt: 'Leipzig', bundesland: 'Sachsen', termin_start: '2026-03-19', termin_ende: '2026-03-22', besucher: 242238, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 20788, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.leipziger-buchmesse.de' }, { rang: 9, messe: 'ESSEN MOTOR SHOW', thema: 'Performance, Tuning, Motorsport, Classic Cars', stadt: 'Essen', bundesland: 'Nordrhein-Westfalen', termin_start: '2026-11-28', termin_ende: '2026-12-06', besucher: 202827, besucher_jahr: 2024, besucher_status: 'AUMA-Kennzahl 2024 (kein neuerer Wert)', ausstellungsflaeche_m2: 33781, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Vorjahreswert, da kein neuerer veröffentlichter Wert in AUMA. Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.essen-motorshow.de' }, { rang: 10, messe: 'boot Düsseldorf', thema: 'Boote, Wassersport, Tauchen, Yachting', stadt: 'Düsseldorf', bundesland: 'Nordrhein-Westfalen', termin_start: '2027-01-23', termin_ende: '2027-01-31', besucher: 198339, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 94867, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.boot.de' }, { rang: 11, messe: 'IFA', thema: 'Consumer Electronics, Home Appliances, Tech', stadt: 'Berlin', bundesland: 'Berlin', termin_start: '2026-09-04', termin_ende: '2026-09-08', besucher: 191997, besucher_jahr: 2024, besucher_status: 'AUMA-Kennzahl 2024 (kein neuerer Wert)', ausstellungsflaeche_m2: 107546, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Vorjahreswert, da kein neuerer veröffentlichter Wert in AUMA. Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.ifa-berlin.com' }, { rang: 12, messe: 'FIBO', thema: 'Fitness, Wellness, Gesundheit', stadt: 'Köln', bundesland: 'Nordrhein-Westfalen', termin_start: '2026-04-16', termin_ende: '2026-04-19', besucher: 154890, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 56904, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.fibo.com' }, { rang: 13, messe: 'Anuga', thema: 'Lebensmittel und Getränke', stadt: 'Köln', bundesland: 'Nordrhein-Westfalen', termin_start: '2027-10-09', termin_ende: '2027-10-13', besucher: 143432, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 157545, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.anuga.com' }, { rang: 14, messe: 'HANNOVER MESSE', thema: 'Industrie, Automation, Energie, Digital', stadt: 'Hannover', bundesland: 'Niedersachsen', termin_start: '2026-04-20', termin_ende: '2026-04-24', besucher: 123035, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 101699, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.hannovermesse.de' }, { rang: 15, messe: 'CONSUMENTA Nürnberg', thema: 'Publikumsmesse: Haushalt, Freizeit, Bauen, Genuss', stadt: 'Nürnberg', bundesland: 'Bayern', termin_start: '2026-10-31', termin_ende: '2026-11-08', besucher: 121579, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 30448, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.consumenta.de' }, { rang: 16, messe: 'infa', thema: 'Publikumsmesse: Lifestyle, Haushalt, Genuss', stadt: 'Hannover', bundesland: 'Niedersachsen', termin_start: '2026-10-10', termin_ende: '2026-10-18', besucher: 100361, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 16423, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.infa.de' }, { rang: 17, messe: 'ILA Berlin', thema: 'Luft- und Raumfahrt', stadt: 'Berlin', bundesland: 'Berlin', termin_start: '2026-06-10', termin_ende: '2026-06-14', besucher: 95000, besucher_jahr: 2024, besucher_status: 'AUMA-Kennzahl 2024 (kein neuerer Wert)', ausstellungsflaeche_m2: 32008, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Vorjahreswert, da kein neuerer veröffentlichter Wert in AUMA. Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.ila-berlin.de' }, { rang: 18, messe: 'offerta', thema: 'Einkaufs- und Erlebnismesse für Verbraucher', stadt: 'Karlsruhe', bundesland: 'Baden-Württemberg', termin_start: '2026-10-24', termin_ende: '2026-11-01', besucher: 88738, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 16242, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.offerta.info' }, { rang: 19, messe: 'RETRO CLASSICS', thema: 'Klassische Fahrzeuge und Fahrkultur', stadt: 'Stuttgart', bundesland: 'Baden-Württemberg', termin_start: '2026-02-19', termin_ende: '2026-02-22', besucher: 72386, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 46496, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026). Ticketpreise je Kategorie/VVK.', quelle_homepage: 'https://www.retro-classics.de' }, { rang: 20, messe: 'ITB Berlin', thema: 'Reiseindustrie (B2B/Fachbesucher)', stadt: 'Berlin', bundesland: 'Berlin', termin_start: '2026-03-03', termin_ende: '2026-03-05', besucher: 58232, besucher_jahr: 2025, besucher_status: 'AUMA-Kennzahl 2025', ausstellungsflaeche_m2: 78892, ticketpreis_we_eur: null, ticketpreis_unterderwoche_eur: null, notiz: 'Fachbesucherfokus. Kennzahlen laut AUMA-Messedatenbank (Abruf 21.02.2026).', quelle_homepage: 'https://www.itb.com' } ]; const SORT_TYPES = { tage_bis_start: 'number', rang: 'number', messe: 'text', thema: 'text', stadt: 'text', bundesland: 'text', termin_start: 'date', termin_ende: 'date', besucher: 'number', besucher_jahr: 'number', besucher_status: 'text', ausstellungsflaeche_m2: 'number', ticketpreis_we_eur: 'number', ticketpreis_unterderwoche_eur: 'number', notiz: 'text', quelle_homepage: 'text' }; let sortKey = 'rang'; let sortDirection = 'asc'; let searchTerm = ''; function toNumber(value) { if (typeof value === 'number' && Number.isFinite(value)) { return value; } if (typeof value === 'string' && value.trim()) { const normalized = value.replace(/\./g, '').replace(',', '.').replace(/[^\d.-]/g, ''); const parsed = Number(normalized); return Number.isFinite(parsed) ? parsed : null; } return null; } function toDate(value) { if (!value) { return null; } const parsed = new Date(value); if (Number.isNaN(parsed.getTime())) { return null; } return parsed; } function getDaysUntil(startIso) { const start = toDate(startIso); if (!start) { return null; } const now = new Date(); now.setHours(0, 0, 0, 0); start.setHours(0, 0, 0, 0); return Math.round((start.getTime() - now.getTime()) / 86400000); } function normalizeRow(row) { return { ...row, tage_bis_start: getDaysUntil(row.termin_start) }; } function getSortValue(row, key) { const type = SORT_TYPES[key] || 'text'; const value = row[key]; if (type === 'number') { const numeric = toNumber(value); return numeric === null ? Number.NEGATIVE_INFINITY : numeric; } if (type === 'date') { const date = toDate(value); return date ? date.getTime() : Number.NEGATIVE_INFINITY; } return String(value || '').toLocaleLowerCase('de-DE'); } function formatNumber(value) { if (!Number.isFinite(value)) { return 'k.A.'; } return value.toLocaleString('de-DE'); } function formatPrice(value) { if (!Number.isFinite(value)) { return 'k.A.'; } return value.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); } function formatDate(iso) { const date = toDate(iso); if (!date) { return 'k.A.'; } return date.toLocaleDateString('de-DE'); } function matchesSearch(row, term) { if (!term) { return true; } const haystack = [ row.messe, row.thema, row.stadt, row.bundesland, row.notiz ].join(' ').toLocaleLowerCase('de-DE'); return haystack.includes(term); } function sortRows(rows) { return [...rows].sort((a, b) => { const aValue = getSortValue(a, sortKey); const bValue = getSortValue(b, sortKey); if (aValue === bValue) { const fallback = (a.rang || 0) - (b.rang || 0); return sortDirection === 'asc' ? fallback : -fallback; } if (aValue > bValue) { return sortDirection === 'asc' ? 1 : -1; } return sortDirection === 'asc' ? -1 : 1; }); } function updateSortButtonState() { sortButtons.forEach((button) => { const key = button.dataset.tradeSort; const isActive = key === sortKey; button.classList.toggle('is-active', isActive); const indicator = isActive ? (sortDirection === 'asc' ? '▲' : '▼') : '↕'; const baseLabel = button.dataset.baseLabel || button.textContent.trim(); button.textContent = `${baseLabel} ${indicator}`; }); } function createCell(content) { const td = document.createElement('td'); td.textContent = content; return td; } function render() { const normalizedRows = TRADE_FAIRS.map(normalizeRow); const filtered = normalizedRows.filter((row) => matchesSearch(row, searchTerm)); const sorted = sortRows(filtered); tableBody.innerHTML = ''; if (!sorted.length) { const emptyRow = document.createElement('tr'); const emptyCell = document.createElement('td'); emptyCell.colSpan = 16; emptyCell.textContent = 'Keine Messe zum Suchbegriff gefunden.'; emptyRow.appendChild(emptyCell); tableBody.appendChild(emptyRow); } else { sorted.forEach((row) => { const tr = document.createElement('tr'); tr.appendChild(createCell(Number.isFinite(row.tage_bis_start) ? String(row.tage_bis_start) : 'k.A.')); tr.appendChild(createCell(String(row.rang))); tr.appendChild(createCell(row.messe)); tr.appendChild(createCell(row.thema)); tr.appendChild(createCell(row.stadt)); tr.appendChild(createCell(row.bundesland)); tr.appendChild(createCell(formatDate(row.termin_start))); tr.appendChild(createCell(formatDate(row.termin_ende))); tr.appendChild(createCell(formatNumber(row.besucher))); tr.appendChild(createCell(formatNumber(row.besucher_jahr))); tr.appendChild(createCell(row.besucher_status)); tr.appendChild(createCell(formatNumber(row.ausstellungsflaeche_m2))); tr.appendChild(createCell(formatPrice(row.ticketpreis_we_eur))); tr.appendChild(createCell(formatPrice(row.ticketpreis_unterderwoche_eur))); tr.appendChild(createCell(row.notiz)); const sourceCell = document.createElement('td'); if (row.quelle_homepage) { const link = document.createElement('a'); link.href = row.quelle_homepage; link.target = '_blank'; link.rel = 'noopener'; link.textContent = row.quelle_homepage; sourceCell.appendChild(link); } else { sourceCell.textContent = 'k.A.'; } tr.appendChild(sourceCell); tableBody.appendChild(tr); }); } const activeSortButton = sortButtons.find((button) => button.dataset.tradeSort === sortKey); const sortLabel = activeSortButton?.dataset.baseLabel || sortKey; meta.textContent = `${sorted.length} von ${TRADE_FAIRS.length} Messen | Sortierung: ${sortLabel} (${sortDirection === 'asc' ? 'aufsteigend' : 'absteigend'})`; } sortButtons.forEach((button) => { const label = button.textContent.trim(); button.dataset.baseLabel = label; button.addEventListener('click', () => { const key = button.dataset.tradeSort; if (!key) { return; } if (sortKey === key) { sortDirection = sortDirection === 'asc' ? 'desc' : 'asc'; } else { sortKey = key; sortDirection = key === 'rang' ? 'asc' : 'desc'; } sortButtons.forEach((btn) => { const baseLabel = btn.dataset.baseLabel || btn.textContent; btn.textContent = baseLabel; }); updateSortButtonState(); render(); }); }); searchInput.addEventListener('input', () => { searchTerm = searchInput.value.trim().toLocaleLowerCase('de-DE'); render(); }); updateSortButtonState(); render(); })();