[refactor](trx-frontend-http): wire JS frontend to decoder registry
Fetch /decoders on page load and use the registry to drive all decoder-related UI instead of hardcoded lists: - bookmarks.js: bmReadDecoders/bmWriteDecoders and bookmark form checkboxes generated from registry; bmApply() decoder toggle gate uses registry active_modes instead of hardcoded DIG/FM check - background-decode.js: delete SUPPORTED_DECODERS constant, derive bookmarkDecoderKinds() from registry - app.js: _decoderToggles and SSE status sync built from registry; updateDecodeStatus() and setModeBoundDecodeStatus() driven by registry mode_bound/toggle entries - index.html: replace 8 hardcoded decoder checkboxes with dynamic container populated from registry Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -1,3 +1,29 @@
|
|||||||
|
// --- Decoder registry (fetched from /decoders on load) ---
|
||||||
|
/** @type {Array<{id:string,label:string,activation:string,active_modes:string[],background_decode:boolean,bookmark_selectable:boolean}>} */
|
||||||
|
let decoderRegistry = [];
|
||||||
|
window.decoderRegistry = decoderRegistry;
|
||||||
|
|
||||||
|
/** Callbacks invoked once the decoder registry is fetched. */
|
||||||
|
const _decoderRegistryReadyCallbacks = [];
|
||||||
|
window.onDecoderRegistryReady = function (fn) {
|
||||||
|
if (decoderRegistry.length > 0) fn();
|
||||||
|
else _decoderRegistryReadyCallbacks.push(fn);
|
||||||
|
};
|
||||||
|
|
||||||
|
(async function fetchDecoderRegistry() {
|
||||||
|
try {
|
||||||
|
const resp = await fetch("/decoders");
|
||||||
|
if (resp.ok) {
|
||||||
|
decoderRegistry = await resp.json();
|
||||||
|
window.decoderRegistry = decoderRegistry;
|
||||||
|
for (const fn of _decoderRegistryReadyCallbacks) fn();
|
||||||
|
_decoderRegistryReadyCallbacks.length = 0;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to fetch decoder registry:", e);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// --- Persistent settings (localStorage) ---
|
// --- Persistent settings (localStorage) ---
|
||||||
const STORAGE_PREFIX = "trx_";
|
const STORAGE_PREFIX = "trx_";
|
||||||
function saveSetting(key, value) {
|
function saveSetting(key, value) {
|
||||||
@@ -363,15 +389,18 @@ const rdsPsOverlay = document.getElementById("rds-ps-overlay");
|
|||||||
let overviewPeakHoldMs = Number(loadSetting("overviewPeakHoldMs", 2000));
|
let overviewPeakHoldMs = Number(loadSetting("overviewPeakHoldMs", 2000));
|
||||||
let decodeHistoryRetentionMin = 24 * 60;
|
let decodeHistoryRetentionMin = 24 * 60;
|
||||||
|
|
||||||
// Cached decoder toggle buttons — avoids 8× getElementById per render() call.
|
// Cached decoder toggle buttons — built from the registry, keyed by status
|
||||||
const _decoderToggles = {
|
// field name (e.g. "ft8_decode_enabled"). Lazily populated on first SSE.
|
||||||
ft8: { el: document.getElementById("ft8-decode-toggle-btn"), last: null },
|
const _decoderToggles = {};
|
||||||
ft4: { el: document.getElementById("ft4-decode-toggle-btn"), last: null },
|
function _ensureDecoderToggles() {
|
||||||
ft2: { el: document.getElementById("ft2-decode-toggle-btn"), last: null },
|
if (Object.keys(_decoderToggles).length > 0) return;
|
||||||
wspr: { el: document.getElementById("wspr-decode-toggle-btn"), last: null },
|
for (const d of decoderRegistry) {
|
||||||
hfAprs: { el: document.getElementById("hf-aprs-decode-toggle-btn"), last: null },
|
if (d.activation !== "toggle") continue;
|
||||||
lrpt: { el: document.getElementById("lrpt-decode-toggle-btn"), last: null },
|
const key = d.id.replace(/-/g, "_") + "_decode_enabled";
|
||||||
};
|
const el = document.getElementById(d.id + "-decode-toggle-btn");
|
||||||
|
if (el) _decoderToggles[key] = { el, last: null, label: d.label };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function syncDecoderToggle(entry, enabled, label) {
|
function syncDecoderToggle(entry, enabled, label) {
|
||||||
if (!entry.el || entry.last === enabled) return;
|
if (!entry.el || entry.last === enabled) return;
|
||||||
@@ -3233,47 +3262,28 @@ function render(update) {
|
|||||||
updateSdrSquelchControlVisibility();
|
updateSdrSquelchControlVisibility();
|
||||||
}
|
}
|
||||||
const modeUpper = update.status && update.status.mode ? normalizeMode(update.status.mode).toUpperCase() : "";
|
const modeUpper = update.status && update.status.mode ? normalizeMode(update.status.mode).toUpperCase() : "";
|
||||||
const aisStatus = document.getElementById("ais-status");
|
// Mode-bound decoder status (driven by registry).
|
||||||
const vdesStatus = document.getElementById("vdes-status");
|
for (const d of decoderRegistry) {
|
||||||
const aprsStatus = document.getElementById("aprs-status");
|
if (d.activation !== "mode_bound") continue;
|
||||||
const cwStatus = document.getElementById("cw-status");
|
const el = document.getElementById(d.id + "-status");
|
||||||
const ft8Status = document.getElementById("ft8-status");
|
if (!el) continue;
|
||||||
const wsprStatus = document.getElementById("wspr-status");
|
const connText = _decodeConnectedText[d.id] || "Connected, listening for packets";
|
||||||
setModeBoundDecodeStatus(
|
setModeBoundDecodeStatus(el, d.active_modes, "Select " + d.active_modes[0] + " mode to decode", connText);
|
||||||
aisStatus,
|
}
|
||||||
["AIS"],
|
|
||||||
"Select AIS mode to decode",
|
|
||||||
"Connected, listening for packets",
|
|
||||||
);
|
|
||||||
if (window.updateAisBar) window.updateAisBar();
|
if (window.updateAisBar) window.updateAisBar();
|
||||||
setModeBoundDecodeStatus(
|
|
||||||
vdesStatus,
|
|
||||||
["VDES"],
|
|
||||||
"Select VDES mode to decode",
|
|
||||||
"Connected, listening for bursts",
|
|
||||||
);
|
|
||||||
if (window.updateVdesBar) window.updateVdesBar();
|
if (window.updateVdesBar) window.updateVdesBar();
|
||||||
setModeBoundDecodeStatus(
|
|
||||||
aprsStatus,
|
|
||||||
["PKT"],
|
|
||||||
"Select PKT mode to decode",
|
|
||||||
"Connected, listening for packets",
|
|
||||||
);
|
|
||||||
if (window.updateAprsBar) window.updateAprsBar();
|
if (window.updateAprsBar) window.updateAprsBar();
|
||||||
if (window.updateFt8Bar) window.updateFt8Bar();
|
if (window.updateFt8Bar) window.updateFt8Bar();
|
||||||
setModeBoundDecodeStatus(
|
// Toggle-gated decoder status: clear "Receiving" when decoder disabled or mode wrong.
|
||||||
cwStatus,
|
for (const d of decoderRegistry) {
|
||||||
["CW", "CWR"],
|
if (d.activation !== "toggle") continue;
|
||||||
"Select CW mode to decode",
|
const key = d.id.replace(/-/g, "_") + "_decode_enabled";
|
||||||
"Connected, listening for CW",
|
const enabled = !!update[key];
|
||||||
);
|
const modeMatch = d.active_modes.includes(modeUpper);
|
||||||
const ft8Enabled = !!update.ft8_decode_enabled;
|
const el = document.getElementById(d.id + "-status");
|
||||||
if (ft8Status && (!ft8Enabled || (modeUpper !== "DIG" && modeUpper !== "USB")) && ft8Status.textContent === "Receiving") {
|
if (el && (!enabled || !modeMatch) && el.textContent === "Receiving") {
|
||||||
ft8Status.textContent = "Connected, listening for packets";
|
el.textContent = "Connected, listening for packets";
|
||||||
}
|
}
|
||||||
const wsprEnabled = !!update.wspr_decode_enabled;
|
|
||||||
if (wsprStatus && (!wsprEnabled || (modeUpper !== "DIG" && modeUpper !== "USB")) && wsprStatus.textContent === "Receiving") {
|
|
||||||
wsprStatus.textContent = "Connected, listening for packets";
|
|
||||||
}
|
}
|
||||||
if (update.status && typeof update.status.tx_en === "boolean") {
|
if (update.status && typeof update.status.tx_en === "boolean") {
|
||||||
lastTxEn = update.status.tx_en;
|
lastTxEn = update.status.tx_en;
|
||||||
@@ -3289,12 +3299,10 @@ function render(update) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Decoder toggle buttons: only write DOM when the enabled flag actually changes.
|
// Decoder toggle buttons: only write DOM when the enabled flag actually changes.
|
||||||
syncDecoderToggle(_decoderToggles.ft8, !!update.ft8_decode_enabled, "FT8");
|
_ensureDecoderToggles();
|
||||||
syncDecoderToggle(_decoderToggles.ft4, !!update.ft4_decode_enabled, "FT4");
|
for (const [key, entry] of Object.entries(_decoderToggles)) {
|
||||||
syncDecoderToggle(_decoderToggles.ft2, !!update.ft2_decode_enabled, "FT2");
|
syncDecoderToggle(entry, !!update[key], entry.label);
|
||||||
syncDecoderToggle(_decoderToggles.wspr, !!update.wspr_decode_enabled, "WSPR");
|
}
|
||||||
syncDecoderToggle(_decoderToggles.hfAprs, !!update.hf_aprs_decode_enabled, "HF APRS");
|
|
||||||
syncDecoderToggle(_decoderToggles.lrpt, !!update.lrpt_decode_enabled, "Meteor LRPT");
|
|
||||||
if (window.updateSatLiveState) window.updateSatLiveState(update);
|
if (window.updateSatLiveState) window.updateSatLiveState(update);
|
||||||
const cwAutoEl = document.getElementById("cw-auto");
|
const cwAutoEl = document.getElementById("cw-auto");
|
||||||
const cwWpmEl = document.getElementById("cw-wpm");
|
const cwWpmEl = document.getElementById("cw-wpm");
|
||||||
@@ -8895,23 +8903,26 @@ function setModeBoundDecodeStatus(el, activeModes, inactiveText, connectedText)
|
|||||||
if (el.textContent === "Receiving" && isActiveMode) return;
|
if (el.textContent === "Receiving" && isActiveMode) return;
|
||||||
el.textContent = isActiveMode ? connectedText : inactiveText;
|
el.textContent = isActiveMode ? connectedText : inactiveText;
|
||||||
}
|
}
|
||||||
|
// Custom connected-state text overrides per decoder.
|
||||||
|
const _decodeConnectedText = {
|
||||||
|
vdes: "Connected, listening for bursts",
|
||||||
|
cw: "Connected, listening for CW",
|
||||||
|
};
|
||||||
function updateDecodeStatus(text) {
|
function updateDecodeStatus(text) {
|
||||||
const ais = document.getElementById("ais-status");
|
// Mode-bound decoders: show mode-gated status text.
|
||||||
const vdes = document.getElementById("vdes-status");
|
for (const d of decoderRegistry) {
|
||||||
const aprs = document.getElementById("aprs-status");
|
if (d.activation !== "mode_bound") continue;
|
||||||
const cw = document.getElementById("cw-status");
|
const el = document.getElementById(d.id + "-status");
|
||||||
const ft8 = document.getElementById("ft8-status");
|
if (!el) continue;
|
||||||
const ft4 = document.getElementById("ft4-status");
|
const connText = _decodeConnectedText[d.id] || text;
|
||||||
const ft2 = document.getElementById("ft2-status");
|
setModeBoundDecodeStatus(el, d.active_modes, "Select " + d.active_modes[0] + " mode to decode", connText);
|
||||||
setModeBoundDecodeStatus(ais, ["AIS"], "Select AIS mode to decode", text);
|
}
|
||||||
const vdesText = text === "Connected, listening for packets" ? "Connected, listening for bursts" : text;
|
// Toggle-gated decoders: update status text if not currently receiving.
|
||||||
setModeBoundDecodeStatus(vdes, ["VDES"], "Select VDES mode to decode", vdesText);
|
for (const d of decoderRegistry) {
|
||||||
setModeBoundDecodeStatus(aprs, ["PKT"], "Select PKT mode to decode", text);
|
if (d.activation !== "toggle") continue;
|
||||||
const cwText = text === "Connected, listening for packets" ? "Connected, listening for CW" : text;
|
const el = document.getElementById(d.id + "-status");
|
||||||
setModeBoundDecodeStatus(cw, ["CW", "CWR"], "Select CW mode to decode", cwText);
|
if (el && el.textContent !== "Receiving") el.textContent = text;
|
||||||
if (ft8 && ft8.textContent !== "Receiving") ft8.textContent = text;
|
}
|
||||||
if (ft4 && ft4.textContent !== "Receiving") ft4.textContent = text;
|
|
||||||
if (ft2 && ft2.textContent !== "Receiving") ft2.textContent = text;
|
|
||||||
}
|
}
|
||||||
function dispatchDecodeMessage(msg, skipStats) {
|
function dispatchDecodeMessage(msg, skipStats) {
|
||||||
if (msg.type === "ais" && window.onServerAis) window.onServerAis(msg);
|
if (msg.type === "ais" && window.onServerAis) window.onServerAis(msg);
|
||||||
|
|||||||
@@ -468,15 +468,8 @@
|
|||||||
<input type="text" id="bm-locator" class="status-input" maxlength="6" placeholder="e.g. JO93" />
|
<input type="text" id="bm-locator" class="status-input" maxlength="6" placeholder="e.g. JO93" />
|
||||||
</label>
|
</label>
|
||||||
<div class="bm-label">Digital modes
|
<div class="bm-label">Digital modes
|
||||||
<div class="bm-decoder-checks">
|
<div class="bm-decoder-checks" id="bm-decoder-checkboxes">
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-aprs" value="aprs" /> APRS</label>
|
<!-- Populated dynamically from /decoders registry -->
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-ais" value="ais" /> AIS</label>
|
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-ft8" value="ft8" /> FT8</label>
|
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-ft4" value="ft4" /> FT4</label>
|
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-ft2" value="ft2" /> FT2</label>
|
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-wspr" value="wspr" /> WSPR</label>
|
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-hf-aprs" value="hf-aprs" /> HF APRS</label>
|
|
||||||
<label class="bm-decoder-check"><input type="checkbox" id="bm-dec-lrpt" value="lrpt" /> Meteor LRPT</label>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="bm-label bm-label-wide">Comment
|
<label class="bm-label bm-label-wide">Comment
|
||||||
|
|||||||
+18
-9
@@ -5,7 +5,11 @@
|
|||||||
(function () {
|
(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const SUPPORTED_DECODERS = ["aprs", "ais", "ft8", "wspr", "hf-aprs"];
|
function bgdSupportedIds() {
|
||||||
|
return (window.decoderRegistry || [])
|
||||||
|
.filter(function (d) { return d.background_decode; })
|
||||||
|
.map(function (d) { return d.id; });
|
||||||
|
}
|
||||||
|
|
||||||
let backgroundDecodeRole = null;
|
let backgroundDecodeRole = null;
|
||||||
let currentRigId = null;
|
let currentRigId = null;
|
||||||
@@ -93,17 +97,22 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function bookmarkDecoderKinds(bookmark) {
|
function bookmarkDecoderKinds(bookmark) {
|
||||||
const decoders = Array.isArray(bookmark && bookmark.decoders) ? bookmark.decoders : [];
|
var ids = bgdSupportedIds();
|
||||||
const supported = decoders
|
var decoders = Array.isArray(bookmark && bookmark.decoders) ? bookmark.decoders : [];
|
||||||
|
var explicit = decoders
|
||||||
.map(function (item) { return String(item || "").trim().toLowerCase(); })
|
.map(function (item) { return String(item || "").trim().toLowerCase(); })
|
||||||
.filter(function (item, index, arr) {
|
.filter(function (item, index, arr) {
|
||||||
return SUPPORTED_DECODERS.includes(item) && arr.indexOf(item) === index;
|
return ids.indexOf(item) >= 0 && arr.indexOf(item) === index;
|
||||||
});
|
});
|
||||||
if (supported.length > 0) return supported;
|
if (explicit.length > 0) return explicit;
|
||||||
const mode = String(bookmark && bookmark.mode || "").trim().toUpperCase();
|
// Fall back: infer from mode via mode-bound entries in the registry.
|
||||||
if (mode === "AIS") return ["ais"];
|
var mode = String(bookmark && bookmark.mode || "").trim().toUpperCase();
|
||||||
if (mode === "PKT") return ["aprs"];
|
return (window.decoderRegistry || [])
|
||||||
return supported;
|
.filter(function (d) {
|
||||||
|
return d.activation === "mode_bound" && d.background_decode
|
||||||
|
&& d.active_modes.indexOf(mode) >= 0;
|
||||||
|
})
|
||||||
|
.map(function (d) { return d.id; });
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderBackgroundDecode() {
|
function renderBackgroundDecode() {
|
||||||
|
|||||||
@@ -228,29 +228,36 @@ function bmChangePage(delta) {
|
|||||||
|
|
||||||
// Read decoder checkboxes and return an array of selected decoder names.
|
// Read decoder checkboxes and return an array of selected decoder names.
|
||||||
function bmReadDecoders() {
|
function bmReadDecoders() {
|
||||||
const decoders = [];
|
return (window.decoderRegistry || [])
|
||||||
if (document.getElementById("bm-dec-aprs").checked) decoders.push("aprs");
|
.filter(d => d.bookmark_selectable)
|
||||||
if (document.getElementById("bm-dec-ais").checked) decoders.push("ais");
|
.filter(d => document.getElementById("bm-dec-" + d.id)?.checked)
|
||||||
if (document.getElementById("bm-dec-ft8").checked) decoders.push("ft8");
|
.map(d => d.id);
|
||||||
if (document.getElementById("bm-dec-ft4").checked) decoders.push("ft4");
|
|
||||||
if (document.getElementById("bm-dec-ft2").checked) decoders.push("ft2");
|
|
||||||
if (document.getElementById("bm-dec-wspr").checked) decoders.push("wspr");
|
|
||||||
if (document.getElementById("bm-dec-hf-aprs").checked) decoders.push("hf-aprs");
|
|
||||||
if (document.getElementById("bm-dec-lrpt").checked) decoders.push("lrpt");
|
|
||||||
return decoders;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set decoder checkboxes to match the given array.
|
// Set decoder checkboxes to match the given array.
|
||||||
function bmWriteDecoders(decoders) {
|
function bmWriteDecoders(decoders) {
|
||||||
const list = decoders || [];
|
const set = new Set(decoders || []);
|
||||||
document.getElementById("bm-dec-aprs").checked = list.includes("aprs");
|
(window.decoderRegistry || [])
|
||||||
document.getElementById("bm-dec-ais").checked = list.includes("ais");
|
.filter(d => d.bookmark_selectable)
|
||||||
document.getElementById("bm-dec-ft8").checked = list.includes("ft8");
|
.forEach(d => {
|
||||||
document.getElementById("bm-dec-ft4").checked = list.includes("ft4");
|
const el = document.getElementById("bm-dec-" + d.id);
|
||||||
document.getElementById("bm-dec-ft2").checked = list.includes("ft2");
|
if (el) el.checked = set.has(d.id);
|
||||||
document.getElementById("bm-dec-wspr").checked = list.includes("wspr");
|
});
|
||||||
document.getElementById("bm-dec-hf-aprs").checked = list.includes("hf-aprs");
|
}
|
||||||
document.getElementById("bm-dec-lrpt").checked = list.includes("lrpt");
|
|
||||||
|
// Build decoder checkboxes dynamically from the registry.
|
||||||
|
function bmBuildDecoderCheckboxes() {
|
||||||
|
const container = document.getElementById("bm-decoder-checkboxes");
|
||||||
|
if (!container) return;
|
||||||
|
container.innerHTML = "";
|
||||||
|
(window.decoderRegistry || [])
|
||||||
|
.filter(d => d.bookmark_selectable)
|
||||||
|
.forEach(d => {
|
||||||
|
const label = document.createElement("label");
|
||||||
|
label.className = "bm-decoder-check";
|
||||||
|
label.innerHTML = '<input type="checkbox" id="bm-dec-' + d.id + '" value="' + d.id + '" /> ' + d.label;
|
||||||
|
container.appendChild(label);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function bmOpenForm(bm) {
|
function bmOpenForm(bm) {
|
||||||
@@ -428,20 +435,27 @@ async function bmApply(bm) {
|
|||||||
await postPath("/set_freq?hz=" + bm.freq_hz);
|
await postPath("/set_freq?hz=" + bm.freq_hz);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
// Decoder toggles (DIG / FM modes) — also fire-and-forget.
|
// Decoder toggles — fire-and-forget.
|
||||||
|
// Only toggle decoders that are toggle-gated and whose active modes
|
||||||
|
// include the bookmark's mode (driven by the decoder registry).
|
||||||
const hasDecoders = Array.isArray(bm.decoders) && bm.decoders.length > 0;
|
const hasDecoders = Array.isArray(bm.decoders) && bm.decoders.length > 0;
|
||||||
const decoderMode = bm.mode === "DIG" || bm.mode === "FM";
|
const modeUp = (bm.mode || "").toUpperCase();
|
||||||
const decoderPromise = (hasDecoders && decoderMode) ? (async () => {
|
const toggleDecoders = (window.decoderRegistry || []).filter(d =>
|
||||||
|
d.activation === "toggle" && d.active_modes.includes(modeUp)
|
||||||
|
);
|
||||||
|
const shouldToggle = hasDecoders && toggleDecoders.length > 0;
|
||||||
|
const decoderPromise = shouldToggle ? (async () => {
|
||||||
const statusResp = await fetch("/status");
|
const statusResp = await fetch("/status");
|
||||||
if (statusResp.ok) {
|
if (statusResp.ok) {
|
||||||
const st = await statusResp.json();
|
const st = await statusResp.json();
|
||||||
const toggles = [];
|
const toggles = [];
|
||||||
const check = (key) => {
|
for (const d of toggleDecoders) {
|
||||||
if (bm.decoders.includes(key) !== !!st[key.replace(/-/g, "_") + "_decode_enabled"]) {
|
const statusKey = d.id.replace(/-/g, "_") + "_decode_enabled";
|
||||||
toggles.push(postPath("/toggle_" + key.replace(/-/g, "_") + "_decode"));
|
const wanted = bm.decoders.includes(d.id);
|
||||||
|
if (wanted !== !!st[statusKey]) {
|
||||||
|
toggles.push(postPath("/toggle_" + d.id.replace(/-/g, "_") + "_decode"));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
check("ft8"); check("ft4"); check("ft2"); check("wspr"); check("hf-aprs"); check("lrpt");
|
|
||||||
if (toggles.length) await Promise.all(toggles);
|
if (toggles.length) await Promise.all(toggles);
|
||||||
}
|
}
|
||||||
})() : Promise.resolve();
|
})() : Promise.resolve();
|
||||||
@@ -604,6 +618,13 @@ function bmPopulateScopePicker() {
|
|||||||
// scripts run if auth is disabled; otherwise bmFetch() will sync it).
|
// scripts run if auth is disabled; otherwise bmFetch() will sync it).
|
||||||
bmSyncAccess();
|
bmSyncAccess();
|
||||||
|
|
||||||
|
// Build decoder checkboxes from registry. The registry is fetched async
|
||||||
|
// so we rebuild once it arrives to ensure checkboxes are present.
|
||||||
|
bmBuildDecoderCheckboxes();
|
||||||
|
if (typeof window.onDecoderRegistryReady === "function") {
|
||||||
|
window.onDecoderRegistryReady(bmBuildDecoderCheckboxes);
|
||||||
|
}
|
||||||
|
|
||||||
// Scope picker
|
// Scope picker
|
||||||
bmPopulateScopePicker();
|
bmPopulateScopePicker();
|
||||||
const scopePicker = document.getElementById("bm-scope-picker");
|
const scopePicker = document.getElementById("bm-scope-picker");
|
||||||
|
|||||||
Reference in New Issue
Block a user