添加模糊记忆功能

This commit is contained in:
ytc1012
2025-12-11 13:41:09 +08:00
parent ea0976b75b
commit ff85d891d4
5 changed files with 845 additions and 11 deletions

View File

@@ -43,18 +43,24 @@
} else {
disableBlurMode();
}
sendResponse({ success: true });
} else if (request.action === 'clearAll') {
console.log('[BlurText] Clear all blurs');
clearAllBlurs();
sendResponse({ success: true });
} else if (request.action === 'updateIntensity') {
blurIntensity = request.intensity;
console.log('[BlurText] Update intensity:', blurIntensity);
updateAllBlurIntensity();
sendResponse({ success: true });
} else if (request.action === 'switchMode') {
blurMode = request.mode;
console.log('[BlurText] Switch mode:', blurMode);
updateModeUI();
sendResponse({ success: true });
}
return true; // 保持消息通道开放
});
// 启用模糊模式
@@ -375,6 +381,9 @@
// 隐藏按钮
hideBlurButton();
// 保存到存储
saveBlurData();
} catch (error) {
console.error('[BlurText] Error blurring selection:', error);
showSelectionError(selection, '无法模糊该选区');
@@ -431,6 +440,9 @@
span.parentNode.replaceChild(fragment, span);
console.log('[BlurText] Selection span removed, remaining elements:', blurredElements.size);
// 保存到存储
saveBlurData();
}
// 鼠标悬停高亮
@@ -509,6 +521,9 @@
blurredElements.add(element);
}
console.log('[BlurText] Total blurred elements:', blurredElements.size);
// 保存到存储
saveBlurData();
}
// 清除所有模糊
@@ -527,6 +542,9 @@
});
areaOverlays = [];
// 清除存储数据
clearPageBlurData();
// 如果在模糊模式下,显示提示
if (isBlurMode) {
showHint('已清除所有模糊效果', 2000);
@@ -647,6 +665,9 @@
blurredElements.add(overlay);
console.log('[BlurText] Area overlay created, total overlays:', areaOverlays.length);
// 保存到存储
saveBlurData();
}
// 移除区域覆盖层
@@ -660,6 +681,9 @@
overlay.parentNode.removeChild(overlay);
}
console.log('[BlurText] Area overlay removed, remaining:', areaOverlays.length);
// 保存到存储
saveBlurData();
}
// 隐藏绘制框
@@ -707,7 +731,272 @@
}
}
// 页面加载完成后,恢复之前的模糊状态(未来功能)
// 这里可以添加持久化存储功能
// ========== 模糊记忆功能(持久化存储)==========
// 获取当前页面的存储键
function getPageKey() {
return window.location.href;
}
// 生成元素的唯一选择器
function generateSelector(element) {
if (element.id) {
return '#' + element.id;
}
// 构建路径选择器
const path = [];
let current = element;
while (current && current !== document.body) {
let selector = current.tagName.toLowerCase();
// 添加类名(如果有)
if (current.className && typeof current.className === 'string') {
const classes = current.className.split(' ').filter(c =>
c && !c.startsWith('blurtext-')
).join('.');
if (classes) {
selector += '.' + classes;
}
}
// 计算同类型元素的索引
if (current.parentNode) {
const siblings = Array.from(current.parentNode.children).filter(
el => el.tagName === current.tagName
);
if (siblings.length > 1) {
const index = siblings.indexOf(current) + 1;
selector += `:nth-of-type(${index})`;
}
}
path.unshift(selector);
current = current.parentNode;
}
return path.join(' > ');
}
// 生成文本节点的 XPath
function getTextNodeXPath(textNode) {
const parent = textNode.parentNode;
if (!parent) return null;
const parentXPath = getElementXPath(parent);
const textNodes = Array.from(parent.childNodes).filter(
node => node.nodeType === Node.TEXT_NODE
);
const index = textNodes.indexOf(textNode) + 1;
return `${parentXPath}/text()[${index}]`;
}
// 生成元素的 XPath
function getElementXPath(element) {
if (element.id) {
return `//*[@id="${element.id}"]`;
}
const path = [];
let current = element;
while (current && current !== document.body) {
const tagName = current.tagName.toLowerCase();
const siblings = Array.from(current.parentNode.children).filter(
el => el.tagName === current.tagName
);
let selector = tagName;
if (siblings.length > 1) {
const index = siblings.indexOf(current) + 1;
selector += `[${index}]`;
}
path.unshift(selector);
current = current.parentNode;
}
return '/html/body/' + path.join('/');
}
// 根据 XPath 查找元素
function getElementByXPath(xpath) {
const result = document.evaluate(
xpath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
);
return result.singleNodeValue;
}
// 保存模糊数据到存储
function saveBlurData() {
const pageKey = getPageKey();
const data = {
elements: [],
selections: [],
areas: [],
timestamp: Date.now()
};
// 收集所有模糊数据
blurredElements.forEach(element => {
if (element.classList.contains('blurtext-area-overlay')) {
// 区域模式
data.areas.push({
left: parseInt(element.style.left),
top: parseInt(element.style.top),
width: parseInt(element.style.width),
height: parseInt(element.style.height),
intensity: blurIntensity
});
} else if (element.classList.contains('blurtext-selection-wrapped')) {
// 文本选择模式
const textNode = element.firstChild;
if (textNode && textNode.nodeType === Node.TEXT_NODE) {
const xpath = getTextNodeXPath(textNode);
if (xpath) {
data.selections.push({
text: textNode.textContent,
xpath: xpath,
parentXPath: getElementXPath(element.parentNode),
intensity: blurIntensity
});
}
}
} else {
// 元素模式
const selector = generateSelector(element);
data.elements.push({
selector: selector,
intensity: blurIntensity
});
}
});
// 存储到 chrome.storage.local
chrome.storage.local.get(['blurredData'], (result) => {
const blurredData = result.blurredData || {};
blurredData[pageKey] = data;
chrome.storage.local.set({ blurredData }, () => {
console.log('[BlurText] Blur data saved for:', pageKey, data);
});
});
}
// 从存储中恢复模糊数据
function restoreBlurData() {
const pageKey = getPageKey();
chrome.storage.local.get(['blurredData'], (result) => {
const blurredData = result.blurredData || {};
const pageData = blurredData[pageKey];
if (!pageData) {
console.log('[BlurText] No saved blur data for this page');
return;
}
console.log('[BlurText] Restoring blur data:', pageData);
// 恢复元素模式的模糊
pageData.elements?.forEach(item => {
try {
const element = document.querySelector(item.selector);
if (element) {
element.classList.add('blurtext-blurred');
element.style.setProperty('--blur-intensity', `${item.intensity}px`);
blurredElements.add(element);
console.log('[BlurText] Restored element blur:', item.selector);
}
} catch (error) {
console.warn('[BlurText] Failed to restore element:', item.selector, error);
}
});
// 恢复文本选择模式的模糊
pageData.selections?.forEach(item => {
try {
const textNode = getElementByXPath(item.xpath);
if (textNode && textNode.nodeType === Node.TEXT_NODE) {
const text = textNode.textContent;
const index = text.indexOf(item.text);
if (index !== -1) {
// 创建 Range 并包裹文本
const range = document.createRange();
range.setStart(textNode, index);
range.setEnd(textNode, index + item.text.length);
const span = document.createElement('span');
span.className = 'blurtext-blurred blurtext-selection-wrapped';
span.style.setProperty('--blur-intensity', `${item.intensity}px`);
span.style.cursor = 'pointer';
// 添加鼠标悬停和点击事件
span.addEventListener('mouseenter', () => {
showElementTooltip(span, '点击恢复此文本');
});
span.addEventListener('mouseleave', () => {
hideElementTooltip();
});
span.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
hideElementTooltip();
unblurSelectionSpan(span);
// 注意unblurSelectionSpan 内部会调用 saveBlurData()
});
range.surroundContents(span);
blurredElements.add(span);
console.log('[BlurText] Restored selection blur:', item.text);
}
}
} catch (error) {
console.warn('[BlurText] Failed to restore selection:', item.text, error);
}
});
// 恢复区域模式的模糊
pageData.areas?.forEach(item => {
try {
createAreaOverlay(item.left, item.top, item.width, item.height);
console.log('[BlurText] Restored area blur:', item);
} catch (error) {
console.warn('[BlurText] Failed to restore area:', item, error);
}
});
// 如果恢复了模糊效果,显示提示
if (blurredElements.size > 0) {
showHint(`已恢复 ${blurredElements.size} 个模糊效果`, 3000);
}
});
}
// 清除当前页面的存储数据
function clearPageBlurData() {
const pageKey = getPageKey();
chrome.storage.local.get(['blurredData'], (result) => {
const blurredData = result.blurredData || {};
delete blurredData[pageKey];
chrome.storage.local.set({ blurredData }, () => {
console.log('[BlurText] Cleared blur data for:', pageKey);
});
});
}
// 页面加载完成后,恢复之前的模糊状态
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', restoreBlurData);
} else {
restoreBlurData();
}
})();