124 lines
4.2 KiB
JavaScript
124 lines
4.2 KiB
JavaScript
// Generated, do not edit. sha256:a469a46a90e6bcc2ab27a831978cd788d57e02abb6e3347f99750cb9fb53c286
|
|
import { claimNextCommand, resolveCommand } from './data/commands.js';
|
|
import { CONFIG, PLACE_LABELS, hashFromLocation, commandTooLate } from '../shared/config.js';
|
|
import { t } from './i18n/index.js';
|
|
import { esc } from './ui/escape.js';
|
|
|
|
const TAB = (globalThis.crypto?.randomUUID?.() || `tab-${Date.now()}-${Math.random()}`).slice(0, 40);
|
|
|
|
const KAN = Object.freeze(['navigate', 'locate']);
|
|
|
|
let bezig = false;
|
|
|
|
export function initCommands() {
|
|
document.addEventListener('commands-changed', () => { pakOp(); });
|
|
pakOp();
|
|
}
|
|
|
|
export async function pakOp() {
|
|
if (bezig) return;
|
|
bezig = true;
|
|
try {
|
|
const opdracht = await claimNextCommand(TAB, KAN);
|
|
if (opdracht) await voerUit(opdracht);
|
|
} catch { }
|
|
finally { bezig = false; }
|
|
}
|
|
|
|
async function voerUit(opdracht) {
|
|
if (opdracht.kind === 'locate') {
|
|
await resolveCommand(opdracht.id, TAB, 'done', hashFromLocation(location.hash));
|
|
return;
|
|
}
|
|
if (opdracht.kind !== 'navigate') {
|
|
await resolveCommand(opdracht.id, TAB, 'rejected', t('commands.unknownKind'));
|
|
return;
|
|
}
|
|
const hash = opdracht.payload && typeof opdracht.payload.hash === 'string' ? opdracht.payload.hash : '';
|
|
if (!hash.startsWith('#/')) {
|
|
await resolveCommand(opdracht.id, TAB, 'rejected', t('commands.badTarget'));
|
|
return;
|
|
}
|
|
|
|
if (commandTooLate(opdracht.expiresAt)) {
|
|
await resolveCommand(opdracht.id, TAB, 'expired', t('commands.tooLate'));
|
|
return;
|
|
}
|
|
|
|
const doorgaan = await aftellen(plekNaam(opdracht.payload));
|
|
if (!doorgaan) {
|
|
await resolveCommand(opdracht.id, TAB, 'rejected', t('commands.stopped'));
|
|
return;
|
|
}
|
|
location.hash = hash;
|
|
await resolveCommand(opdracht.id, TAB, 'done');
|
|
}
|
|
|
|
function plekNaam({ route, tab, sub }) {
|
|
const label = (id) => { try { return t(PLACE_LABELS[id] || `nav.${id}`); } catch { return id; } };
|
|
return [label(route), tab && label(tab), sub && label(sub)].filter(Boolean).join(' → ');
|
|
}
|
|
|
|
let directVoortaan = false;
|
|
|
|
function toonBalk(inhoud) {
|
|
const bar = document.createElement('div');
|
|
bar.className = 'cmd-bar';
|
|
bar.setAttribute('role', 'alert');
|
|
bar.innerHTML = inhoud;
|
|
document.body.appendChild(bar);
|
|
return bar;
|
|
}
|
|
|
|
const knop = (data, tekst, soort = 'secondary') =>
|
|
`<button type="button" class="btn btn-${soort} btn-sm" ${data}>${tekst}</button>`;
|
|
|
|
const knoppen = (...items) => `<div class="cmd-bar-buttons">${items.join('')}</div>`;
|
|
|
|
function meldDirect(plek) {
|
|
const bar = toonBalk(`<span class="cmd-bar-text">${t('commands.movedTo')} <strong>${esc(plek)}</strong></span>`
|
|
+ knoppen(knop('data-countdown-back', t('commands.countdownBack'))));
|
|
const weg = setTimeout(() => bar.remove(), CONFIG.COMMANDS.NOTICE_SECONDS * 1000);
|
|
bar.querySelector('[data-countdown-back]').addEventListener('click', () => {
|
|
directVoortaan = false;
|
|
clearTimeout(weg);
|
|
bar.remove();
|
|
});
|
|
}
|
|
|
|
function aftellen(plek) {
|
|
if (directVoortaan) { meldDirect(plek); return Promise.resolve(true); }
|
|
|
|
const seconden = CONFIG.COMMANDS.COUNTDOWN_SECONDS;
|
|
return new Promise((klaar) => {
|
|
let over = seconden;
|
|
const tekst = () => `${t('commands.goingTo')} <strong>${esc(plek)}</strong> (${over})`;
|
|
const bar = toonBalk(`<span class="cmd-bar-text">${tekst()}</span>`
|
|
+ knoppen(
|
|
knop('data-now', t('commands.goNow'), 'primary'),
|
|
knop('data-always', t('commands.goAlways')),
|
|
knop('data-stop', t('commands.stop')),
|
|
));
|
|
|
|
const op = (doorgaan) => {
|
|
clearInterval(tik);
|
|
document.removeEventListener('keydown', opEscape);
|
|
bar.remove();
|
|
klaar(doorgaan);
|
|
};
|
|
const opEscape = (e) => { if (e.key === 'Escape') op(false); };
|
|
bar.querySelector('[data-stop]').addEventListener('click', () => op(false));
|
|
const nu = bar.querySelector('[data-now]');
|
|
nu.addEventListener('click', () => op(true));
|
|
nu.focus();
|
|
bar.querySelector('[data-always]').addEventListener('click', () => { directVoortaan = true; op(true); });
|
|
document.addEventListener('keydown', opEscape);
|
|
|
|
const tik = setInterval(() => {
|
|
over -= 1;
|
|
if (over <= 0) { op(true); return; }
|
|
bar.querySelector('.cmd-bar-text').innerHTML = tekst();
|
|
}, 1000);
|
|
});
|
|
}
|