Files
blurweb/content.js

411 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// content.js - 核心功能实现
(function() {
'use strict';
console.log('[BlurText] Content script loaded');
let isBlurMode = false;
let blurMode = 'element'; // 'element' or 'selection'
let blurIntensity = 10;
let blurredElements = new Set();
let hintElement = null;
let blurButton = null; // 浮动模糊按钮
// 初始化:从存储中加载配置
chrome.storage.local.get(['blurIntensity'], (result) => {
if (result.blurIntensity) {
blurIntensity = result.blurIntensity;
console.log('[BlurText] Loaded blur intensity:', blurIntensity);
}
});
// 监听来自 popup 的消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('[BlurText] Received message:', request);
if (request.action === 'toggleBlurMode') {
isBlurMode = request.enabled;
blurMode = request.mode || 'element';
blurIntensity = request.intensity || 10;
console.log('[BlurText] Toggle blur mode:', isBlurMode, 'mode:', blurMode, 'intensity:', blurIntensity);
if (isBlurMode) {
enableBlurMode();
} else {
disableBlurMode();
}
} else if (request.action === 'clearAll') {
console.log('[BlurText] Clear all blurs');
clearAllBlurs();
} else if (request.action === 'updateIntensity') {
blurIntensity = request.intensity;
console.log('[BlurText] Update intensity:', blurIntensity);
updateAllBlurIntensity();
} else if (request.action === 'switchMode') {
blurMode = request.mode;
console.log('[BlurText] Switch mode:', blurMode);
updateModeUI();
}
});
// 启用模糊模式
function enableBlurMode() {
console.log('[BlurText] Enabling blur mode, mode:', blurMode);
const modeText = blurMode === 'selection' ? '文本选择模式 - 拖动选择文字后点击模糊按钮' : '元素模式 - 点击元素进行模糊';
showHint(`模糊模式已开启 - ${modeText},按 ESC 退出`);
// 根据模式添加对应的样式和事件
if (blurMode === 'element') {
document.body.classList.add('blurtext-mode');
document.addEventListener('click', handleClick, true);
document.addEventListener('mouseover', handleMouseOver, true);
document.addEventListener('mouseout', handleMouseOut, true);
} else if (blurMode === 'selection') {
// 文本选择模式不需要 crosshair 光标
document.addEventListener('mouseup', handleTextSelection, true);
}
// 键盘事件对两种模式都需要
document.addEventListener('keydown', handleKeydown, true);
console.log('[BlurText] Event listeners attached');
}
// 禁用模糊模式
function disableBlurMode() {
document.body.classList.remove('blurtext-mode');
hideHint();
hideBlurButton();
// 移除所有事件监听
document.removeEventListener('click', handleClick, true);
document.removeEventListener('keydown', handleKeydown, true);
document.removeEventListener('mouseover', handleMouseOver, true);
document.removeEventListener('mouseout', handleMouseOut, true);
document.removeEventListener('mouseup', handleTextSelection, true);
// 清除所有高亮和预览
removeAllHighlights();
}
// 更新模式UI
function updateModeUI() {
if (!isBlurMode) return;
console.log('[BlurText] Switching mode to:', blurMode);
// 先移除所有旧的事件监听和样式
document.body.classList.remove('blurtext-mode');
document.removeEventListener('click', handleClick, true);
document.removeEventListener('mouseover', handleMouseOver, true);
document.removeEventListener('mouseout', handleMouseOut, true);
document.removeEventListener('mouseup', handleTextSelection, true);
// 清除旧模式的UI元素
hideBlurButton();
removeAllHighlights();
// 根据新模式添加事件监听和样式
if (blurMode === 'element') {
document.body.classList.add('blurtext-mode');
document.addEventListener('click', handleClick, true);
document.addEventListener('mouseover', handleMouseOver, true);
document.addEventListener('mouseout', handleMouseOut, true);
showHint('已切换到元素模式 - 点击元素进行模糊', 3000);
} else if (blurMode === 'selection') {
// 文本选择模式不需要 crosshair 光标
document.addEventListener('mouseup', handleTextSelection, true);
showHint('已切换到文本选择模式 - 拖动选择文字后点击模糊按钮', 3000);
}
console.log('[BlurText] Mode switched successfully');
}
// 处理点击事件
function handleClick(e) {
console.log('[BlurText] Click detected, isBlurMode:', isBlurMode, 'blurMode:', blurMode);
if (!isBlurMode || blurMode !== 'element') return;
// 阻止默认行为
e.preventDefault();
e.stopPropagation();
let target = e.target;
console.log('[BlurText] Target element:', target.tagName, target.className, 'text:', target.textContent?.substring(0, 20));
// 如果是提示元素,忽略
if (target.classList.contains('blurtext-hint')) {
console.log('[BlurText] Ignored hint element');
return;
}
// 切换模糊状态
toggleBlur(target);
}
// 处理键盘事件ESC 退出)
function handleKeydown(e) {
if (e.key === 'Escape' && isBlurMode) {
isBlurMode = false;
disableBlurMode();
// 通知 popup
chrome.runtime.sendMessage({ action: 'blurModeDisabled' });
}
}
// 处理文本选择(文本选择模式)
function handleTextSelection(e) {
if (!isBlurMode || blurMode !== 'selection') return;
// 避免点击模糊按钮时触发
if (e.target.classList.contains('blurtext-blur-button')) {
return;
}
// 避免点击已模糊的文本段落时触发(这些段落有自己的点击事件)
if (e.target.classList.contains('blurtext-selection-wrapped')) {
return;
}
const selection = window.getSelection();
const selectedText = selection.toString().trim();
console.log('[BlurText] Text selection:', selectedText);
if (selectedText.length > 0) {
// 显示模糊按钮
showBlurButton(selection);
} else {
// 没有选中文本,隐藏按钮
hideBlurButton();
}
}
// 显示模糊按钮
function showBlurButton(selection) {
// 移除旧按钮
hideBlurButton();
// 获取选区的位置
const range = selection.getRangeAt(0);
const rect = range.getBoundingClientRect();
// 创建模糊按钮
blurButton = document.createElement('div');
blurButton.className = 'blurtext-blur-button';
blurButton.textContent = '🔒 模糊选中文本';
blurButton.style.position = 'fixed';
blurButton.style.left = `${rect.left + rect.width / 2}px`;
blurButton.style.top = `${rect.bottom + 10}px`;
blurButton.style.transform = 'translateX(-50%)';
blurButton.style.zIndex = '2147483647';
// 点击按钮模糊文本
blurButton.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
blurSelectedText();
});
document.body.appendChild(blurButton);
}
// 隐藏模糊按钮
function hideBlurButton() {
if (blurButton && blurButton.parentNode) {
blurButton.parentNode.removeChild(blurButton);
blurButton = null;
}
}
// 模糊选中的文本
function blurSelectedText() {
const selection = window.getSelection();
if (!selection.rangeCount) return;
try {
const range = selection.getRangeAt(0);
// 创建 span 包裹选中的文本
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);
// 添加到模糊元素集合
blurredElements.add(span);
console.log('[BlurText] Text selection blurred, total elements:', blurredElements.size);
// 清除选择
selection.removeAllRanges();
// 隐藏按钮
hideBlurButton();
// 显示提示
showHint('文本已模糊(点击可单独恢复)', 2000);
} catch (error) {
console.error('[BlurText] Error blurring selection:', error);
showHint('无法模糊该选区可能包含复杂的HTML结构', 3000);
hideBlurButton();
}
}
// 恢复单个选择模式的模糊段落
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;
const target = e.target;
if (target.classList.contains('blurtext-hint') ||
target.classList.contains('blurtext-blurred')) {
return;
}
// 移除之前的高亮
removeAllHighlights();
// 直接高亮元素
target.classList.add('blurtext-highlight');
}
// 移除所有高亮
function removeAllHighlights() {
const highlighted = document.querySelectorAll('.blurtext-highlight');
highlighted.forEach(el => {
el.classList.remove('blurtext-highlight');
});
}
// 鼠标移出取消高亮
function handleMouseOut(e) {
if (!isBlurMode || blurMode !== 'element') return;
// 延迟移除,避免在元素间移动时闪烁
setTimeout(() => {
// 检查鼠标是否还在模糊模式下的元素上
const hoveredElement = document.elementFromPoint(e.clientX, e.clientY);
if (!hoveredElement ||
hoveredElement.classList.contains('blurtext-hint') ||
hoveredElement.classList.contains('blurtext-blurred')) {
return;
}
// 如果鼠标不在任何高亮元素上,清除所有高亮
const highlighted = document.querySelector('.blurtext-highlight:hover');
if (!highlighted) {
removeAllHighlights();
}
}, 100);
}
// 切换元素模糊状态
function toggleBlur(element) {
if (blurredElements.has(element)) {
// 取消模糊
console.log('[BlurText] Removing blur from element');
element.classList.remove('blurtext-blurred');
element.style.removeProperty('--blur-intensity');
blurredElements.delete(element);
} else {
// 添加模糊
console.log('[BlurText] Adding blur to element, intensity:', blurIntensity);
element.classList.add('blurtext-blurred');
element.style.setProperty('--blur-intensity', `${blurIntensity}px`);
blurredElements.add(element);
}
console.log('[BlurText] Total blurred elements:', blurredElements.size);
}
// 清除所有模糊
function clearAllBlurs() {
blurredElements.forEach(element => {
element.classList.remove('blurtext-blurred');
element.style.removeProperty('--blur-intensity');
});
blurredElements.clear();
// 如果在模糊模式下,显示提示
if (isBlurMode) {
showHint('已清除所有模糊效果', 2000);
}
}
// 更新所有已模糊元素的强度
function updateAllBlurIntensity() {
blurredElements.forEach(element => {
element.style.setProperty('--blur-intensity', `${blurIntensity}px`);
});
}
// 显示提示
function showHint(message, duration = null) {
// 移除旧提示
hideHint();
// 创建新提示
hintElement = document.createElement('div');
hintElement.className = 'blurtext-hint';
hintElement.textContent = message;
document.body.appendChild(hintElement);
// 如果指定了持续时间,自动隐藏
if (duration) {
setTimeout(() => {
hideHint();
}, duration);
}
}
// 隐藏提示
function hideHint() {
if (hintElement && hintElement.parentNode) {
hintElement.parentNode.removeChild(hintElement);
hintElement = null;
}
}
// 页面加载完成后,恢复之前的模糊状态(未来功能)
// 这里可以添加持久化存储功能
})();