diff --git a/public/app.js b/public/app.js
index c023cbda..766c095e 100644
--- a/public/app.js
+++ b/public/app.js
@@ -148,6 +148,18 @@ function connectWS() {
function onWS(fn) { wsListeners.push(fn); }
function offWS(fn) { wsListeners = wsListeners.filter(f => f !== fn); }
+/* Global escapeHtml — used by multiple pages */
+function escapeHtml(s) {
+ if (!s) return '';
+ return s.replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"');
+}
+
+/* Global debounce */
+function debounce(fn, ms) {
+ let t;
+ return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); };
+}
+
/* Debounced WS helper — batches rapid messages, calls fn with array of msgs */
function debouncedOnWS(fn, ms) {
if (typeof ms === 'undefined') ms = 250;
diff --git a/public/nodes.js b/public/nodes.js
index b7ee02ba..a236564d 100644
--- a/public/nodes.js
+++ b/public/nodes.js
@@ -5,10 +5,6 @@
let nodes = [];
const PAYLOAD_TYPES = {0:'Request',1:'Response',2:'Direct Msg',3:'ACK',4:'Advert',5:'Channel Msg',7:'Anon Req',8:'Path',9:'Trace'};
- function escapeHtml(s) {
- if (!s) return '';
- return s.replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"');
- }
let counts = {};
let selectedKey = null;
let activeTab = 'all';
@@ -202,6 +198,8 @@
renderLeft();
} catch (e) {
console.error('Failed to load nodes:', e);
+ const tbody = document.getElementById('nodesBody');
+ if (tbody) tbody.innerHTML = '
Failed to load nodes. Please try again. |
';
}
}
@@ -441,11 +439,5 @@
});
}
- // Minimal QR-like visual (encode pubkey as a grid pattern - not a real QR but visually useful)
- function debounce(fn, ms) {
- let t;
- return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); };
- }
-
registerPage('nodes', { init, destroy });
})();
diff --git a/public/packets.js b/public/packets.js
index 31bf3c86..56dc2be6 100644
--- a/public/packets.js
+++ b/public/packets.js
@@ -253,6 +253,8 @@
renderLeft();
} catch (e) {
console.error('Failed to load packets:', e);
+ const tbody = document.getElementById('pktBody');
+ if (tbody) tbody.innerHTML = 'Failed to load packets. Please try again. |
';
}
}
@@ -492,6 +494,11 @@
const groupBtn = document.getElementById('fGroup');
if (groupBtn) groupBtn.classList.toggle('active', groupByHash);
+ if (!packets.length) {
+ tbody.innerHTML = '| No packets found |
';
+ return;
+ }
+
if (groupByHash) {
let html = '';
for (const p of packets) {
@@ -714,10 +721,6 @@
}
}
- function escapeHtml(s) {
- return s.replace(/&/g,'&').replace(//g,'>');
- }
-
function buildDecodedTable(decoded) {
let rows = '';
for (const [k, v] of Object.entries(decoded)) {
@@ -938,12 +941,6 @@
return '' + key + '' + val + '
';
}
- // Debounce helper
- function debounce(fn, ms) {
- let t;
- return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); };
- }
-
// Load regions from config
(async () => {
try {