123 lines
4.6 KiB
JavaScript
123 lines
4.6 KiB
JavaScript
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));
|
|
// Debug: check rotation
|
|
const rotateCount = schema.slides.reduce((acc, s) => acc + s.objects.filter(o => o.options?.rotate).length, 0);
|
|
console.log('[WebToPPT] schema:', schema.slides.length, 'slides,', rotateCount, 'shapes with rotation');
|
|
|
|
// 4. 生成 PPTX
|
|
setProgress(85, '正在打包...');
|
|
const blob = await WebToPPT.schemaToPptxBlob(schema);
|
|
|
|
// 5. 转 base64
|
|
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 base64 = btoa(binary);
|
|
|
|
// 6. 存到 storage,让 background 下载
|
|
setProgress(95, '正在下载...');
|
|
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`;
|
|
|
|
await chrome.storage.session.set({ pptxBase64: base64, pptxFilename: filename });
|
|
const dlResult = await chrome.runtime.sendMessage({ type: 'WEB_TO_PPT_DOWNLOAD' });
|
|
if (!dlResult || !dlResult.ok) throw new Error(dlResult?.error || '下载失败');
|
|
|
|
setProgress(100, '导出完成');
|
|
setResult('success', '已下载到 Downloads/web-to-ppt/');
|
|
|
|
} 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, '');
|
|
});
|