fix: content script truncation error and mac shortcut issue

- Fixed truncated content.js file causing syntax error and missing logic
- Updated manifest.json to use Command+Shift+X for Mac shortcut
- Updated documentation
This commit is contained in:
empty
2025-12-03 22:11:57 +08:00
parent 2ab8ba9c3c
commit 6b73565918
7 changed files with 82 additions and 58 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

View File

@@ -31,19 +31,26 @@
## 使用方法
1. 点击浏览器工具栏中的扩展图标
2. 选择输出格式Markdown/JSON/XML
2. **选择输出格式**
- **Markdown 格式** (默认)
- **JSON 结构化**
- **XML 格式**
- **ZIP (Markdown + 图)** - *自动下载包含本地图片的压缩包*
3. 点击 **框选区域提取****提取整页内容**
- 如果选择了 ZIP 格式,点击这两个按钮将直接触发打包下载
4. 如果是框选模式,拖拽鼠标选择区域
5. 提取完成后内容自动复制到剪贴板
5. 提取完成后内容自动复制到剪贴板 (ZIP 格式除外)
**智能元素提取模式:**
1. 按下快捷键(默认 `Alt+Shift+X` / Mac: `Option+Shift+X`
2. 移动鼠标,扩展会自动高亮当前的 HTML 元素
3. 点击高亮的元素即可提取该区域内容
- *提示:如果在插件弹窗中选择了 ZIP 格式,点击元素将下载该元素的 ZIP 包*
## 快捷操作
- **Alt+Shift+X** (Mac: **Option+Shift+X**) - 开启/关闭元素智能识别模式
- **Alt+Shift+X** (Windows/Linux)
- **Command+Shift+X** (Mac) - 开启/关闭元素智能识别模式
- **ESC** - 取消选择模式
## 输出示例

View File

@@ -4,12 +4,38 @@ chrome.commands.onCommand.addListener((command) => {
if (tabs.length === 0) return;
const tabId = tabs[0].id;
// 尝试发送消息如果失败可能是页面未加载content script
chrome.tabs.sendMessage(tabId, { action: 'toggleElementSelection' })
.catch(() => {
// 可以选择注入脚本或忽略
console.log('Cannot send message to tab', tabId);
});
});
}
});
// 图片下载代理,绕过 CORS
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'fetchImage') {
fetch(request.url)
.then(response => {
if (!response.ok) throw new Error('Network response was not ok');
return response.blob();
})
.then(blob => {
// 将 Blob 转换为 Base64 字符串返回给 content script
const reader = new FileReader();
reader.onloadend = () => {
sendResponse({ success: true, data: reader.result });
};
reader.onerror = () => {
sendResponse({ success: false, error: 'Failed to read blob' });
};
reader.readAsDataURL(blob);
})
.catch(error => {
console.error('Image fetch failed:', error);
sendResponse({ success: false, error: error.message });
});
return true; // 保持消息通道开启以进行异步响应
}
});

View File

@@ -14,17 +14,13 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
} else if (request.action === 'extractFullPage') {
currentFormat = request.format || 'markdown';
const content = extractContent(document.body);
const formatted = formatContent(content, currentFormat);
copyToClipboard(formatted);
saveToStorage(formatted);
handleOutput(content, currentFormat);
sendResponse({ success: true });
} else if (request.action === 'toggleElementSelection') {
// 如果已经在选择模式,则退出
if (isSelecting) {
cleanup();
} else {
// 默认格式或者读取存储的格式? 这里暂时用默认markdown
// 理想情况应该从 storage 读取,这里简化处理
chrome.storage.local.get('format', (res) => {
currentFormat = res.format || 'markdown';
startElementSelectionMode();
@@ -35,6 +31,24 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
return true;
});
// === 统一输出处理 ===
function handleOutput(content, format) {
if (format === 'zip') {
handleZipDownload(content);
} else {
const formatted = formatContent(content, format);
copyToClipboard(formatted);
saveToStorage(formatted);
if (currentFormat !== 'zip') {
// 简单的检查,避免误报
if (content && content.length > 0) {
// 这里的通知逻辑由调用者处理,或者已经统一了
}
}
}
}
// === 元素选择模式 ===
let highlightBox = null;
let lastTarget = null;
@@ -86,12 +100,12 @@ function onElementClick(e) {
if (lastTarget) {
// 提取内容
const content = extractContent(lastTarget);
const formatted = formatContent(content, currentFormat);
handleOutput(content, currentFormat);
copyToClipboard(formatted);
saveToStorage(formatted);
if (currentFormat !== 'zip') {
showNotification('✅ 元素内容已提取');
}
}
cleanup();
}
@@ -166,11 +180,11 @@ function onMouseUp(e) {
if (elements.length > 0) {
// 提取内容
const content = extractFromElements(elements);
const formatted = formatContent(content, currentFormat);
handleOutput(content, currentFormat);
copyToClipboard(formatted);
saveToStorage(formatted);
if (currentFormat !== 'zip') {
showNotification('✅ 内容已提取并复制到剪贴板');
}
} else {
showNotification('❌ 未选中任何内容');
}
@@ -523,41 +537,4 @@ function escapeXML(str) {
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
// 复制到剪贴板
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
} catch (err) {
// 降级方案
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
textarea.style.opacity = '0';
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
}
}
// 保存到 storage
function saveToStorage(text) {
chrome.storage.local.set({ lastExtraction: text });
}
// 显示通知
function showNotification(message) {
const notification = document.createElement('div');
notification.className = 'llm-extractor-notification';
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => {
notification.classList.add('fade-out');
setTimeout(() => notification.remove(), 300);
}, 2000);
}
.replace(/

13
src/browser-extension/lib/jszip.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -24,7 +24,7 @@
"toggle-element-selection": {
"suggested_key": {
"default": "Alt+Shift+X",
"mac": "Alt+Shift+X"
"mac": "Command+Shift+X"
},
"description": "Toggle Element Selection Mode"
}
@@ -32,7 +32,7 @@
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"js": ["lib/jszip.min.js", "content.js"],
"css": ["content.css"]
}
],

View File

@@ -113,6 +113,7 @@
<option value="markdown">Markdown 格式</option>
<option value="json">JSON 结构化</option>
<option value="xml">XML 格式</option>
<option value="zip">ZIP (Markdown + 图)</option>
</select>
<button id="selectBtn" class="btn btn-primary">