Spaces:
Sleeping
Sleeping
Fix popup.js: match new HTML element IDs, null-safe all DOM access, wrap all chrome calls in try/catch
Browse files- extension/popup.js +98 -58
extension/popup.js
CHANGED
|
@@ -1,18 +1,27 @@
|
|
| 1 |
/**
|
| 2 |
-
* ClauseGuard — Popup Script
|
| 3 |
-
* Shows scan summary, usage, and quick actions
|
| 4 |
*/
|
| 5 |
|
| 6 |
document.addEventListener("DOMContentLoaded", async () => {
|
| 7 |
const resultsView = document.getElementById("results-view");
|
| 8 |
const emptyView = document.getElementById("empty-view");
|
| 9 |
|
|
|
|
|
|
|
| 10 |
// Get current tab
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
if (!tab?.id) return;
|
| 13 |
|
| 14 |
-
// Load stored results
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
if (results && results.risk_score !== undefined) {
|
| 18 |
showResults(results);
|
|
@@ -22,61 +31,88 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
| 22 |
}
|
| 23 |
|
| 24 |
// Load usage
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
});
|
| 59 |
|
| 60 |
function showResults(results) {
|
| 61 |
-
document.getElementById("results-view")
|
| 62 |
-
document.getElementById("empty-view")
|
|
|
|
|
|
|
| 63 |
|
| 64 |
-
|
|
|
|
|
|
|
| 65 |
|
| 66 |
-
|
|
|
|
| 67 |
const badge = document.getElementById("grade-badge");
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 80 |
const counts = { HIGH: 0, MEDIUM: 0, LOW: 0 };
|
| 81 |
(results.results || []).forEach(r => {
|
| 82 |
(r.categories || []).forEach(c => {
|
|
@@ -84,22 +120,26 @@ function showResults(results) {
|
|
| 84 |
});
|
| 85 |
});
|
| 86 |
|
| 87 |
-
document.getElementById("
|
| 88 |
-
document.getElementById("
|
| 89 |
-
document.getElementById("
|
|
|
|
|
|
|
|
|
|
| 90 |
}
|
| 91 |
|
| 92 |
function updateUsage(usage) {
|
| 93 |
if (!usage) return;
|
| 94 |
const text = document.getElementById("usage-text");
|
| 95 |
const fill = document.getElementById("usage-fill");
|
|
|
|
| 96 |
|
| 97 |
if (usage.plan === "free") {
|
| 98 |
-
text.textContent =
|
| 99 |
-
fill.style.width =
|
| 100 |
if (usage.used >= usage.limit) fill.style.background = "#ef4444";
|
| 101 |
} else {
|
| 102 |
-
text.textContent =
|
| 103 |
fill.style.width = "100%";
|
| 104 |
fill.style.background = "#22c55e";
|
| 105 |
}
|
|
|
|
| 1 |
/**
|
| 2 |
+
* ClauseGuard — Popup Script (matches redesigned popup.html)
|
|
|
|
| 3 |
*/
|
| 4 |
|
| 5 |
document.addEventListener("DOMContentLoaded", async () => {
|
| 6 |
const resultsView = document.getElementById("results-view");
|
| 7 |
const emptyView = document.getElementById("empty-view");
|
| 8 |
|
| 9 |
+
if (!resultsView || !emptyView) return;
|
| 10 |
+
|
| 11 |
// Get current tab
|
| 12 |
+
let tab;
|
| 13 |
+
try {
|
| 14 |
+
const [t] = await chrome.tabs.query({ active: true, currentWindow: true });
|
| 15 |
+
tab = t;
|
| 16 |
+
} catch { return; }
|
| 17 |
+
|
| 18 |
if (!tab?.id) return;
|
| 19 |
|
| 20 |
+
// Load stored results
|
| 21 |
+
let results = null;
|
| 22 |
+
try {
|
| 23 |
+
results = await chrome.runtime.sendMessage({ type: "GET_RESULTS", tabId: tab.id });
|
| 24 |
+
} catch {}
|
| 25 |
|
| 26 |
if (results && results.risk_score !== undefined) {
|
| 27 |
showResults(results);
|
|
|
|
| 31 |
}
|
| 32 |
|
| 33 |
// Load usage
|
| 34 |
+
try {
|
| 35 |
+
const usage = await chrome.runtime.sendMessage({ type: "CHECK_USAGE" });
|
| 36 |
+
updateUsage(usage);
|
| 37 |
+
} catch {}
|
| 38 |
+
|
| 39 |
+
// Scan button
|
| 40 |
+
const btnScan = document.getElementById("btn-scan");
|
| 41 |
+
if (btnScan) {
|
| 42 |
+
btnScan.addEventListener("click", async () => {
|
| 43 |
+
btnScan.innerHTML = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/><line x1="7" x2="17" y1="12" y2="12"/></svg> Scanning...';
|
| 44 |
+
btnScan.disabled = true;
|
| 45 |
+
|
| 46 |
+
try {
|
| 47 |
+
await chrome.tabs.sendMessage(tab.id, { type: "TRIGGER_SCAN" });
|
| 48 |
+
setTimeout(async () => {
|
| 49 |
+
try {
|
| 50 |
+
const newResults = await chrome.runtime.sendMessage({ type: "GET_RESULTS", tabId: tab.id });
|
| 51 |
+
if (newResults && newResults.risk_score !== undefined) showResults(newResults);
|
| 52 |
+
} catch {}
|
| 53 |
+
btnScan.innerHTML = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/><path d="M7 12h10"/></svg> Scan this page';
|
| 54 |
+
btnScan.disabled = false;
|
| 55 |
+
}, 3000);
|
| 56 |
+
} catch {
|
| 57 |
+
btnScan.textContent = "Error — refresh and retry";
|
| 58 |
+
btnScan.disabled = false;
|
| 59 |
+
}
|
| 60 |
+
});
|
| 61 |
+
}
|
| 62 |
|
| 63 |
+
// Re-scan button
|
| 64 |
+
const btnRescan = document.getElementById("btn-rescan");
|
| 65 |
+
if (btnRescan) {
|
| 66 |
+
btnRescan.addEventListener("click", async () => {
|
| 67 |
+
try { await chrome.tabs.sendMessage(tab.id, { type: "TRIGGER_SCAN" }); } catch {}
|
| 68 |
+
window.close();
|
| 69 |
+
});
|
| 70 |
+
}
|
| 71 |
|
| 72 |
+
// Details button
|
| 73 |
+
const btnDetails = document.getElementById("btn-details");
|
| 74 |
+
if (btnDetails) {
|
| 75 |
+
btnDetails.addEventListener("click", () => {
|
| 76 |
+
try { chrome.sidePanel.open({ tabId: tab.id }); } catch {}
|
| 77 |
+
window.close();
|
| 78 |
+
});
|
| 79 |
+
}
|
| 80 |
});
|
| 81 |
|
| 82 |
function showResults(results) {
|
| 83 |
+
const rv = document.getElementById("results-view");
|
| 84 |
+
const ev = document.getElementById("empty-view");
|
| 85 |
+
if (rv) rv.style.display = "block";
|
| 86 |
+
if (ev) ev.style.display = "none";
|
| 87 |
|
| 88 |
+
// Score
|
| 89 |
+
const scoreEl = document.getElementById("risk-score");
|
| 90 |
+
if (scoreEl) scoreEl.textContent = results.risk_score;
|
| 91 |
|
| 92 |
+
// Grade badge
|
| 93 |
+
const grade = results.grade || "C";
|
| 94 |
const badge = document.getElementById("grade-badge");
|
| 95 |
+
if (badge) {
|
| 96 |
+
const gradeMap = {
|
| 97 |
+
F: { cls: "grade-f", label: "Grade F" },
|
| 98 |
+
D: { cls: "grade-d", label: "Grade D" },
|
| 99 |
+
C: { cls: "grade-c", label: "Grade C" },
|
| 100 |
+
B: { cls: "grade-b", label: "Grade B" },
|
| 101 |
+
A: { cls: "grade-a", label: "Grade A" },
|
| 102 |
+
};
|
| 103 |
+
const g = gradeMap[grade] || gradeMap.C;
|
| 104 |
+
badge.className = "grade " + g.cls;
|
| 105 |
+
badge.textContent = g.label;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
// Progress bar
|
| 109 |
+
const bar = document.getElementById("bar-fill");
|
| 110 |
+
if (bar) {
|
| 111 |
+
bar.style.width = results.risk_score + "%";
|
| 112 |
+
bar.className = "bar-fill " + (results.risk_score >= 60 ? "bar-red" : results.risk_score >= 30 ? "bar-amber" : "bar-green");
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
// Severity counts
|
| 116 |
const counts = { HIGH: 0, MEDIUM: 0, LOW: 0 };
|
| 117 |
(results.results || []).forEach(r => {
|
| 118 |
(r.categories || []).forEach(c => {
|
|
|
|
| 120 |
});
|
| 121 |
});
|
| 122 |
|
| 123 |
+
const cHigh = document.getElementById("c-high");
|
| 124 |
+
const cMed = document.getElementById("c-med");
|
| 125 |
+
const cLow = document.getElementById("c-low");
|
| 126 |
+
if (cHigh) cHigh.textContent = counts.HIGH;
|
| 127 |
+
if (cMed) cMed.textContent = counts.MEDIUM;
|
| 128 |
+
if (cLow) cLow.textContent = counts.LOW;
|
| 129 |
}
|
| 130 |
|
| 131 |
function updateUsage(usage) {
|
| 132 |
if (!usage) return;
|
| 133 |
const text = document.getElementById("usage-text");
|
| 134 |
const fill = document.getElementById("usage-fill");
|
| 135 |
+
if (!text || !fill) return;
|
| 136 |
|
| 137 |
if (usage.plan === "free") {
|
| 138 |
+
text.textContent = "Free: " + usage.used + "/" + usage.limit + " scans";
|
| 139 |
+
fill.style.width = Math.min(100, (usage.used / usage.limit) * 100) + "%";
|
| 140 |
if (usage.used >= usage.limit) fill.style.background = "#ef4444";
|
| 141 |
} else {
|
| 142 |
+
text.textContent = usage.plan.toUpperCase() + " — unlimited";
|
| 143 |
fill.style.width = "100%";
|
| 144 |
fill.style.background = "#22c55e";
|
| 145 |
}
|