fix(street-level): re-check after every await; close the old photo; fresh panel views

Address samehkhamis's review on #1113:

- show_street_level checks the turn, the camera's owner (navigation stamp,
  re-taken where its own flight lands, or a press/wheel on the globe) and
  the hiding modes after the flight, the map switch, the layer switch-on and
  the lookup; a photo that opened after either is closed again. The hidden
  panel is also refused before the flight.
- An open photo closes before a new request arms or looks up, so a place
  with no imagery shows its own error.
- The panel posts every view with `fresh`; the inline app opens a billed
  photo only for a fresh one.
- A passed-through view's street_level point moves with a new camera
  position; revealPanel does nothing above 720px, scrolling included.
- Document that the app's own links do not carry `sl`.
This commit is contained in:
Said Turksever committed 2026-11-06 00:40:20 +00:00
1 parent 14f7326dbf
commit 30e6cd39c7
15 files changed
+486 -57

No files matched your search

+53
View File
@@ -188,6 +188,59 @@ test('an embedded page takes views only from its parent and answers it', async (
remove();
});
test('an inline panel opens a billed photo only for a view whose result is fresh', async () => {
const windowRef = new EventTarget();
windowRef.parent = windowRef;
windowRef.postMessage = () => {};
windowRef.document = { body: { classList: new Set() } };
windowRef.document.body.classList.add = Set.prototype.add;
Object.assign(windowRef, {
requestAnimationFrame: () => 1,
cancelAnimationFrame() {},
setInterval: () => 1,
clearInterval() {},
});
const { calls, run } = recorder();
globalThis.GEV_EMBED_INLINE = true;
try {
const remove = installViews({
shell: { initialRestorePromise: Promise.resolve() },
viewer: fakeViewer(),
dataManager: fakeLayers(new Set()),
run,
location: { search: '', hash: '' },
windowRef,
});
const view = {
camera: { lat: 48.8584, lon: 2.2945 },
map: 'photoreal',
street_level: { provider: 'google', lat: 48.8584, lon: 2.2945 },
};
for (const [id, fresh] of [
[1, true],
[2, false],
[3, undefined],
]) {
const event = new Event('message');
Object.assign(event, {
source: windowRef,
data: { type: 'gev:view', id, view, fresh },
});
windowRef.dispatchEvent(event);
}
await new Promise((resolve) => setTimeout(resolve, 20));
assert.deepEqual(
calls
.filter(([name]) => name === 'show_street_level')
.map(([, args]) => args.autoOpen ?? true),
[true, false, false],
);
remove();
} finally {
delete globalThis.GEV_EMBED_INLINE;
}
});
test('an app loaded inline into a panel page talks through its own window', async () => {
const posted = [];
const windowRef = new EventTarget();