[fix](trx-frontend-http): smooth decode history loading
Reduce main-thread stalls while decode history replays.\n\nCoalesce decoder list redraws and map maintenance so spectrum\nand controls stay responsive during history import.\n\nVerification: node --check on modified frontend JS files.\n\nCo-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -2951,6 +2951,35 @@ function yieldToMain() {
|
|||||||
return new Promise((resolve) => setTimeout(resolve, 0));
|
return new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const uiFrameJobs = new Map();
|
||||||
|
let uiFrameJobsHandle = null;
|
||||||
|
|
||||||
|
function flushUiFrameJobs() {
|
||||||
|
uiFrameJobsHandle = null;
|
||||||
|
const jobs = Array.from(uiFrameJobs.values());
|
||||||
|
uiFrameJobs.clear();
|
||||||
|
for (const job of jobs) {
|
||||||
|
try {
|
||||||
|
job();
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Deferred UI job failed:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleUiFrameJob(key, job) {
|
||||||
|
if (typeof job !== "function") return;
|
||||||
|
uiFrameJobs.set(key, job);
|
||||||
|
if (uiFrameJobsHandle !== null) return;
|
||||||
|
if (typeof requestAnimationFrame === "function") {
|
||||||
|
uiFrameJobsHandle = requestAnimationFrame(flushUiFrameJobs);
|
||||||
|
} else {
|
||||||
|
uiFrameJobsHandle = setTimeout(flushUiFrameJobs, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.trxScheduleUiFrameJob = scheduleUiFrameJob;
|
||||||
|
|
||||||
async function postPath(path) {
|
async function postPath(path) {
|
||||||
const resp = await fetch(path, { method: "POST" });
|
const resp = await fetch(path, { method: "POST" });
|
||||||
if (authEnabled && resp.status === 401) {
|
if (authEnabled && resp.status === 401) {
|
||||||
@@ -5397,8 +5426,7 @@ window.aprsMapAddStation = function(call, lat, lon, info, symbolTable, symbolCod
|
|||||||
stationMarkers.set(call, entry);
|
stationMarkers.set(call, entry);
|
||||||
if (aprsMap) {
|
if (aprsMap) {
|
||||||
_aprsAddMarkerToMap(call, entry);
|
_aprsAddMarkerToMap(call, entry);
|
||||||
rebuildMapLocatorFilters();
|
scheduleDecodeMapMaintenance();
|
||||||
applyMapFilter();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -5537,8 +5565,7 @@ window.aisMapAddVessel = function(msg) {
|
|||||||
trackPoints: [nextPoint],
|
trackPoints: [nextPoint],
|
||||||
msg,
|
msg,
|
||||||
});
|
});
|
||||||
rebuildMapLocatorFilters();
|
scheduleDecodeMapMaintenance();
|
||||||
applyMapFilter();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
window.vdesMapAddPoint = function(msg) {
|
window.vdesMapAddPoint = function(msg) {
|
||||||
@@ -5572,8 +5599,7 @@ window.vdesMapAddPoint = function(msg) {
|
|||||||
marker._vdesKey = key;
|
marker._vdesKey = key;
|
||||||
entry.marker = marker;
|
entry.marker = marker;
|
||||||
mapMarkers.add(marker);
|
mapMarkers.add(marker);
|
||||||
rebuildMapLocatorFilters();
|
scheduleDecodeMapMaintenance();
|
||||||
applyMapFilter();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function maidenheadToBounds(grid) {
|
function maidenheadToBounds(grid) {
|
||||||
@@ -5642,6 +5668,14 @@ function updateMapP2pPathsToggle() {
|
|||||||
btn.classList.toggle("is-active", mapP2pRadioPathsEnabled);
|
btn.classList.toggle("is-active", mapP2pRadioPathsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scheduleDecodeMapMaintenance() {
|
||||||
|
scheduleUiFrameJob("decode-map-maintenance", () => {
|
||||||
|
rebuildDecodeContactPaths();
|
||||||
|
rebuildMapLocatorFilters();
|
||||||
|
applyMapFilter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function escapeMapHtml(input) {
|
function escapeMapHtml(input) {
|
||||||
return String(input)
|
return String(input)
|
||||||
.replaceAll("&", "&")
|
.replaceAll("&", "&")
|
||||||
@@ -5913,8 +5947,7 @@ window.ft8MapAddLocator = function(message, grids, type = "ft8", station = null,
|
|||||||
existing.marker.setPopupContent(tooltipHtml);
|
existing.marker.setPopupContent(tooltipHtml);
|
||||||
sendLocatorOverlayToBack(existing.marker);
|
sendLocatorOverlayToBack(existing.marker);
|
||||||
assignLocatorMarkerMeta(existing.marker, existing.sourceType, existing.bandMeta);
|
assignLocatorMarkerMeta(existing.marker, existing.sourceType, existing.bandMeta);
|
||||||
rebuildMapLocatorFilters();
|
scheduleDecodeMapMaintenance();
|
||||||
applyMapFilter();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5936,9 +5969,7 @@ window.ft8MapAddLocator = function(message, grids, type = "ft8", station = null,
|
|||||||
locatorMarkers.set(key, { marker, grid, stations, stationDetails, sourceType: markerType, bandMeta });
|
locatorMarkers.set(key, { marker, grid, stations, stationDetails, sourceType: markerType, bandMeta });
|
||||||
mapMarkers.add(marker);
|
mapMarkers.add(marker);
|
||||||
}
|
}
|
||||||
rebuildDecodeContactPaths();
|
scheduleDecodeMapMaintenance();
|
||||||
rebuildMapLocatorFilters();
|
|
||||||
applyMapFilter();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Sub-tab navigation ---
|
// --- Sub-tab navigation ---
|
||||||
@@ -6691,12 +6722,31 @@ function dispatchDecodeMessage(msg) {
|
|||||||
if (msg.type === "wspr" && window.onServerWspr) window.onServerWspr(msg);
|
if (msg.type === "wspr" && window.onServerWspr) window.onServerWspr(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DECODE_HISTORY_MAX_BATCH = 12;
|
||||||
|
const DECODE_HISTORY_SLICE_BUDGET_MS = 6;
|
||||||
|
|
||||||
|
function scheduleDecodeHistoryDrainStep(callback) {
|
||||||
|
if (typeof callback !== "function") return;
|
||||||
|
if (typeof requestAnimationFrame === "function") {
|
||||||
|
requestAnimationFrame(() => callback());
|
||||||
|
} else {
|
||||||
|
setTimeout(callback, 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function drainDecodeHistory(buffer, index, onDone) {
|
function drainDecodeHistory(buffer, index, onDone) {
|
||||||
const CHUNK = 30;
|
const startedAt = typeof performance !== "undefined" && typeof performance.now === "function"
|
||||||
const end = Math.min(index + CHUNK, buffer.length);
|
? performance.now()
|
||||||
for (let i = index; i < end; i++) dispatchDecodeMessage(buffer[i]);
|
: 0;
|
||||||
if (end < buffer.length) {
|
let nextIndex = index;
|
||||||
setTimeout(() => drainDecodeHistory(buffer, end, onDone), 0);
|
while (nextIndex < buffer.length) {
|
||||||
|
dispatchDecodeMessage(buffer[nextIndex]);
|
||||||
|
nextIndex += 1;
|
||||||
|
if (nextIndex - index >= DECODE_HISTORY_MAX_BATCH) break;
|
||||||
|
if (startedAt > 0 && (performance.now() - startedAt) >= DECODE_HISTORY_SLICE_BUDGET_MS) break;
|
||||||
|
}
|
||||||
|
if (nextIndex < buffer.length) {
|
||||||
|
scheduleDecodeHistoryDrainStep(() => drainDecodeHistory(buffer, nextIndex, onDone));
|
||||||
} else if (typeof onDone === "function") {
|
} else if (typeof onDone === "function") {
|
||||||
onDone();
|
onDone();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,22 @@ let aisMessageHistory = [];
|
|||||||
let aisPaused = false;
|
let aisPaused = false;
|
||||||
let aisBufferedWhilePaused = 0;
|
let aisBufferedWhilePaused = 0;
|
||||||
|
|
||||||
|
function scheduleAisUi(key, job) {
|
||||||
|
if (typeof window.trxScheduleUiFrameJob === "function") {
|
||||||
|
window.trxScheduleUiFrameJob(key, job);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
job();
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleAisHistoryRender() {
|
||||||
|
scheduleAisUi("ais-history", () => renderAisHistory());
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleAisBarUpdate() {
|
||||||
|
scheduleAisUi("ais-bar", () => updateAisBar());
|
||||||
|
}
|
||||||
|
|
||||||
function formatAisMhz(freqHz) {
|
function formatAisMhz(freqHz) {
|
||||||
return `${(freqHz / 1_000_000).toFixed(3)} MHz`;
|
return `${(freqHz / 1_000_000).toFixed(3)} MHz`;
|
||||||
}
|
}
|
||||||
@@ -283,10 +299,11 @@ function renderAisHistory() {
|
|||||||
updateAisSummary();
|
updateAisSummary();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aisMessagesEl.innerHTML = "";
|
const fragment = document.createDocumentFragment();
|
||||||
for (let i = 0; i < aisMessageHistory.length; i += 1) {
|
for (let i = 0; i < aisMessageHistory.length; i += 1) {
|
||||||
aisMessagesEl.appendChild(renderAisRow(aisMessageHistory[i]));
|
fragment.appendChild(renderAisRow(aisMessageHistory[i]));
|
||||||
}
|
}
|
||||||
|
aisMessagesEl.replaceChildren(fragment);
|
||||||
updateAisSummary();
|
updateAisSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,13 +318,13 @@ function addAisMessage(msg) {
|
|||||||
|
|
||||||
aisMessageHistory.unshift(msg);
|
aisMessageHistory.unshift(msg);
|
||||||
if (aisMessageHistory.length > AIS_MAX_MESSAGES) aisMessageHistory.length = AIS_MAX_MESSAGES;
|
if (aisMessageHistory.length > AIS_MAX_MESSAGES) aisMessageHistory.length = AIS_MAX_MESSAGES;
|
||||||
updateAisBar();
|
scheduleAisBarUpdate();
|
||||||
|
|
||||||
if (aisPaused) {
|
if (aisPaused) {
|
||||||
aisBufferedWhilePaused += 1;
|
aisBufferedWhilePaused += 1;
|
||||||
updateAisSummary();
|
updateAisSummary();
|
||||||
} else {
|
} else {
|
||||||
renderAisHistory();
|
scheduleAisHistoryRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.lat != null && msg.lon != null && window.aisMapAddVessel) {
|
if (msg.lat != null && msg.lon != null && window.aisMapAddVessel) {
|
||||||
|
|||||||
@@ -21,6 +21,22 @@ let aprsHideCrc = false;
|
|||||||
let aprsCollapseDup = false;
|
let aprsCollapseDup = false;
|
||||||
let aprsTypeFilter = "all";
|
let aprsTypeFilter = "all";
|
||||||
|
|
||||||
|
function scheduleAprsUi(key, job) {
|
||||||
|
if (typeof window.trxScheduleUiFrameJob === "function") {
|
||||||
|
window.trxScheduleUiFrameJob(key, job);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
job();
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleAprsHistoryRender() {
|
||||||
|
scheduleAprsUi("aprs-history", () => renderAprsHistory());
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleAprsBarUpdate() {
|
||||||
|
scheduleAprsUi("aprs-bar", () => updateAprsBar());
|
||||||
|
}
|
||||||
|
|
||||||
function renderAprsInfo(pkt) {
|
function renderAprsInfo(pkt) {
|
||||||
const bytes = Array.isArray(pkt.info_bytes) ? pkt.info_bytes : null;
|
const bytes = Array.isArray(pkt.info_bytes) ? pkt.info_bytes : null;
|
||||||
if (bytes && bytes.length > 0) {
|
if (bytes && bytes.length > 0) {
|
||||||
@@ -294,10 +310,11 @@ function renderAprsHistory() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const visible = aprsVisiblePackets();
|
const visible = aprsVisiblePackets();
|
||||||
aprsPacketsEl.innerHTML = "";
|
const fragment = document.createDocumentFragment();
|
||||||
for (let i = 0; i < visible.length; i++) {
|
for (let i = 0; i < visible.length; i++) {
|
||||||
aprsPacketsEl.appendChild(renderAprsRow(visible[i], i === 0));
|
fragment.appendChild(renderAprsRow(visible[i], i === 0));
|
||||||
}
|
}
|
||||||
|
aprsPacketsEl.replaceChildren(fragment);
|
||||||
updateAprsSummary();
|
updateAprsSummary();
|
||||||
updateAprsChipState();
|
updateAprsChipState();
|
||||||
}
|
}
|
||||||
@@ -354,7 +371,7 @@ function addAprsPacket(pkt) {
|
|||||||
window.aprsMapAddStation(pkt.srcCall, pkt.lat, pkt.lon, pkt.info, pkt.symbolTable, pkt.symbolCode, pkt);
|
window.aprsMapAddStation(pkt.srcCall, pkt.lat, pkt.lon, pkt.info, pkt.symbolTable, pkt.symbolCode, pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkt.crcOk) updateAprsBar();
|
if (pkt.crcOk) scheduleAprsBarUpdate();
|
||||||
|
|
||||||
if (aprsPaused) {
|
if (aprsPaused) {
|
||||||
aprsBufferedWhilePaused += 1;
|
aprsBufferedWhilePaused += 1;
|
||||||
@@ -363,7 +380,7 @@ function addAprsPacket(pkt) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderAprsHistory();
|
scheduleAprsHistoryRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById("aprs-clear-btn").addEventListener("click", async () => {
|
document.getElementById("aprs-clear-btn").addEventListener("click", async () => {
|
||||||
|
|||||||
@@ -13,6 +13,22 @@ let ft8MessageHistory = [];
|
|||||||
let ft8Paused = false;
|
let ft8Paused = false;
|
||||||
let ft8BufferedWhilePaused = 0;
|
let ft8BufferedWhilePaused = 0;
|
||||||
|
|
||||||
|
function scheduleFt8Ui(key, job) {
|
||||||
|
if (typeof window.trxScheduleUiFrameJob === "function") {
|
||||||
|
window.trxScheduleUiFrameJob(key, job);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
job();
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleFt8HistoryRender() {
|
||||||
|
scheduleFt8Ui("ft8-history", () => renderFt8History());
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleFt8BarUpdate() {
|
||||||
|
scheduleFt8Ui("ft8-bar", () => updateFt8Bar());
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeFt8DisplayFreqHz(freqHz) {
|
function normalizeFt8DisplayFreqHz(freqHz) {
|
||||||
const rawHz = Number(freqHz);
|
const rawHz = Number(freqHz);
|
||||||
if (!Number.isFinite(rawHz)) return null;
|
if (!Number.isFinite(rawHz)) return null;
|
||||||
@@ -66,23 +82,24 @@ function renderFt8History() {
|
|||||||
updateFt8PauseUi();
|
updateFt8PauseUi();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ft8MessagesEl.innerHTML = "";
|
const fragment = document.createDocumentFragment();
|
||||||
for (let i = 0; i < ft8MessageHistory.length; i += 1) {
|
for (let i = 0; i < ft8MessageHistory.length; i += 1) {
|
||||||
ft8MessagesEl.appendChild(renderFt8Row(ft8MessageHistory[i]));
|
fragment.appendChild(renderFt8Row(ft8MessageHistory[i]));
|
||||||
}
|
}
|
||||||
|
ft8MessagesEl.replaceChildren(fragment);
|
||||||
updateFt8PauseUi();
|
updateFt8PauseUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
function addFt8Message(msg) {
|
function addFt8Message(msg) {
|
||||||
ft8MessageHistory.unshift(msg);
|
ft8MessageHistory.unshift(msg);
|
||||||
if (ft8MessageHistory.length > FT8_MAX_MESSAGES) ft8MessageHistory.length = FT8_MAX_MESSAGES;
|
if (ft8MessageHistory.length > FT8_MAX_MESSAGES) ft8MessageHistory.length = FT8_MAX_MESSAGES;
|
||||||
updateFt8Bar();
|
scheduleFt8BarUpdate();
|
||||||
if (ft8Paused) {
|
if (ft8Paused) {
|
||||||
ft8BufferedWhilePaused += 1;
|
ft8BufferedWhilePaused += 1;
|
||||||
updateFt8PauseUi();
|
updateFt8PauseUi();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderFt8History();
|
scheduleFt8HistoryRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
function ft8BarRfText(msg) {
|
function ft8BarRfText(msg) {
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ let hfAprsHideCrc = false;
|
|||||||
let hfAprsCollapseDup = false;
|
let hfAprsCollapseDup = false;
|
||||||
let hfAprsTypeFilter = "all";
|
let hfAprsTypeFilter = "all";
|
||||||
|
|
||||||
|
function scheduleHfAprsHistoryRender() {
|
||||||
|
if (typeof window.trxScheduleUiFrameJob === "function") {
|
||||||
|
window.trxScheduleUiFrameJob("hf-aprs-history", () => renderHfAprsHistory());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderHfAprsHistory();
|
||||||
|
}
|
||||||
|
|
||||||
function hfAprsPacketCategory(pkt) {
|
function hfAprsPacketCategory(pkt) {
|
||||||
const type = String(pkt.type || "").toLowerCase();
|
const type = String(pkt.type || "").toLowerCase();
|
||||||
const info = String(pkt.info || "").toLowerCase();
|
const info = String(pkt.info || "").toLowerCase();
|
||||||
@@ -294,10 +302,11 @@ function renderHfAprsHistory() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const visible = hfAprsVisiblePackets();
|
const visible = hfAprsVisiblePackets();
|
||||||
hfAprsPacketsEl.innerHTML = "";
|
const fragment = document.createDocumentFragment();
|
||||||
for (let i = 0; i < visible.length; i++) {
|
for (let i = 0; i < visible.length; i++) {
|
||||||
hfAprsPacketsEl.appendChild(renderHfAprsRow(visible[i], i === 0));
|
fragment.appendChild(renderHfAprsRow(visible[i], i === 0));
|
||||||
}
|
}
|
||||||
|
hfAprsPacketsEl.replaceChildren(fragment);
|
||||||
updateHfAprsSummary();
|
updateHfAprsSummary();
|
||||||
updateHfAprsChipState();
|
updateHfAprsChipState();
|
||||||
}
|
}
|
||||||
@@ -324,7 +333,7 @@ function addHfAprsPacket(pkt) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHfAprsHistory();
|
scheduleHfAprsHistoryRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
document.getElementById("hf-aprs-decode-toggle-btn")?.addEventListener("click", async () => {
|
document.getElementById("hf-aprs-decode-toggle-btn")?.addEventListener("click", async () => {
|
||||||
|
|||||||
@@ -15,6 +15,22 @@ let vdesMessageHistory = [];
|
|||||||
let vdesPaused = false;
|
let vdesPaused = false;
|
||||||
let vdesBufferedWhilePaused = 0;
|
let vdesBufferedWhilePaused = 0;
|
||||||
|
|
||||||
|
function scheduleVdesUi(key, job) {
|
||||||
|
if (typeof window.trxScheduleUiFrameJob === "function") {
|
||||||
|
window.trxScheduleUiFrameJob(key, job);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
job();
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleVdesHistoryRender() {
|
||||||
|
scheduleVdesUi("vdes-history", () => renderVdesHistory());
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleVdesBarUpdate() {
|
||||||
|
scheduleVdesUi("vdes-bar", () => updateVdesBar());
|
||||||
|
}
|
||||||
|
|
||||||
function currentVdesCenterText() {
|
function currentVdesCenterText() {
|
||||||
const raw = (document.getElementById("freq")?.value || "").replace(/[^\d]/g, "");
|
const raw = (document.getElementById("freq")?.value || "").replace(/[^\d]/g, "");
|
||||||
const hz = raw ? Number(raw) : 0;
|
const hz = raw ? Number(raw) : 0;
|
||||||
@@ -216,10 +232,11 @@ function renderVdesHistory() {
|
|||||||
updateVdesSummary();
|
updateVdesSummary();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
vdesMessagesEl.innerHTML = "";
|
const fragment = document.createDocumentFragment();
|
||||||
for (let i = 0; i < vdesMessageHistory.length; i += 1) {
|
for (let i = 0; i < vdesMessageHistory.length; i += 1) {
|
||||||
vdesMessagesEl.appendChild(renderVdesRow(vdesMessageHistory[i]));
|
fragment.appendChild(renderVdesRow(vdesMessageHistory[i]));
|
||||||
}
|
}
|
||||||
|
vdesMessagesEl.replaceChildren(fragment);
|
||||||
updateVdesSummary();
|
updateVdesSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,13 +251,13 @@ function addVdesMessage(msg) {
|
|||||||
|
|
||||||
vdesMessageHistory.unshift(msg);
|
vdesMessageHistory.unshift(msg);
|
||||||
if (vdesMessageHistory.length > VDES_MAX_MESSAGES) vdesMessageHistory.length = VDES_MAX_MESSAGES;
|
if (vdesMessageHistory.length > VDES_MAX_MESSAGES) vdesMessageHistory.length = VDES_MAX_MESSAGES;
|
||||||
updateVdesBar();
|
scheduleVdesBarUpdate();
|
||||||
|
|
||||||
if (vdesPaused) {
|
if (vdesPaused) {
|
||||||
vdesBufferedWhilePaused += 1;
|
vdesBufferedWhilePaused += 1;
|
||||||
updateVdesSummary();
|
updateVdesSummary();
|
||||||
} else {
|
} else {
|
||||||
renderVdesHistory();
|
scheduleVdesHistoryRender();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ let wsprMessageHistory = [];
|
|||||||
let wsprPaused = false;
|
let wsprPaused = false;
|
||||||
let wsprBufferedWhilePaused = 0;
|
let wsprBufferedWhilePaused = 0;
|
||||||
|
|
||||||
|
function scheduleWsprHistoryRender() {
|
||||||
|
if (typeof window.trxScheduleUiFrameJob === "function") {
|
||||||
|
window.trxScheduleUiFrameJob("wspr-history", () => renderWsprHistory());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
renderWsprHistory();
|
||||||
|
}
|
||||||
|
|
||||||
function fmtWsprTime(tsMs) {
|
function fmtWsprTime(tsMs) {
|
||||||
if (!tsMs) return "--:--:--";
|
if (!tsMs) return "--:--:--";
|
||||||
return new Date(tsMs).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
return new Date(tsMs).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
||||||
@@ -55,10 +63,11 @@ function renderWsprHistory() {
|
|||||||
updateWsprPauseUi();
|
updateWsprPauseUi();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wsprMessagesEl.innerHTML = "";
|
const fragment = document.createDocumentFragment();
|
||||||
for (let i = 0; i < wsprMessageHistory.length; i += 1) {
|
for (let i = 0; i < wsprMessageHistory.length; i += 1) {
|
||||||
wsprMessagesEl.appendChild(renderWsprRow(wsprMessageHistory[i]));
|
fragment.appendChild(renderWsprRow(wsprMessageHistory[i]));
|
||||||
}
|
}
|
||||||
|
wsprMessagesEl.replaceChildren(fragment);
|
||||||
updateWsprPauseUi();
|
updateWsprPauseUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +79,7 @@ function addWsprMessage(msg) {
|
|||||||
updateWsprPauseUi();
|
updateWsprPauseUi();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
renderWsprHistory();
|
scheduleWsprHistoryRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
function escapeWsprHtml(input) {
|
function escapeWsprHtml(input) {
|
||||||
|
|||||||
Reference in New Issue
Block a user