880 lines
27 KiB
JavaScript
880 lines
27 KiB
JavaScript
(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]'));
|
|
const SORT_STATE_KEY = 'fb_trade_fairs_sort_v1';
|
|
|
|
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 2025',
|
|
ausstellungsflaeche_m2: 420107,
|
|
ticketpreis_we_eur: 38,
|
|
ticketpreis_unterderwoche_eur: 38,
|
|
notiz: 'Besucher laut AUMA. Tagesticket aus zuletzt verfuegbarem Preisstand (TradeFairDates, 2025).',
|
|
quelle_homepage: 'https://bauma.de'
|
|
},
|
|
{
|
|
rang: 2,
|
|
messe: 'IAA MOBILITY',
|
|
thema: 'Mobilitaet, Auto, Tech, Open Space',
|
|
stadt: 'München',
|
|
bundesland: 'Bayern',
|
|
termin_start: '2027-09-08',
|
|
termin_ende: '2027-09-12',
|
|
besucher: 500000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veranstalterangabe 2025 (>500.000)',
|
|
ausstellungsflaeche_m2: null,
|
|
ticketpreis_we_eur: 39,
|
|
ticketpreis_unterderwoche_eur: 29,
|
|
notiz: 'Open Space teils frei; Ticketpreise laut IAA-Ticketseite (ab EUR 29, Family Pass ab EUR 39).',
|
|
quelle_homepage: 'https://www.iaa-mobility.com'
|
|
},
|
|
{
|
|
rang: 3,
|
|
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 2025',
|
|
ausstellungsflaeche_m2: 229886,
|
|
ticketpreis_we_eur: 29,
|
|
ticketpreis_unterderwoche_eur: 29,
|
|
notiz: 'Besucher laut AUMA. Ticketpreis laut Agritechnica-Ticketseite (Tagesticket EUR 29).',
|
|
quelle_homepage: 'https://www.agritechnica.com'
|
|
},
|
|
{
|
|
rang: 4,
|
|
messe: 'IdeenExpo',
|
|
thema: 'Technik, Naturwissenschaften, Erlebnis, Ausbildung',
|
|
stadt: 'Hannover',
|
|
bundesland: 'Niedersachsen',
|
|
termin_start: '2026-06-20',
|
|
termin_ende: '2026-06-28',
|
|
besucher: 430000,
|
|
besucher_jahr: 2024,
|
|
besucher_status: 'Veranstalter/Pressestand 2024',
|
|
ausstellungsflaeche_m2: null,
|
|
ticketpreis_we_eur: 0,
|
|
ticketpreis_unterderwoche_eur: 0,
|
|
notiz: 'Eintritt frei (IdeenExpo). Besucherzahl aus dem letzten veroeffentlichten Durchgang.',
|
|
quelle_homepage: 'https://www.ideenexpo.de'
|
|
},
|
|
{
|
|
rang: 5,
|
|
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: 357000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veranstalter/Branchenpresse 2025',
|
|
ausstellungsflaeche_m2: 73515,
|
|
ticketpreis_we_eur: 40,
|
|
ticketpreis_unterderwoche_eur: 30.5,
|
|
notiz: 'Wochenende hoeher als Werktag (Preisstand 2025 aus Gaming-/Ticketberichten).',
|
|
quelle_homepage: 'https://www.gamescom.global/en'
|
|
},
|
|
{
|
|
rang: 6,
|
|
messe: 'Grüne Woche',
|
|
thema: 'Ernaehrung, Landwirtschaft, Garten, Genuss',
|
|
stadt: 'Berlin',
|
|
bundesland: 'Berlin',
|
|
termin_start: '2027-01-15',
|
|
termin_ende: '2027-01-24',
|
|
besucher: 307000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veranstalterangabe 2025',
|
|
ausstellungsflaeche_m2: 42500,
|
|
ticketpreis_we_eur: 16,
|
|
ticketpreis_unterderwoche_eur: 16,
|
|
notiz: 'Tagesticket Erwachsene laut Gruene-Woche-Ticketseite (Preisstand 2025).',
|
|
quelle_homepage: 'https://www.gruenewoche.de'
|
|
},
|
|
{
|
|
rang: 7,
|
|
messe: 'CARAVAN SALON DUESSELDORF',
|
|
thema: 'Reisemobile, Caravans, Camping, Touristik',
|
|
stadt: 'Düsseldorf',
|
|
bundesland: 'Nordrhein-Westfalen',
|
|
termin_start: '2026-08-28',
|
|
termin_ende: '2026-09-06',
|
|
besucher: 269000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veranstalter/Branchenpresse 2025',
|
|
ausstellungsflaeche_m2: 121439,
|
|
ticketpreis_we_eur: 20,
|
|
ticketpreis_unterderwoche_eur: 18,
|
|
notiz: 'Preisstand zuletzt verfuegbarer Ticketinfos (Weekend hoeher als Weekday).',
|
|
quelle_homepage: 'https://www.caravan-salon.de'
|
|
},
|
|
{
|
|
rang: 8,
|
|
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 2025',
|
|
ausstellungsflaeche_m2: 52769,
|
|
ticketpreis_we_eur: 10,
|
|
ticketpreis_unterderwoche_eur: 10,
|
|
notiz: 'Tagesticket Erwachsene an der Kasse EUR 10 (VVK guenstiger).',
|
|
quelle_homepage: 'https://www.maimarkt.de'
|
|
},
|
|
{
|
|
rang: 9,
|
|
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 2025',
|
|
ausstellungsflaeche_m2: 75587,
|
|
ticketpreis_we_eur: 18,
|
|
ticketpreis_unterderwoche_eur: 15,
|
|
notiz: 'Preisstaffel laut CMT-Partner-/Infoseiten (Wochenende teurer).',
|
|
quelle_homepage: 'https://www.messe-stuttgart.de/cmt'
|
|
},
|
|
{
|
|
rang: 10,
|
|
messe: 'Frankfurter Buchmesse',
|
|
thema: 'Buecher, Kultur, Medien, Publishing',
|
|
stadt: 'Frankfurt am Main',
|
|
bundesland: 'Hessen',
|
|
termin_start: '2026-10-07',
|
|
termin_ende: '2026-10-11',
|
|
besucher: 238000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veranstalter/Branchenpresse 2025',
|
|
ausstellungsflaeche_m2: null,
|
|
ticketpreis_we_eur: 35,
|
|
ticketpreis_unterderwoche_eur: 30,
|
|
notiz: 'Preisniveau aus zuletzt veroeffentlichtem Ticketstand (Publikumstage teils teurer).',
|
|
quelle_homepage: 'https://www.buchmesse.de'
|
|
},
|
|
{
|
|
rang: 11,
|
|
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: 222819,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veranstalter/Pressestand 2025',
|
|
ausstellungsflaeche_m2: 20788,
|
|
ticketpreis_we_eur: 35,
|
|
ticketpreis_unterderwoche_eur: 28,
|
|
notiz: 'Ticketpreise laut offizieller Leipzig-Messe-Preisliste 2026 (Sa am hoechsten).',
|
|
quelle_homepage: 'https://www.leipziger-buchmesse.de'
|
|
},
|
|
{
|
|
rang: 12,
|
|
messe: 'SPIEL Essen',
|
|
thema: 'Brettspiele, Tabletop, Family Entertainment',
|
|
stadt: 'Essen',
|
|
bundesland: 'Nordrhein-Westfalen',
|
|
termin_start: '2026-10-22',
|
|
termin_ende: '2026-10-25',
|
|
besucher: 220000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veranstalterangabe 2025',
|
|
ausstellungsflaeche_m2: null,
|
|
ticketpreis_we_eur: 23.5,
|
|
ticketpreis_unterderwoche_eur: 23.5,
|
|
notiz: 'Tagesticket Erwachsene laut Ticketberichten 2025 (einheitlicher Preis).',
|
|
quelle_homepage: 'https://www.spiel-essen.de'
|
|
},
|
|
{
|
|
rang: 13,
|
|
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 2024 (letzter verfuegbarer Wert)',
|
|
ausstellungsflaeche_m2: 33781,
|
|
ticketpreis_we_eur: 20,
|
|
ticketpreis_unterderwoche_eur: 20,
|
|
notiz: 'Tagesticket aus zuletzt publiziertem Ticketstand.',
|
|
quelle_homepage: 'https://www.essen-motorshow.de'
|
|
},
|
|
{
|
|
rang: 14,
|
|
messe: 'boot Duesseldorf',
|
|
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 2025',
|
|
ausstellungsflaeche_m2: 94867,
|
|
ticketpreis_we_eur: 19,
|
|
ticketpreis_unterderwoche_eur: 19,
|
|
notiz: 'Preis aus offiziellem Ticket-/Club-Stand (2-fuer-1 Aktion auf Basis Tagesticket).',
|
|
quelle_homepage: 'https://www.boot.de'
|
|
},
|
|
{
|
|
rang: 15,
|
|
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 2024 (letzter verfuegbarer Wert)',
|
|
ausstellungsflaeche_m2: 107546,
|
|
ticketpreis_we_eur: 19.5,
|
|
ticketpreis_unterderwoche_eur: 19.5,
|
|
notiz: 'Preisniveau aus Ticketberichten zum letzten verfuegbaren IFA-Durchgang.',
|
|
quelle_homepage: 'https://www.ifa-berlin.com'
|
|
},
|
|
{
|
|
rang: 16,
|
|
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 2025',
|
|
ausstellungsflaeche_m2: 56904,
|
|
ticketpreis_we_eur: 44,
|
|
ticketpreis_unterderwoche_eur: 44,
|
|
notiz: 'Tagesticket laut FIBO-Ticketseite (ab EUR 44).',
|
|
quelle_homepage: 'https://www.fibo.com'
|
|
},
|
|
{
|
|
rang: 17,
|
|
messe: 'IAA TRANSPORTATION',
|
|
thema: 'Nutzfahrzeuge, Logistik, Transporttechnologie',
|
|
stadt: 'Hannover',
|
|
bundesland: 'Niedersachsen',
|
|
termin_start: '2026-09-15',
|
|
termin_ende: '2026-09-20',
|
|
besucher: 145000,
|
|
besucher_jahr: 2024,
|
|
besucher_status: 'Veranstalterangabe 2024',
|
|
ausstellungsflaeche_m2: null,
|
|
ticketpreis_we_eur: 20,
|
|
ticketpreis_unterderwoche_eur: 20,
|
|
notiz: 'Ticketpreis laut offizieller IAA-Transportation-Ticketseite (ab EUR 20).',
|
|
quelle_homepage: 'https://www.iaa-transportation.com'
|
|
},
|
|
{
|
|
rang: 18,
|
|
messe: 'Anuga',
|
|
thema: 'Lebensmittel und Getraenke',
|
|
stadt: 'Köln',
|
|
bundesland: 'Nordrhein-Westfalen',
|
|
termin_start: '2027-10-09',
|
|
termin_ende: '2027-10-13',
|
|
besucher: 143432,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'AUMA 2025',
|
|
ausstellungsflaeche_m2: 157545,
|
|
ticketpreis_we_eur: 80,
|
|
ticketpreis_unterderwoche_eur: 80,
|
|
notiz: 'Tagesticket laut TradeFairDates (Stand zuletzt verfuegbarer Preis).',
|
|
quelle_homepage: 'https://www.anuga.com'
|
|
},
|
|
{
|
|
rang: 19,
|
|
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 2025',
|
|
ausstellungsflaeche_m2: 101699,
|
|
ticketpreis_we_eur: null,
|
|
ticketpreis_unterderwoche_eur: 39,
|
|
notiz: 'Messe liegt auf Werktagen; Tagesticket laut TradeFairDates EUR 39.',
|
|
quelle_homepage: 'https://www.hannovermesse.de'
|
|
},
|
|
{
|
|
rang: 20,
|
|
messe: 'CONSUMENTA',
|
|
thema: 'Publikumsmesse: Haushalt, Freizeit, Bauen, Genuss',
|
|
stadt: 'Nürnberg',
|
|
bundesland: 'Bayern',
|
|
termin_start: '2026-10-31',
|
|
termin_ende: '2026-11-08',
|
|
besucher: 123000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veroeffentlichter Wert 2025',
|
|
ausstellungsflaeche_m2: 30448,
|
|
ticketpreis_we_eur: 16,
|
|
ticketpreis_unterderwoche_eur: 16,
|
|
notiz: 'Aktionstags-Preisstand vorhanden; regulaere Ticketpreise fuer 2026 noch im Rollout.',
|
|
quelle_homepage: 'https://www.consumenta.de'
|
|
},
|
|
{
|
|
rang: 21,
|
|
messe: 'f.re.e München',
|
|
thema: 'Reisen, Freizeit, Caravaning, Outdoor',
|
|
stadt: 'München',
|
|
bundesland: 'Bayern',
|
|
termin_start: '2026-02-18',
|
|
termin_ende: '2026-02-22',
|
|
besucher: 120000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veroeffentlichter Wert 2025',
|
|
ausstellungsflaeche_m2: null,
|
|
ticketpreis_we_eur: 17,
|
|
ticketpreis_unterderwoche_eur: 14,
|
|
notiz: 'Preisniveau aus zuletzt veroeffentlichtem Ticketstand (Wochenende hoeher).',
|
|
quelle_homepage: 'https://free-muenchen.de'
|
|
},
|
|
{
|
|
rang: 22,
|
|
messe: 'infa',
|
|
thema: 'Publikumsmesse: Lifestyle, Haushalt, Genuss',
|
|
stadt: 'Hannover',
|
|
bundesland: 'Niedersachsen',
|
|
termin_start: '2026-10-10',
|
|
termin_ende: '2026-10-18',
|
|
besucher: 112228,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veroeffentlichter Wert 2025',
|
|
ausstellungsflaeche_m2: 16423,
|
|
ticketpreis_we_eur: 15,
|
|
ticketpreis_unterderwoche_eur: 15,
|
|
notiz: 'Tagesticket laut zuletzt verfuegbarem Preisstand.',
|
|
quelle_homepage: 'https://www.infa.de'
|
|
},
|
|
{
|
|
rang: 23,
|
|
messe: 'ITB Berlin',
|
|
thema: 'Reiseindustrie (B2B/Fachbesucher)',
|
|
stadt: 'Berlin',
|
|
bundesland: 'Berlin',
|
|
termin_start: '2026-03-03',
|
|
termin_ende: '2026-03-05',
|
|
besucher: 100000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veroeffentlichter Wert 2025',
|
|
ausstellungsflaeche_m2: 78892,
|
|
ticketpreis_we_eur: null,
|
|
ticketpreis_unterderwoche_eur: 65,
|
|
notiz: 'B2B-Fachmesse ohne Wochenend-Tag. Ticketpreis laut offizieller ITB-Ticketseite.',
|
|
quelle_homepage: 'https://www.itb.com'
|
|
},
|
|
{
|
|
rang: 24,
|
|
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 2024 (letzter verfuegbarer Wert)',
|
|
ausstellungsflaeche_m2: 32008,
|
|
ticketpreis_we_eur: 22,
|
|
ticketpreis_unterderwoche_eur: 22,
|
|
notiz: 'Tagesticket laut ILA-Besucherinfo (EUR 22, Kinder frei).',
|
|
quelle_homepage: 'https://www.ila-berlin.de'
|
|
},
|
|
{
|
|
rang: 25,
|
|
messe: 'Heim+Handwerk',
|
|
thema: 'Wohnen, Handwerk, Lifestyle',
|
|
stadt: 'München',
|
|
bundesland: 'Bayern',
|
|
termin_start: '2026-11-25',
|
|
termin_ende: '2026-11-29',
|
|
besucher: 90000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veroeffentlichter Wert 2025',
|
|
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.',
|
|
quelle_homepage: 'https://www.heim-handwerk.de'
|
|
},
|
|
{
|
|
rang: 26,
|
|
messe: 'offerta',
|
|
thema: 'Einkaufs- und Erlebnismesse fuer 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 2025',
|
|
ausstellungsflaeche_m2: 16242,
|
|
ticketpreis_we_eur: 10,
|
|
ticketpreis_unterderwoche_eur: 10,
|
|
notiz: 'Preisniveau aus regional veroeffentlichtem Ticketstand (offerta Karlsruhe).',
|
|
quelle_homepage: 'https://www.offerta.info'
|
|
},
|
|
{
|
|
rang: 27,
|
|
messe: 'Reise + Camping Essen',
|
|
thema: 'Reisen, Camping, Fahrrad, Outdoor',
|
|
stadt: 'Essen',
|
|
bundesland: 'Nordrhein-Westfalen',
|
|
termin_start: '2026-02-25',
|
|
termin_ende: '2026-03-01',
|
|
besucher: 80000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veroeffentlichter Wert 2025',
|
|
ausstellungsflaeche_m2: null,
|
|
ticketpreis_we_eur: 12,
|
|
ticketpreis_unterderwoche_eur: 12,
|
|
notiz: 'Online-Tagesticket laut Messe-Essen-Presse (EUR 12).',
|
|
quelle_homepage: 'https://www.reise-camping.de'
|
|
},
|
|
{
|
|
rang: 28,
|
|
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 2025',
|
|
ausstellungsflaeche_m2: 46496,
|
|
ticketpreis_we_eur: 25,
|
|
ticketpreis_unterderwoche_eur: 25,
|
|
notiz: 'Tagesticket laut offizieller Retro-Classics-Preisliste.',
|
|
quelle_homepage: 'https://www.retro-classics.de'
|
|
},
|
|
{
|
|
rang: 29,
|
|
messe: 'Freizeit Messe Nürnberg',
|
|
thema: 'Freizeit, Touristik, Garten',
|
|
stadt: 'Nürnberg',
|
|
bundesland: 'Bayern',
|
|
termin_start: '2026-03-04',
|
|
termin_ende: '2026-03-08',
|
|
besucher: 71000,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veroeffentlichter Wert 2025',
|
|
ausstellungsflaeche_m2: null,
|
|
ticketpreis_we_eur: 16,
|
|
ticketpreis_unterderwoche_eur: 15,
|
|
notiz: 'Ticketpreise laut offizieller Freizeit-Messe-Preistabelle 2026.',
|
|
quelle_homepage: 'https://www.freizeitmesse.de'
|
|
},
|
|
{
|
|
rang: 30,
|
|
messe: 'Thueringen Ausstellung',
|
|
thema: 'Haus, Bau, Modernisieren, Lifestyle',
|
|
stadt: 'Erfurt',
|
|
bundesland: 'Thüringen',
|
|
termin_start: '2026-02-28',
|
|
termin_ende: '2026-03-08',
|
|
besucher: 69988,
|
|
besucher_jahr: 2025,
|
|
besucher_status: 'Veroeffentlichter Wert 2025',
|
|
ausstellungsflaeche_m2: null,
|
|
ticketpreis_we_eur: 14,
|
|
ticketpreis_unterderwoche_eur: 14,
|
|
notiz: 'Tagesticket Erwachsene laut offizieller Thueringen-Ausstellung-Preisliste.',
|
|
quelle_homepage: 'https://thueringen-ausstellung.de'
|
|
}
|
|
];
|
|
|
|
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 normalizeSortState(rawState) {
|
|
if (!rawState || typeof rawState !== 'object') {
|
|
return null;
|
|
}
|
|
|
|
const key = rawState.sortKey;
|
|
const direction = rawState.sortDirection;
|
|
if (!Object.prototype.hasOwnProperty.call(SORT_TYPES, key)) {
|
|
return null;
|
|
}
|
|
if (direction !== 'asc' && direction !== 'desc') {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
sortKey: key,
|
|
sortDirection: direction
|
|
};
|
|
}
|
|
|
|
function loadSortState() {
|
|
try {
|
|
const raw = localStorage.getItem(SORT_STATE_KEY);
|
|
if (!raw) {
|
|
return;
|
|
}
|
|
const parsed = JSON.parse(raw);
|
|
const normalized = normalizeSortState(parsed);
|
|
if (!normalized) {
|
|
return;
|
|
}
|
|
sortKey = normalized.sortKey;
|
|
sortDirection = normalized.sortDirection;
|
|
} catch (_error) {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
function persistSortState() {
|
|
try {
|
|
localStorage.setItem(SORT_STATE_KEY, JSON.stringify({
|
|
sortKey,
|
|
sortDirection
|
|
}));
|
|
} catch (_error) {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
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 buildTradeFairQueries(row) {
|
|
const base = String(row.messe || '').trim();
|
|
const city = String(row.stadt || '').trim();
|
|
const topic = String(row.thema || '').split(',')[0].trim();
|
|
|
|
return [...new Set([
|
|
base,
|
|
[base, city].filter(Boolean).join(' '),
|
|
[base, topic].filter(Boolean).join(' ')
|
|
].map((entry) => entry.trim()).filter(Boolean))];
|
|
}
|
|
|
|
function openQueryFallback(query) {
|
|
const trimmed = String(query || '').trim();
|
|
if (!trimmed) {
|
|
return 0;
|
|
}
|
|
|
|
if (typeof window.buildBookmarkSearchUrl === 'function') {
|
|
const built = window.buildBookmarkSearchUrl(trimmed);
|
|
if (built) {
|
|
window.open(built, '_blank', 'noopener');
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
const url = new URL('https://www.facebook.com/search/posts');
|
|
url.searchParams.set('q', trimmed);
|
|
window.open(url.toString(), '_blank', 'noopener');
|
|
return 1;
|
|
}
|
|
|
|
function openTradeFairSearch(row) {
|
|
const queries = buildTradeFairQueries(row);
|
|
if (!queries.length) {
|
|
return;
|
|
}
|
|
|
|
if (typeof window.openBookmarkQueries === 'function') {
|
|
const opened = window.openBookmarkQueries(queries);
|
|
if (opened > 0) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
queries.forEach((query) => {
|
|
openQueryFallback(query);
|
|
});
|
|
}
|
|
|
|
function createMesseCell(row) {
|
|
const td = document.createElement('td');
|
|
const button = document.createElement('button');
|
|
button.type = 'button';
|
|
button.className = 'bookmark-subpage__messe-link';
|
|
button.textContent = row.messe || 'k.A.';
|
|
button.title = 'Als Bookmark-Suche oeffnen (3 Tabs)';
|
|
button.addEventListener('click', () => {
|
|
openTradeFairSearch(row);
|
|
});
|
|
td.appendChild(button);
|
|
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(createMesseCell(row));
|
|
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';
|
|
}
|
|
|
|
persistSortState();
|
|
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();
|
|
});
|
|
|
|
loadSortState();
|
|
updateSortButtonState();
|
|
render();
|
|
})();
|