mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
fix: retain shell feedback bindings and stop disposed panel work
This commit is contained in:
1 parent
03ad8142e6
commit
945a809994
5 files changed
+63
-29
No files matched your search
@@ -33,7 +33,10 @@ try {
|
||||
const ui = window.__godsEyeView.styleManager;
|
||||
const counts = {};
|
||||
const watchObserver = (name) => {
|
||||
const owner = name === '_draggableResizeObserver' ? ui._panelPosition : ui._panelLayout;
|
||||
const owner =
|
||||
name === '_draggableResizeObserver'
|
||||
? ui._panelPosition
|
||||
: ui._panelLayout;
|
||||
const observer = owner[name];
|
||||
if (!observer) return false;
|
||||
const disconnect = observer.disconnect.bind(observer);
|
||||
@@ -110,6 +113,12 @@ try {
|
||||
if (type === 'resize' && callback === resizeHandler) counts.resize++;
|
||||
return removeEventListener.call(this, type, callback, options);
|
||||
};
|
||||
const { setSplitFlapText } = await import('/src/splitFlap.js');
|
||||
const feedbackLabel = document.getElementById('global-loading-label');
|
||||
setSplitFlapText(feedbackLabel, 'CHECKING LIVE DATA');
|
||||
setSplitFlapText(feedbackLabel, 'LOAD COMPLETE');
|
||||
const permanentText =
|
||||
feedbackLabel.querySelector('.gev-flap-text')?.firstChild;
|
||||
try {
|
||||
const disposal = ui.dispose();
|
||||
const focusBefore = document.activeElement;
|
||||
@@ -167,7 +176,11 @@ try {
|
||||
counts[field] === 1 && ui._contextControls[field] === null,
|
||||
),
|
||||
observersReleased: observed.every(
|
||||
(name) => counts[name] === 1 && ui[name] === null,
|
||||
(name) =>
|
||||
counts[name] === 1 &&
|
||||
(name === '_draggableResizeObserver'
|
||||
? ui._panelPosition
|
||||
: ui._panelLayout)[name] === null,
|
||||
),
|
||||
subscriptionReleased:
|
||||
counts.cctv === 1 && ui._cctvControls._cctvUnsubscribe === null,
|
||||
@@ -176,6 +189,19 @@ try {
|
||||
ui._radioControls.destroyed &&
|
||||
ui._locationControls.destroyed &&
|
||||
ui._cctvControls.destroyed,
|
||||
feedbackTextPreserved:
|
||||
permanentText?.nodeType === Node.TEXT_NODE &&
|
||||
feedbackLabel.querySelector('.gev-flap-text')?.firstChild ===
|
||||
permanentText &&
|
||||
permanentText.data === 'LOAD COMPLETE' &&
|
||||
!feedbackLabel.classList.contains('gev-flap-active') &&
|
||||
feedbackLabel.querySelector('.gev-flap-cells')?.childNodes.length ===
|
||||
0,
|
||||
shellWorkReleased:
|
||||
ui._lifetime.destroyed &&
|
||||
ui._lifetime.frames.size === 0 &&
|
||||
ui._lifetime.timers.size === 0 &&
|
||||
ui._lifetime.removers.size === 0,
|
||||
idempotent: once === JSON.stringify(counts),
|
||||
};
|
||||
} finally {
|
||||
@@ -215,6 +241,14 @@ try {
|
||||
'Cockpit cleanup releases listeners and returns all Display groups home',
|
||||
result.cockpitReleased,
|
||||
);
|
||||
check(
|
||||
'feedback teardown preserves the permanent accessible text node',
|
||||
result.feedbackTextPreserved,
|
||||
);
|
||||
check(
|
||||
'shell teardown cancels deferred work and releases listeners',
|
||||
result.shellWorkReleased,
|
||||
);
|
||||
check('repeated UI disposal is inert', result.idempotent);
|
||||
check(
|
||||
'disposal and subsequent resize produce no uncaught browser errors',
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { setSplitFlapText } from '../splitFlap.js';
|
||||
import { UiLifetime } from './uiLifetime.js';
|
||||
import { RecordingControls } from './recordingControls.js';
|
||||
import { readShellElements } from './shellElements.js';
|
||||
@@ -86,8 +87,6 @@ import {
|
||||
stampInitialShareGesture,
|
||||
} from '../navigationPolicy.js';
|
||||
|
||||
/** Versioned localStorage namespace prefix to invalidate stale panel layouts. */
|
||||
|
||||
const SHARE_PANEL_STATE_SPECS = Object.freeze([
|
||||
{ id: 'control-panel', pinnable: true },
|
||||
{ id: 'location-bar', pinnable: true },
|
||||
@@ -108,28 +107,7 @@ const COCKPIT_ENTRY_COLLAPSE_PANEL_IDS = Object.freeze([
|
||||
'global-context-panel',
|
||||
'radio-panel',
|
||||
]);
|
||||
/**
|
||||
* Position keys are versioned separately from collapsed-state keys so layout
|
||||
* default changes (e.g. right-rail origin) can reset positions without also
|
||||
* resetting every panel's open/closed preference.
|
||||
*/
|
||||
|
||||
const DETECTION_ALLOCATION_STORAGE_KEY = 'gev:detection-allocation:v1';
|
||||
/** Z ladder: panels promote within [100, 139]; voice pill 150, toast 200, clean-view-exit 300. */
|
||||
|
||||
/**
|
||||
* Fixed UI regions that can occupy the left accordion's vertical lane.
|
||||
* Rectangles are filtered at runtime for visibility and horizontal overlap,
|
||||
* so right-side/center controls do not reduce the lane unless they actually
|
||||
* intersect it at the current viewport size.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fixed UI regions that can occupy the right control lane. Runtime rectangle
|
||||
* filtering keeps the rail clear of whichever HUD variant is currently
|
||||
* visible without tying the layout to one screen height.
|
||||
*/
|
||||
|
||||
/** Display labels shown in the mini-status readout for each active style. */
|
||||
const STYLE_STATUS_LABELS = {
|
||||
normal: 'NORMAL',
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
/** Own rail measurement, layout scheduling and dock tray observation. */
|
||||
import { layoutLeftPanelRail, layoutRightPanelRail } from './panelRails.js';
|
||||
const COCKPIT_LAYOUT_SETTLE_MS = 240;
|
||||
/**
|
||||
* Fixed UI regions that can occupy the left accordion's vertical lane.
|
||||
* Rectangles are filtered at runtime for visibility and horizontal overlap,
|
||||
* so right-side/center controls do not reduce the lane unless they actually
|
||||
* intersect it at the current viewport size.
|
||||
*/
|
||||
const LEFT_STACK_OBSTACLE_SELECTOR = [
|
||||
'#cockpit-hud .cockpit-topline',
|
||||
'#cockpit-hud .cockpit-topline > div',
|
||||
@@ -26,6 +32,11 @@ const LEFT_STACK_OBSTACLE_SELECTOR = [
|
||||
'#pp-toggles',
|
||||
'#param-slider-panel',
|
||||
].join(', ');
|
||||
/**
|
||||
* Fixed UI regions that can occupy the right control lane. Runtime rectangle
|
||||
* filtering keeps the rail clear of whichever HUD variant is currently
|
||||
* visible without tying the layout to one screen height.
|
||||
*/
|
||||
const RIGHT_STACK_OBSTACLE_SELECTOR = [
|
||||
'#cockpit-hud .cockpit-topline',
|
||||
'#cockpit-hud .cockpit-topline > div',
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
/** Own panel position preferences, viewport clamping and drag listeners. */
|
||||
/** Versioned localStorage namespace prefix to invalidate stale panel layouts. */
|
||||
const PANEL_LAYOUT_STORAGE_VERSION = 'v6';
|
||||
/**
|
||||
* Position keys are versioned separately from collapsed-state keys so layout
|
||||
* default changes (e.g. right-rail origin) can reset positions without also
|
||||
* resetting every panel's open/closed preference.
|
||||
*/
|
||||
const PANEL_POSITION_STORAGE_VERSION = 'v8';
|
||||
/** Z ladder: panels promote within [100, 139]; voice pill 150, toast 200, clean-view-exit 300. */
|
||||
const PANEL_Z_BASE = 100;
|
||||
const PANEL_Z_MAX = 139;
|
||||
export class PanelPositionControls {
|
||||
@@ -22,6 +29,7 @@ export class PanelPositionControls {
|
||||
this.destroyed = false;
|
||||
}
|
||||
listen(target, type, callback) {
|
||||
if (this.destroyed || !target) return;
|
||||
const listener = (event) => {
|
||||
if (!this.destroyed) callback(event);
|
||||
};
|
||||
@@ -29,6 +37,7 @@ export class PanelPositionControls {
|
||||
this.removers.push(() => target.removeEventListener(type, listener));
|
||||
}
|
||||
_reclampDraggablePanels() {
|
||||
if (this.destroyed) return;
|
||||
const el = this._ppToggles;
|
||||
if (!el || !el.style.top || el.style.top === 'auto') return;
|
||||
const top = parseInt(el.style.top, 10);
|
||||
@@ -56,6 +65,7 @@ export class PanelPositionControls {
|
||||
}
|
||||
|
||||
_initPanelDrag() {
|
||||
if (this.destroyed) return;
|
||||
const dragSpecs = [
|
||||
{
|
||||
id: 'pp-toggles',
|
||||
@@ -258,10 +268,6 @@ export class PanelPositionControls {
|
||||
};
|
||||
const onUp = () => {
|
||||
cancel();
|
||||
panelEl.classList.remove('panel-dragging');
|
||||
window.removeEventListener('pointermove', onMove);
|
||||
window.removeEventListener('pointerup', onUp);
|
||||
window.removeEventListener('pointercancel', onUp);
|
||||
if (panelId === 'pp-toggles') {
|
||||
this._pinPanelToRight(panelEl);
|
||||
}
|
||||
|
||||
@@ -201,6 +201,11 @@ test('panel disposal cancels a live drag without saving or accepting later point
|
||||
window.dispatchEvent(new Event('pointerup'));
|
||||
assert.deepEqual(panel.style, before);
|
||||
assert.equal(panel.classList.contains('panel-dragging'), false);
|
||||
owner._makePanelDraggable('sample', panel, handle);
|
||||
owner._initPanelDrag();
|
||||
owner._ppToggles.style.top = '10000px';
|
||||
owner._reclampDraggablePanels();
|
||||
assert.equal(owner._ppToggles.style.top, '10000px');
|
||||
assert.equal(owner.removers.length, 0);
|
||||
assert.deepEqual(f.writes, []);
|
||||
} finally {
|
||||
|
||||
Reference in new issue
Block a user