mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
Merge upstream main into feat/tools-area-breakdowns
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
38b95fb3b1
7 files changed
+104
-9
No files matched your search
@@ -1,7 +1,11 @@
|
||||
import { searchHls } from './catalog.js';
|
||||
import { gibsTemplate, wvsSnapshotUrl } from './model.js';
|
||||
|
||||
/** NASA-compatible imagery acquisition; transport and URL builders are replaceable. */
|
||||
/**
|
||||
* NASA-compatible imagery acquisition; transport and URL builders are replaceable.
|
||||
* Thumbnail responses must expose Data-Present: true for image admission, or
|
||||
* false for confirmed empty coverage, including injected getThumbnail sources.
|
||||
*/
|
||||
export function createRecentImagerySource({
|
||||
fetchImpl = (...args) => globalThis.fetch(...args),
|
||||
search = searchHls,
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createThumbnailLoader } from './thumbnails.js';
|
||||
test('missing or malformed presence evidence cannot prove thumbnail pixels', async () => {
|
||||
for (const header of [null, 'unknown', '', 'true', 'false']) {
|
||||
let decodes = 0;
|
||||
const loader = createThumbnailLoader({
|
||||
requestThumbnail: async () => ({
|
||||
ok: true,
|
||||
headers: { get: (key) => (key === 'Data-Present' ? header : null) },
|
||||
blob: async () => {
|
||||
decodes++;
|
||||
return new Blob(['fixture']);
|
||||
},
|
||||
}),
|
||||
createObjectUrl: () => 'blob:fixture',
|
||||
});
|
||||
loader.request(
|
||||
{ key: 'fixture', product: 'S30', day: '2026-09-18' },
|
||||
{ west: 0, east: 1, south: 0, north: 1 },
|
||||
);
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
assert.equal(
|
||||
loader.get('fixture').status,
|
||||
header === 'true' ? 'present' : header === 'false' ? 'empty' : 'error',
|
||||
);
|
||||
assert.equal(decodes, header === 'true' ? 1 : 0);
|
||||
loader.destroy();
|
||||
}
|
||||
});
|
||||
@@ -100,12 +100,12 @@ export function createThumbnailLoader({
|
||||
cancelled = true;
|
||||
} else if (response?.ok) {
|
||||
const present = String(
|
||||
response.headers?.get?.('Data-Present') ?? 'true',
|
||||
response.headers?.get?.('Data-Present') ?? '',
|
||||
).toLowerCase();
|
||||
acquisitionTime = response.headers?.get?.('Acquisition-Time') || null;
|
||||
if (present === 'false') {
|
||||
status = 'empty';
|
||||
} else {
|
||||
} else if (present === 'true') {
|
||||
const blob = await response.blob();
|
||||
if (controller.signal.aborted) cancelled = true;
|
||||
else {
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createSurfaceKeyboard } from './surfaceKeyboard.js';
|
||||
test('surface cycling never targets deliberately excluded controls', () => {
|
||||
let handler;
|
||||
const documentRef = {
|
||||
activeElement: {},
|
||||
addEventListener: (_, fn) => (handler = fn),
|
||||
removeEventListener() {},
|
||||
};
|
||||
const node = ({
|
||||
attributes = {},
|
||||
fieldsetDisabled = false,
|
||||
inert = false,
|
||||
} = {}) => ({
|
||||
hasAttribute: (name) => Object.hasOwn(attributes, name),
|
||||
getClientRects: () => [{}],
|
||||
getAttribute: (name) => attributes[name] ?? null,
|
||||
matches: (selector) => selector === ':disabled' && fieldsetDisabled,
|
||||
closest: (selector) =>
|
||||
selector === '[inert]' && inert ? { inert: true } : null,
|
||||
focus() {
|
||||
documentRef.activeElement = this;
|
||||
},
|
||||
});
|
||||
const ignored = [
|
||||
node({ attributes: { tabindex: '-1' } }),
|
||||
node({ fieldsetDisabled: true }),
|
||||
node({ inert: true }),
|
||||
];
|
||||
const first = node({}),
|
||||
last = node({});
|
||||
const controls = [...ignored, first, last];
|
||||
const root = {
|
||||
ownerDocument: documentRef,
|
||||
querySelectorAll: () => controls,
|
||||
contains: (n) => controls.includes(n),
|
||||
};
|
||||
const surface = createSurfaceKeyboard({
|
||||
root,
|
||||
isActive: () => true,
|
||||
onEscape() {},
|
||||
});
|
||||
surface.activate();
|
||||
const press = (shiftKey) =>
|
||||
handler({
|
||||
key: 'Tab',
|
||||
shiftKey,
|
||||
preventDefault() {},
|
||||
stopPropagation() {},
|
||||
});
|
||||
press(false);
|
||||
assert.equal(documentRef.activeElement, first);
|
||||
press(true);
|
||||
assert.equal(documentRef.activeElement, last);
|
||||
surface.destroy();
|
||||
});
|
||||
@@ -39,7 +39,11 @@ export function createSurfaceKeyboard({
|
||||
),
|
||||
].filter(
|
||||
(node) =>
|
||||
!node.hasAttribute('disabled') && node.getClientRects().length > 0,
|
||||
!node.hasAttribute('disabled') &&
|
||||
!node.matches?.(':disabled') &&
|
||||
!(Number(node.getAttribute?.('tabindex')) < 0) &&
|
||||
!node.closest?.('[inert]') &&
|
||||
node.getClientRects().length > 0,
|
||||
);
|
||||
if (!order.length) return;
|
||||
const first = order[0];
|
||||
|
||||
Reference in new issue
Block a user