Einige kleine verbesserungen #1

Open
Scarriffle wants to merge 115 commits from beta into master
Showing only changes of commit 3152c744a0 - Show all commits

View File

@@ -40,6 +40,38 @@ let state = {
selectedEventColor: '', // '' = use calendar color selectedEventColor: '', // '' = use calendar color
}; };
// ── URL state ────────────────────────────────────────────
// View + Date werden in der URL als #date=YYYY-MM-DD&view=<view> gespiegelt,
// damit Reload/PWA-restore den letzten Stand wiederherstellen statt auf
// heute zu springen.
const VALID_VIEWS = ['month', 'week', 'day', 'quarter', 'agenda'];
function readUrlState() {
const hash = window.location.hash.replace(/^#/, '');
if (!hash) return {};
const params = new URLSearchParams(hash);
const out = {};
const view = params.get('view');
if (view && VALID_VIEWS.includes(view)) out.view = view;
const date = params.get('date');
if (date && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
const d = new Date(date + 'T00:00:00');
if (!isNaN(d.getTime())) out.date = d;
}
return out;
}
function writeUrlState() {
const d = state.currentDate;
const dateStr = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
const newHash = `date=${dateStr}&view=${state.currentView}`;
if (window.location.hash.replace(/^#/,'') !== newHash) {
// replaceState statt pushState: prev/next-Klicks sollen nicht jeden
// einzelnen Tag in den Browser-History-Stack drücken
window.history.replaceState(null, '', '#' + newHash);
}
}
// ── Public init ─────────────────────────────────────────── // ── Public init ───────────────────────────────────────────
export async function initCalendar() { export async function initCalendar() {
const [settings, accounts, localCalendars, icalSubscriptions, googleAccounts, haAccounts] = await Promise.all([ const [settings, accounts, localCalendars, icalSubscriptions, googleAccounts, haAccounts] = await Promise.all([
@@ -61,6 +93,11 @@ export async function initCalendar() {
state.dimPast = settings.dim_past_events; state.dimPast = settings.dim_past_events;
weekStartDay = settings.week_start_day || 'monday'; weekStartDay = settings.week_start_day || 'monday';
// URL state takes precedence over defaults (settings + today)
const urlState = readUrlState();
if (urlState.date) state.currentDate = urlState.date;
if (urlState.view) state.currentView = urlState.view;
setLang(settings.language || 'de'); setLang(settings.language || 'de');
applyTheme(settings); applyTheme(settings);
updateViewButtons(); updateViewButtons();
@@ -78,6 +115,22 @@ export async function initCalendar() {
bindProfileModal(); bindProfileModal();
bindSwipeNavigation(); bindSwipeNavigation();
handleHAOAuthReturn(); handleHAOAuthReturn();
// Browser-Back/Forward: URL-Hash → State synchronisieren
window.addEventListener('hashchange', () => {
const u = readUrlState();
let changed = false;
if (u.view && u.view !== state.currentView) {
state.currentView = u.view;
updateViewButtons();
changed = true;
}
if (u.date && !isSameDay(u.date, state.currentDate)) {
state.currentDate = u.date;
changed = true;
}
if (changed) fetchAndRender();
});
} }
function handleHAOAuthReturn() { function handleHAOAuthReturn() {
@@ -91,7 +144,7 @@ function handleHAOAuthReturn() {
}; };
if (params.has('ha_connected')) { if (params.has('ha_connected')) {
showToast('Home Assistant verbunden'); showToast('Home Assistant verbunden');
window.history.replaceState({}, '', window.location.pathname); window.history.replaceState({}, '', window.location.pathname + window.location.hash);
fetchAndRender(true); fetchAndRender(true);
api.get('/homeassistant/accounts').then(accs => { api.get('/homeassistant/accounts').then(accs => {
state.haAccounts = accs || []; state.haAccounts = accs || [];
@@ -101,7 +154,7 @@ function handleHAOAuthReturn() {
} else if (params.has('ha_error')) { } else if (params.has('ha_error')) {
const code = params.get('ha_error'); const code = params.get('ha_error');
showToast(errMap[code] || `HA-Anmeldung fehlgeschlagen: ${code}`, true); showToast(errMap[code] || `HA-Anmeldung fehlgeschlagen: ${code}`, true);
window.history.replaceState({}, '', window.location.pathname); window.history.replaceState({}, '', window.location.pathname + window.location.hash);
} }
} }
@@ -196,6 +249,7 @@ async function fetchAndRender(force = false, silent = false) {
renderView(); renderView();
updateTitle(); updateTitle();
renderMiniCal(); renderMiniCal();
writeUrlState();
prefetchIfNeeded(start, end); // extend cache in background if approaching an edge prefetchIfNeeded(start, end); // extend cache in background if approaching an edge
return; return;
} }
@@ -224,6 +278,7 @@ async function fetchAndRender(force = false, silent = false) {
renderView(); renderView();
updateTitle(); updateTitle();
renderMiniCal(); renderMiniCal();
writeUrlState();
} }
function getViewRange() { function getViewRange() {