[fix](trx-frontend-http): keep layout sections togglable #24
@@ -637,6 +637,22 @@ function elementById(id) {
|
|||||||
};
|
};
|
||||||
const layoutCapabilities = { broadcast: false, digital: false };
|
const layoutCapabilities = { broadcast: false, digital: false };
|
||||||
let activeRigId = null;
|
let activeRigId = null;
|
||||||
|
const layoutSections = [
|
||||||
|
{ id: "advanced-radio-controls", key: "advanced" },
|
||||||
|
{ id: "audio-controls", key: "audio" },
|
||||||
|
{ id: "scheduler-controls", key: "scheduler" }
|
||||||
|
];
|
||||||
|
const seededSections = /* @__PURE__ */ new Set();
|
||||||
|
let appliedLayoutName = null;
|
||||||
|
function seedLayoutSections(layout, layoutChanged) {
|
||||||
|
layoutSections.forEach(({ id, key }) => {
|
||||||
|
const section = document.getElementById(id);
|
||||||
|
if (!section) return;
|
||||||
|
if (!layoutChanged && seededSections.has(id)) return;
|
||||||
|
seededSections.add(id);
|
||||||
|
section.open = layout[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
function layoutStorageKey() {
|
function layoutStorageKey() {
|
||||||
return activeRigId ? `trxOperatorLayout:${activeRigId}` : "trxOperatorLayout";
|
return activeRigId ? `trxOperatorLayout:${activeRigId}` : "trxOperatorLayout";
|
||||||
}
|
}
|
||||||
@@ -690,12 +706,9 @@ function elementById(id) {
|
|||||||
const layout = layouts[permittedName];
|
const layout = layouts[permittedName];
|
||||||
document.body.dataset.operatorLayout = permittedName in layouts ? permittedName : "compact";
|
document.body.dataset.operatorLayout = permittedName in layouts ? permittedName : "compact";
|
||||||
if (options.persist !== false) localStorage.setItem(layoutStorageKey(), permittedName);
|
if (options.persist !== false) localStorage.setItem(layoutStorageKey(), permittedName);
|
||||||
const details = document.getElementById("advanced-radio-controls");
|
const layoutChanged = appliedLayoutName !== permittedName;
|
||||||
if (details) details.open = layout.advanced;
|
appliedLayoutName = permittedName;
|
||||||
const audioDetails = document.getElementById("audio-controls");
|
seedLayoutSections(layout, layoutChanged);
|
||||||
if (audioDetails) audioDetails.open = layout.audio;
|
|
||||||
const schedulerDetails = document.getElementById("scheduler-controls");
|
|
||||||
if (schedulerDetails) schedulerDetails.open = layout.scheduler;
|
|
||||||
if (options.navigate && typeof browserWindow.navigateToTab === "function") {
|
if (options.navigate && typeof browserWindow.navigateToTab === "function") {
|
||||||
browserWindow.navigateToTab(layout.preferredTab);
|
browserWindow.navigateToTab(layout.preferredTab);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -195,6 +195,31 @@ function elementById<T extends HTMLElement>(id: string): T {
|
|||||||
const layoutCapabilities: Record<LayoutCapability, boolean> = { broadcast: false, digital: false };
|
const layoutCapabilities: Record<LayoutCapability, boolean> = { broadcast: false, digital: false };
|
||||||
let activeRigId: string | null = null;
|
let activeRigId: string | null = null;
|
||||||
|
|
||||||
|
// A layout seeds the collapsible sections; it does not hold them there.
|
||||||
|
// applyLayout runs on every rig-state refresh, so re-applying the disclosure
|
||||||
|
// state unconditionally would reopen or close sections under the operator
|
||||||
|
// once a second — the reason a section could not be expanded while a layout
|
||||||
|
// that collapses it was selected. Sections are therefore written only when
|
||||||
|
// the layout actually changes, or the first time each one appears in the DOM
|
||||||
|
// (the advanced controls are built after the first applyLayout call).
|
||||||
|
const layoutSections: { id: string; key: "advanced" | "audio" | "scheduler" }[] = [
|
||||||
|
{ id: "advanced-radio-controls", key: "advanced" },
|
||||||
|
{ id: "audio-controls", key: "audio" },
|
||||||
|
{ id: "scheduler-controls", key: "scheduler" },
|
||||||
|
];
|
||||||
|
const seededSections = new Set<string>();
|
||||||
|
let appliedLayoutName: LayoutName | null = null;
|
||||||
|
|
||||||
|
function seedLayoutSections(layout: OperatorLayout, layoutChanged: boolean) {
|
||||||
|
layoutSections.forEach(({ id, key }) => {
|
||||||
|
const section = document.getElementById(id) as HTMLDetailsElement | null;
|
||||||
|
if (!section) return;
|
||||||
|
if (!layoutChanged && seededSections.has(id)) return;
|
||||||
|
seededSections.add(id);
|
||||||
|
section.open = layout[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function layoutStorageKey() {
|
function layoutStorageKey() {
|
||||||
return activeRigId ? `trxOperatorLayout:${activeRigId}` : "trxOperatorLayout";
|
return activeRigId ? `trxOperatorLayout:${activeRigId}` : "trxOperatorLayout";
|
||||||
}
|
}
|
||||||
@@ -255,12 +280,9 @@ function elementById<T extends HTMLElement>(id: string): T {
|
|||||||
const layout = layouts[permittedName];
|
const layout = layouts[permittedName];
|
||||||
document.body.dataset.operatorLayout = permittedName in layouts ? permittedName : "compact";
|
document.body.dataset.operatorLayout = permittedName in layouts ? permittedName : "compact";
|
||||||
if (options.persist !== false) localStorage.setItem(layoutStorageKey(), permittedName);
|
if (options.persist !== false) localStorage.setItem(layoutStorageKey(), permittedName);
|
||||||
const details = document.getElementById("advanced-radio-controls") as HTMLDetailsElement | null;
|
const layoutChanged = appliedLayoutName !== permittedName;
|
||||||
if (details) details.open = layout.advanced;
|
appliedLayoutName = permittedName;
|
||||||
const audioDetails = document.getElementById("audio-controls") as HTMLDetailsElement | null;
|
seedLayoutSections(layout, layoutChanged);
|
||||||
if (audioDetails) audioDetails.open = layout.audio;
|
|
||||||
const schedulerDetails = document.getElementById("scheduler-controls") as HTMLDetailsElement | null;
|
|
||||||
if (schedulerDetails) schedulerDetails.open = layout.scheduler;
|
|
||||||
if (options.navigate && typeof browserWindow.navigateToTab === "function") {
|
if (options.navigate && typeof browserWindow.navigateToTab === "function") {
|
||||||
browserWindow.navigateToTab(layout.preferredTab);
|
browserWindow.navigateToTab(layout.preferredTab);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,4 +143,31 @@ ui.applyLayout("digital");
|
|||||||
assert.equal(document.body.dataset.operatorLayout, "compact");
|
assert.equal(document.body.dataset.operatorLayout, "compact");
|
||||||
assert.equal(localStorage.getItem("trxOperatorLayout:rig-b"), "compact");
|
assert.equal(localStorage.getItem("trxOperatorLayout:rig-b"), "compact");
|
||||||
|
|
||||||
|
// A layout seeds the collapsible sections but must not hold them there:
|
||||||
|
// applyLayout runs on every rig-state refresh, so an operator who expands a
|
||||||
|
// section a layout collapses by default had it shut again about once a second.
|
||||||
|
const schedulerSection = new Element("details", document);
|
||||||
|
schedulerSection.id = "scheduler-controls";
|
||||||
|
const audioSection = new Element("details", document);
|
||||||
|
audioSection.id = "audio-controls";
|
||||||
|
|
||||||
|
ui.setActiveRig("rig-c");
|
||||||
|
ui.applyLayout("compact");
|
||||||
|
assert.equal(schedulerSection.open, false, "compact seeds the scheduler section closed");
|
||||||
|
|
||||||
|
schedulerSection.open = true; // operator expands it
|
||||||
|
ui.applyLayout("compact"); // the next rig-state refresh
|
||||||
|
assert.equal(schedulerSection.open, true, "re-applying the same layout leaves sections alone");
|
||||||
|
ui.setActiveRig("rig-c");
|
||||||
|
assert.equal(schedulerSection.open, true, "a rig-state refresh leaves sections alone");
|
||||||
|
|
||||||
|
// Choosing a different layout is an explicit request for its defaults.
|
||||||
|
ui.applyLayout("full");
|
||||||
|
assert.equal(schedulerSection.open, true, "full seeds the scheduler section open");
|
||||||
|
assert.equal(audioSection.open, true, "full seeds the audio section open");
|
||||||
|
audioSection.open = false;
|
||||||
|
ui.applyLayout("compact");
|
||||||
|
assert.equal(audioSection.open, false, "compact seeds the audio section closed");
|
||||||
|
assert.equal(schedulerSection.open, false, "switching layout reseeds every section");
|
||||||
|
|
||||||
console.log("ui-core component tests passed");
|
console.log("ui-core component tests passed");
|
||||||
|
|||||||
Reference in New Issue
Block a user