[feat](trx-frontend-http): add Live/History views to WEFAX tab
Restructure the WEFAX tab to match the SAT/LRPT pattern with a view switcher bar. Live view shows decoder description, live canvas, and latest image card. History view adds a filterable, sortable table of all decoded images with Clear All button. 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:
@@ -929,18 +929,51 @@
|
|||||||
<div id="subtab-wefax" class="sub-tab-panel" style="display:none;">
|
<div id="subtab-wefax" class="sub-tab-panel" style="display:none;">
|
||||||
<div class="ft8-controls">
|
<div class="ft8-controls">
|
||||||
<button id="wefax-decode-toggle-btn" type="button">Enable WEFAX</button>
|
<button id="wefax-decode-toggle-btn" type="button">Enable WEFAX</button>
|
||||||
<button id="wefax-clear-btn" type="button" style="margin-left:0.5rem; font-size:0.8rem;">Clear</button>
|
|
||||||
<small id="wefax-status" style="color:var(--text-muted);">Idle</small>
|
<small id="wefax-status" style="color:var(--text-muted);">Idle</small>
|
||||||
</div>
|
</div>
|
||||||
<div id="wefax-live-container" style="display:none; margin:0.5rem 0;">
|
<!-- View selector -->
|
||||||
<div style="display:flex; align-items:center; gap:0.5rem; margin-bottom:0.3rem;">
|
<div class="sat-view-bar">
|
||||||
<strong>Receiving</strong>
|
<button id="wefax-view-live" class="sat-view-btn sat-view-active" type="button">Live</button>
|
||||||
<small id="wefax-live-info" style="color:var(--text-muted);"></small>
|
<button id="wefax-view-history" class="sat-view-btn" type="button">History</button>
|
||||||
|
</div>
|
||||||
|
<!-- Live view -->
|
||||||
|
<div id="wefax-live-view">
|
||||||
|
<div style="margin:0 0 0.5rem;">
|
||||||
|
<div style="color:var(--text-muted); font-size:0.82rem; line-height:1.5;">
|
||||||
|
<strong>Weather Facsimile</strong> — HF/satellite image reception (60/90/120/240 LPM).
|
||||||
|
Tune to a WEFAX station in USB mode and enable the decoder to begin receiving.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<canvas id="wefax-live-canvas" width="1809" height="800"
|
<div id="wefax-live-container" style="display:none; margin:0.5rem 0;">
|
||||||
style="width:100%; image-rendering:pixelated; background:#000;"></canvas>
|
<div style="display:flex; align-items:center; gap:0.5rem; margin-bottom:0.3rem;">
|
||||||
|
<strong>Receiving</strong>
|
||||||
|
<small id="wefax-live-info" style="color:var(--text-muted);"></small>
|
||||||
|
</div>
|
||||||
|
<canvas id="wefax-live-canvas" width="1809" height="800"
|
||||||
|
style="width:100%; image-rendering:pixelated; background:#000;"></canvas>
|
||||||
|
</div>
|
||||||
|
<div id="wefax-live-latest" style="margin-top:0.5rem;"></div>
|
||||||
|
</div>
|
||||||
|
<!-- History view -->
|
||||||
|
<div id="wefax-history-view" style="display:none;">
|
||||||
|
<div class="sat-history-controls">
|
||||||
|
<input id="wefax-filter" class="ft8-filter" type="text" placeholder="Filter (e.g. IOC, LPM)" />
|
||||||
|
<select id="wefax-sort" class="sat-sort-select">
|
||||||
|
<option value="newest">Newest first</option>
|
||||||
|
<option value="oldest">Oldest first</option>
|
||||||
|
</select>
|
||||||
|
<button id="wefax-clear-btn" type="button" style="font-size:0.8rem;">Clear All</button>
|
||||||
|
</div>
|
||||||
|
<div class="sat-history-header">
|
||||||
|
<span class="sat-col-time">Time</span>
|
||||||
|
<span class="sat-col-type">IOC</span>
|
||||||
|
<span class="sat-col-sat">LPM</span>
|
||||||
|
<span class="sat-col-lines">Lines</span>
|
||||||
|
<span class="sat-col-link">Image</span>
|
||||||
|
</div>
|
||||||
|
<div id="wefax-history-list"></div>
|
||||||
|
<small id="wefax-history-count" style="color:var(--text-muted);font-size:0.75rem;">No images yet</small>
|
||||||
</div>
|
</div>
|
||||||
<div id="wefax-gallery" style="display:flex; flex-wrap:wrap; gap:0.5rem;"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="tab-map" class="tab-panel" data-tab="map" style="display:none;">
|
<div id="tab-map" class="tab-panel" data-tab="map" style="display:none;">
|
||||||
|
|||||||
@@ -1,23 +1,38 @@
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// wefax.js — WEFAX decoder plugin for trx-frontend-http
|
// wefax.js — WEFAX decoder plugin for trx-frontend-http
|
||||||
|
// Live view: decoder state, live canvas, latest image card
|
||||||
|
// History view: filterable table of all decoded images
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
// --- DOM refs ---
|
// ── DOM references (cached once) ───────────────────────────────────
|
||||||
var wefaxStatus = document.getElementById('wefax-status');
|
var wefaxDom = {
|
||||||
var wefaxLiveContainer= document.getElementById('wefax-live-container');
|
status: document.getElementById('wefax-status'),
|
||||||
var wefaxLiveInfo = document.getElementById('wefax-live-info');
|
liveView: document.getElementById('wefax-live-view'),
|
||||||
var wefaxLiveCanvas = document.getElementById('wefax-live-canvas');
|
historyView: document.getElementById('wefax-history-view'),
|
||||||
var wefaxGallery = document.getElementById('wefax-gallery');
|
liveContainer: document.getElementById('wefax-live-container'),
|
||||||
var wefaxToggleBtn = document.getElementById('wefax-decode-toggle-btn');
|
liveInfo: document.getElementById('wefax-live-info'),
|
||||||
var wefaxClearBtn = document.getElementById('wefax-clear-btn');
|
liveCanvas: document.getElementById('wefax-live-canvas'),
|
||||||
|
liveLatest: document.getElementById('wefax-live-latest'),
|
||||||
|
historyList: document.getElementById('wefax-history-list'),
|
||||||
|
historyCount: document.getElementById('wefax-history-count'),
|
||||||
|
filterInput: document.getElementById('wefax-filter'),
|
||||||
|
sortSelect: document.getElementById('wefax-sort'),
|
||||||
|
toggleBtn: document.getElementById('wefax-decode-toggle-btn'),
|
||||||
|
clearBtn: document.getElementById('wefax-clear-btn'),
|
||||||
|
viewLiveBtn: document.getElementById('wefax-view-live'),
|
||||||
|
viewHistoryBtn: document.getElementById('wefax-view-history'),
|
||||||
|
};
|
||||||
|
|
||||||
// --- State ---
|
// ── State ───────────────────────────────────────────────────────────
|
||||||
var wefaxImageHistory = [];
|
var wefaxImageHistory = [];
|
||||||
var wefaxLiveCtx = null;
|
var WEFAX_MAX_IMAGES = 100;
|
||||||
|
var wefaxLiveCtx = null;
|
||||||
var wefaxLiveLineCount = 0;
|
var wefaxLiveLineCount = 0;
|
||||||
var wefaxLivePixelsPerLine = 1809;
|
var wefaxLivePixelsPerLine = 1809;
|
||||||
|
var wefaxActiveView = 'live';
|
||||||
|
var wefaxFilterText = '';
|
||||||
|
|
||||||
// --- Helpers ---
|
// ── Helpers ─────────────────────────────────────────────────────────
|
||||||
function currentWefaxHistoryRetentionMs() {
|
function currentWefaxHistoryRetentionMs() {
|
||||||
return window.getDecodeHistoryRetentionMs ? window.getDecodeHistoryRetentionMs() : 24 * 60 * 60 * 1000;
|
return window.getDecodeHistoryRetentionMs ? window.getDecodeHistoryRetentionMs() : 24 * 60 * 60 * 1000;
|
||||||
}
|
}
|
||||||
@@ -35,26 +50,51 @@ function escapeHtml(s) {
|
|||||||
.replace(/"/g, '"');
|
.replace(/"/g, '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Live canvas rendering ---
|
function scheduleWefaxUi(key, job) {
|
||||||
|
if (typeof window.trxScheduleUiFrameJob === 'function') {
|
||||||
|
window.trxScheduleUiFrameJob(key, job);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
job();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── View switching ──────────────────────────────────────────────────
|
||||||
|
function switchWefaxView(view) {
|
||||||
|
wefaxActiveView = view;
|
||||||
|
if (wefaxDom.liveView) wefaxDom.liveView.style.display = view === 'live' ? '' : 'none';
|
||||||
|
if (wefaxDom.historyView) wefaxDom.historyView.style.display = view === 'history' ? '' : 'none';
|
||||||
|
|
||||||
|
[wefaxDom.viewLiveBtn, wefaxDom.viewHistoryBtn].forEach(function (btn) {
|
||||||
|
if (btn) btn.classList.remove('sat-view-active');
|
||||||
|
});
|
||||||
|
if (view === 'live' && wefaxDom.viewLiveBtn) wefaxDom.viewLiveBtn.classList.add('sat-view-active');
|
||||||
|
if (view === 'history' && wefaxDom.viewHistoryBtn) wefaxDom.viewHistoryBtn.classList.add('sat-view-active');
|
||||||
|
|
||||||
|
if (view === 'history') renderWefaxHistoryTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wefaxDom.viewLiveBtn) wefaxDom.viewLiveBtn.addEventListener('click', function () { switchWefaxView('live'); });
|
||||||
|
if (wefaxDom.viewHistoryBtn) wefaxDom.viewHistoryBtn.addEventListener('click', function () { switchWefaxView('history'); });
|
||||||
|
|
||||||
|
// ── Live canvas rendering ───────────────────────────────────────────
|
||||||
function resetLiveCanvas(pixelsPerLine) {
|
function resetLiveCanvas(pixelsPerLine) {
|
||||||
wefaxLivePixelsPerLine = pixelsPerLine;
|
wefaxLivePixelsPerLine = pixelsPerLine;
|
||||||
wefaxLiveLineCount = 0;
|
wefaxLiveLineCount = 0;
|
||||||
wefaxLiveCanvas.width = pixelsPerLine;
|
wefaxDom.liveCanvas.width = pixelsPerLine;
|
||||||
wefaxLiveCanvas.height = 800;
|
wefaxDom.liveCanvas.height = 800;
|
||||||
wefaxLiveCtx = wefaxLiveCanvas.getContext('2d');
|
wefaxLiveCtx = wefaxDom.liveCanvas.getContext('2d');
|
||||||
wefaxLiveCtx.fillStyle = '#000';
|
wefaxLiveCtx.fillStyle = '#000';
|
||||||
wefaxLiveCtx.fillRect(0, 0, wefaxLiveCanvas.width, wefaxLiveCanvas.height);
|
wefaxLiveCtx.fillRect(0, 0, wefaxDom.liveCanvas.width, wefaxDom.liveCanvas.height);
|
||||||
wefaxLiveContainer.style.display = '';
|
if (wefaxDom.liveContainer) wefaxDom.liveContainer.style.display = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function paintLine(lineBytes) {
|
function paintLine(lineBytes) {
|
||||||
if (!wefaxLiveCtx) return;
|
if (!wefaxLiveCtx) return;
|
||||||
var y = wefaxLiveLineCount;
|
var y = wefaxLiveLineCount;
|
||||||
|
|
||||||
if (y >= wefaxLiveCanvas.height) {
|
if (y >= wefaxDom.liveCanvas.height) {
|
||||||
var old = wefaxLiveCtx.getImageData(0, 0, wefaxLiveCanvas.width, wefaxLiveCanvas.height);
|
var old = wefaxLiveCtx.getImageData(0, 0, wefaxDom.liveCanvas.width, wefaxDom.liveCanvas.height);
|
||||||
wefaxLiveCanvas.height *= 2;
|
wefaxDom.liveCanvas.height *= 2;
|
||||||
wefaxLiveCtx.putImageData(old, 0, 0);
|
wefaxLiveCtx.putImageData(old, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,59 +110,144 @@ function paintLine(lineBytes) {
|
|||||||
wefaxLiveLineCount++;
|
wefaxLiveLineCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Gallery rendering ---
|
// ── Live view: latest image card ────────────────────────────────────
|
||||||
|
function renderWefaxLatestCard() {
|
||||||
|
if (!wefaxDom.liveLatest) return;
|
||||||
|
if (wefaxImageHistory.length === 0) {
|
||||||
|
wefaxDom.liveLatest.innerHTML =
|
||||||
|
'<div style="color:var(--text-muted);font-size:0.82rem;">No images decoded yet. Enable the decoder and tune to a WEFAX station.</div>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
function renderGalleryThumbnail(msg) {
|
var img = wefaxImageHistory[0];
|
||||||
var card = document.createElement('div');
|
var ts = img._ts || '--';
|
||||||
card.className = 'wefax-card';
|
var date = img._tsMs ? new Date(img._tsMs).toLocaleDateString() : '';
|
||||||
card.style.cssText =
|
var meta = [
|
||||||
'border:1px solid var(--border-color); border-radius:4px; ' +
|
img.ioc + ' IOC',
|
||||||
'padding:0.4rem; max-width:280px; cursor:pointer;';
|
img.lpm + ' LPM',
|
||||||
|
img.line_count + ' lines',
|
||||||
|
date + ' ' + ts,
|
||||||
|
].join(' \u00b7 ');
|
||||||
|
|
||||||
var ts = msg._tsMs ? new Date(msg._tsMs).toLocaleString() : '\u2014';
|
var imgSrc = img._dataUrl
|
||||||
var info = msg.ioc + ' IOC \u00b7 ' + msg.lpm + ' LPM \u00b7 ' + msg.line_count + ' lines';
|
? img._dataUrl
|
||||||
|
: img.path
|
||||||
var imgSrc = msg._dataUrl
|
? '/images/' + escapeHtml(img.path.split('/').pop())
|
||||||
? msg._dataUrl
|
|
||||||
: msg.path
|
|
||||||
? '/images/' + escapeHtml(msg.path.split('/').pop())
|
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
var html = '<div class="sat-latest-card">';
|
||||||
|
html += '<div class="sat-latest-title">Latest decoded image</div>';
|
||||||
|
html += '<div class="sat-latest-meta">' + escapeHtml(meta) + '</div>';
|
||||||
if (imgSrc) {
|
if (imgSrc) {
|
||||||
card.innerHTML =
|
html += '<a href="' + imgSrc + '" target="_blank" style="font-size:0.8rem;color:var(--accent);display:inline-block;margin-top:0.25rem;">View full image</a>';
|
||||||
'<img src="' + imgSrc + '"' +
|
|
||||||
' alt="WEFAX" loading="lazy"' +
|
|
||||||
' style="width:100%; image-rendering:pixelated;" />' +
|
|
||||||
'<div style="font-size:0.8rem; margin-top:0.2rem;">' + escapeHtml(ts) + '</div>' +
|
|
||||||
'<div style="font-size:0.75rem; color:var(--text-muted);">' + info + '</div>';
|
|
||||||
} else {
|
|
||||||
card.innerHTML =
|
|
||||||
'<div style="font-size:0.8rem;">' + escapeHtml(ts) + '</div>' +
|
|
||||||
'<div style="font-size:0.75rem; color:var(--text-muted);">' + info + '</div>';
|
|
||||||
}
|
}
|
||||||
return card;
|
html += '</div>';
|
||||||
|
wefaxDom.liveLatest.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderWefaxGallery() {
|
// ── History view: table ─────────────────────────────────────────────
|
||||||
|
function getWefaxFilteredHistory() {
|
||||||
|
var items = wefaxImageHistory;
|
||||||
|
|
||||||
|
if (wefaxFilterText) {
|
||||||
|
items = items.filter(function (i) {
|
||||||
|
var haystack = [
|
||||||
|
String(i.ioc || ''),
|
||||||
|
String(i.lpm || ''),
|
||||||
|
String(i.line_count || ''),
|
||||||
|
].join(' ').toUpperCase();
|
||||||
|
return haystack.indexOf(wefaxFilterText) >= 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var sortVal = wefaxDom.sortSelect ? wefaxDom.sortSelect.value : 'newest';
|
||||||
|
if (sortVal === 'oldest') items = items.slice().reverse();
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderWefaxHistoryRow(img) {
|
||||||
|
var row = document.createElement('div');
|
||||||
|
row.className = 'sat-history-row';
|
||||||
|
|
||||||
|
var ts = img._ts || '--';
|
||||||
|
var date = img._tsMs ? new Date(img._tsMs).toLocaleDateString([], { month: 'short', day: 'numeric' }) : '';
|
||||||
|
var ioc = img.ioc || '--';
|
||||||
|
var lpm = img.lpm || '--';
|
||||||
|
var lines = img.line_count || 0;
|
||||||
|
|
||||||
|
var imgSrc = img._dataUrl
|
||||||
|
? img._dataUrl
|
||||||
|
: img.path
|
||||||
|
? '/images/' + escapeHtml(img.path.split('/').pop())
|
||||||
|
: null;
|
||||||
|
var link = imgSrc
|
||||||
|
? '<a href="' + imgSrc + '" target="_blank" style="color:var(--accent);">View</a>'
|
||||||
|
: '--';
|
||||||
|
|
||||||
|
row.innerHTML = [
|
||||||
|
'<span>' + escapeHtml(date + ' ' + ts) + '</span>',
|
||||||
|
'<span>' + escapeHtml(String(ioc)) + '</span>',
|
||||||
|
'<span>' + escapeHtml(String(lpm)) + '</span>',
|
||||||
|
'<span>' + lines + '</span>',
|
||||||
|
'<span>' + link + '</span>',
|
||||||
|
].join('');
|
||||||
|
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderWefaxHistoryTable() {
|
||||||
|
if (!wefaxDom.historyList) return;
|
||||||
pruneWefaxHistory();
|
pruneWefaxHistory();
|
||||||
var frag = document.createDocumentFragment();
|
var items = getWefaxFilteredHistory();
|
||||||
for (var i = 0; i < wefaxImageHistory.length; i++) {
|
var fragment = document.createDocumentFragment();
|
||||||
frag.appendChild(renderGalleryThumbnail(wefaxImageHistory[i]));
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
fragment.appendChild(renderWefaxHistoryRow(items[i]));
|
||||||
}
|
}
|
||||||
wefaxGallery.innerHTML = '';
|
wefaxDom.historyList.replaceChildren(fragment);
|
||||||
wefaxGallery.appendChild(frag);
|
|
||||||
}
|
|
||||||
|
|
||||||
function scheduleWefaxGalleryRender() {
|
if (wefaxDom.historyCount) {
|
||||||
if (window.trxScheduleUiFrameJob) {
|
var total = wefaxImageHistory.length;
|
||||||
window.trxScheduleUiFrameJob('wefax-gallery', renderWefaxGallery);
|
var shown = items.length;
|
||||||
} else {
|
wefaxDom.historyCount.textContent =
|
||||||
requestAnimationFrame(renderWefaxGallery);
|
total === 0
|
||||||
|
? 'No images yet'
|
||||||
|
: shown === total
|
||||||
|
? total + ' image' + (total === 1 ? '' : 's')
|
||||||
|
: shown + ' of ' + total + ' images';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- SSE event handlers (public API) ---
|
// ── Add image to history ────────────────────────────────────────────
|
||||||
|
function addWefaxImage(msg) {
|
||||||
|
var tsMs = Number.isFinite(msg.ts_ms) ? Number(msg.ts_ms) : Date.now();
|
||||||
|
msg._tsMs = tsMs;
|
||||||
|
msg._ts = new Date(tsMs).toLocaleTimeString([], {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Capture the live canvas as a data URI for thumbnails.
|
||||||
|
if (wefaxLiveCtx && wefaxLiveLineCount > 0) {
|
||||||
|
var trimmed = wefaxLiveCtx.getImageData(0, 0, wefaxDom.liveCanvas.width, wefaxLiveLineCount);
|
||||||
|
wefaxDom.liveCanvas.height = wefaxLiveLineCount;
|
||||||
|
wefaxLiveCtx.putImageData(trimmed, 0, 0);
|
||||||
|
try { msg._dataUrl = wefaxDom.liveCanvas.toDataURL('image/png'); } catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
wefaxImageHistory.unshift(msg);
|
||||||
|
if (wefaxImageHistory.length > WEFAX_MAX_IMAGES) {
|
||||||
|
wefaxImageHistory = wefaxImageHistory.slice(0, WEFAX_MAX_IMAGES);
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduleWefaxUi('wefax-latest', renderWefaxLatestCard);
|
||||||
|
if (wefaxActiveView === 'history') {
|
||||||
|
scheduleWefaxUi('wefax-history', renderWefaxHistoryTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── SSE event handlers (public API) ─────────────────────────────────
|
||||||
window.onServerWefaxProgress = function (msg) {
|
window.onServerWefaxProgress = function (msg) {
|
||||||
if (msg.line_count <= 1 || !wefaxLiveCtx) {
|
if (msg.line_count <= 1 || !wefaxLiveCtx) {
|
||||||
resetLiveCanvas(msg.pixels_per_line || 1809);
|
resetLiveCanvas(msg.pixels_per_line || 1809);
|
||||||
@@ -135,70 +260,84 @@ window.onServerWefaxProgress = function (msg) {
|
|||||||
paintLine(bytes);
|
paintLine(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wefaxLiveInfo) {
|
if (wefaxDom.liveInfo) {
|
||||||
wefaxLiveInfo.textContent =
|
wefaxDom.liveInfo.textContent =
|
||||||
'Line ' + msg.line_count + ' \u00b7 ' + msg.ioc + ' IOC \u00b7 ' + msg.lpm + ' LPM';
|
'Line ' + msg.line_count + ' \u00b7 ' + msg.ioc + ' IOC \u00b7 ' + msg.lpm + ' LPM';
|
||||||
}
|
}
|
||||||
if (wefaxStatus) {
|
if (wefaxDom.status) {
|
||||||
wefaxStatus.textContent = 'Receiving \u2014 line ' + msg.line_count;
|
wefaxDom.status.textContent = 'Receiving \u2014 line ' + msg.line_count;
|
||||||
wefaxStatus.style.color = 'var(--text-accent)';
|
wefaxDom.status.style.color = 'var(--text-accent)';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.onServerWefax = function (msg) {
|
window.onServerWefax = function (msg) {
|
||||||
msg._tsMs = msg.ts_ms || Date.now();
|
addWefaxImage(msg);
|
||||||
|
|
||||||
// Capture the live canvas as a data URI for gallery thumbnails.
|
if (wefaxDom.liveContainer) wefaxDom.liveContainer.style.display = 'none';
|
||||||
if (wefaxLiveCtx && wefaxLiveLineCount > 0) {
|
if (wefaxDom.status) {
|
||||||
var trimmed = wefaxLiveCtx.getImageData(0, 0, wefaxLiveCanvas.width, wefaxLiveLineCount);
|
wefaxDom.status.textContent = 'Complete \u2014 ' + msg.line_count + ' lines';
|
||||||
wefaxLiveCanvas.height = wefaxLiveLineCount;
|
wefaxDom.status.style.color = '';
|
||||||
wefaxLiveCtx.putImageData(trimmed, 0, 0);
|
|
||||||
try { msg._dataUrl = wefaxLiveCanvas.toDataURL('image/png'); } catch (e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
wefaxImageHistory.unshift(msg);
|
|
||||||
pruneWefaxHistory();
|
|
||||||
scheduleWefaxGalleryRender();
|
|
||||||
|
|
||||||
if (wefaxStatus) {
|
|
||||||
wefaxStatus.textContent = 'Complete \u2014 ' + msg.line_count + ' lines';
|
|
||||||
wefaxStatus.style.color = '';
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.restoreWefaxHistory = function (messages) {
|
window.restoreWefaxHistory = function (messages) {
|
||||||
if (!messages || !messages.length) return;
|
if (!messages || !messages.length) return;
|
||||||
for (var i = 0; i < messages.length; i++) {
|
for (var i = 0; i < messages.length; i++) {
|
||||||
messages[i]._tsMs = messages[i].ts_ms || Date.now();
|
var tsMs = Number.isFinite(messages[i].ts_ms) ? Number(messages[i].ts_ms) : Date.now();
|
||||||
|
messages[i]._tsMs = tsMs;
|
||||||
|
messages[i]._ts = new Date(tsMs).toLocaleTimeString([], {
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
wefaxImageHistory = messages.concat(wefaxImageHistory);
|
wefaxImageHistory = messages.concat(wefaxImageHistory);
|
||||||
pruneWefaxHistory();
|
pruneWefaxHistory();
|
||||||
scheduleWefaxGalleryRender();
|
scheduleWefaxUi('wefax-latest', renderWefaxLatestCard);
|
||||||
|
if (wefaxActiveView === 'history') {
|
||||||
|
scheduleWefaxUi('wefax-history', renderWefaxHistoryTable);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.pruneWefaxHistoryView = function () {
|
window.pruneWefaxHistoryView = function () {
|
||||||
pruneWefaxHistory();
|
pruneWefaxHistory();
|
||||||
scheduleWefaxGalleryRender();
|
renderWefaxHistoryTable();
|
||||||
|
renderWefaxLatestCard();
|
||||||
};
|
};
|
||||||
|
|
||||||
window.resetWefaxHistoryView = function () {
|
window.resetWefaxHistoryView = function () {
|
||||||
wefaxImageHistory = [];
|
wefaxImageHistory = [];
|
||||||
if (wefaxGallery) wefaxGallery.innerHTML = '';
|
if (wefaxDom.historyList) wefaxDom.historyList.innerHTML = '';
|
||||||
if (wefaxLiveContainer) wefaxLiveContainer.style.display = 'none';
|
if (wefaxDom.liveContainer) wefaxDom.liveContainer.style.display = 'none';
|
||||||
wefaxLiveCtx = null;
|
wefaxLiveCtx = null;
|
||||||
wefaxLiveLineCount = 0;
|
wefaxLiveLineCount = 0;
|
||||||
if (wefaxStatus) {
|
renderWefaxLatestCard();
|
||||||
wefaxStatus.textContent = 'Idle';
|
renderWefaxHistoryTable();
|
||||||
wefaxStatus.style.color = '';
|
if (wefaxDom.status) {
|
||||||
|
wefaxDom.status.textContent = 'Idle';
|
||||||
|
wefaxDom.status.style.color = '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// --- Button handlers ---
|
// ── Filter / sort handlers ──────────────────────────────────────────
|
||||||
if (wefaxToggleBtn) {
|
if (wefaxDom.filterInput) {
|
||||||
wefaxToggleBtn.addEventListener('click', async function () {
|
wefaxDom.filterInput.addEventListener('input', function () {
|
||||||
|
wefaxFilterText = wefaxDom.filterInput.value.trim().toUpperCase();
|
||||||
|
scheduleWefaxUi('wefax-history', renderWefaxHistoryTable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (wefaxDom.sortSelect) {
|
||||||
|
wefaxDom.sortSelect.addEventListener('change', function () {
|
||||||
|
scheduleWefaxUi('wefax-history', renderWefaxHistoryTable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Button handlers ─────────────────────────────────────────────────
|
||||||
|
if (wefaxDom.toggleBtn) {
|
||||||
|
wefaxDom.toggleBtn.addEventListener('click', async function () {
|
||||||
try {
|
try {
|
||||||
if (window.takeSchedulerControlForDecoderDisable) {
|
if (window.takeSchedulerControlForDecoderDisable) {
|
||||||
await window.takeSchedulerControlForDecoderDisable(wefaxToggleBtn);
|
await window.takeSchedulerControlForDecoderDisable(wefaxDom.toggleBtn);
|
||||||
}
|
}
|
||||||
await postPath('/toggle_wefax_decode');
|
await postPath('/toggle_wefax_decode');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -206,8 +345,8 @@ if (wefaxToggleBtn) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (wefaxClearBtn) {
|
if (wefaxDom.clearBtn) {
|
||||||
wefaxClearBtn.addEventListener('click', async function () {
|
wefaxDom.clearBtn.addEventListener('click', async function () {
|
||||||
try {
|
try {
|
||||||
await postPath('/clear_wefax_decode');
|
await postPath('/clear_wefax_decode');
|
||||||
window.resetWefaxHistoryView();
|
window.resetWefaxHistoryView();
|
||||||
@@ -216,3 +355,6 @@ if (wefaxClearBtn) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Initial render ──────────────────────────────────────────────────
|
||||||
|
renderWefaxLatestCard();
|
||||||
|
|||||||
Reference in New Issue
Block a user