mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-15 15:52:21 +00:00
Keep history entries untouched by unfinished globe picks and restore each visited entry's layers
A picked engine now lives in the switch until it runs; only then is the address written, so a pick superseded by Back or one that fails rewrites no entry. An engine-changing history visit holds the outgoing share link, which neither restores nor writes the visited entry, and the running engine takes the address back once the switch settles, restoring any entry visited while it was held or not yet listening. Handed-off layers keep running where the incoming address agrees with the outgoing one and follow a visited entry where it differs. A failed recovery keeps the error on the loading screen with an engine picker for a retry, and a failing reveal of the new globe no longer blocks the cover removal or later requests.
This commit is contained in:
1 parent
9cc34e324f
commit
a066a2d1ca
10 files changed
+539
-113
No files matched your search
+63
-29
@@ -34,27 +34,20 @@ window.addEventListener('pagehide', (event) => {
|
||||
.finally(() => renderers.clear());
|
||||
});
|
||||
|
||||
// Registered before any engine starts, so these run ahead of the running
|
||||
// session's own share-link listeners. A history visit that changes the
|
||||
// engine belongs to the switch: the outgoing engine must not start restoring
|
||||
// that entry's share (and release the followed subject) just before it hands
|
||||
// the session off. The incoming engine reads the entry's view as it starts.
|
||||
let swallowedHash = null;
|
||||
window.addEventListener('popstate', (event) => {
|
||||
// Registered before any engine starts, so it runs ahead of the session's own
|
||||
// share-link listeners. A history visit that changes the engine belongs to
|
||||
// the switch: the outgoing engine's share link neither restores that entry
|
||||
// (releasing the followed subject just before the handoff) nor writes its
|
||||
// own view onto it. The incoming engine reads the entry as it starts, and
|
||||
// settle() hands the address back to whichever engine then runs.
|
||||
window.addEventListener('popstate', () => {
|
||||
if (!engineSwitch) return;
|
||||
swallowedHash = null;
|
||||
if (pageEngineKind() !== engineSwitch.state().engine) {
|
||||
event.stopImmediatePropagation();
|
||||
swallowedHash = location.hash;
|
||||
}
|
||||
if (pageEngineKind() !== engineSwitch.state().engine)
|
||||
application
|
||||
?.getComponents()
|
||||
.controls?.styleManager?.shareLinkManager?.holdNavigation?.();
|
||||
void engineSwitch.reconcile();
|
||||
});
|
||||
window.addEventListener('hashchange', (event) => {
|
||||
// Back/Forward fires hashchange after popstate for the same entry.
|
||||
if (swallowedHash !== null && location.hash === swallowedHash)
|
||||
event.stopImmediatePropagation();
|
||||
swallowedHash = null;
|
||||
});
|
||||
|
||||
function createApplication(kind, engineSwitch) {
|
||||
layerSession.restoringView = engineSwitch;
|
||||
@@ -83,7 +76,11 @@ async function leave(from) {
|
||||
if (components) {
|
||||
cover ??= keepGlobeFrame(components.scene.engine);
|
||||
cockpit = components.controls.styleManager.getCockpitState();
|
||||
handOffSession(layerSession);
|
||||
handOffSession(layerSession, {
|
||||
addressLayerIds:
|
||||
components.controls.styleManager.shareLinkManager?.currentLayerState?.()
|
||||
?.enabledLayerIds,
|
||||
});
|
||||
renderers.retain(from);
|
||||
}
|
||||
await application?.destroy();
|
||||
@@ -127,20 +124,56 @@ async function enter(kind) {
|
||||
}
|
||||
|
||||
async function settle() {
|
||||
const engine = liveComponents()?.scene.engine;
|
||||
if (cover && engine) await waitForFirstFrame(engine);
|
||||
// A page left without an engine keeps the last handoff for the next try.
|
||||
if (engine) {
|
||||
layerSession.handoffLayers = null;
|
||||
cockpit = null;
|
||||
const components = liveComponents();
|
||||
try {
|
||||
if (cover && components) await waitForFirstFrame(components.scene.engine);
|
||||
} finally {
|
||||
cover?.remove();
|
||||
cover = null;
|
||||
}
|
||||
cover?.remove();
|
||||
cover = null;
|
||||
// A page left without an engine keeps the last handoff for the next try.
|
||||
if (!components) return;
|
||||
layerSession.handoffLayers = null;
|
||||
cockpit = null;
|
||||
withdrawEngineRetry();
|
||||
// The running engine owns the address again, including an entry visited
|
||||
// before its share link listened or while it was held.
|
||||
components.controls.styleManager.shareLinkManager?.resumeNavigation?.();
|
||||
}
|
||||
|
||||
function present() {
|
||||
const { kind, busy } = engineSwitch.state();
|
||||
display.presentGlobeEngine({ kind, busy, select });
|
||||
for (const button of loading.querySelectorAll('.engine-switch-retry button'))
|
||||
button.disabled = busy;
|
||||
}
|
||||
|
||||
// No engine runs after a failed recovery. The error stays on the loading
|
||||
// screen with an engine picker, so a new attempt needs no reload.
|
||||
function offerEngineRetry() {
|
||||
const content = loading.querySelector('.loader-content') ?? loading;
|
||||
if (content.querySelector('.engine-switch-retry')) return;
|
||||
const group = document.createElement('div');
|
||||
group.className = 'engine-switch-retry';
|
||||
group.setAttribute('role', 'group');
|
||||
group.setAttribute('aria-label', t('Globe Engine'));
|
||||
for (const [kind, name] of [
|
||||
['cesium', 'Cesium'],
|
||||
['navara', 'Navara'],
|
||||
]) {
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.dataset.engine = kind;
|
||||
button.textContent = name;
|
||||
button.setAttribute('translate', 'no');
|
||||
button.addEventListener('click', () => select(kind));
|
||||
group.append(button);
|
||||
}
|
||||
content.append(group);
|
||||
}
|
||||
|
||||
function withdrawEngineRetry() {
|
||||
loading.querySelector('.engine-switch-retry')?.remove();
|
||||
}
|
||||
|
||||
function report(error) {
|
||||
@@ -198,8 +231,9 @@ createApplication(initialKind, false)
|
||||
onChange: present,
|
||||
onFailure(error, { recovered }) {
|
||||
const style = recovered && liveComponents()?.controls.styleManager;
|
||||
if (style) style._showToast(describeError(error));
|
||||
else report(error);
|
||||
if (style) return style._showToast(describeError(error));
|
||||
report(error);
|
||||
offerEngineRetry();
|
||||
},
|
||||
});
|
||||
present();
|
||||
|
||||
Reference in new issue
Block a user