diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..147a504 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,172 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +BlurText is a Chrome/Edge browser extension (Manifest V3) for protecting privacy during screen sharing and recording by blurring sensitive text on web pages. The extension is written in vanilla JavaScript with no framework dependencies. + +**Key Characteristics:** +- Chinese language UI (all text, comments, and documentation in Chinese) +- Manifest V3 standard with Chrome Extension APIs +- CSS `filter: blur()` for visual obfuscation +- Chrome Storage API for local configuration persistence + +## Architecture + +### Core Components + +**Extension Structure:** +1. **[manifest.json](manifest.json)** - Extension configuration (Manifest V3) +2. **[popup.html](popup.html)** + **[popup.js](popup.js)** - Browser action UI and control logic +3. **[content.js](content.js)** - Content script injected into all web pages (core functionality) +4. **[content.css](content.css)** - Injected styles for blur effects and UI overlays + +### Communication Flow + +``` +User clicks extension icon + → popup.js loads and displays UI + → User toggles blur mode or changes settings + → popup.js sends chrome.tabs.sendMessage() to content.js + → content.js applies blur mode or updates settings + → content.js stores state in blurredElements Set +``` + +**Message Types (popup.js → content.js):** +- `toggleBlurMode` - Enable/disable blur mode with mode and intensity +- `clearAll` - Remove all blur effects +- `updateIntensity` - Change blur strength on existing blurred elements +- `switchMode` - Change between element and selection modes + +**Message Types (content.js → popup.js):** +- `blurModeDisabled` - Notify when user presses ESC to exit + +### Two Blur Modes + +**1. Element Mode (`blurMode = 'element'`)** +- Default mode with crosshair cursor +- Click any DOM element to toggle blur +- Hover shows dashed outline highlight +- Stores references to blurred elements in `blurredElements` Set +- Does NOT modify DOM structure (only adds/removes CSS classes) + +**2. Selection Mode (`blurMode = 'selection'`)** +- Select text with mouse drag +- Floating button appears below selection +- Wraps selected text in `
- 手机号: - 138-8888-9999 -
-``` -- 鼠标悬停 `` → 高亮手机号 -- 点击 → 模糊手机号 ✅ - -### 场景 3:纯文本(需要手动处理) -```html -用户 张三 的手机号是 138-8888-9999
-``` -- 悬停任意位置 → 高亮整个 `` -- 点击 → 模糊整段文字 -- **如需只模糊"张三"**:先手动编辑 HTML,用 `张三` 包裹 - ---- - -## 🔧 技术实现 - -### 简化后的核心逻辑 - -**content.js 核心函数**: - -```javascript -// 1. 处理点击 - 简单直接 -function handleClick(e) { - if (!isBlurMode) return; - e.preventDefault(); - e.stopPropagation(); - - let target = e.target; - if (target.classList.contains('blurtext-hint')) return; - - // 直接切换目标元素的模糊状态 - toggleBlur(target); -} - -// 2. 处理悬停 - 高亮预览 -function handleMouseOver(e) { - if (!isBlurMode) return; - - const target = e.target; - if (target.classList.contains('blurtext-hint') || - target.classList.contains('blurtext-blurred')) { - return; - } - - removeAllHighlights(); - target.classList.add('blurtext-highlight'); -} - -// 3. 移除高亮 - 简单清理 -function removeAllHighlights() { - const highlighted = document.querySelectorAll('.blurtext-highlight'); - highlighted.forEach(el => { - el.classList.remove('blurtext-highlight'); - }); -} -``` - -**代码行数对比**: -- 之前:531 行(包含文本节点检测、智能识别、预览管理) -- 现在:约 250 行(移除了约 280 行复杂逻辑) -- 减少 53% 代码量,提升稳定性 - ---- - -## 🧪 测试步骤 - -1. 刷新扩展(`chrome://extensions/`) -2. 打开任意网页 -3. 点击扩展图标,开启模糊模式 -4. **测试基础模糊**: - - 鼠标悬停在任意元素上 → 看到蓝色边框 - - 点击元素 → 成功模糊 ✅ - - 再次点击 → 取消模糊 ✅ -5. **测试强度调整**: - - 打开 popup,拖动滑块 - - 已模糊的元素实时更新强度 ✅ -6. **测试批量清除**: - - 点击"清除所有模糊"按钮 - - 所有模糊效果移除 ✅ - ---- - -## 📝 后续计划 - -基于简单稳定的架构,未来可以考虑: - -1. **框选模糊**:拖拽鼠标框选区域进行模糊 -2. **模糊记忆**:页面刷新后保持模糊状态 -3. **快捷键**:Ctrl+B 快速切换模糊模式 -4. **预设模板**:保存常用的模糊配置 -5. **图片模糊**:支持模糊图片元素 - ---- - -## 💡 开发经验总结 - -**设计原则**: -1. **简单优于复杂**:不要过度设计,用户需要的是稳定可靠的功能 -2. **所见即所得**:悬停预览必须和点击结果完全一致 -3. **DOM 操作要谨慎**:频繁的 DOM 修改容易引入 bug -4. **渐进增强**:先做好基础功能,再逐步添加高级特性 - -**避免的陷阱**: -- ❌ 自动检测和包裹文本节点(DOM 操作复杂,容易出问题) -- ❌ 临时元素管理(生命周期难以控制) -- ❌ 智能识别(正则匹配不够可靠) -- ✅ 让用户明确点击目标元素(简单直接) diff --git a/INSTALL.md b/INSTALL.md deleted file mode 100644 index 663a70d..0000000 --- a/INSTALL.md +++ /dev/null @@ -1,186 +0,0 @@ -# 安装和调试指南 - -## 🚀 快速开始 - -### 第一步:生成图标 - -1. 在浏览器中打开 `icon-generator.html` 文件 -2. 右键点击每个图标,选择"另存为图像" -3. 将图标保存到 `icons/` 文件夹,文件名分别为: - - `icon16.png` - - `icon32.png` - - `icon48.png` - - `icon128.png` - -> 💡 **提示**: 如果右键保存不方便,可以点击每个图标下方的"下载"按钮 - -### 第二步:安装扩展 - -1. 打开 Chrome 浏览器 -2. 在地址栏输入 `chrome://extensions/` 并回车 -3. 开启右上角的"**开发者模式**"开关 -4. 点击"**加载已解压的扩展程序**" -5. 选择 `blurweb` 文件夹 -6. 看到扩展出现在列表中,说明安装成功! - -### 第三步:测试功能 - -#### 方法一:使用测试页面 - -1. 在浏览器中打开 `test.html` 文件 -2. 按照页面上的说明进行测试 - -#### 方法二:测试任意网页 - -1. 打开任意网页(如百度、GitHub 等) -2. 点击浏览器工具栏的 BlurText 图标(紫色图标) -3. 点击"开启模糊模式"按钮 -4. 在网页上点击任意文字,观察模糊效果 - -## 🔍 故障排查 - -### 问题 1:点击文字没有反应 - -**可能原因和解决方法:** - -#### 1. 扩展未正确加载 -- 检查:访问 `chrome://extensions/`,确认 BlurText 已启用 -- 解决:如果未启用,点击开关启用;如果有错误提示,重新加载扩展 - -#### 2. Content Script 未注入 -- 检查:按 F12 打开开发者工具,查看 Console 标签页 -- 应该看到:`[BlurText] Content script loaded` -- 如果没有,刷新页面(F5)后重试 - -#### 3. 消息未发送成功 -- 检查:右键点击扩展图标 → 检查弹出窗口 → 查看 Console -- 应该看到:`[BlurText] Toggle button clicked` 和 `[BlurText] Message sent successfully` -- 如果看到错误,尝试重新加载扩展 - -#### 4. 页面刷新问题 -- 解决:在安装扩展后,刷新所有打开的网页 -- 或者重新打开新标签页测试 - -### 问题 2:提示"请刷新页面后重试" - -**原因:** Content Script 尚未注入到页面 - -**解决:** -1. 刷新当前页面(F5) -2. 再次点击扩展图标 -3. 点击"开启模糊模式" - -### 问题 3:扩展图标不显示 - -**原因:** 图标文件未正确生成或路径错误 - -**解决:** -1. 确认 `icons/` 文件夹存在 -2. 确认包含所有 4 个图标文件 -3. 文件名必须完全匹配:`icon16.png`, `icon32.png`, `icon48.png`, `icon128.png` -4. 重新加载扩展 - -### 问题 4:某些网页无法使用 - -**原因:** 浏览器限制扩展在特殊页面运行 - -**说明:** 以下页面不支持扩展: -- `chrome://` 开头的页面(如设置页、扩展页) -- `chrome-extension://` 开头的页面 -- Chrome Web Store 页面 -- 新标签页(某些情况下) - -**解决:** 在普通网页上使用(如百度、GitHub、新闻网站等) - -## 🐛 调试技巧 - -### 查看 Content Script 日志 - -1. 在网页上按 F12 打开开发者工具 -2. 切换到 Console 标签 -3. 筛选显示 `[BlurText]` 日志 -4. 开启模糊模式后,应该看到: - ``` - [BlurText] Content script loaded - [BlurText] Received message: {action: "toggleBlurMode", ...} - [BlurText] Toggle blur mode: true intensity: 10 - [BlurText] Enabling blur mode - [BlurText] Event listeners attached - ``` - -### 查看 Popup 日志 - -1. 右键点击扩展图标 -2. 选择"检查弹出窗口" -3. 在打开的开发者工具中查看 Console -4. 点击按钮时应该看到对应的日志 - -### 测试点击事件 - -1. 开启模糊模式 -2. 点击网页任意元素 -3. Console 中应该显示: - ``` - [BlurText] Click detected, isBlurMode: true - [BlurText] Target element: DIV some-class - [BlurText] Adding blur to element, intensity: 10 - [BlurText] Total blurred elements: 1 - ``` - -### 检查 CSS 是否生效 - -1. 开启模糊模式后点击一个元素 -2. 右键该元素 → 检查 -3. 在 Elements 标签中,应该看到元素有 `blurtext-blurred` 类 -4. 在 Styles 中应该看到: - ```css - .blurtext-blurred { - filter: blur(10px); - ... - } - ``` - -## ✅ 确认安装成功的标志 - -1. ✅ `chrome://extensions/` 中看到 BlurText 扩展 -2. ✅ 扩展已启用(开关是蓝色的) -3. ✅ 工具栏显示紫色扩展图标 -4. ✅ 点击图标弹出精美的控制面板 -5. ✅ 打开 `test.html` 能看到测试页面 -6. ✅ 开启模糊模式后,页面顶部显示紫色提示条 -7. ✅ 鼠标悬停在文字上有蓝色虚线边框 -8. ✅ 点击文字后变模糊 - -## 📞 获取帮助 - -如果以上方法都无法解决问题: - -1. **检查浏览器版本**:确保使用最新版 Chrome/Edge -2. **尝试其他网页**:在多个网站测试 -3. **查看完整日志**:保存 Console 中的所有日志信息 -4. **重新安装**: - - 移除扩展 - - 关闭浏览器 - - 重新打开浏览器 - - 重新加载扩展 - -## 🎯 预期效果演示 - -### 正常工作流程 - -1. 点击扩展图标 → 弹出控制面板 ✅ -2. 点击"开启模糊模式" → 页面顶部显示提示 ✅ -3. 鼠标移到文字上 → 蓝色虚线边框 ✅ -4. 点击文字 → 变模糊 ✅ -5. 再次点击 → 取消模糊 ✅ -6. 按 ESC → 退出模糊模式 ✅ - -### 视觉效果 - -- **模糊前**: 文字清晰可读 -- **模糊后**: 文字变得模糊,像毛玻璃效果 -- **模糊强度**: 可通过滑块调节,范围 5px-20px - ---- - -**如果一切正常,恭喜你成功安装了 BlurText!🎉** diff --git a/content.css b/content.css index bbc7bbe..66f191f 100644 --- a/content.css +++ b/content.css @@ -10,8 +10,8 @@ position: relative !important; } -/* 模糊元素的悬停效果 */ -.blurtext-blurred:hover::after { +/* 元素模式下的悬停效果 */ +body.blurtext-mode .blurtext-blurred:hover::after { content: '点击取消模糊' !important; position: absolute !important; top: 50% !important; @@ -28,6 +28,48 @@ filter: none !important; } +/* 文本选择模式包裹的元素悬停效果 */ +.blurtext-selection-wrapped { + transition: all 0.1s ease !important; +} + +.blurtext-selection-wrapped:hover { + background-color: rgba(102, 126, 234, 0.2) !important; + outline: 2px solid rgba(102, 126, 234, 0.5) !important; + outline-offset: 2px !important; +} + +.blurtext-selection-wrapped:hover::after { + content: '🔓 点击恢复' !important; + position: absolute !important; + top: 50% !important; + left: 50% !important; + transform: translate(-50%, -50%) !important; + background: rgba(102, 126, 234, 0.98) !important; + color: white !important; + padding: 6px 12px !important; + border-radius: 6px !important; + font-size: 13px !important; + font-weight: 600 !important; + white-space: nowrap !important; + z-index: 999999 !important; + pointer-events: none !important; + filter: none !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3) !important; + animation: blurtext-tooltipPop 0.15s ease !important; +} + +@keyframes blurtext-tooltipPop { + from { + opacity: 0; + transform: translate(-50%, -50%) scale(0.8); + } + to { + opacity: 1; + transform: translate(-50%, -50%) scale(1); + } +} + /* 模糊模式下的鼠标样式 */ body.blurtext-mode * { cursor: crosshair !important; diff --git a/content.js b/content.js index fde1276..0d6275e 100644 --- a/content.js +++ b/content.js @@ -166,6 +166,11 @@ return; } + // 避免点击已模糊的文本段落时触发(这些段落有自己的点击事件) + if (e.target.classList.contains('blurtext-selection-wrapped')) { + return; + } + const selection = window.getSelection(); const selectedText = selection.toString().trim(); @@ -229,6 +234,15 @@ const span = document.createElement('span'); span.className = 'blurtext-blurred blurtext-selection-wrapped'; span.style.setProperty('--blur-intensity', `${blurIntensity}px`); + span.style.cursor = 'pointer'; + span.title = '点击恢复此段文本'; + + // 添加点击事件,允许单独恢复 + span.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + unblurSelectionSpan(span); + }); // 包裹选中的内容 range.surroundContents(span); @@ -245,7 +259,7 @@ hideBlurButton(); // 显示提示 - showHint('文本已模糊', 2000); + showHint('文本已模糊(点击可单独恢复)', 2000); } catch (error) { console.error('[BlurText] Error blurring selection:', error); showHint('无法模糊该选区(可能包含复杂的HTML结构)', 3000); @@ -253,6 +267,30 @@ } } + // 恢复单个选择模式的模糊段落 + function unblurSelectionSpan(span) { + if (!span || !span.parentNode) return; + + console.log('[BlurText] Unblurring selection span'); + + // 从集合中移除 + blurredElements.delete(span); + + // 获取 span 的内容 + const fragment = document.createDocumentFragment(); + while (span.firstChild) { + fragment.appendChild(span.firstChild); + } + + // 用原内容替换 span + span.parentNode.replaceChild(fragment, span); + + // 显示提示 + showHint('已恢复此段文本', 1500); + + console.log('[BlurText] Selection span removed, remaining elements:', blurredElements.size); + } + // 鼠标悬停高亮 function handleMouseOver(e) { if (!isBlurMode || blurMode !== 'element') return; diff --git a/test-textnode.html b/test-textnode.html deleted file mode 100644 index abb02e3..0000000 --- a/test-textnode.html +++ /dev/null @@ -1,205 +0,0 @@ - - -
- - -测试 BlurText 自动处理纯文本节点的能力
- -<span> 中,然后模糊。
- 姓名:李四
-年龄:28
-城市:上海
-💡 测试方法:
-手机号:138-8888-9999
-邮箱:user@example.com
-API Key: sk-1234567890abcdefghijk
-💡 测试方法:
-用户 张三 的手机号是 186-0000-1234,邮箱是 zhangsan@company.com
-💡 测试方法:
-💡 测试方法:
-document.caretRangeFromPoint() 检测是否点在文本节点上/\d{3,}[-\d]*//[\w\.-]+@[\w\.-]+\.\w+//[a-zA-Z0-9_-]{10,}/<span> 包裹该部分<span> 应用模糊效果
- [BlurText] Detected text node: ...[BlurText] Found sensitive value: ...[BlurText] Wrapped text node in span
- <span>)。
- 姓名:张三
-<p>
- <strong>姓名:</strong>
- <span>张三</span>
-</p>
- ✅ 效果:
-<strong> 标签<span> 标签<p><div class="sensitive-info">
- <strong>手机号:</strong>
- <span>138-0000-1234</span>
-</div>
- ✅ 效果:
-姓名:张三
-<p>
- <strong>姓名:</strong>
- 张三
-</p>
- ❌ 问题:
-<p><p>(包括"姓名:")// 错误 ❌
-<p>手机号:138-0000-1234</p>
-
-// 正确 ✅
-<p>手机号:<span>138-0000-1234</span></p>
- <!-- 表单字段 -->
-<div class="field">
- <label>姓名</label>
- <span class="value">张三</span>
-</div>
-
-<!-- 列表项 -->
-<ul>
- <li>
- <strong>API Key:</strong>
- <code>sk-1234567890abcdef</code>
- </li>
-</ul>
-
-<!-- 表格 -->
-<table>
- <tr>
- <td>手机号</td>
- <td><span>138-0000-1234</span></td>
- </tr>
-</table>
- <span> 或其他标签中打开 test.html 测试页面,我已经更新了 HTML 结构,现在可以:
-