(function () { function runPageInits() { var inits = window.__tsPageInits || []; inits.forEach(function (fn) { if (typeof fn === 'function') { try { fn(); } catch (err) { console.error('Page init failed', err); } } }); } function buildPartialUrl(rawUrl) { var url = new URL(rawUrl, window.location.origin); url.searchParams.set('partial', '1'); return url.toString(); } function updateActiveLinks(pathname) { document.querySelectorAll('[data-partial-link="1"]').forEach(function (link) { var linkPath = new URL(link.href, window.location.origin).pathname.replace(/\/+/g, '/').replace(/\/$/, '') || '/'; var currentPath = pathname.replace(/\/+/g, '/').replace(/\/$/, '') || '/'; link.classList.toggle('active', linkPath === currentPath); }); } function loadPartial(href, pushState) { var body = document.body; if (!body || !body.hasAttribute('data-partial-root')) { window.location.href = href; return; } if (window.__tsNavigating) { return; } var mainContent = document.querySelector('.main-content'); if (!mainContent) { window.location.href = href; return; } window.__tsNavigating = true; body.classList.add('is-loading'); fetch(buildPartialUrl(href), { headers: { 'X-Requested-With': 'TimesheetPartial' }, credentials: 'same-origin' }) .then(function (response) { if (!response.ok) { throw new Error('Failed to load content'); } return response.text(); }) .then(function (html) { mainContent.innerHTML = html; if (pushState) { window.history.pushState({}, '', href); } updateActiveLinks(new URL(href, window.location.origin).pathname); runPageInits(); }) .catch(function () { window.location.href = href; }) .finally(function () { body.classList.remove('is-loading'); window.__tsNavigating = false; }); } function bindPartialNavigation() { document.addEventListener('click', function (event) { if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) { return; } var link = event.target.closest('a[data-partial-link="1"]'); if (!link) { return; } var href = link.getAttribute('href'); if (!href || href.startsWith('#')) { return; } var url = new URL(href, window.location.origin); if (url.origin !== window.location.origin) { return; } event.preventDefault(); loadPartial(url.toString(), true); }); window.addEventListener('popstate', function () { loadPartial(window.location.href, false); }); } function init() { runPageInits(); bindPartialNavigation(); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } })();