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:
55
dist/kantine.bundle.js
vendored
55
dist/kantine.bundle.js
vendored
@@ -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 ✅');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******/ })()
|
/******/ })()
|
||||||
|
|||||||
@@ -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');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user