mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
refactor: isolate Map Source controls and selection lifecycle
This commit is contained in:
1 parent
78199c2ab3
commit
72d531b18f
14 files changed
+405
-72
No files matched your search
@@ -0,0 +1,75 @@
|
||||
import { renderMapStackChips, syncMapStackChips } from '../mapStackChips.js';
|
||||
|
||||
/**
|
||||
* Own Map Source presentation and selection without constructing map providers.
|
||||
* The supplied controller remains authoritative for availability and active state.
|
||||
*/
|
||||
export function createMapSourceControls({
|
||||
container, statusElement, controller, subscribe,
|
||||
claimSelection = () => {}, onStateChanged = () => {}, onError = () => {},
|
||||
}) {
|
||||
let destroyed = false;
|
||||
let generation = 0;
|
||||
const removers = [];
|
||||
const bind = (element, type, listener) => {
|
||||
element.addEventListener(type, listener);
|
||||
removers.push(() => element.removeEventListener(type, listener));
|
||||
};
|
||||
function render(state) {
|
||||
if (destroyed || !state) return;
|
||||
syncMapStackChips(container, state.activeId);
|
||||
if (statusElement) {
|
||||
const stack = state.activeStack;
|
||||
statusElement.textContent = state.status === 'switching' ? '...' : (stack?.shortLabel || stack?.label || 'MAP');
|
||||
statusElement.classList.toggle('warn', !!state.lastError);
|
||||
}
|
||||
}
|
||||
async function select(stackId, { syncShare = true } = {}) {
|
||||
if (destroyed) return null;
|
||||
const current = ++generation;
|
||||
if (syncShare) claimSelection();
|
||||
const before = controller.getActiveId();
|
||||
render(controller.getState('switching'));
|
||||
let state;
|
||||
try {
|
||||
state = await controller.setStack(stackId);
|
||||
} catch (error) {
|
||||
if (!destroyed && current === generation) {
|
||||
render(controller.getState());
|
||||
onError(error?.message || String(error));
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
if (destroyed || current !== generation) return state;
|
||||
render(controller.getState());
|
||||
if (state?.activeId === before && stackId !== before && state?.lastError) onError(state.lastError);
|
||||
if (syncShare) onStateChanged();
|
||||
return state;
|
||||
}
|
||||
function refresh() {
|
||||
if (destroyed) return;
|
||||
for (const remove of removers.splice(0)) remove();
|
||||
renderMapStackChips(container, controller.getStacks(), {
|
||||
activeId: controller.getActiveId(),
|
||||
onSelect: (id) => { void select(id).catch(() => {}); },
|
||||
bind,
|
||||
});
|
||||
render(controller.getState());
|
||||
}
|
||||
const unsubscribe = subscribe(() => {
|
||||
if (destroyed) return;
|
||||
render(controller.getState());
|
||||
onStateChanged();
|
||||
});
|
||||
refresh();
|
||||
return {
|
||||
render, select, refresh,
|
||||
destroy() {
|
||||
if (destroyed) return;
|
||||
destroyed = true;
|
||||
generation++;
|
||||
unsubscribe?.();
|
||||
for (const remove of removers.splice(0)) remove();
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user