Files
PostTracker/web/trade-fairs.js

593 lines
19 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]'));
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();
})();