no message
This commit is contained in:
@@ -12,38 +12,14 @@
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<!-- Datum: sichtbares Feld + unsichtbare Picker als Overlay -->
|
||||
<label id="dateWrap" style="display:flex;gap:6px;align-items:center; position:relative;">
|
||||
<label style="display:flex;gap:6px;align-items:center;">
|
||||
<span>Datum</span>
|
||||
|
||||
<!-- Sichtbar -->
|
||||
<input id="dateText" type="text" readonly
|
||||
style="width:210px; padding:4px 10px; font-weight:900; font-size:14px;
|
||||
opacity:.95; cursor:pointer; border:1px solid rgba(255,255,255,.25);
|
||||
border-radius:6px; background:rgba(0,0,0,.18); color:#fff;" />
|
||||
|
||||
<!-- Overlay Picker (transparent, exakt über dateText) -->
|
||||
<input id="date" type="date" aria-label="Datum"
|
||||
style="position:absolute; left:52px; top:0; height:100%;
|
||||
width:210px; opacity:0; cursor:pointer; display:none;" />
|
||||
|
||||
<input id="week" type="week" aria-label="Woche"
|
||||
style="position:absolute; left:52px; top:0; height:100%;
|
||||
width:210px; opacity:0; cursor:pointer; display:none;" />
|
||||
|
||||
<input id="month" type="month" aria-label="Monat"
|
||||
style="position:absolute; left:52px; top:0; height:100%;
|
||||
width:210px; opacity:0; cursor:pointer; display:none;" />
|
||||
|
||||
<!-- Jahr: nativer Picker existiert nicht -> Select -->
|
||||
<select id="yearSel"
|
||||
style="position:absolute; left:52px; top:0; height:100%;
|
||||
width:210px; font-weight:900; display:none;
|
||||
border:1px solid rgba(255,255,255,.25);
|
||||
border-radius:6px; background:rgba(0,0,0,.35); color:#fff;">
|
||||
</select>
|
||||
<input id="date" type="date" />
|
||||
</label>
|
||||
|
||||
<!-- Label rechts neben Date-Picker -->
|
||||
<div id="dateLabel" style="font-weight:900;opacity:.95;min-width:140px;"></div>
|
||||
|
||||
<button id="prev" type="button">◀</button>
|
||||
<button id="today" type="button">Heute</button>
|
||||
<button id="next" type="button">▶</button>
|
||||
@@ -138,6 +114,9 @@
|
||||
<script>
|
||||
(function () {
|
||||
const elRange = document.getElementById('range');
|
||||
const elDate = document.getElementById('date');
|
||||
const elDateLbl = document.getElementById('dateLabel');
|
||||
|
||||
const elPrev = document.getElementById('prev');
|
||||
const elToday = document.getElementById('today');
|
||||
const elNext = document.getElementById('next');
|
||||
@@ -147,16 +126,9 @@
|
||||
const elGrid = document.getElementById('grid');
|
||||
const elErr = document.getElementById('err');
|
||||
|
||||
const elDateText = document.getElementById('dateText');
|
||||
const elDate = document.getElementById('date');
|
||||
const elWeek = document.getElementById('week');
|
||||
const elMonth = document.getElementById('month');
|
||||
const elYearSel = document.getElementById('yearSel');
|
||||
|
||||
elGrid.innerHTML = '<div style="opacity:.75;padding:12px;">Lade Daten…</div>';
|
||||
|
||||
const pad2 = (n) => String(n).padStart(2,'0');
|
||||
function toYmd(d){ return `${d.getFullYear()}-${pad2(d.getMonth()+1)}-${pad2(d.getDate())}`; }
|
||||
function toNum(x){ const n = Number(x); return Number.isFinite(n) ? n : 0; }
|
||||
function clamp01(x){ return (!Number.isFinite(x)) ? 0 : (x<0?0:(x>1?1:x)); }
|
||||
function escapeHtml(s){
|
||||
@@ -179,24 +151,6 @@
|
||||
return { week: weekNo, year: isoYear };
|
||||
}
|
||||
|
||||
// YYYY-Www -> Montag YYYY-MM-DD
|
||||
function isoWeekToMondayYmd(isoWeekStr){
|
||||
const m = /^(\d{4})-W(\d{2})$/.exec(isoWeekStr || '');
|
||||
if (!m) return '';
|
||||
const year = parseInt(m[1],10);
|
||||
const week = parseInt(m[2],10);
|
||||
|
||||
const jan4 = new Date(Date.UTC(year,0,4));
|
||||
const jan4Dow = jan4.getUTCDay() || 7;
|
||||
const mondayWeek1 = new Date(jan4);
|
||||
mondayWeek1.setUTCDate(jan4.getUTCDate() - (jan4Dow - 1));
|
||||
|
||||
const monday = new Date(mondayWeek1);
|
||||
monday.setUTCDate(mondayWeek1.getUTCDate() + (week-1)*7);
|
||||
|
||||
return `${monday.getUTCFullYear()}-${pad2(monday.getUTCMonth()+1)}-${pad2(monday.getUTCDate())}`;
|
||||
}
|
||||
|
||||
function showErr(e){
|
||||
const msg = (e && e.message) ? e.message : String(e);
|
||||
elErr.textContent = 'JS-Fehler: ' + msg;
|
||||
@@ -226,69 +180,30 @@
|
||||
}
|
||||
function safeRefreshSoon(){ setTimeout(() => safeRequestAction('Refresh', 1), 150); }
|
||||
|
||||
// aktiven Picker anzeigen
|
||||
function setActivePicker(range){
|
||||
elDate.style.display = 'none';
|
||||
elWeek.style.display = 'none';
|
||||
elMonth.style.display = 'none';
|
||||
elYearSel.style.display = 'none';
|
||||
|
||||
if (range === 'total') return;
|
||||
if (range === 'day') elDate.style.display = 'block';
|
||||
if (range === 'week') elWeek.style.display = 'block';
|
||||
if (range === 'month') elMonth.style.display = 'block';
|
||||
if (range === 'year') elYearSel.style.display = 'block';
|
||||
}
|
||||
|
||||
// dateText setzen
|
||||
function setDateText(range, ymd){
|
||||
if (range === 'total'){ elDateText.value = 'Gesamt'; return; }
|
||||
if (!ymd || !/^\d{4}-\d{2}-\d{2}$/.test(ymd)) { elDateText.value = ''; return; }
|
||||
// Label rechts vom Datum (immer aus dem gewählten Tag berechnet)
|
||||
function setDateLabel(range, ymd){
|
||||
if (!ymd || !/^\d{4}-\d{2}-\d{2}$/.test(ymd)) { elDateLbl.textContent = ''; return; }
|
||||
const d = new Date(ymd + 'T00:00:00');
|
||||
|
||||
if (range === 'day'){
|
||||
elDateText.value = `${pad2(d.getDate())}.${pad2(d.getMonth()+1)}.${d.getFullYear()}`;
|
||||
} else if (range === 'week'){
|
||||
const iso = getISOWeekYear(d);
|
||||
elDateText.value = `Woche ${iso.week}: ${iso.year}`;
|
||||
} else if (range === 'month'){
|
||||
elDateText.value = `${monthNameDe(d.getMonth())} ${d.getFullYear()}`;
|
||||
} else if (range === 'year'){
|
||||
elDateText.value = `${d.getFullYear()}`;
|
||||
} else {
|
||||
elDateText.value = '';
|
||||
}
|
||||
if (range === 'total') { elDateLbl.textContent = 'Gesamt'; return; }
|
||||
if (range === 'day') { elDateLbl.textContent = `${pad2(d.getDate())}.${pad2(d.getMonth()+1)}.${d.getFullYear()}`; return; }
|
||||
if (range === 'week') { const iso = getISOWeekYear(d); elDateLbl.textContent = `Woche ${iso.week}: ${iso.year}`; return; }
|
||||
if (range === 'month') { elDateLbl.textContent = `${monthNameDe(d.getMonth())} ${d.getFullYear()}`; return; }
|
||||
if (range === 'year') { elDateLbl.textContent = String(d.getFullYear()); return; }
|
||||
elDateLbl.textContent = '';
|
||||
}
|
||||
|
||||
// Jahr-Select bauen
|
||||
function buildYearOptions(baseYmd){
|
||||
const base = (baseYmd && /^\d{4}-\d{2}-\d{2}$/.test(baseYmd)) ? new Date(baseYmd+'T00:00:00') : new Date();
|
||||
const y0 = base.getFullYear();
|
||||
const from = y0 - 15;
|
||||
const to = y0 + 1;
|
||||
|
||||
elYearSel.innerHTML = '';
|
||||
for (let y = to; y >= from; y--){
|
||||
const opt = document.createElement('option');
|
||||
opt.value = String(y);
|
||||
opt.textContent = String(y);
|
||||
elYearSel.appendChild(opt);
|
||||
}
|
||||
}
|
||||
|
||||
// Zeitraum-Spanne
|
||||
function fmtRangeSpan(range, tStart, tEnd){
|
||||
if (!tStart || !tEnd) return '';
|
||||
if (range === 'total') return 'Zeitraum: Gesamt';
|
||||
|
||||
const s = new Date(tStart * 1000);
|
||||
const e = new Date((tEnd * 1000) - 1000); // tEnd exklusiv -> -1s
|
||||
const e = new Date((tEnd * 1000) - 1000);
|
||||
|
||||
const dmy = (d) => `${pad2(d.getDate())}.${pad2(d.getMonth()+1)}.${d.getFullYear()}`;
|
||||
return `Zeitraum: ${dmy(s)} - ${dmy(e)}`;
|
||||
}
|
||||
|
||||
// Donut (ohne Box/Rand)
|
||||
function donutCard({ title, percent, subtitle, color }){
|
||||
const share = clamp01(percent / 100);
|
||||
const r = 56;
|
||||
@@ -340,34 +255,12 @@
|
||||
const autark = (cons > 0) ? (eigenClamped / cons * 100) : 0;
|
||||
|
||||
if (data?.range) elRange.value = data.range;
|
||||
if (data?.date) elDate.value = data.date;
|
||||
|
||||
// Basisdatum (immer YYYY-MM-DD vom Backend)
|
||||
const ymd = data?.date || '';
|
||||
if (ymd && /^\d{4}-\d{2}-\d{2}$/.test(ymd)) elDate.value = ymd;
|
||||
elDate.disabled = (data?.range === 'total');
|
||||
|
||||
// aktiven Picker setzen
|
||||
setActivePicker(elRange.value);
|
||||
|
||||
// Jahr-Select vorbereiten
|
||||
buildYearOptions(ymd);
|
||||
|
||||
// Picker synchronisieren
|
||||
if (elRange.value === 'week' && ymd){
|
||||
const d = new Date(ymd + 'T00:00:00');
|
||||
const iso = getISOWeekYear(d);
|
||||
elWeek.value = `${iso.year}-W${pad2(iso.week)}`;
|
||||
}
|
||||
if (elRange.value === 'month' && ymd){
|
||||
const d = new Date(ymd + 'T00:00:00');
|
||||
elMonth.value = `${d.getFullYear()}-${pad2(d.getMonth()+1)}`;
|
||||
}
|
||||
if (elRange.value === 'year' && ymd){
|
||||
const d = new Date(ymd + 'T00:00:00');
|
||||
elYearSel.value = String(d.getFullYear());
|
||||
}
|
||||
|
||||
// sichtbares Datumsfeld
|
||||
setDateText(elRange.value, ymd);
|
||||
// Datum-Label (Tag bleibt im Picker!)
|
||||
setDateLabel(elRange.value, elDate.value);
|
||||
|
||||
// Zeitraum-Spanne
|
||||
elPeriod.textContent = (data?.tStart && data?.tEnd)
|
||||
@@ -423,48 +316,23 @@
|
||||
render(data);
|
||||
};
|
||||
|
||||
// ---------- UI EVENTS ----------
|
||||
// UI events
|
||||
elRange.addEventListener('change', () => {
|
||||
const r = elRange.value;
|
||||
setActivePicker(r);
|
||||
safeRequestAction('SetRange', r);
|
||||
// kein direktes SetDate hier nötig; der Nutzer wählt danach passend (Week/Month/Year)
|
||||
safeRequestAction('SetRange', elRange.value);
|
||||
// Label sofort updaten (Backend kommt dann eh gleich nach)
|
||||
setDateLabel(elRange.value, elDate.value);
|
||||
});
|
||||
|
||||
// Tag
|
||||
elDate.addEventListener('change', () => {
|
||||
const ymd = elDate.value;
|
||||
setDateText('day', ymd);
|
||||
safeRequestAction('SetDate', ymd);
|
||||
});
|
||||
|
||||
// Woche
|
||||
elWeek.addEventListener('change', () => {
|
||||
const mondayYmd = isoWeekToMondayYmd(elWeek.value);
|
||||
if (!mondayYmd) return;
|
||||
elDate.value = mondayYmd;
|
||||
setDateText('week', mondayYmd);
|
||||
safeRequestAction('SetDate', mondayYmd);
|
||||
});
|
||||
|
||||
// Monat
|
||||
elMonth.addEventListener('change', () => {
|
||||
const v = elMonth.value; // YYYY-MM
|
||||
if (!/^\d{4}-\d{2}$/.test(v)) return;
|
||||
const ymd = `${v}-01`;
|
||||
elDate.value = ymd;
|
||||
setDateText('month', ymd);
|
||||
safeRequestAction('SetDate', ymd);
|
||||
});
|
||||
|
||||
// Jahr
|
||||
elYearSel.addEventListener('change', () => {
|
||||
const y = elYearSel.value;
|
||||
const ymd = `${y}-01-01`;
|
||||
elDate.value = ymd;
|
||||
setDateText('year', ymd);
|
||||
safeRequestAction('SetDate', ymd);
|
||||
});
|
||||
let dateTimer = null;
|
||||
function pushDateNow(){
|
||||
if (dateTimer) clearTimeout(dateTimer);
|
||||
dateTimer = setTimeout(() => {
|
||||
setDateLabel(elRange.value, elDate.value);
|
||||
safeRequestAction('SetDate', elDate.value);
|
||||
}, 80);
|
||||
}
|
||||
elDate.addEventListener('input', pushDateNow);
|
||||
elDate.addEventListener('change', pushDateNow);
|
||||
|
||||
elPrev.addEventListener('click', () => safeRequestAction('Prev', 1));
|
||||
elToday.addEventListener('click', () => safeRequestAction('Today', 1));
|
||||
|
||||
Reference in New Issue
Block a user