mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-13 14:52:19 +00:00
Fix Data Library share restore, dense tile layers and EPC partition reads
- Share links: the compact /share/<code> format carries the switched-on library entries (field 29), so Copy Link keeps them; a share opened in the same tab restores them; any share decides what is on, so one with every library entry off no longer switches on the recipient's stored entries. - A tile entry too dense at its minimum zoom (Norway cadastre z14, depth z11) is hidden below that scale via minimumTerrainLevel instead of allocating millions of tiles when zoomed out. - EPC partitions keep the full extent for exclusion and the 98 % extent for ranking only; the old trimmed-only extents are retired. - Partition index footers that fail transiently are retried; an incomplete index is never cached as complete, a complete prior index is kept, and it is rebuilt after five minutes. - Views that leave touching partitions unread are partial; listing and footer bodies are capped and ranges validated. - The Browse dialog relabels after a language switch.
This commit is contained in:
1 parent
871b7f0fcc
commit
24ccdd4dc3
20 files changed
+1220
-162
No files matched your search
+85
-20
@@ -69,6 +69,9 @@ export function createDataLibrary({
|
||||
let serverPresent = false;
|
||||
let selection = { added: [], on: [] };
|
||||
let started = false;
|
||||
// Set once availability is known; a share navigated to before then waits.
|
||||
let loaded = false;
|
||||
let queuedShare = null;
|
||||
let destroyed = false;
|
||||
const listeners = new Set();
|
||||
const pending = new Map();
|
||||
@@ -165,6 +168,73 @@ export function createDataLibrary({
|
||||
persist();
|
||||
});
|
||||
|
||||
/** Entry ids for share tokens; unknown tokens are skipped. */
|
||||
const idsForTokens = (list) =>
|
||||
(list || []).map((token) => tokens.idByToken.get(token)).filter(Boolean);
|
||||
|
||||
/**
|
||||
* The share this page opened with: null without one, else the entry ids it
|
||||
* switches on ([] for a share that switches none on).
|
||||
*/
|
||||
function openingShare() {
|
||||
if (shareLink && shareLink.initialLibraryTokens !== undefined) {
|
||||
const linked = shareLink.initialLibraryTokens;
|
||||
return linked === null ? null : idsForTokens(linked);
|
||||
}
|
||||
const hash = String(initialHash || '').replace(/^#/, '');
|
||||
if (!hash) return null;
|
||||
const params = new URLSearchParams(hash);
|
||||
const linked = decodeLibraryParam(params, tokens.idByToken);
|
||||
// Any share (a camera position) decides what is on; no `lib`, nothing.
|
||||
if (linked === null && params.has('lat') && params.has('lon')) return [];
|
||||
return linked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a selection: register and switch on what `on` names, switch off
|
||||
* every other added entry that is on. `origin` marks it as a restore so it
|
||||
* is never remembered as the viewer's own choice.
|
||||
*/
|
||||
function applySelection(next, origin) {
|
||||
selection = normalizeLibrarySelection(next, switchable);
|
||||
for (const id of selection.added) {
|
||||
const entry = byId.get(id);
|
||||
if (!entry || !addable(id)) continue;
|
||||
const wanted = selection.on.includes(id);
|
||||
if (wanted && !register(entry)) continue;
|
||||
if (!isRegistered(id)) continue;
|
||||
const layerId = libraryLayerId(id);
|
||||
if (wanted === (dataManager.isEnabled?.(layerId) === true)) continue;
|
||||
dataManager
|
||||
.setEnabled(layerId, wanted, { origin })
|
||||
.catch((error) =>
|
||||
console.warn(`[Library] ${id} restore failed:`, error),
|
||||
);
|
||||
}
|
||||
writeStoredLibrarySelection(storage, selection);
|
||||
shareLink?.onLibraryStateChange?.();
|
||||
notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* A share opened in this tab after start-up: its entries join the library
|
||||
* and it alone decides which are on.
|
||||
* @param {string[]} shareTokens
|
||||
*/
|
||||
function applyShare(shareTokens) {
|
||||
if (destroyed) return;
|
||||
if (!loaded) {
|
||||
queuedShare = [...(shareTokens || [])];
|
||||
return;
|
||||
}
|
||||
const linked = idsForTokens(shareTokens);
|
||||
applySelection(
|
||||
{ added: [...selection.added, ...linked], on: linked },
|
||||
'share-restore',
|
||||
);
|
||||
}
|
||||
shareLink?.setLibraryShareListener?.(applyShare);
|
||||
|
||||
shareLink?.setLibraryParamsEncoder?.((params) =>
|
||||
encodeLibraryParam(
|
||||
params,
|
||||
@@ -186,29 +256,23 @@ export function createDataLibrary({
|
||||
availability = answer.availability;
|
||||
serverPresent = answer.server;
|
||||
const stored = readStoredLibrarySelection(storage, switchable);
|
||||
const hash = String(initialHash || '').replace(/^#/, '');
|
||||
const linked = hash
|
||||
? decodeLibraryParam(new URLSearchParams(hash), tokens.idByToken)
|
||||
: null;
|
||||
// A share opened in this tab while availability loaded wins over the
|
||||
// opening one.
|
||||
const linked = queuedShare ? idsForTokens(queuedShare) : openingShare();
|
||||
queuedShare = null;
|
||||
loaded = true;
|
||||
// A link's entries join the viewer's library and open switched on; with a
|
||||
// link, it alone decides what is on, as it does for core layers.
|
||||
const added = [...stored.added, ...(linked || [])];
|
||||
const on = linked ?? stored.on;
|
||||
selection = normalizeLibrarySelection({ added, on }, switchable);
|
||||
const restoreOrigin = linked ? 'share-restore' : 'local-restore';
|
||||
for (const id of selection.added) {
|
||||
// link, it alone decides what is on, as it does for core layers, so a
|
||||
// share with every library entry off switches the stored ones off.
|
||||
// Added entries register even while off, so their rows show.
|
||||
for (const id of [...stored.added, ...(linked || [])]) {
|
||||
const entry = byId.get(id);
|
||||
if (!entry || !addable(id) || !register(entry)) continue;
|
||||
if (selection.on.includes(id))
|
||||
dataManager
|
||||
.setEnabled(libraryLayerId(id), true, { origin: restoreOrigin })
|
||||
.catch((error) =>
|
||||
console.warn(`[Library] ${id} restore failed:`, error),
|
||||
);
|
||||
if (entry && addable(id)) register(entry);
|
||||
}
|
||||
writeStoredLibrarySelection(storage, selection);
|
||||
shareLink?.onLibraryStateChange?.();
|
||||
notify();
|
||||
applySelection(
|
||||
{ added: [...stored.added, ...(linked || [])], on: linked ?? stored.on },
|
||||
linked ? 'share-restore' : 'local-restore',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -388,6 +452,7 @@ export function createDataLibrary({
|
||||
destroyed = true;
|
||||
unsubscribeManager?.();
|
||||
shareLink?.setLibraryParamsEncoder?.(null);
|
||||
shareLink?.setLibraryShareListener?.(null);
|
||||
listeners.clear();
|
||||
},
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user