librelad 875a60f90f LibrePortal v0.1.0 — initial release
A free, open, self-hosted app platform (GNU AGPLv3): one-click app deploys,
Traefik reverse proxy with automatic SSL, rootless Docker support, gluetun
VPN routing, and a web dashboard to manage it all.

Free & open forever to self-host; optional paid hosted services fund it.
See PROMISE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Signed-off-by: librelad <librelad@digitalangels.vip>
2026-05-21 20:37:54 +01:00

65 lines
1.5 KiB
JavaScript
Executable File

// DOM Helper Functions - Shared across all pages
// DOM helpers
function safeGetElement(id) {
const element = document.getElementById(id);
if (!element) {
//console.log(`${id} element not found`);
}
return element;
}
function safeQuerySelector(selector) {
const element = document.querySelector(selector);
if (!element) {
//console.log(`${selector} element not found`);
}
return element;
}
function safeQuerySelectorAll(selector) {
const elements = document.querySelectorAll(selector);
if (!elements || elements.length === 0) {
//console.log(`${selector} elements not found`);
}
return elements;
}
// Navigation helpers
function setupActiveNavigation() {
const navItems = document.querySelectorAll('.nav-item');
navItems.forEach(item => {
if (item.textContent.includes('App Center')) {
item.classList.add('active');
}
});
}
// Wait for element to appear
function waitForElement(id, timeout = 5000) {
return new Promise((resolve, reject) => {
const element = document.getElementById(id);
if (element) {
resolve(element);
return;
}
const observer = new MutationObserver(() => {
const element = document.getElementById(id);
if (element) {
observer.disconnect();
resolve(element);
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
setTimeout(() => {
observer.disconnect();
reject(new Error(`Element ${id} not found within ${timeout}ms`));
}, timeout);
});
}