[refactor](trx-frontend): define module service boundaries

This commit is contained in:
sjg
2026-08-01 01:38:16 +02:00
parent 98b396bd98
commit fc98c2a974
3 changed files with 56 additions and 54 deletions
@@ -645,7 +645,7 @@ function flushDeferredDecodeMapSync() {
if (!decodeMapSyncPending || decodeHistoryReplayActive || !window.trx?.map?.aprsMap) return; if (!decodeMapSyncPending || decodeHistoryReplayActive || !window.trx?.map?.aprsMap) return;
decodeMapSyncPending = false; decodeMapSyncPending = false;
scheduleUiFrameJob("decode-map-maintenance", () => { scheduleUiFrameJob("decode-map-maintenance", () => {
window.trx.map?.pruneMapHistory(); window.trx.modules.map?.pruneMapHistory();
}); });
} }
@@ -1279,7 +1279,7 @@ function applyRigList(activeRigId, rigIds, displayNames) {
if (typeof bmPopulateScopePicker === "function") bmPopulateScopePicker(); if (typeof bmPopulateScopePicker === "function") bmPopulateScopePicker();
if (typeof bmFetch === "function") bmFetch(document.getElementById("bm-category-filter")?.value || ""); if (typeof bmFetch === "function") bmFetch(document.getElementById("bm-category-filter")?.value || "");
} }
window.trx.map?.updateMapRigFilter(); window.trx.modules.map?.updateMapRigFilter();
} }
@@ -1305,7 +1305,7 @@ async function refreshRigList() {
serverRigs = rigs; serverRigs = rigs;
serverActiveRigId = data.active_remote || null; serverActiveRigId = data.active_remote || null;
applyRigList(data.active_remote, rigIds, displayNames); applyRigList(data.active_remote, rigIds, displayNames);
window.trx.map?.syncAprsReceiverMarker(); window.trx.modules.map?.syncAprsReceiverMarker();
} catch (e) { } catch (e) {
// Non-fatal: SSE/status path still drives main UI. // Non-fatal: SSE/status path still drives main UI.
} }
@@ -3143,9 +3143,9 @@ function render(update) {
const grid = latLonToMaidenhead(serverLat, serverLon); const grid = latLonToMaidenhead(serverLat, serverLon);
locationSubtitle.textContent = `Location: ${grid}`; locationSubtitle.textContent = `Location: ${grid}`;
locationSubtitle.style.display = ""; locationSubtitle.style.display = "";
window.trx.map?.reverseGeocodeLocation(serverLat, serverLon, grid); window.trx.modules.map?.reverseGeocodeLocation(serverLat, serverLon, grid);
} }
window.trx.map?.syncAprsReceiverMarker(); window.trx.modules.map?.syncAprsReceiverMarker();
if (typeof update.initial_map_zoom === "number" && Number.isFinite(update.initial_map_zoom)) { if (typeof update.initial_map_zoom === "number" && Number.isFinite(update.initial_map_zoom)) {
initialMapZoom = Math.max(1, Math.round(update.initial_map_zoom)); initialMapZoom = Math.max(1, Math.round(update.initial_map_zoom));
} }
@@ -3894,7 +3894,7 @@ async function switchRigFromSelect(selectEl) {
if (typeof setSchedulerRig === "function") setSchedulerRig(lastActiveRigId); if (typeof setSchedulerRig === "function") setSchedulerRig(lastActiveRigId);
if (typeof setBackgroundDecodeRig === "function") setBackgroundDecodeRig(lastActiveRigId); if (typeof setBackgroundDecodeRig === "function") setBackgroundDecodeRig(lastActiveRigId);
if (typeof bmFetch === "function") bmFetch(document.getElementById("bm-category-filter")?.value || ""); if (typeof bmFetch === "function") bmFetch(document.getElementById("bm-category-filter")?.value || "");
window.trx.map?.syncAprsReceiverMarker(); window.trx.modules.map?.syncAprsReceiverMarker();
// Switch this session's rig and reconnect SSE to the new rig's // Switch this session's rig and reconnect SSE to the new rig's
// state channel. // state channel.
try { try {
@@ -4480,23 +4480,23 @@ function updateTabHistory(name, replaceHistory = false) {
} }
// Initialise the Leaflet map, waiting for both Leaflet (L) and map-core.js // Initialise the Leaflet map, waiting for both Leaflet (L) and map-core.js
// (window.trx.map) if they haven't loaded yet. // (window.trx.modules.map) if they haven't loaded yet.
let _mapInitTimer = null; let _mapInitTimer = null;
function _initMapWhenReady() { function _initMapWhenReady() {
const loadingEl = document.getElementById("map-loading"); const loadingEl = document.getElementById("map-loading");
if (window.trx.map && typeof L !== "undefined") { if (window.trx.modules.map && typeof L !== "undefined") {
if (_mapInitTimer) { clearInterval(_mapInitTimer); _mapInitTimer = null; } if (_mapInitTimer) { clearInterval(_mapInitTimer); _mapInitTimer = null; }
if (loadingEl) loadingEl.classList.add("is-hidden"); if (loadingEl) loadingEl.classList.add("is-hidden");
window.trx.map.initAprsMap(); window.trx.modules.map.initAprsMap();
window.trx.map.sizeAprsMapToViewport(); window.trx.modules.map.sizeAprsMapToViewport();
// The map panel was just made visible (display:none → ""); the browser // The map panel was just made visible (display:none → ""); the browser
// may not have laid it out yet, so getBoundingClientRect() can return // may not have laid it out yet, so getBoundingClientRect() can return
// stale/zero dimensions. Double-rAF ensures a full layout pass has // stale/zero dimensions. Double-rAF ensures a full layout pass has
// completed before we re-measure and tell Leaflet about its real size. // completed before we re-measure and tell Leaflet about its real size.
requestAnimationFrame(() => { requestAnimationFrame(() => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
window.trx.map.sizeAprsMapToViewport(); window.trx.modules.map.sizeAprsMapToViewport();
if (window.trx.map.aprsMap) window.trx.map.aprsMap.invalidateSize(); if (window.trx.modules.map.aprsMap) window.trx.modules.map.aprsMap.invalidateSize();
}); });
}); });
return; return;
@@ -4544,7 +4544,7 @@ function navigateToTab(name, options = {}) {
_initMapWhenReady(); _initMapWhenReady();
} }
if (name === "statistics") { if (name === "statistics") {
window.trx.map?.scheduleStatsRender(); window.trx.modules.map?.scheduleStatsRender();
} }
if (name === "recorder") { if (name === "recorder") {
refreshRecorderStatus(); refreshRecorderStatus();
@@ -4721,10 +4721,11 @@ if (headerAuthBtn) {
// ── Shared namespace for lazy-loaded modules ──────────────────────────────── // ── Shared namespace for lazy-loaded modules ────────────────────────────────
// Modules (map-core.js, screenshot.js) access core state and utilities via // Modules (map-core.js, screenshot.js) access core state and utilities via
// window.trx. Modules register their own APIs as sub-namespaces // window.trx. Modules register their own APIs as sub-namespaces
// (e.g. window.trx.map, window.trx.screenshot). // (e.g. window.trx.modules.map, window.trx.modules.screenshot).
window.trx = Object.create(null); const trxState = Object.create(null);
const trxModules = Object.create(null);
// -- State getters (backed by core-scoped variables) -- // -- State getters (backed by core-scoped variables) --
Object.defineProperties(window.trx, { Object.defineProperties(trxState, {
serverLat: { get() { return serverLat; }, set(v) { serverLat = v; } }, serverLat: { get() { return serverLat; }, set(v) { serverLat = v; } },
serverLon: { get() { return serverLon; }, set(v) { serverLon = v; } }, serverLon: { get() { return serverLon; }, set(v) { serverLon = v; } },
lastFreqHz: { get() { return lastFreqHz; } }, lastFreqHz: { get() { return lastFreqHz; } },
@@ -4762,7 +4763,7 @@ Object.defineProperties(window.trx, {
signalOverlayGl: { get() { return signalOverlayGl; } }, signalOverlayGl: { get() { return signalOverlayGl; } },
}); });
// -- Shared utility functions -- // -- Shared utility functions --
Object.assign(window.trx, { const trxCore = Object.freeze({
saveSetting, loadSetting, showHint, escapeMapHtml, formatFreq, formatFreqForHumans, saveSetting, loadSetting, showHint, escapeMapHtml, formatFreq, formatFreqForHumans,
formatWavelength, formatBwLabel, formatUptime, formatSigStrength, formatSignal, formatWavelength, formatBwLabel, formatUptime, formatSigStrength, formatSignal,
postPath, scheduleUiFrameJob, navigateToTab, rigBadgeColor, postPath, scheduleUiFrameJob, navigateToTab, rigBadgeColor,
@@ -4772,18 +4773,19 @@ Object.assign(window.trx, {
currentTheme, canvasPalette, currentStyle, currentTheme, canvasPalette, currentStyle,
cssColorToRgba, rgbaWithAlpha, isBinsArray, estimateNoiseFloorDb, cssColorToRgba, rgbaWithAlpha, isBinsArray, estimateNoiseFloorDb,
spectrumVisibleRange, drawSpectrum, spectrumVisibleRange, drawSpectrum,
bandForHz: function(hz) { return window.trx.map?.bandForHz?.(hz); }, bandForHz: function(hz) { return trxModules.map?.bandForHz?.(hz); },
markDecodeMapSyncPending, markDecodeMapSyncPending,
decodeHistoryMapRenderingDeferred, decodeHistoryMapRenderingDeferred,
updateDocumentTitle, updateDocumentTitle,
activeChannelRds, activeChannelRds,
}); });
Object.defineProperties(window.trx, { Object.defineProperties(trxState, {
decodeHistoryReplayActive: { get() { return decodeHistoryReplayActive; } }, decodeHistoryReplayActive: { get() { return decodeHistoryReplayActive; } },
decodeMapSyncPending: { get() { return decodeMapSyncPending; } }, decodeMapSyncPending: { get() { return decodeMapSyncPending; } },
_activeTab: { get() { return _activeTab; } }, _activeTab: { get() { return _activeTab; } },
locationSubtitle: { get() { return locationSubtitle; } }, locationSubtitle: { get() { return locationSubtitle; } },
}); });
window.trx = Object.freeze({ state: trxState, core: trxCore, modules: trxModules });
// Load plugin scripts now that window.trx is populated. Dynamic scripts are // Load plugin scripts now that window.trx is populated. Dynamic scripts are
// async so they must not be created before the namespace they depend on exists. // async so they must not be created before the namespace they depend on exists.
@@ -4797,7 +4799,7 @@ window.addEventListener("resize", resizeHeaderSignalCanvas);
// ── Map module (extracted to map-core.js, lazy-loaded) ────────────────────── // ── Map module (extracted to map-core.js, lazy-loaded) ──────────────────────
// The map, statistics, and geolocation code (~3,450 lines) has been moved to // The map, statistics, and geolocation code (~3,450 lines) has been moved to
// map-core.js and is loaded on demand when the Map tab is first activated. // map-core.js and is loaded on demand when the Map tab is first activated.
// Core communicates with the map module via window.trx.map.* namespace. // Core communicates with the map module via window.trx.modules.map.* namespace.
// ── Geo utilities (shared with map-core.js via window.trx) ───────────────── // ── Geo utilities (shared with map-core.js via window.trx) ─────────────────
function haversineKm(lat1, lon1, lat2, lon2) { function haversineKm(lat1, lon1, lat2, lon2) {
@@ -4932,7 +4934,7 @@ document.querySelectorAll(".sub-tab-bar").forEach(_wireSubTabBar);
window.addEventListener("resize", () => { window.addEventListener("resize", () => {
const mapTab = document.getElementById("tab-map"); const mapTab = document.getElementById("tab-map");
if (!mapTab || mapTab.style.display === "none") return; if (!mapTab || mapTab.style.display === "none") return;
window.trx.map?.sizeAprsMapToViewport(); window.trx.modules.map?.sizeAprsMapToViewport();
}); });
// --- Signal measurement --- // --- Signal measurement ---
@@ -6102,8 +6104,8 @@ function dispatchDecodeMessage(msg, skipStats) {
if (msg.type === "wefax" && window.onServerWefax) window.onServerWefax(msg); if (msg.type === "wefax" && window.onServerWefax) window.onServerWefax(msg);
if (msg.type === "wefax_progress" && window.onServerWefaxProgress) window.onServerWefaxProgress(msg); if (msg.type === "wefax_progress" && window.onServerWefaxProgress) window.onServerWefaxProgress(msg);
if (!skipStats && msg.type && msg.type !== "lrpt_image" && msg.type !== "lrpt_progress" && msg.type !== "wefax" && msg.type !== "wefax_progress") { if (!skipStats && msg.type && msg.type !== "lrpt_image" && msg.type !== "lrpt_progress" && msg.type !== "wefax" && msg.type !== "wefax_progress") {
window.trx.map?.statsRecordDecode(msg.type, msg.rig_id || msg.remote || null); window.trx.modules.map?.statsRecordDecode(msg.type, msg.rig_id || msg.remote || null);
window.trx.map?.scheduleStatsRender(); window.trx.modules.map?.scheduleStatsRender();
} }
} }
@@ -6112,10 +6114,10 @@ function dispatchDecodeBatch(batch) {
// Record statistics for every message in the batch regardless of dispatch path. // Record statistics for every message in the batch regardless of dispatch path.
for (const msg of batch) { for (const msg of batch) {
if (msg.type && msg.type !== "lrpt_image" && msg.type !== "lrpt_progress" && msg.type !== "wefax" && msg.type !== "wefax_progress") { if (msg.type && msg.type !== "lrpt_image" && msg.type !== "lrpt_progress" && msg.type !== "wefax" && msg.type !== "wefax_progress") {
window.trx.map?.statsRecordDecode(msg.type, msg.rig_id || msg.remote || null); window.trx.modules.map?.statsRecordDecode(msg.type, msg.rig_id || msg.remote || null);
} }
} }
window.trx.map?.scheduleStatsRender(); window.trx.modules.map?.scheduleStatsRender();
const type = String(batch[0]?.type || ""); const type = String(batch[0]?.type || "");
const uniformType = batch.every((msg) => String(msg?.type || "") === type); const uniformType = batch.every((msg) => String(msg?.type || "") === type);
if (uniformType) { if (uniformType) {
@@ -6200,9 +6202,9 @@ function restoreDecodeHistoryGroup(kind, messages) {
// Record statistics for restored history messages. // Record statistics for restored history messages.
if (kind !== "lrpt_image" && kind !== "lrpt_progress" && kind !== "wefax" && kind !== "wefax_progress") { if (kind !== "lrpt_image" && kind !== "lrpt_progress" && kind !== "wefax" && kind !== "wefax_progress") {
for (const msg of messages) { for (const msg of messages) {
window.trx.map?.statsRecordDecode(kind, msg.rig_id || msg.remote || null, msg.ts_ms || undefined); window.trx.modules.map?.statsRecordDecode(kind, msg.rig_id || msg.remote || null, msg.ts_ms || undefined);
} }
window.trx.map?.scheduleStatsRender(); window.trx.modules.map?.scheduleStatsRender();
} }
if (kind === "ais") { if (kind === "ais") {
if (window.restoreAisHistory) { window.restoreAisHistory(messages); } if (window.restoreAisHistory) { window.restoreAisHistory(messages); }
@@ -8000,12 +8002,12 @@ window.addEventListener("keydown", (event) => {
// S — spectrum screenshot (lazy-loads screenshot.js on first use) // S — spectrum screenshot (lazy-loads screenshot.js on first use)
if (key === "s") { if (key === "s") {
event.preventDefault(); event.preventDefault();
if (window.trx.screenshot) { if (window.trx.modules.screenshot) {
void window.trx.screenshot.captureSpectrumScreenshot(); void window.trx.modules.screenshot.captureSpectrumScreenshot();
} else { } else {
const s = document.createElement("script"); const s = document.createElement("script");
s.src = "/screenshot.js"; s.src = "/screenshot.js";
s.onload = () => { void window.trx.screenshot?.captureSpectrumScreenshot(); }; s.onload = () => { void window.trx.modules.screenshot?.captureSpectrumScreenshot(); };
document.body.appendChild(s); document.body.appendChild(s);
} }
return; return;
@@ -3,10 +3,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// Map, statistics, and geolocation module (lazy-loaded on map tab activation). // Map, statistics, and geolocation module (lazy-loaded on map tab activation).
// Communicates with app.js core via window.trx namespace. // Communicates with app.js through explicit state/core/module services.
(function () { (function () {
"use strict"; "use strict";
const T = window.trx; const { state: T, core: C, modules } = window.trx;
// Destructure shared utility functions for convenience // Destructure shared utility functions for convenience
const { saveSetting, loadSetting, showHint, escapeMapHtml, formatFreq, formatFreqForHumans, const { saveSetting, loadSetting, showHint, escapeMapHtml, formatFreq, formatFreqForHumans,
@@ -14,7 +14,7 @@
formatUptime, latLonToMaidenhead, locatorToLatLon, haversineKm, formatUptime, latLonToMaidenhead, locatorToLatLon, haversineKm,
formatDistanceKm, formatTimeAgo, currentDecodeHistoryRetentionMs, formatDistanceKm, formatTimeAgo, currentDecodeHistoryRetentionMs,
formatWavelength, bookmarkDistanceText, buildBookmarkTooltipText, formatWavelength, bookmarkDistanceText, buildBookmarkTooltipText,
nearestBookmarkForHz } = T; nearestBookmarkForHz } = C;
function updateMapRigFilter() { function updateMapRigFilter() {
const el = document.getElementById("map-rig-filter"); const el = document.getElementById("map-rig-filter");
@@ -261,7 +261,7 @@
if (canRenderMap) { if (canRenderMap) {
refreshAprsTrack(call, entry); refreshAprsTrack(call, entry);
} else { } else {
T.markDecodeMapSyncPending(); C.markDecodeMapSyncPending();
} }
if (!visible) { if (!visible) {
if (canRenderMap && selectedAprsTrackCall && String(selectedAprsTrackCall) === String(call)) { if (canRenderMap && selectedAprsTrackCall && String(selectedAprsTrackCall) === String(call)) {
@@ -294,7 +294,7 @@
if (canRenderMap) { if (canRenderMap) {
refreshAisTrack(key, entry); refreshAisTrack(key, entry);
} else { } else {
T.markDecodeMapSyncPending(); C.markDecodeMapSyncPending();
} }
if (!visible) { if (!visible) {
if (canRenderMap && selectedAisTrackMmsi && String(selectedAisTrackMmsi) === String(key)) { if (canRenderMap && selectedAisTrackMmsi && String(selectedAisTrackMmsi) === String(key)) {
@@ -337,7 +337,7 @@
entry.stations = new Set(); entry.stations = new Set();
entry.bandMeta = new Map(); entry.bandMeta = new Map();
if (canRenderMap) setRetainedMapMarkerVisible(entry.marker, false); if (canRenderMap) setRetainedMapMarkerVisible(entry.marker, false);
else T.markDecodeMapSyncPending(); else C.markDecodeMapSyncPending();
return false; return false;
} }
const nextStations = new Set(); const nextStations = new Set();
@@ -352,7 +352,7 @@
); );
const count = Math.max(nextDetails.size, nextStations.size || 0, 1); const count = Math.max(nextDetails.size, nextStations.size || 0, 1);
if (!canRenderMap) { if (!canRenderMap) {
T.markDecodeMapSyncPending(); C.markDecodeMapSyncPending();
return true; return true;
} }
ensureDecodeLocatorMarker(entry); ensureDecodeLocatorMarker(entry);
@@ -392,7 +392,7 @@
pruneLocatorEntry(key, entry, cutoffMs); pruneLocatorEntry(key, entry, cutoffMs);
} }
if (!aprsMap || T.decodeHistoryReplayActive) { if (!aprsMap || T.decodeHistoryReplayActive) {
T.markDecodeMapSyncPending(); C.markDecodeMapSyncPending();
return; return;
} }
rebuildDecodeContactPaths(); rebuildDecodeContactPaths();
@@ -415,7 +415,7 @@
function locatorFilterColor(type) { function locatorFilterColor(type) {
const hues = locatorThemeHues(); const hues = locatorThemeHues();
const lightTheme = T.currentTheme() === "light"; const lightTheme = C.currentTheme() === "light";
const sat = lightTheme ? 66 : 76; const sat = lightTheme ? 66 : 76;
const light = lightTheme ? 42 : 56; const light = lightTheme ? 42 : 56;
const hue = type === "bookmark" const hue = type === "bookmark"
@@ -539,7 +539,7 @@
} }
function locatorThemeHues() { function locatorThemeHues() {
const pal = T.canvasPalette(); const pal = C.canvasPalette();
const baseHue = paletteHue(pal?.spectrumLine, 145); const baseHue = paletteHue(pal?.spectrumLine, 145);
const waveHue = paletteHue(pal?.waveformLine, baseHue + 34); const waveHue = paletteHue(pal?.waveformLine, baseHue + 34);
const peakHue = paletteHue(pal?.waveformPeak, baseHue - 42); const peakHue = paletteHue(pal?.waveformPeak, baseHue - 42);
@@ -560,7 +560,7 @@
function locatorBandChipColor(label) { function locatorBandChipColor(label) {
const hues = locatorThemeHues(); const hues = locatorThemeHues();
const lightTheme = T.currentTheme() === "light"; const lightTheme = C.currentTheme() === "light";
const hue = wrapHue(hues.bandBase + locatorBandIndex(label) * 137.508); const hue = wrapHue(hues.bandBase + locatorBandIndex(label) * 137.508);
const sat = lightTheme ? 68 : 78; const sat = lightTheme ? 68 : 78;
const light = lightTheme ? 44 : 58; const light = lightTheme ? 44 : 58;
@@ -606,7 +606,7 @@
const safeCount = Math.max(1, Number.isFinite(count) ? count : 1); const safeCount = Math.max(1, Number.isFinite(count) ? count : 1);
const intensity = Math.min(1, Math.log2(safeCount + 1) / 5); const intensity = Math.min(1, Math.log2(safeCount + 1) / 5);
const hue = locatorHueForEntry(entry); const hue = locatorHueForEntry(entry);
const lightTheme = T.currentTheme() === "light"; const lightTheme = C.currentTheme() === "light";
const strokeSat = lightTheme ? 62 : 74; const strokeSat = lightTheme ? 62 : 74;
const fillSat = lightTheme ? 68 : 78; const fillSat = lightTheme ? 68 : 78;
const strokeLight = lightTheme ? 40 : 56; const strokeLight = lightTheme ? 40 : 56;
@@ -1573,7 +1573,7 @@
stageResizeObserver = new ResizeObserver(() => sizeAprsMapToViewport()); stageResizeObserver = new ResizeObserver(() => sizeAprsMapToViewport());
stageResizeObserver.observe(stage); stageResizeObserver.observe(stage);
} }
updateMapBaseLayerForTheme(T.currentTheme()); updateMapBaseLayerForTheme(C.currentTheme());
syncAprsReceiverMarker(); syncAprsReceiverMarker();
// Rebuild popup content on open (keeps age/distance/rig list fresh) // Rebuild popup content on open (keeps age/distance/rig list fresh)
@@ -2307,18 +2307,18 @@
existing.rigIds.add(msgRigId); existing.rigIds.add(msgRigId);
} }
if (!visible) { if (!visible) {
if (!T.decodeHistoryMapRenderingDeferred()) { if (!C.decodeHistoryMapRenderingDeferred()) {
setRetainedMapMarkerVisible(existing.marker, false); setRetainedMapMarkerVisible(existing.marker, false);
} else { } else {
T.markDecodeMapSyncPending(); C.markDecodeMapSyncPending();
} }
return; return;
} }
if (!T.decodeHistoryMapRenderingDeferred()) { if (!C.decodeHistoryMapRenderingDeferred()) {
ensureVdesMarker(key, existing); ensureVdesMarker(key, existing);
setRetainedMapMarkerVisible(existing.marker, true); setRetainedMapMarkerVisible(existing.marker, true);
} else { } else {
T.markDecodeMapSyncPending(); C.markDecodeMapSyncPending();
} }
if (aprsMap && existing.marker && !T.decodeHistoryReplayActive) { if (aprsMap && existing.marker && !T.decodeHistoryReplayActive) {
existing.marker.setLatLng([msg.lat, msg.lon]); existing.marker.setLatLng([msg.lat, msg.lon]);
@@ -2334,11 +2334,11 @@
}; };
vdesMarkers.set(key, entry); vdesMarkers.set(key, entry);
if (!visible) return; if (!visible) return;
if (!T.decodeHistoryMapRenderingDeferred()) { if (!C.decodeHistoryMapRenderingDeferred()) {
ensureVdesMarker(key, entry); ensureVdesMarker(key, entry);
setRetainedMapMarkerVisible(entry.marker, true); setRetainedMapMarkerVisible(entry.marker, true);
} else { } else {
T.markDecodeMapSyncPending(); C.markDecodeMapSyncPending();
} }
if (aprsMap && entry.marker && !T.decodeHistoryReplayActive) { if (aprsMap && entry.marker && !T.decodeHistoryReplayActive) {
entry.marker.setPopupContent(popupHtml); entry.marker.setPopupContent(popupHtml);
@@ -2365,7 +2365,7 @@
if (T.locationSubtitle) { if (T.locationSubtitle) {
T.locationSubtitle.textContent = `Location: ${grid} · ${label}`; T.locationSubtitle.textContent = `Location: ${grid} · ${label}`;
} }
T.updateDocumentTitle(T.activeChannelRds()); C.updateDocumentTitle(C.activeChannelRds());
}) })
.catch(() => {}); .catch(() => {});
} }
@@ -2443,8 +2443,8 @@
} }
function scheduleDecodeMapMaintenance() { function scheduleDecodeMapMaintenance() {
if (T.decodeHistoryMapRenderingDeferred()) { if (C.decodeHistoryMapRenderingDeferred()) {
T.markDecodeMapSyncPending(); C.markDecodeMapSyncPending();
return; return;
} }
scheduleUiFrameJob("decode-map-maintenance", () => { scheduleUiFrameJob("decode-map-maintenance", () => {
@@ -3461,7 +3461,7 @@
} }
// Register module API for core to call // Register module API for core to call
window.trx.map = { modules.map = {
initAprsMap, initAprsMap,
sizeAprsMapToViewport, sizeAprsMapToViewport,
syncAprsReceiverMarker, syncAprsReceiverMarker,
@@ -257,7 +257,7 @@
} }
// Register module API // Register module API
window.trx.screenshot = { window.trx.modules.screenshot = {
captureSpectrumScreenshot, captureSpectrumScreenshot,
buildSpectrumSnapshotCanvas, buildSpectrumSnapshotCanvas,
saveCanvasAsPng, saveCanvasAsPng,