Add draggable trade fair columns with persisted order and last-searched column
This commit is contained in:
@@ -1555,6 +1555,7 @@
|
|||||||
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="tage_bis_start">Tage bis Start</button></th>
|
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="tage_bis_start">Tage bis Start</button></th>
|
||||||
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="rang">Rang</button></th>
|
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="rang">Rang</button></th>
|
||||||
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="messe">Messe</button></th>
|
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="messe">Messe</button></th>
|
||||||
|
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="zuletzt_gesucht_am">Zuletzt gesucht am</button></th>
|
||||||
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="thema">Thema</button></th>
|
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="thema">Thema</button></th>
|
||||||
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="stadt">Stadt</button></th>
|
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="stadt">Stadt</button></th>
|
||||||
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="bundesland">Bundesland</button></th>
|
<th><button type="button" class="bookmark-subpage__sort" data-trade-sort="bundesland">Bundesland</button></th>
|
||||||
|
|||||||
@@ -1883,6 +1883,7 @@ h1 {
|
|||||||
.bookmark-subpage__table th {
|
.bookmark-subpage__table th {
|
||||||
background: #f3f4f6;
|
background: #f3f4f6;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bookmark-subpage__sort {
|
.bookmark-subpage__sort {
|
||||||
@@ -1905,6 +1906,32 @@ h1 {
|
|||||||
color: #0f4bb8;
|
color: #0f4bb8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bookmark-subpage__table th[draggable="true"] {
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-subpage__table th.is-dragging {
|
||||||
|
opacity: 0.55;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-subpage__table th.is-drop-before::before,
|
||||||
|
.bookmark-subpage__table th.is-drop-after::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
bottom: 3px;
|
||||||
|
width: 2px;
|
||||||
|
background: #0f4bb8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-subpage__table th.is-drop-before::before {
|
||||||
|
left: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bookmark-subpage__table th.is-drop-after::after {
|
||||||
|
right: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
.bookmark-subpage__messe-link {
|
.bookmark-subpage__messe-link {
|
||||||
border: none;
|
border: none;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@@ -1921,11 +1948,18 @@ h1 {
|
|||||||
color: #1d4ed8;
|
color: #1d4ed8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bookmark-subpage__table td:nth-child(4),
|
.bookmark-subpage__table th[data-column-key="thema"],
|
||||||
.bookmark-subpage__table td:nth-child(15) {
|
.bookmark-subpage__table td[data-column="thema"],
|
||||||
|
.bookmark-subpage__table th[data-column-key="notiz"],
|
||||||
|
.bookmark-subpage__table td[data-column="notiz"] {
|
||||||
min-width: 320px;
|
min-width: 320px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bookmark-subpage__table th[data-column-key="zuletzt_gesucht_am"],
|
||||||
|
.bookmark-subpage__table td[data-column="zuletzt_gesucht_am"] {
|
||||||
|
min-width: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
.bookmark-subpage__table a {
|
.bookmark-subpage__table a {
|
||||||
color: #1d4ed8;
|
color: #1d4ed8;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,48 @@
|
|||||||
const searchInput = document.getElementById('tradeFairSearchInput');
|
const searchInput = document.getElementById('tradeFairSearchInput');
|
||||||
const meta = document.getElementById('tradeFairMeta');
|
const meta = document.getElementById('tradeFairMeta');
|
||||||
const sortButtons = Array.from(document.querySelectorAll('.bookmark-subpage__sort[data-trade-sort]'));
|
const sortButtons = Array.from(document.querySelectorAll('.bookmark-subpage__sort[data-trade-sort]'));
|
||||||
|
const table = tableBody ? tableBody.closest('table') : null;
|
||||||
|
const headerRow = table ? table.querySelector('thead tr') : null;
|
||||||
const SORT_STATE_KEY = 'fb_trade_fairs_sort_v1';
|
const SORT_STATE_KEY = 'fb_trade_fairs_sort_v1';
|
||||||
|
const COLUMN_ORDER_STATE_KEY = 'fb_trade_fairs_columns_v1';
|
||||||
|
const LAST_OPEN_STATE_KEY = 'fb_trade_fairs_last_open_v1';
|
||||||
|
const DEFAULT_COLUMN_ORDER = [
|
||||||
|
'tage_bis_start',
|
||||||
|
'rang',
|
||||||
|
'messe',
|
||||||
|
'zuletzt_gesucht_am',
|
||||||
|
'thema',
|
||||||
|
'stadt',
|
||||||
|
'bundesland',
|
||||||
|
'termin_start',
|
||||||
|
'termin_ende',
|
||||||
|
'besucher',
|
||||||
|
'besucher_jahr',
|
||||||
|
'besucher_status',
|
||||||
|
'ausstellungsflaeche_m2',
|
||||||
|
'ticketpreis_we_eur',
|
||||||
|
'ticketpreis_unterderwoche_eur',
|
||||||
|
'notiz',
|
||||||
|
'quelle_homepage'
|
||||||
|
];
|
||||||
|
|
||||||
if (!tableBody || !searchInput || !meta || !sortButtons.length) {
|
if (!tableBody || !searchInput || !meta || !sortButtons.length || !table || !headerRow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const headerCellsByKey = new Map();
|
||||||
|
sortButtons.forEach((button) => {
|
||||||
|
const key = button.dataset.tradeSort;
|
||||||
|
const th = button.closest('th');
|
||||||
|
if (!key || !th) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
th.dataset.columnKey = key;
|
||||||
|
th.draggable = true;
|
||||||
|
headerCellsByKey.set(key, th);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (headerCellsByKey.size !== DEFAULT_COLUMN_ORDER.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,6 +565,7 @@
|
|||||||
tage_bis_start: 'number',
|
tage_bis_start: 'number',
|
||||||
rang: 'number',
|
rang: 'number',
|
||||||
messe: 'text',
|
messe: 'text',
|
||||||
|
zuletzt_gesucht_am: 'date',
|
||||||
thema: 'text',
|
thema: 'text',
|
||||||
stadt: 'text',
|
stadt: 'text',
|
||||||
bundesland: 'text',
|
bundesland: 'text',
|
||||||
@@ -544,6 +584,8 @@
|
|||||||
let sortKey = 'rang';
|
let sortKey = 'rang';
|
||||||
let sortDirection = 'asc';
|
let sortDirection = 'asc';
|
||||||
let searchTerm = '';
|
let searchTerm = '';
|
||||||
|
let draggedColumnKey = null;
|
||||||
|
let lastOpenedByTradeFair = {};
|
||||||
|
|
||||||
function toNumber(value) {
|
function toNumber(value) {
|
||||||
if (typeof value === 'number' && Number.isFinite(value)) {
|
if (typeof value === 'number' && Number.isFinite(value)) {
|
||||||
@@ -582,7 +624,8 @@
|
|||||||
function normalizeRow(row) {
|
function normalizeRow(row) {
|
||||||
return {
|
return {
|
||||||
...row,
|
...row,
|
||||||
tage_bis_start: getDaysUntil(row.termin_start)
|
tage_bis_start: getDaysUntil(row.termin_start),
|
||||||
|
zuletzt_gesucht_am: lastOpenedByTradeFair[getTradeFairOpenKey(row)] || null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -676,6 +719,145 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeColumnOrder(rawOrder) {
|
||||||
|
if (!Array.isArray(rawOrder) || rawOrder.length !== DEFAULT_COLUMN_ORDER.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filtered = rawOrder.filter((key) => DEFAULT_COLUMN_ORDER.includes(key));
|
||||||
|
if (filtered.length !== DEFAULT_COLUMN_ORDER.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (new Set(filtered).size !== DEFAULT_COLUMN_ORDER.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColumnOrderFromHeader() {
|
||||||
|
const keys = Array.from(headerRow.children)
|
||||||
|
.map((th) => th.dataset.columnKey)
|
||||||
|
.filter((key) => DEFAULT_COLUMN_ORDER.includes(key));
|
||||||
|
|
||||||
|
if (keys.length !== DEFAULT_COLUMN_ORDER.length) {
|
||||||
|
return [...DEFAULT_COLUMN_ORDER];
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyColumnOrder(order) {
|
||||||
|
order.forEach((key) => {
|
||||||
|
const th = headerCellsByKey.get(key);
|
||||||
|
if (th) {
|
||||||
|
headerRow.appendChild(th);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadColumnOrder() {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(COLUMN_ORDER_STATE_KEY);
|
||||||
|
if (!raw) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
const normalized = normalizeColumnOrder(parsed);
|
||||||
|
if (!normalized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
applyColumnOrder(normalized);
|
||||||
|
} catch (_error) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistColumnOrder() {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(COLUMN_ORDER_STATE_KEY, JSON.stringify(getColumnOrderFromHeader()));
|
||||||
|
} catch (_error) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeLastOpenedState(rawState) {
|
||||||
|
if (!rawState || typeof rawState !== 'object' || Array.isArray(rawState)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const normalized = {};
|
||||||
|
Object.entries(rawState).forEach(([key, value]) => {
|
||||||
|
if (typeof key !== 'string' || typeof value !== 'string') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const parsed = new Date(value);
|
||||||
|
if (Number.isNaN(parsed.getTime())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
normalized[key] = parsed.toISOString();
|
||||||
|
});
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadLastOpenedState() {
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(LAST_OPEN_STATE_KEY);
|
||||||
|
if (!raw) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return normalizeLastOpenedState(JSON.parse(raw));
|
||||||
|
} catch (_error) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistLastOpenedState() {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(LAST_OPEN_STATE_KEY, JSON.stringify(lastOpenedByTradeFair));
|
||||||
|
} catch (_error) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTradeFairOpenKey(row) {
|
||||||
|
const messe = String(row.messe || '').trim().toLocaleLowerCase('de-DE');
|
||||||
|
const city = String(row.stadt || '').trim().toLocaleLowerCase('de-DE');
|
||||||
|
return `${messe}|${city}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTradeFairLastOpened(row) {
|
||||||
|
const key = getTradeFairOpenKey(row);
|
||||||
|
if (!key) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const nowIso = new Date().toISOString();
|
||||||
|
lastOpenedByTradeFair[key] = nowIso;
|
||||||
|
persistLastOpenedState();
|
||||||
|
return nowIso;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDateTime(iso) {
|
||||||
|
const parsed = new Date(iso);
|
||||||
|
if (Number.isNaN(parsed.getTime())) {
|
||||||
|
return 'k.A.';
|
||||||
|
}
|
||||||
|
return parsed.toLocaleString('de-DE');
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatLastSearched(iso) {
|
||||||
|
if (!iso) {
|
||||||
|
return 'noch nie';
|
||||||
|
}
|
||||||
|
return formatDateTime(iso);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTradeFairHoverTitle(row) {
|
||||||
|
const key = getTradeFairOpenKey(row);
|
||||||
|
const lastOpened = key ? lastOpenedByTradeFair[key] : '';
|
||||||
|
const suffix = lastOpened ? formatDateTime(lastOpened) : 'noch nie';
|
||||||
|
return `Als Bookmark-Suche oeffnen (3 Tabs)\\nZuletzt geoeffnet: ${suffix}`;
|
||||||
|
}
|
||||||
|
|
||||||
function loadSortState() {
|
function loadSortState() {
|
||||||
try {
|
try {
|
||||||
const raw = localStorage.getItem(SORT_STATE_KEY);
|
const raw = localStorage.getItem(SORT_STATE_KEY);
|
||||||
@@ -716,8 +898,102 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createCell(content) {
|
function clearDropMarkers() {
|
||||||
|
Array.from(headerRow.children).forEach((th) => {
|
||||||
|
if (th.dataset.columnKey !== draggedColumnKey) {
|
||||||
|
th.classList.remove('is-dragging');
|
||||||
|
}
|
||||||
|
th.classList.remove('is-drop-before', 'is-drop-after');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupColumnDragAndDrop() {
|
||||||
|
Array.from(headerCellsByKey.values()).forEach((th) => {
|
||||||
|
th.addEventListener('dragstart', (event) => {
|
||||||
|
const key = th.dataset.columnKey;
|
||||||
|
if (!key) {
|
||||||
|
event.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
draggedColumnKey = key;
|
||||||
|
clearDropMarkers();
|
||||||
|
th.classList.add('is-dragging');
|
||||||
|
if (event.dataTransfer) {
|
||||||
|
event.dataTransfer.effectAllowed = 'move';
|
||||||
|
try {
|
||||||
|
event.dataTransfer.setData('text/plain', key);
|
||||||
|
} catch (_error) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
th.addEventListener('dragover', (event) => {
|
||||||
|
if (!draggedColumnKey || th.dataset.columnKey === draggedColumnKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
clearDropMarkers();
|
||||||
|
const rect = th.getBoundingClientRect();
|
||||||
|
const insertAfter = event.clientX >= rect.left + (rect.width / 2);
|
||||||
|
th.classList.toggle('is-drop-before', !insertAfter);
|
||||||
|
th.classList.toggle('is-drop-after', insertAfter);
|
||||||
|
if (event.dataTransfer) {
|
||||||
|
event.dataTransfer.dropEffect = 'move';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
th.addEventListener('dragleave', () => {
|
||||||
|
th.classList.remove('is-drop-before', 'is-drop-after');
|
||||||
|
});
|
||||||
|
|
||||||
|
th.addEventListener('drop', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const targetKey = th.dataset.columnKey;
|
||||||
|
const sourceKey = draggedColumnKey || (event.dataTransfer ? event.dataTransfer.getData('text/plain') : '');
|
||||||
|
|
||||||
|
if (!sourceKey || !targetKey || sourceKey === targetKey) {
|
||||||
|
draggedColumnKey = null;
|
||||||
|
clearDropMarkers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sourceTh = headerCellsByKey.get(sourceKey);
|
||||||
|
const targetTh = headerCellsByKey.get(targetKey);
|
||||||
|
if (!sourceTh || !targetTh) {
|
||||||
|
draggedColumnKey = null;
|
||||||
|
clearDropMarkers();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rect = targetTh.getBoundingClientRect();
|
||||||
|
const insertAfter = event.clientX >= rect.left + (rect.width / 2);
|
||||||
|
if (insertAfter) {
|
||||||
|
headerRow.insertBefore(sourceTh, targetTh.nextSibling);
|
||||||
|
} else {
|
||||||
|
headerRow.insertBefore(sourceTh, targetTh);
|
||||||
|
}
|
||||||
|
|
||||||
|
draggedColumnKey = null;
|
||||||
|
clearDropMarkers();
|
||||||
|
persistColumnOrder();
|
||||||
|
render();
|
||||||
|
});
|
||||||
|
|
||||||
|
th.addEventListener('dragend', () => {
|
||||||
|
draggedColumnKey = null;
|
||||||
|
clearDropMarkers();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCell(content, columnKey) {
|
||||||
const td = document.createElement('td');
|
const td = document.createElement('td');
|
||||||
|
if (columnKey) {
|
||||||
|
td.dataset.column = columnKey;
|
||||||
|
}
|
||||||
td.textContent = content;
|
td.textContent = content;
|
||||||
return td;
|
return td;
|
||||||
}
|
}
|
||||||
@@ -757,81 +1033,106 @@
|
|||||||
function openTradeFairSearch(row) {
|
function openTradeFairSearch(row) {
|
||||||
const queries = buildTradeFairQueries(row);
|
const queries = buildTradeFairQueries(row);
|
||||||
if (!queries.length) {
|
if (!queries.length) {
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let opened = 0;
|
||||||
if (typeof window.openBookmarkQueries === 'function') {
|
if (typeof window.openBookmarkQueries === 'function') {
|
||||||
const opened = window.openBookmarkQueries(queries);
|
opened = window.openBookmarkQueries(queries);
|
||||||
if (opened > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queries.forEach((query) => {
|
if (opened === 0) {
|
||||||
openQueryFallback(query);
|
queries.forEach((query) => {
|
||||||
});
|
opened += openQueryFallback(query);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opened > 0) {
|
||||||
|
setTradeFairLastOpened(row);
|
||||||
|
}
|
||||||
|
return opened;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMesseCell(row) {
|
function createMesseCell(row) {
|
||||||
const td = document.createElement('td');
|
const td = document.createElement('td');
|
||||||
|
td.dataset.column = 'messe';
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
button.type = 'button';
|
button.type = 'button';
|
||||||
button.className = 'bookmark-subpage__messe-link';
|
button.className = 'bookmark-subpage__messe-link';
|
||||||
button.textContent = row.messe || 'k.A.';
|
button.textContent = row.messe || 'k.A.';
|
||||||
button.title = 'Als Bookmark-Suche oeffnen (3 Tabs)';
|
button.title = getTradeFairHoverTitle(row);
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
openTradeFairSearch(row);
|
const opened = openTradeFairSearch(row);
|
||||||
|
if (opened > 0) {
|
||||||
|
button.title = getTradeFairHoverTitle(row);
|
||||||
|
render();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
td.appendChild(button);
|
td.appendChild(button);
|
||||||
return td;
|
return td;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createSourceCell(row) {
|
||||||
|
const sourceCell = document.createElement('td');
|
||||||
|
sourceCell.dataset.column = 'quelle_homepage';
|
||||||
|
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.';
|
||||||
|
}
|
||||||
|
return sourceCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createRowCells(row) {
|
||||||
|
return {
|
||||||
|
tage_bis_start: createCell(Number.isFinite(row.tage_bis_start) ? String(row.tage_bis_start) : 'k.A.', 'tage_bis_start'),
|
||||||
|
rang: createCell(String(row.rang), 'rang'),
|
||||||
|
messe: createMesseCell(row),
|
||||||
|
zuletzt_gesucht_am: createCell(formatLastSearched(row.zuletzt_gesucht_am), 'zuletzt_gesucht_am'),
|
||||||
|
thema: createCell(row.thema, 'thema'),
|
||||||
|
stadt: createCell(row.stadt, 'stadt'),
|
||||||
|
bundesland: createCell(row.bundesland, 'bundesland'),
|
||||||
|
termin_start: createCell(formatDate(row.termin_start), 'termin_start'),
|
||||||
|
termin_ende: createCell(formatDate(row.termin_ende), 'termin_ende'),
|
||||||
|
besucher: createCell(formatNumber(row.besucher), 'besucher'),
|
||||||
|
besucher_jahr: createCell(formatNumber(row.besucher_jahr), 'besucher_jahr'),
|
||||||
|
besucher_status: createCell(row.besucher_status, 'besucher_status'),
|
||||||
|
ausstellungsflaeche_m2: createCell(formatNumber(row.ausstellungsflaeche_m2), 'ausstellungsflaeche_m2'),
|
||||||
|
ticketpreis_we_eur: createCell(formatPrice(row.ticketpreis_we_eur), 'ticketpreis_we_eur'),
|
||||||
|
ticketpreis_unterderwoche_eur: createCell(formatPrice(row.ticketpreis_unterderwoche_eur), 'ticketpreis_unterderwoche_eur'),
|
||||||
|
notiz: createCell(row.notiz, 'notiz'),
|
||||||
|
quelle_homepage: createSourceCell(row)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
const normalizedRows = TRADE_FAIRS.map(normalizeRow);
|
const normalizedRows = TRADE_FAIRS.map(normalizeRow);
|
||||||
const filtered = normalizedRows.filter((row) => matchesSearch(row, searchTerm));
|
const filtered = normalizedRows.filter((row) => matchesSearch(row, searchTerm));
|
||||||
const sorted = sortRows(filtered);
|
const sorted = sortRows(filtered);
|
||||||
|
const columnOrder = getColumnOrderFromHeader();
|
||||||
|
|
||||||
tableBody.innerHTML = '';
|
tableBody.innerHTML = '';
|
||||||
|
|
||||||
if (!sorted.length) {
|
if (!sorted.length) {
|
||||||
const emptyRow = document.createElement('tr');
|
const emptyRow = document.createElement('tr');
|
||||||
const emptyCell = document.createElement('td');
|
const emptyCell = document.createElement('td');
|
||||||
emptyCell.colSpan = 16;
|
emptyCell.colSpan = columnOrder.length;
|
||||||
emptyCell.textContent = 'Keine Messe zum Suchbegriff gefunden.';
|
emptyCell.textContent = 'Keine Messe zum Suchbegriff gefunden.';
|
||||||
emptyRow.appendChild(emptyCell);
|
emptyRow.appendChild(emptyCell);
|
||||||
tableBody.appendChild(emptyRow);
|
tableBody.appendChild(emptyRow);
|
||||||
} else {
|
} else {
|
||||||
sorted.forEach((row) => {
|
sorted.forEach((row) => {
|
||||||
const tr = document.createElement('tr');
|
const tr = document.createElement('tr');
|
||||||
|
const rowCells = createRowCells(row);
|
||||||
tr.appendChild(createCell(Number.isFinite(row.tage_bis_start) ? String(row.tage_bis_start) : 'k.A.'));
|
columnOrder.forEach((columnKey) => {
|
||||||
tr.appendChild(createCell(String(row.rang)));
|
const cell = rowCells[columnKey] || createCell('k.A.', columnKey);
|
||||||
tr.appendChild(createMesseCell(row));
|
tr.appendChild(cell);
|
||||||
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);
|
tableBody.appendChild(tr);
|
||||||
});
|
});
|
||||||
@@ -873,6 +1174,9 @@
|
|||||||
render();
|
render();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
lastOpenedByTradeFair = loadLastOpenedState();
|
||||||
|
loadColumnOrder();
|
||||||
|
setupColumnDragAndDrop();
|
||||||
loadSortState();
|
loadSortState();
|
||||||
updateSortButtonState();
|
updateSortButtonState();
|
||||||
render();
|
render();
|
||||||
|
|||||||
Reference in New Issue
Block a user