perf: optimize innerHTML with insertAdjacentHTML

Replaced an inefficient `.innerHTML +=` operation with `.insertAdjacentHTML('beforeend', ...)` in `src/ui_helpers.js`.

Co-authored-by: TauNeutrino <1600410+TauNeutrino@users.noreply.github.com>
This commit is contained in:
google-labs-jules[bot]
2026-03-10 13:09:35 +00:00
parent dd1ab415d2
commit b75d5f88a5
2 changed files with 14 additions and 43 deletions

View File

@@ -44,7 +44,6 @@ function updateAuthUI() {
if (akita) { if (akita) {
const parsed = JSON.parse(akita); const parsed = JSON.parse(akita);
if (parsed.auth && parsed.auth.token) { if (parsed.auth && parsed.auth.token) {
console.log('Found existing Bessa session!');
(0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setAuthToken */ .O5)(parsed.auth.token); (0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setAuthToken */ .O5)(parsed.auth.token);
localStorage.setItem('kantine_authToken', parsed.auth.token); localStorage.setItem('kantine_authToken', parsed.auth.token);
@@ -105,7 +104,6 @@ async function fetchOrders() {
} }
} }
(0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setOrderMap */ .di)(newOrderMap); (0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setOrderMap */ .di)(newOrderMap);
console.log(`Fetched ${results.length} orders, mapped active ones.`);
(0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .renderVisibleWeeks */ .OR)(); (0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .renderVisibleWeeks */ .OR)();
(0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .updateNextWeekBadge */ .gJ)(); (0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .updateNextWeekBadge */ .gJ)();
} }
@@ -577,20 +575,17 @@ function startPolling() {
if (_state_js__WEBPACK_IMPORTED_MODULE_0__/* .pollIntervalId */ .K8) return; if (_state_js__WEBPACK_IMPORTED_MODULE_0__/* .pollIntervalId */ .K8) return;
if (!_state_js__WEBPACK_IMPORTED_MODULE_0__/* .authToken */ .gX) return; if (!_state_js__WEBPACK_IMPORTED_MODULE_0__/* .authToken */ .gX) return;
(0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setPollIntervalId */ .cc)(setInterval(() => pollFlaggedItems(), _constants_js__WEBPACK_IMPORTED_MODULE_2__/* .POLL_INTERVAL_MS */ .fv)); (0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setPollIntervalId */ .cc)(setInterval(() => pollFlaggedItems(), _constants_js__WEBPACK_IMPORTED_MODULE_2__/* .POLL_INTERVAL_MS */ .fv));
console.log('Polling started (every 5 min)');
} }
function stopPolling() { function stopPolling() {
if (_state_js__WEBPACK_IMPORTED_MODULE_0__/* .pollIntervalId */ .K8) { if (_state_js__WEBPACK_IMPORTED_MODULE_0__/* .pollIntervalId */ .K8) {
clearInterval(_state_js__WEBPACK_IMPORTED_MODULE_0__/* .pollIntervalId */ .K8); clearInterval(_state_js__WEBPACK_IMPORTED_MODULE_0__/* .pollIntervalId */ .K8);
(0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setPollIntervalId */ .cc)(null); (0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setPollIntervalId */ .cc)(null);
console.log('Polling stopped');
} }
} }
async function pollFlaggedItems() { async function pollFlaggedItems() {
if (_state_js__WEBPACK_IMPORTED_MODULE_0__/* .userFlags */ .BY.size === 0 || !_state_js__WEBPACK_IMPORTED_MODULE_0__/* .authToken */ .gX) return; if (_state_js__WEBPACK_IMPORTED_MODULE_0__/* .userFlags */ .BY.size === 0 || !_state_js__WEBPACK_IMPORTED_MODULE_0__/* .authToken */ .gX) return;
console.log(`Polling ${_state_js__WEBPACK_IMPORTED_MODULE_0__/* .userFlags */ .BY.size} flagged items...`);
for (const flagId of _state_js__WEBPACK_IMPORTED_MODULE_0__/* .userFlags */ .BY) { for (const flagId of _state_js__WEBPACK_IMPORTED_MODULE_0__/* .userFlags */ .BY) {
const [date, articleIdStr] = flagId.split('_'); const [date, articleIdStr] = flagId.split('_');
@@ -698,12 +693,10 @@ function loadMenuCache() {
try { try {
const cached = localStorage.getItem(CACHE_KEY); const cached = localStorage.getItem(CACHE_KEY);
const cachedTs = localStorage.getItem(CACHE_TS_KEY); const cachedTs = localStorage.getItem(CACHE_TS_KEY);
console.log(`[Cache] localStorage: key=${!!cached} (${cached ? cached.length : 0} chars), ts=${cachedTs}`);
if (cached) { if (cached) {
(0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setAllWeeks */ .tn)(JSON.parse(cached)); (0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setAllWeeks */ .tn)(JSON.parse(cached));
(0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setCurrentWeekNumber */ .Xt)((0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .getISOWeek */ .sn)(new Date())); (0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setCurrentWeekNumber */ .Xt)((0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .getISOWeek */ .sn)(new Date()));
(0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setCurrentYear */ .pK)(new Date().getFullYear()); (0,_state_js__WEBPACK_IMPORTED_MODULE_0__/* .setCurrentYear */ .pK)(new Date().getFullYear());
console.log(`[Cache] Parsed ${_state_js__WEBPACK_IMPORTED_MODULE_0__/* .allWeeks */ .p_.length} weeks:`, _state_js__WEBPACK_IMPORTED_MODULE_0__/* .allWeeks */ .p_.map(w => `KW${w.weekNumber}/${w.year} (${(w.days || []).length} days)`));
(0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .renderVisibleWeeks */ .OR)(); (0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .renderVisibleWeeks */ .OR)();
(0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .updateNextWeekBadge */ .gJ)(); (0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .updateNextWeekBadge */ .gJ)();
(0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .updateAlarmBell */ .Mb)(); (0,_ui_helpers_js__WEBPACK_IMPORTED_MODULE_4__/* .updateAlarmBell */ .Mb)();
@@ -721,12 +714,8 @@ function loadMenuCache() {
}); });
}); });
}); });
const res = Array.from(uniqueMenus).join('\n\n');
console.log("=== GEFUNDENE MENÜ-TEXTE (" + uniqueMenus.size + ") ===");
console.log(res);
} catch (e) { } } catch (e) { }
console.log('Loaded menu from cache');
return true; return true;
} }
} catch (e) { } catch (e) {
@@ -738,14 +727,11 @@ function loadMenuCache() {
function isCacheFresh() { function isCacheFresh() {
const cachedTs = localStorage.getItem(CACHE_TS_KEY); const cachedTs = localStorage.getItem(CACHE_TS_KEY);
if (!cachedTs) { if (!cachedTs) {
console.log('[Cache] No timestamp found');
return false; return false;
} }
const ageMs = Date.now() - new Date(cachedTs).getTime(); const ageMs = Date.now() - new Date(cachedTs).getTime();
const ageMin = Math.round(ageMs / 60000);
if (ageMs > 60 * 60 * 1000) { if (ageMs > 60 * 60 * 1000) {
console.log(`[Cache] Stale: ${ageMin}min old (max 60)`);
return false; return false;
} }
@@ -753,7 +739,6 @@ function isCacheFresh() {
const thisYear = (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .getWeekYear */ .Ao)(new Date()); const thisYear = (0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .getWeekYear */ .Ao)(new Date());
const hasCurrentWeek = _state_js__WEBPACK_IMPORTED_MODULE_0__/* .allWeeks */ .p_.some(w => w.weekNumber === thisWeek && w.year === thisYear && w.days && w.days.length > 0); const hasCurrentWeek = _state_js__WEBPACK_IMPORTED_MODULE_0__/* .allWeeks */ .p_.some(w => w.weekNumber === thisWeek && w.year === thisYear && w.days && w.days.length > 0);
console.log(`[Cache] Age: ${ageMin}min, looking for KW${thisWeek}/${thisYear}, found: ${hasCurrentWeek}`);
return hasCurrentWeek; return hasCurrentWeek;
} }
@@ -812,9 +797,6 @@ async function loadMenuDataFromAPI() {
if (detailResp.ok) { if (detailResp.ok) {
const detailData = await detailResp.json(); const detailData = await detailResp.json();
if (completed === 0) {
console.log('[Kantine Debug] Raw API response for', dateStr, ':', JSON.stringify(detailData).substring(0, 2000));
}
const menuGroups = detailData.results || []; const menuGroups = detailData.results || [];
let dayItems = []; let dayItems = [];
for (const group of menuGroups) { for (const group of menuGroups) {
@@ -823,10 +805,6 @@ async function loadMenuDataFromAPI() {
} }
} }
if (dayItems.length > 0) { if (dayItems.length > 0) {
if (completed === 0) {
console.log('[Kantine Debug] First item keys:', Object.keys(dayItems[0]));
console.log('[Kantine Debug] First item:', JSON.stringify(dayItems[0]).substring(0, 500));
}
allDays.push({ allDays.push({
date: dateStr, date: dateStr,
menu_items: dayItems, menu_items: dayItems,
@@ -930,7 +908,7 @@ async function loadMenuDataFromAPI() {
Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 842)).then(uiHelpers => { Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 842)).then(uiHelpers => {
uiHelpers.showErrorModal( uiHelpers.showErrorModal(
'Keine Verbindung', 'Keine Verbindung',
`Die Menüdaten konnten nicht geladen werden. Möglicherweise besteht keine Verbindung zur API oder zur Bessa-Webseite.<br><br><small style="color:var(--text-secondary)">${error.message}</small>`, `Die Menüdaten konnten nicht geladen werden. Möglicherweise besteht keine Verbindung zur API oder zur Bessa-Webseite.<br><br><small style="color:var(--text-secondary)">${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(error.message)}</small>`,
'Zur Original-Seite', 'Zur Original-Seite',
'https://web.bessa.app/knapp-kantine' 'https://web.bessa.app/knapp-kantine'
); );
@@ -978,7 +956,7 @@ function showToast(message, type = 'info') {
const toast = document.createElement('div'); const toast = document.createElement('div');
toast.className = `toast toast-${type}`; toast.className = `toast toast-${type}`;
const icon = type === 'success' ? 'check_circle' : type === 'error' ? 'error' : 'info'; const icon = type === 'success' ? 'check_circle' : type === 'error' ? 'error' : 'info';
toast.innerHTML = `<span class="material-icons-round">${icon}</span><span>${message}</span>`; toast.innerHTML = `<span class="material-icons-round">${icon}</span><span>${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(message)}</span>`;
container.appendChild(toast); container.appendChild(toast);
requestAnimationFrame(() => toast.classList.add('show')); requestAnimationFrame(() => toast.classList.add('show'));
setTimeout(() => { setTimeout(() => {
@@ -1193,7 +1171,7 @@ function updateNextWeekBadge() {
} }
if (highlightCount > 0) { if (highlightCount > 0) {
badge.innerHTML += `<span class="highlight-count" title="${highlightCount} Highlight Menüs">(${highlightCount})</span>`; badge.insertAdjacentHTML('beforeend', `<span class="highlight-count" title="${highlightCount} Highlight Menüs">(${highlightCount})</span>`);
badge.title += `${highlightCount} Highlights gefunden`; badge.title += `${highlightCount} Highlights gefunden`;
badge.classList.add('has-highlights'); badge.classList.add('has-highlights');
} }
@@ -1478,7 +1456,10 @@ function createDayCard(day) {
let tagsHtml = ''; let tagsHtml = '';
if (matchedTags.length > 0) { if (matchedTags.length > 0) {
const badges = matchedTags.map(t => `<span class="tag-badge-small"><span class="material-icons-round" style="font-size:10px;margin-right:2px">star</span>${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(t)}</span>`).join(''); let badges = '';
for (const t of matchedTags) {
badges += `<span class="tag-badge-small"><span class="material-icons-round" style="font-size:10px;margin-right:2px">star</span>${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(t)}</span>`;
}
tagsHtml = `<div class="matched-tags">${badges}</div>`; tagsHtml = `<div class="matched-tags">${badges}</div>`;
} }
@@ -1574,12 +1555,9 @@ async function checkForUpdates() {
})); }));
const latest = versions[0].tag; const latest = versions[0].tag;
console.log(`[Kantine] Version Check: Local [${currentVersion}] vs Latest [${latest}] (${devMode ? 'dev' : 'stable'})`);
if (!(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .isNewer */ .U4)(latest, currentVersion)) return; if (!(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .isNewer */ .U4)(latest, currentVersion)) return;
console.log(`[Kantine] Update verfügbar: ${latest}`);
const headerTitle = document.querySelector('.header-left h1'); const headerTitle = document.querySelector('.header-left h1');
if (headerTitle && !headerTitle.querySelector('.update-icon')) { if (headerTitle && !headerTitle.querySelector('.update-icon')) {
const icon = document.createElement('a'); const icon = document.createElement('a');
@@ -1636,12 +1614,12 @@ function openVersionMenu() {
let action = ''; let action = '';
if (!isCurrent) { if (!isCurrent) {
action = `<a href="${v.url}" target="_blank" class="install-link" title="${v.tag} installieren">Installieren</a>`; action = `<a href="${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(v.url)}" target="_blank" class="install-link" title="${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(v.tag)} installieren">Installieren</a>`;
} }
li.innerHTML = ` li.innerHTML = `
<div class="version-info"> <div class="version-info">
<strong>${v.tag}</strong> <strong>${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(v.tag)}</strong>
${badge} ${badge}
</div> </div>
${action} ${action}
@@ -1674,7 +1652,7 @@ function openVersionMenu() {
} }
} catch (e) { } catch (e) {
container.innerHTML = `<p style="color:#e94560;">Fehler: ${e.message}</p>`; container.innerHTML = `<p style="color:#e94560;">Fehler: ${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(e.message)}</p>`;
} }
} }
@@ -1781,7 +1759,7 @@ function showErrorModal(title, htmlContent, btnText, url) {
<div class="modal-header"> <div class="modal-header">
<h2 style="color: var(--error-color); display: flex; align-items: center; gap: 10px;"> <h2 style="color: var(--error-color); display: flex; align-items: center; gap: 10px;">
<span class="material-icons-round">signal_wifi_off</span> <span class="material-icons-round">signal_wifi_off</span>
${title} ${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(title)}
</h2> </h2>
</div> </div>
<div style="padding: 20px;"> <div style="padding: 20px;">
@@ -1802,7 +1780,7 @@ function showErrorModal(title, htmlContent, btnText, url) {
justify-content: center; justify-content: center;
transition: transform 0.1s; transition: transform 0.1s;
"> ">
${btnText} ${(0,_utils_js__WEBPACK_IMPORTED_MODULE_1__/* .escapeHtml */ .ZD)(btnText)}
<span class="material-icons-round">open_in_new</span> <span class="material-icons-round">open_in_new</span>
</button> </button>
</div> </div>
@@ -2678,9 +2656,7 @@ function bindEvents() {
if (window.__KANTINE_LOADED) { if (!window.__KANTINE_LOADED) {
console.log("Kantine Wrapper already loaded.");
} else {
window.__KANTINE_LOADED = true; window.__KANTINE_LOADED = true;
injectUI(); injectUI();
@@ -2692,10 +2668,7 @@ if (window.__KANTINE_LOADED) {
if (hadCache) { if (hadCache) {
document.getElementById('loading').classList.add('hidden'); document.getElementById('loading').classList.add('hidden');
if (!(0,actions/* isCacheFresh */.VL)()) { if (!(0,actions/* isCacheFresh */.VL)()) {
console.log('Cache stale or incomplete refreshing from API');
(0,actions/* loadMenuDataFromAPI */.m9)(); (0,actions/* loadMenuDataFromAPI */.m9)();
} else {
console.log('Cache fresh & complete skipping API refresh');
} }
} else { } else {
(0,actions/* loadMenuDataFromAPI */.m9)(); (0,actions/* loadMenuDataFromAPI */.m9)();
@@ -2707,8 +2680,6 @@ if (window.__KANTINE_LOADED) {
(0,ui_helpers/* checkForUpdates */.Ux)(); (0,ui_helpers/* checkForUpdates */.Ux)();
setInterval(ui_helpers/* checkForUpdates */.Ux, 60 * 60 * 1000); setInterval(ui_helpers/* checkForUpdates */.Ux, 60 * 60 * 1000);
console.log('Kantine Wrapper loaded ✅');
} }
/******/ })() /******/ })()

View File

@@ -73,7 +73,7 @@ export function updateNextWeekBadge() {
} }
if (highlightCount > 0) { if (highlightCount > 0) {
badge.innerHTML += `<span class="highlight-count" title="${highlightCount} Highlight Menüs">(${highlightCount})</span>`; badge.insertAdjacentHTML('beforeend', `<span class="highlight-count" title="${highlightCount} Highlight Menüs">(${highlightCount})</span>`);
badge.title += `${highlightCount} Highlights gefunden`; badge.title += `${highlightCount} Highlights gefunden`;
badge.classList.add('has-highlights'); badge.classList.add('has-highlights');
} }