Checklisten-Häkchen in Dashboards speichern (localStorage)
Beim Ausliefern von /dashboards/*.html wird ein Skript injiziert, das den Zustand der Checklisten-Checkboxen im localStorage speichert (Key = Label-Text, pro Dashboard-URL) und beim Laden wiederherstellt, inkl. update()-Aufruf für Zähler/Progress-Bar und 'Liste zurücksetzen'-Button. Funktioniert in allen bestehenden und künftigen Dashboards; Marker verhindert Doppel-Injektion, path.basename verhindert Traversal.
This commit is contained in:
1 parent
ab4f8e8570
commit
12f01b86d6
1 file changed
+70
@@ -1,6 +1,7 @@
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
|
const fs = require('fs');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const webpush = require('web-push');
|
const webpush = require('web-push');
|
||||||
|
|
||||||
@@ -416,6 +417,75 @@ function sendPush(session, result) {
|
|||||||
// Statische Dateien & Dashboard-Dateien
|
// Statische Dateien & Dashboard-Dateien
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Wird in jedes ausgelieferte Dashboard-HTML injiziert: speichert den Zustand
|
||||||
|
// der Checklisten-Häkchen im localStorage und stellt ihn beim Laden wieder her
|
||||||
|
// (inkl. „Liste zurücksetzen"-Button). Key = Label-Text der Checkbox, damit
|
||||||
|
// der Stand auch bei Layout-Änderungen stabil bleibt.
|
||||||
|
const CHECKLIST_SCRIPT = `<script>
|
||||||
|
(function () {
|
||||||
|
var KEY = 'rc-checks:' + location.pathname;
|
||||||
|
var boxes = document.querySelectorAll('input[type=checkbox]');
|
||||||
|
if (!boxes.length) return;
|
||||||
|
var saved = {};
|
||||||
|
try { saved = JSON.parse(localStorage.getItem(KEY) || '{}'); } catch (e) {}
|
||||||
|
|
||||||
|
function labelFor(box, i) {
|
||||||
|
var li = box.closest('li');
|
||||||
|
var t = li ? li.querySelector('.check-text') : null;
|
||||||
|
var text = (t || li || {}).textContent || '';
|
||||||
|
return text.trim() || 'item-' + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
boxes.forEach(function (box, i) {
|
||||||
|
var k = labelFor(box, i);
|
||||||
|
if (saved[k] !== undefined) box.checked = !!saved[k];
|
||||||
|
box.addEventListener('change', function () {
|
||||||
|
saved[k] = box.checked;
|
||||||
|
try { localStorage.setItem(KEY, JSON.stringify(saved)); } catch (e) {}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function refresh() {
|
||||||
|
if (typeof update === 'function') update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// „Liste zurücksetzen"-Button am Anfang der ersten Checklisten-Section
|
||||||
|
var firstBox = boxes[0];
|
||||||
|
var section = firstBox.closest('section') || firstBox.closest('div') || document.body;
|
||||||
|
var btn = document.createElement('button');
|
||||||
|
btn.type = 'button';
|
||||||
|
btn.textContent = '↺ Liste zurücksetzen';
|
||||||
|
btn.style.cssText =
|
||||||
|
'margin:0 0 12px;padding:6px 14px;font-size:12px;font-weight:600;border-radius:8px;' +
|
||||||
|
'border:1px solid rgba(100,116,139,.4);background:transparent;color:inherit;cursor:pointer;';
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
if (!confirm('Alle Häkchen dieser Liste zurücksetzen?')) return;
|
||||||
|
try { localStorage.removeItem(KEY); } catch (e) {}
|
||||||
|
saved = {};
|
||||||
|
boxes.forEach(function (b) { b.checked = false; });
|
||||||
|
refresh();
|
||||||
|
});
|
||||||
|
section.insertBefore(btn, section.firstChild);
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
})();
|
||||||
|
</script>`;
|
||||||
|
|
||||||
|
const CHECKLIST_MARKER = 'rc-checks';
|
||||||
|
|
||||||
|
app.get('/dashboards/:name.html', (req, res, next) => {
|
||||||
|
const name = path.basename(req.params.name);
|
||||||
|
const file = path.join(__dirname, 'dashboards', `${name}.html`);
|
||||||
|
fs.readFile(file, 'utf8', (err, html) => {
|
||||||
|
if (err) return next();
|
||||||
|
if (!html.includes(CHECKLIST_MARKER)) {
|
||||||
|
html = html.replace(/<\/body>/i, `${CHECKLIST_SCRIPT}\n</body>`);
|
||||||
|
}
|
||||||
|
res.setHeader('Cache-Control', 'no-cache');
|
||||||
|
res.type('html').send(html);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
'/dashboards',
|
'/dashboards',
|
||||||
express.static(path.join(__dirname, 'dashboards'), {
|
express.static(path.join(__dirname, 'dashboards'), {
|
||||||
|
|||||||
Reference in new issue
Block a user