// Loaded by normal Hub pages; dormant when the remote feature is disabled. (async () => { if (/^\/sag\/\d+\/v5\/?$/.test(location.pathname)) return; const {api, bootstrap, requestId} = await import('/static/js/remote-api.js'); try { await bootstrap(); } catch (_) { return; } const panel = document.createElement('div'); panel.style.cssText = 'position:fixed;right:12px;top:74px;z-index:1025;background:var(--bg-card,#fff);border:1px solid #ccd6df;border-radius:8px;padding:6px;display:flex;gap:8px;align-items:center;font-size:12px'; const link = document.createElement('a'); link.href = '/remote/manage'; link.textContent = 'Fjernbetjening'; const button = document.createElement('button'); button.className = 'btn btn-sm btn-outline-secondary'; button.textContent = 'Følg i denne fane'; panel.append(link, button); document.body.append(panel); const previousTabId = sessionStorage.getItem('hubRemoteTab'); const tabId = requestId(); let following = sessionStorage.getItem('hubRemoteFollow') === 'yes'; // Browsers copy sessionStorage when duplicating a tab. Detect a living original // so a duplicate cannot silently take over its remote connection. if (typeof BroadcastChannel !== 'undefined') { const channel = new BroadcastChannel('hub-remote-tabs'); let duplicate = false; channel.onmessage = ({data}) => { if (data.type === 'probe' && data.previous === tabId) channel.postMessage({type:'occupied',target:data.target}); if (data.type === 'occupied' && data.target === tabId) duplicate = true; }; if (previousTabId) { channel.postMessage({type:'probe',previous:previousTabId,target:tabId}); await new Promise(resolve => setTimeout(resolve, 150)); if (duplicate) { following = false; sessionStorage.setItem('hubRemoteFollow', 'no'); } } window.addEventListener('pagehide', () => channel.close(), {once:true}); } sessionStorage.setItem('hubRemoteTab', tabId); let sequence = 0, pending = false; let dirty = false; document.addEventListener('input', event => { if (event.isTrusted && !panel.contains(event.target)) dirty = true; }); document.addEventListener('change', event => { if (event.isTrusted && !panel.contains(event.target)) dirty = true; }); const label = () => { button.textContent = following ? 'Stop med at følge' : 'Følg i denne fane'; }; async function enable() { const result = await api('/follow', {tab_id: tabId, enable: true}); following = result.following; sequence = result.sequence; sessionStorage.setItem('hubRemoteFollow', following ? 'yes' : 'no'); label(); } button.onclick = async () => { if (pending) return; pending = true; button.disabled = true; try { if (following) { await api('/follow', {tab_id: tabId, disable: true}); following = false; sessionStorage.setItem('hubRemoteFollow', 'no'); label(); } else await enable(); } catch (error) { button.title = error.message; } finally { pending = false; button.disabled = false; } }; async function poll() { if (!following || pending || document.hidden) return; pending = true; try { const result = await api('/follow', {tab_id: tabId, after: sequence}); following = result.following; sequence = result.sequence; label(); if (!following) sessionStorage.setItem('hubRemoteFollow', 'no'); if (result.selection) { const path = `/sag/${result.selection.case_id}`; if (!location.pathname.match(new RegExp(`^${path}(/|$)`))) { // Keep an in-progress user edit visible before leaving the page. const editing = dirty || ['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement?.tagName); if (!editing || confirm('Fjernbetjeningen har valgt en anden sag. Skift nu?')) location.assign(path); } } } catch (error) { button.title = 'Forbindelse afbrudt · ' + error.message; } finally { pending = false; } } if (following) { try { await enable(); } catch (_) { following = false; } } label(); setInterval(poll, 3000); document.addEventListener('visibilitychange', () => { if (!document.hidden) poll(); }); })();