Fix extension not fully disabling when toggled off

The fetch/XHR interception correctly checked settings.enabled, but
several other features ignored it — highlights, reveal mode, and
PII auto-detect all continued running after disabling. This adds
settings.enabled checks to the MutationObserver, highlightMatches,
auto-detect input/paste listeners, reveal mode, and cleans up
visual artifacts (highlights, warnings) when the extension is
toggled off.

https://claude.ai/code/session_015TEttQgcq5FALLKLb3uEW8
This commit is contained in:
Claude
2026-03-30 22:26:58 +00:00
parent d6707d9cf6
commit f021e50c08
+18 -9
View File
@@ -1076,6 +1076,7 @@
function highlightMatches(root) { function highlightMatches(root) {
if (!hasHighlightAPI) return; if (!hasHighlightAPI) return;
if (!settings.enabled) { hlSubstituted.clear(); hlRevealed.clear(); return; }
// Clear previous ranges // Clear previous ranges
hlSubstituted.clear(); hlSubstituted.clear();
@@ -1158,7 +1159,7 @@
// Watch for ANY new content on the page // Watch for ANY new content on the page
function observeResponses() { function observeResponses() {
const observer = new MutationObserver((mutations) => { const observer = new MutationObserver((mutations) => {
if (!hasSubstitutions()) return; if (!settings.enabled || !hasSubstitutions()) return;
// Always schedule highlight refresh for new content (yellow markers) // Always schedule highlight refresh for new content (yellow markers)
let hasNewContent = false; let hasNewContent = false;
@@ -1223,21 +1224,22 @@
let revealInterval = null; let revealInterval = null;
function checkRevealToggle() { function checkRevealToggle() {
if (settings.revealMode && !prevRevealMode) { const effectiveReveal = settings.revealMode && settings.enabled;
if (effectiveReveal && !prevRevealMode) {
// Just turned ON — reveal everything existing // Just turned ON — reveal everything existing
console.log('[Silent Send] Reveal mode ON'); console.log('[Silent Send] Reveal mode ON');
revealAllResponses(); revealAllResponses();
// Keep re-revealing periodically to catch new/streamed content // Keep re-revealing periodically to catch new/streamed content
revealInterval = setInterval(() => { revealInterval = setInterval(() => {
if (settings.revealMode) revealAllResponses(); if (settings.revealMode && settings.enabled) revealAllResponses();
}, 2000); }, 2000);
} else if (!settings.revealMode && prevRevealMode) { } else if (!effectiveReveal && prevRevealMode) {
// Just turned OFF — restore originals // Just turned OFF (or extension disabled) — restore originals
console.log('[Silent Send] Reveal mode OFF'); console.log('[Silent Send] Reveal mode OFF');
if (revealInterval) { clearInterval(revealInterval); revealInterval = null; } if (revealInterval) { clearInterval(revealInterval); revealInterval = null; }
unrevealAllResponses(); unrevealAllResponses();
} }
prevRevealMode = settings.revealMode; prevRevealMode = effectiveReveal;
} }
// Hook into config updates to detect reveal toggle // Hook into config updates to detect reveal toggle
@@ -1246,6 +1248,13 @@
if (event.data?.type === 'ss:config-updated') { if (event.data?.type === 'ss:config-updated') {
// Settings were updated — check if reveal mode changed // Settings were updated — check if reveal mode changed
setTimeout(checkRevealToggle, 100); setTimeout(checkRevealToggle, 100);
// If extension was just disabled, clean up all visual artifacts
if (settings.enabled === false) {
if (hasHighlightAPI && hlSubstituted) { hlSubstituted.clear(); hlRevealed.clear(); }
if (preSendWarningEl) preSendWarningEl.classList.remove('visible');
if (warningEl) warningEl.classList.remove('visible');
}
} }
}); });
@@ -1452,7 +1461,7 @@
} }
document.addEventListener('input', (e) => { document.addEventListener('input', (e) => {
if (settings.autoDetect === false) return; if (!settings.enabled || settings.autoDetect === false) return;
const target = e.target; const target = e.target;
if (target.matches?.('[contenteditable], textarea, input[type="text"]')) { if (target.matches?.('[contenteditable], textarea, input[type="text"]')) {
// Debounce — don't scan on every keystroke // Debounce — don't scan on every keystroke
@@ -1462,7 +1471,7 @@
}, true); }, true);
document.addEventListener('paste', (e) => { document.addEventListener('paste', (e) => {
if (settings.autoDetect === false) return; if (!settings.enabled || settings.autoDetect === false) return;
const target = e.target; const target = e.target;
if (target.matches?.('[contenteditable], textarea, input[type="text"]') || if (target.matches?.('[contenteditable], textarea, input[type="text"]') ||
target.closest?.('[contenteditable]')) { target.closest?.('[contenteditable]')) {
@@ -1499,7 +1508,7 @@
updateRevealBadge(); updateRevealBadge();
// If reveal mode was already on at page load, reveal everything // If reveal mode was already on at page load, reveal everything
if (settings.revealMode && hasSubstitutions()) { if (settings.enabled && settings.revealMode && hasSubstitutions()) {
// Wait for page content to render // Wait for page content to render
setTimeout(revealAllResponses, 1000); setTimeout(revealAllResponses, 1000);
setTimeout(revealAllResponses, 3000); setTimeout(revealAllResponses, 3000);