Test custom.css
This commit is contained in:
@@ -1,22 +1,23 @@
|
||||
/* ============================================================================
|
||||
KalliLab — CUSTOM JAVASCRIPT
|
||||
Basiert auf LionCityGaming/homepage custom.js (MIT License)
|
||||
Anpassungen: KalliLab Tab-Namen, keine HA/EPL/Glance iFrames
|
||||
Home / Media Tabs
|
||||
Reload-Button entfernen
|
||||
Aktiven Tab merken
|
||||
============================================================================ */
|
||||
|
||||
const CONFIG = {
|
||||
STORAGE: {
|
||||
KEY: "lastFocusedTabId",
|
||||
KEY: "kallilab-last-focused-tab-id",
|
||||
},
|
||||
TIMING: {
|
||||
RETRY_DELAY: 500,
|
||||
STANDARD_REFRESH: 1800000, // 30 Minuten
|
||||
QUICK_REFRESH: 60000, // 1 Minute
|
||||
STANDARD_REFRESH: 1800000,
|
||||
QUICK_REFRESH: 60000,
|
||||
RETRY_ON_ERROR: 30000,
|
||||
BATCH_DELAY: 100,
|
||||
},
|
||||
SERVICES: {
|
||||
QUICK_REFRESH: [], // keine kritischen Quick-Refresh Widgets
|
||||
QUICK_REFRESH: [],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -28,17 +29,10 @@ const RELOAD_BUTTON_SELECTORS = [
|
||||
'[role="button"][aria-label="Reload"]',
|
||||
];
|
||||
|
||||
// Keine iFrame-Widgets in KalliLab
|
||||
const IFRAME_CONFIG = [];
|
||||
|
||||
// Tab-Mapping für KalliLab Tabs (5 Tabs)
|
||||
const TAB_MAPPING = {
|
||||
"#ueberblick": ["#Überblick-tab", "#Überblick"],
|
||||
"#system": ["#System-tab", "#System"],
|
||||
"#sicherheit": ["#Sicherheit-tab", "#Sicherheit"],
|
||||
"#dienste": ["#Dienste-tab", "#Dienste"],
|
||||
"#backends": ["#Backends-tab", "#Backends"],
|
||||
"": ["#Überblick-tab", "#Überblick"],
|
||||
const TAB_HASH_MAP = {
|
||||
"#home": "Home-tab",
|
||||
"#media": "Media-tab",
|
||||
"": "Home-tab",
|
||||
};
|
||||
|
||||
const state = {
|
||||
@@ -46,7 +40,6 @@ const state = {
|
||||
currentFocusedTab: null,
|
||||
observers: {
|
||||
reloadButton: null,
|
||||
resize: null,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -105,7 +98,9 @@ function throttle(func, limit) {
|
||||
if (!inThrottle) {
|
||||
func.apply(this, args);
|
||||
inThrottle = true;
|
||||
setTimeout(() => (inThrottle = false), limit);
|
||||
setTimeout(() => {
|
||||
inThrottle = false;
|
||||
}, limit);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -141,6 +136,81 @@ function setupReloadButtonObserver() {
|
||||
return observer;
|
||||
}
|
||||
|
||||
function setTabFocus(tab) {
|
||||
requestAnimationFrame(() => {
|
||||
if (state.currentFocusedTab) {
|
||||
state.currentFocusedTab.classList.remove("tab-focused");
|
||||
}
|
||||
|
||||
state.currentFocusedTab = tab;
|
||||
|
||||
if (state.currentFocusedTab) {
|
||||
state.currentFocusedTab.classList.add("tab-focused");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showTabContent(contentElement) {
|
||||
if (!contentElement || !domCache.tabContents) return;
|
||||
|
||||
domCache.tabContents.forEach((content) => {
|
||||
content.classList.remove("active");
|
||||
content.style.display = "none";
|
||||
});
|
||||
|
||||
contentElement.classList.add("active");
|
||||
contentElement.style.display = "block";
|
||||
domCache.updateActiveTab();
|
||||
}
|
||||
|
||||
function resolveTabContentElement(tab) {
|
||||
if (!tab) return null;
|
||||
|
||||
const ariaControls = tab.getAttribute("aria-controls");
|
||||
if (ariaControls) {
|
||||
return document.getElementById(ariaControls);
|
||||
}
|
||||
|
||||
const tabText = (tab.textContent || "").trim().toLowerCase();
|
||||
const directMatch = Array.from(document.querySelectorAll(".tabcontent")).find((content) => {
|
||||
return content.id.toLowerCase() === tabText;
|
||||
});
|
||||
|
||||
return directMatch || document.querySelector(".tabcontent.active");
|
||||
}
|
||||
|
||||
function activateTab(tab, updateHash = true) {
|
||||
if (!tab) return;
|
||||
|
||||
setTabFocus(tab);
|
||||
storage.save(tab.id);
|
||||
|
||||
const contentToShow = resolveTabContentElement(tab);
|
||||
showTabContent(contentToShow);
|
||||
|
||||
if (updateHash) {
|
||||
const normalized = (tab.textContent || "").trim().toLowerCase();
|
||||
if (normalized === "home") {
|
||||
history.replaceState(null, "", "#home");
|
||||
} else if (normalized === "media") {
|
||||
history.replaceState(null, "", "#media");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleTabFocusFromURL() {
|
||||
const hash = window.location.hash.toLowerCase();
|
||||
const tabId = TAB_HASH_MAP[hash] || TAB_HASH_MAP[""];
|
||||
const tabToFocus = document.getElementById(tabId);
|
||||
|
||||
if (tabToFocus) {
|
||||
activateTab(tabToFocus, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateServiceCard(card, data) {
|
||||
requestAnimationFrame(() => {
|
||||
const titleElement = card.querySelector(".card-title");
|
||||
@@ -154,6 +224,7 @@ function updateServiceCard(card, data) {
|
||||
statusElement.textContent = Array.isArray(data)
|
||||
? `${data.length} items`
|
||||
: (data.status ?? (typeof data === "object" ? "Data received" : ""));
|
||||
statusElement.style.color = "";
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -165,7 +236,7 @@ function updateServiceCardError(card, error) {
|
||||
statusElement.textContent = error.message.includes("404")
|
||||
? "Service unavailable"
|
||||
: "Error loading data";
|
||||
statusElement.style.color = "red";
|
||||
statusElement.style.color = "#ff7b7b";
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -221,53 +292,14 @@ async function batchUpdateServiceCards(cards) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleTabFocusFromURL() {
|
||||
const hash = window.location.hash.toLowerCase();
|
||||
const mapping = TAB_MAPPING[hash] || TAB_MAPPING[""];
|
||||
const [tabSelector, contentSelector] = mapping;
|
||||
|
||||
const tabToFocus = document.querySelector(tabSelector);
|
||||
const contentToShow = document.querySelector(contentSelector);
|
||||
|
||||
if (tabToFocus) {
|
||||
setTabFocus(tabToFocus);
|
||||
storage.save(tabToFocus.id);
|
||||
|
||||
domCache.tabContents.forEach((content) => {
|
||||
content.classList.remove("active");
|
||||
content.style.display = "none";
|
||||
});
|
||||
|
||||
if (contentToShow) {
|
||||
showTabContent(contentToShow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setTabFocus(tab) {
|
||||
requestAnimationFrame(() => {
|
||||
if (state.currentFocusedTab) {
|
||||
state.currentFocusedTab.classList.remove("tab-focused");
|
||||
}
|
||||
state.currentFocusedTab = tab;
|
||||
state.currentFocusedTab.classList.add("tab-focused");
|
||||
});
|
||||
}
|
||||
|
||||
function showTabContent(contentElement) {
|
||||
if (!contentElement) return;
|
||||
|
||||
contentElement.classList.add("active");
|
||||
contentElement.style.display = "block";
|
||||
domCache.updateActiveTab();
|
||||
}
|
||||
|
||||
async function preloadAllTabs() {
|
||||
const tabContents = document.querySelectorAll(".tab-pane");
|
||||
const tabContents = document.querySelectorAll(".tabcontent, .tab-pane");
|
||||
const serviceCards = new Set();
|
||||
|
||||
tabContents.forEach((tab) => {
|
||||
tab.querySelectorAll(".service-card").forEach((card) => serviceCards.add(card));
|
||||
tab.querySelectorAll(".service-card[data-api-endpoint]").forEach((card) => {
|
||||
serviceCards.add(card);
|
||||
});
|
||||
});
|
||||
|
||||
await batchUpdateServiceCards(Array.from(serviceCards));
|
||||
@@ -295,49 +327,45 @@ function setupPeriodicRefresh() {
|
||||
});
|
||||
|
||||
domCache.myTab?.addEventListener("click", (event) => {
|
||||
if (event.target.matches('[id$="-tab"]')) {
|
||||
const tab = event.target.closest('[id$="-tab"]');
|
||||
if (tab) {
|
||||
activateTab(tab);
|
||||
debouncedRefresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initializeTabFocus() {
|
||||
// KalliLab Tab-Selektoren
|
||||
const tabs = document.querySelectorAll(
|
||||
"#Überblick-tab, #System-tab, #Sicherheit-tab, #Dienste-tab, #Backends-tab",
|
||||
);
|
||||
const tabs = document.querySelectorAll('#myTab [id$="-tab"]');
|
||||
if (!tabs.length) return;
|
||||
|
||||
handleTabFocusFromURL();
|
||||
const handledByHash = handleTabFocusFromURL();
|
||||
|
||||
if (!window.location.hash) {
|
||||
if (!handledByHash) {
|
||||
const savedTabId = storage.get();
|
||||
const savedTab = savedTabId && document.getElementById(savedTabId);
|
||||
|
||||
if (savedTab) {
|
||||
setTabFocus(savedTab);
|
||||
activateTab(savedTab, false);
|
||||
} else {
|
||||
const activeTab = document.querySelector(".tabcontent.active");
|
||||
const correspondingTab =
|
||||
activeTab && document.querySelector(`[aria-controls="${activeTab.id}"]`);
|
||||
if (correspondingTab) {
|
||||
setTabFocus(correspondingTab);
|
||||
const activeTab = document.querySelector('#myTab [aria-selected="true"]');
|
||||
if (activeTab) {
|
||||
activateTab(activeTab, false);
|
||||
} else {
|
||||
activateTab(tabs[0], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tabs.forEach((tab) => {
|
||||
const handleTabAction = function () {
|
||||
setTabFocus(this);
|
||||
storage.save(this.id);
|
||||
};
|
||||
tab.addEventListener("click", () => {
|
||||
activateTab(tab);
|
||||
});
|
||||
|
||||
tab.addEventListener("click", handleTabAction);
|
||||
|
||||
tab.addEventListener("keydown", function (e) {
|
||||
tab.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
e.preventDefault();
|
||||
this.click();
|
||||
handleTabAction.call(this);
|
||||
activateTab(tab);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -347,6 +375,10 @@ function initializeTabFocus() {
|
||||
storage.save(state.currentFocusedTab.id);
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("hashchange", () => {
|
||||
handleTabFocusFromURL();
|
||||
});
|
||||
}
|
||||
|
||||
function initializeEverything() {
|
||||
@@ -368,14 +400,21 @@ function initializeEverything() {
|
||||
} else {
|
||||
setTimeout(initializeEverything, CONFIG.TIMING.RETRY_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("orientationchange", () => {
|
||||
setTimeout(removeReloadButton, 100);
|
||||
});
|
||||
function cleanup() {
|
||||
if (state.observers.reloadButton) {
|
||||
state.observers.reloadButton.disconnect();
|
||||
state.observers.reloadButton = null;
|
||||
}
|
||||
|
||||
domCache.clear();
|
||||
state.currentFocusedTab = null;
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", removeReloadButton);
|
||||
window.addEventListener("load", initializeEverything);
|
||||
window.addEventListener("unload", cleanup);
|
||||
|
||||
if (typeof window.htmlLoaded === "function") {
|
||||
const originalHtmlLoaded = window.htmlLoaded;
|
||||
@@ -386,22 +425,11 @@ if (typeof window.htmlLoaded === "function") {
|
||||
}
|
||||
|
||||
if ("ontouchstart" in window) {
|
||||
window.addEventListener("touchend", () => {
|
||||
setTimeout(removeReloadButton, 100);
|
||||
}, { passive: true });
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
if (state.observers.reloadButton) {
|
||||
state.observers.reloadButton.disconnect();
|
||||
state.observers.reloadButton = null;
|
||||
}
|
||||
if (state.observers.resize) {
|
||||
state.observers.resize.disconnect();
|
||||
state.observers.resize = null;
|
||||
}
|
||||
domCache.clear();
|
||||
state.currentFocusedTab = null;
|
||||
}
|
||||
|
||||
window.addEventListener("unload", cleanup);
|
||||
window.addEventListener(
|
||||
"touchend",
|
||||
() => {
|
||||
setTimeout(removeReloadButton, 100);
|
||||
},
|
||||
{ passive: true },
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user