Files
preland/components/navigation-guard.php

71 lines
1.8 KiB
PHP

<?php
// Общий inline-контракт Back для незавершённой публичной операции (api#299/preland#9).
return <<<'JS'
(() => {
let active = false;
let hasHistoryEntry = false;
let releasingHistoryEntry = false;
let returningToSentinel = false;
function pushGuardEntries() {
// Помечаем и текущую запись Tour, и sentinel сверху. Иначе первый Back
// останавливался на немаркированной записи, а второй мог уйти в about:blank.
window.history.replaceState({ publicOperationGuard: true }, '', window.location.href);
window.history.pushState({ publicOperationGuard: true }, '', window.location.href);
hasHistoryEntry = true;
}
function onPopState(event) {
if (releasingHistoryEntry) {
releasingHistoryEntry = false;
return;
}
if (active) {
if (returningToSentinel) {
returningToSentinel = false;
return;
}
returningToSentinel = true;
window.history.go(1);
}
}
function deactivate(onReleased) {
if (!active) {
if (onReleased) {
if (releasingHistoryEntry) {
window.addEventListener('popstate', onReleased, { once: true });
} else {
onReleased();
}
}
return;
}
active = false;
if (hasHistoryEntry) {
hasHistoryEntry = false;
releasingHistoryEntry = true;
if (onReleased) window.addEventListener('popstate', onReleased, { once: true });
window.history.back();
return;
}
if (onReleased) onReleased();
}
window.addEventListener('popstate', onPopState);
window.PublicNavigationGuard = {
activate() {
if (active) return;
releasingHistoryEntry = false;
returningToSentinel = false;
active = true;
pushGuardEntries();
},
deactivate,
allowNavigation: deactivate,
};
})();
JS;