Files
html2pptx/web-to-ppt/popup.js
T
2026-07-27 14:57:08 +08:00

123 lines
4.4 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.
const SETTINGS_KEY = 'webToPixsoSettings';
const DEFAULT_SETTINGS = { useProxy: false, concurrency: '8', captureMode: 'mixed', captureWidth: null };
const MIN_CAPTURE_WIDTH = 320;
const MAX_CAPTURE_WIDTH = 3840;
const captureWidthInput = document.getElementById('captureWidth');
const exportBtn = document.getElementById('exportBtn');
const btnText = document.getElementById('btnText');
const status = document.getElementById('status');
const statusText = document.getElementById('statusText');
const progressFill = document.getElementById('progressFill');
function normalizeCaptureWidth(value, fallback = null) {
const number = Number.parseInt(String(value || '').replace(/\D+/g, ''), 10);
if (!Number.isFinite(number)) return fallback;
return Math.max(MIN_CAPTURE_WIDTH, Math.min(MAX_CAPTURE_WIDTH, number));
}
async function getCurrentViewportWidth() {
try {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
if (!tab?.id) return null;
const [{ result }] = await chrome.scripting.executeScript({
target: { tabId: tab.id },
func: () => Math.round(window.innerWidth || document.documentElement.clientWidth || 0)
});
return normalizeCaptureWidth(result, null);
} catch { return null; }
}
function setProgress(percent, text) {
status.hidden = false;
progressFill.style.width = `${Math.max(0, Math.min(100, percent))}%`;
statusText.textContent = text;
}
function setBusy(isBusy) {
exportBtn.disabled = isBusy;
exportBtn.classList.toggle('loading', isBusy);
exportBtn.classList.remove('success', 'error');
btnText.textContent = isBusy ? '处理中...' : '导出 PPTX';
}
function setResult(kind, text) {
exportBtn.classList.remove('loading', 'success', 'error');
exportBtn.classList.add(kind);
btnText.textContent = text;
}
async function exportPptx() {
setBusy(true);
setProgress(5, '准备采集...');
const captureWidth = normalizeCaptureWidth(captureWidthInput.value, null);
try {
// 1. 采集
setProgress(15, '正在采集页面...');
const captureResult = await chrome.runtime.sendMessage({
type: 'WEB_TO_PPT_CAPTURE_START',
options: { captureWidth }
});
if (!captureResult || !captureResult.ok) throw new Error(captureResult?.error || '采集失败');
// 2. 获取数据
setProgress(40, '采集完成,获取数据...');
const dataResult = await chrome.runtime.sendMessage({ type: 'WEB_TO_PPT_GET_DATA' });
if (!dataResult || !dataResult.ok) throw new Error(dataResult?.error || '获取数据失败');
// 3. 转化
setProgress(50, '正在生成 PPTX...');
const schema = await WebToPPT.convertToPptx(dataResult.data, (msg) => setProgress(60, msg));
// 4. 生成 PPTX
setProgress(85, '正在打包...');
const blob = await WebToPPT.schemaToPptxBlob(schema);
// 5. 下载(data URLpopup 直接调用)
setProgress(95, '正在下载...');
const buffer = await blob.arrayBuffer();
const bytes = new Uint8Array(buffer);
let binary = '';
for (let i = 0; i < bytes.length; i += 0x8000) {
binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));
}
const dataUrl = 'data:application/vnd.openxmlformats-officedocument.presentationml.presentation;base64,' + btoa(binary);
const title = dataResult.data.source?.title || 'webpage';
const safeTitle = title.replace(/[\\/:*?"<>|]+/g, '-').replace(/\s+/g, '-').slice(0, 64) || 'webpage';
const filename = `web-to-ppt/${safeTitle}-${Date.now()}.pptx`;
try {
const dlId = await chrome.downloads.download({ url: dataUrl, filename });
console.log('[WebToPPT] download id:', dlId);
} catch (e) {
console.error('[WebToPPT] download error:', e.message, e);
throw e;
}
setProgress(100, '导出完成');
setResult('success', '导出完成');
} catch (error) {
setProgress(0, error.message || String(error));
setResult('error', '导出失败');
setTimeout(() => {
setBusy(false);
status.hidden = true;
progressFill.style.width = '0';
}, 3000);
}
}
document.addEventListener('DOMContentLoaded', async () => {
const currentWidth = await getCurrentViewportWidth();
captureWidthInput.value = String(currentWidth || '');
});
exportBtn.addEventListener('click', exportPptx);
captureWidthInput.addEventListener('input', () => {
captureWidthInput.value = captureWidthInput.value.replace(/\D+/g, '');
});