127 lines
3.9 KiB
JavaScript
127 lines
3.9 KiB
JavaScript
(function () {
|
|
'use strict';
|
|
|
|
function toPartialUrl(input, fallbackView) {
|
|
const url = new URL(input, window.location.origin);
|
|
if (!url.searchParams.has('view') && fallbackView) {
|
|
url.searchParams.set('view', fallbackView);
|
|
}
|
|
url.searchParams.set('partial', '1');
|
|
return url;
|
|
}
|
|
|
|
async function fetchHtml(url, options) {
|
|
const response = await fetch(url.toString(), {
|
|
credentials: 'same-origin',
|
|
headers: {
|
|
Accept: 'text/html',
|
|
'X-Requested-With': 'XMLHttpRequest'
|
|
},
|
|
...options
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}`);
|
|
}
|
|
|
|
return response.text();
|
|
}
|
|
|
|
function enhanceHost(host, state) {
|
|
host.querySelectorAll('a[href]').forEach((link) => {
|
|
const href = link.getAttribute('href') || '';
|
|
if (!href.startsWith('/apps/boersenchecker')) {
|
|
return;
|
|
}
|
|
|
|
link.addEventListener('click', (event) => {
|
|
event.preventDefault();
|
|
state.load(href);
|
|
});
|
|
});
|
|
|
|
host.querySelectorAll('form').forEach((form) => {
|
|
form.addEventListener('submit', async (event) => {
|
|
event.preventDefault();
|
|
|
|
const method = String(form.getAttribute('method') || 'get').toUpperCase();
|
|
const action = form.getAttribute('action') || state.currentUrl.toString();
|
|
const formData = new FormData(form);
|
|
const url = toPartialUrl(action, state.defaultView);
|
|
|
|
try {
|
|
if (method === 'GET') {
|
|
const next = new URL(url.toString());
|
|
next.search = '';
|
|
next.searchParams.set('partial', '1');
|
|
for (const [key, value] of formData.entries()) {
|
|
next.searchParams.append(key, String(value));
|
|
}
|
|
await state.load(next.toString());
|
|
return;
|
|
}
|
|
|
|
const html = await fetchHtml(url, {
|
|
method,
|
|
body: formData
|
|
});
|
|
state.render(html, url);
|
|
} catch (error) {
|
|
state.renderError(error);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
window.initBoersencheckerApp = function initBoersencheckerApp(host, options) {
|
|
if (!(host instanceof HTMLElement)) {
|
|
return;
|
|
}
|
|
|
|
const entryRoute = String(options?.entryRoute || '/apps/boersenchecker/index.php');
|
|
const defaultView = String(options?.defaultView || 'overview');
|
|
|
|
const state = {
|
|
defaultView,
|
|
currentUrl: toPartialUrl(entryRoute, defaultView),
|
|
async load(targetUrl) {
|
|
const url = toPartialUrl(targetUrl, defaultView);
|
|
this.currentUrl = url;
|
|
host.innerHTML = '<div class="window-app-loading"><p>Börsenchecker wird geladen...</p></div>';
|
|
try {
|
|
const html = await fetchHtml(url);
|
|
this.render(html, url);
|
|
} catch (error) {
|
|
this.renderError(error);
|
|
}
|
|
},
|
|
render(html, url) {
|
|
this.currentUrl = url;
|
|
host.innerHTML = html;
|
|
enhanceHost(host, this);
|
|
if (typeof window.initBoersencheckerCharts === 'function') {
|
|
try {
|
|
window.initBoersencheckerCharts(host);
|
|
} catch (error) {
|
|
const message = error instanceof Error ? error.message : 'Chart-Initialisierung fehlgeschlagen.';
|
|
const statusNode = host.querySelector('[data-bc-chart-status]');
|
|
const chartNode = host.querySelector('[data-bc-chart]');
|
|
if (statusNode instanceof HTMLElement) {
|
|
statusNode.textContent = message;
|
|
}
|
|
if (chartNode instanceof HTMLElement) {
|
|
chartNode.innerHTML = `<div class="muted">${message}</div>`;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
renderError(error) {
|
|
const message = error instanceof Error ? error.message : 'Börsenchecker konnte nicht geladen werden.';
|
|
host.innerHTML = `<div class="window-app-error-state"><p>${message}</p></div>`;
|
|
}
|
|
};
|
|
|
|
state.load(entryRoute);
|
|
};
|
|
})();
|