(function () { "use strict"; const ROOT_ID = "__web_to_pixso_picker_root__"; const BOX_ID = "__web_to_pixso_picker_box__"; const LABEL_ID = "__web_to_pixso_picker_label__"; const ATTR = "data-web-to-pixso-selection-id"; const STORAGE_KEY = "__web_to_pixso_island_position__"; let currentElement = null; let currentSettings = null; let mode = "toolbar"; let dragging = null; function removePicker() { document.getElementById(ROOT_ID)?.remove(); document.getElementById(BOX_ID)?.remove(); document.getElementById(LABEL_ID)?.remove(); document.removeEventListener("mousemove", onMouseMove, true); document.removeEventListener("click", onClick, true); document.removeEventListener("keydown", onKeyDown, true); document.removeEventListener("pointermove", onDragMove, true); document.removeEventListener("pointerup", onDragEnd, true); currentElement = null; mode = "toolbar"; dragging = null; } function elementName(element) { if (!element) return ""; const tag = element.tagName ? element.tagName.toLowerCase() : "element"; const id = element.id ? `#${element.id}` : ""; const className = String(element.className || "") .trim() .split(/\s+/) .filter(Boolean) .slice(0, 2) .map(item => `.${item}`) .join(""); return `${tag}${id}${className}`; } function icon(type) { if (type === "screen") { return ''; } if (type === "select") { return ''; } if (type === "copy") { return ''; } return ''; } function rootCss() { return ` #${ROOT_ID} { color-scheme: light; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; left: 50%; position: fixed; top: 24px; transform: translateX(-50%); user-select: none; z-index: 2147483647; } #${ROOT_ID} .w2p-island { align-items: stretch; background: rgba(36, 36, 38, 0.97); border-radius: 22px; box-shadow: 0 8px 24px rgba(0,0,0,.22); color: white; display: flex; min-height: 56px; overflow: hidden; } #${ROOT_ID} .w2p-action, #${ROOT_ID} .w2p-close, #${ROOT_ID} .w2p-cancel { align-items: center; background: transparent; border: 0; color: white; cursor: pointer; display: flex; font: inherit; gap: 10px; justify-content: center; min-height: 56px; padding: 0 18px; white-space: nowrap; } #${ROOT_ID} .w2p-action { border-right: 1px solid rgba(255,255,255,.14); font-size: 16px; font-weight: 650; } #${ROOT_ID} .w2p-action:hover, #${ROOT_ID} .w2p-close:hover, #${ROOT_ID} .w2p-cancel:hover { background: rgba(255,255,255,.1); } #${ROOT_ID} .w2p-action.active { background: rgba(255,255,255,.12); } #${ROOT_ID} svg { fill: none; height: 20px; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2; width: 20px; } #${ROOT_ID} .w2p-close { min-width: 56px; padding: 0 16px; } #${ROOT_ID} .w2p-status { align-items: center; display: flex; gap: 12px; min-height: 56px; padding: 0 20px; } #${ROOT_ID} .w2p-text { font-size: 16px; font-weight: 650; white-space: nowrap; } #${ROOT_ID} .w2p-spinner { animation: w2p-spin .9s linear infinite; border: 2px solid rgba(255,255,255,.32); border-radius: 50%; border-top-color: #fff; height: 20px; width: 20px; } #${ROOT_ID} .w2p-cancel { border-left: 1px solid rgba(255,255,255,.14); font-size: 15px; padding: 0 18px; } #${BOX_ID} { background: rgba(46, 156, 255, .16); border: 2px dashed #1593ff; border-radius: 6px; box-sizing: border-box; display: none; left: 0; pointer-events: none; position: fixed; top: 0; z-index: 2147483646; } #${LABEL_ID} { background: #fff; border-radius: 6px; box-shadow: 0 8px 22px rgba(0,0,0,.2); color: #333; display: none; font: 14px/1.2 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; max-width: 280px; overflow: hidden; padding: 8px 10px; pointer-events: none; position: fixed; text-overflow: ellipsis; white-space: nowrap; z-index: 2147483647; } @keyframes w2p-spin { to { transform: rotate(360deg); } } `; } function ensureBase() { document.getElementById(ROOT_ID)?.remove(); const root = document.createElement("div"); root.id = ROOT_ID; const style = document.createElement("style"); style.textContent = rootCss(); root.appendChild(style); document.documentElement.appendChild(root); let box = document.getElementById(BOX_ID); if (!box) { box = document.createElement("div"); box.id = BOX_ID; document.documentElement.appendChild(box); } let label = document.getElementById(LABEL_ID); if (!label) { label = document.createElement("div"); label.id = LABEL_ID; document.documentElement.appendChild(label); } restorePosition(root); root.addEventListener("pointerdown", onDragStart, true); return root; } function restorePosition(root) { try { const saved = JSON.parse(sessionStorage.getItem(STORAGE_KEY) || "null"); if (saved && Number.isFinite(saved.left) && Number.isFinite(saved.top)) { root.style.left = `${saved.left}px`; root.style.top = `${saved.top}px`; root.style.transform = "none"; } } catch { // Keep the default centered position when storage is unavailable. } } function savePosition(root) { const rect = root.getBoundingClientRect(); try { sessionStorage.setItem(STORAGE_KEY, JSON.stringify({ left: Math.round(rect.left), top: Math.round(rect.top) })); } catch { // Position persistence is only a convenience. } } function clampIsland(root, snap) { const rect = root.getBoundingClientRect(); let left = rect.left; let top = rect.top; const gap = 10; left = Math.max(gap, Math.min(window.innerWidth - rect.width - gap, left)); top = Math.max(gap, Math.min(window.innerHeight - rect.height - gap, top)); if (snap) { const distances = [ { side: "left", value: left }, { side: "right", value: window.innerWidth - left - rect.width }, { side: "top", value: top }, { side: "bottom", value: window.innerHeight - top - rect.height } ].sort((a, b) => a.value - b.value); if (distances[0].value < 96) { if (distances[0].side === "left") left = gap; if (distances[0].side === "right") left = window.innerWidth - rect.width - gap; if (distances[0].side === "top") top = gap; if (distances[0].side === "bottom") top = window.innerHeight - rect.height - gap; } } root.style.left = `${Math.round(left)}px`; root.style.top = `${Math.round(top)}px`; root.style.transform = "none"; savePosition(root); } function onDragStart(event) { const target = event.target; if (target?.closest?.("button")) return; const root = document.getElementById(ROOT_ID); if (!root) return; const rect = root.getBoundingClientRect(); dragging = { offsetX: event.clientX - rect.left, offsetY: event.clientY - rect.top }; root.style.transform = "none"; document.addEventListener("pointermove", onDragMove, true); document.addEventListener("pointerup", onDragEnd, true); } function onDragMove(event) { if (!dragging) return; event.preventDefault(); const root = document.getElementById(ROOT_ID); if (!root) return; root.style.left = `${event.clientX - dragging.offsetX}px`; root.style.top = `${event.clientY - dragging.offsetY}px`; } function onDragEnd() { const root = document.getElementById(ROOT_ID); dragging = null; document.removeEventListener("pointermove", onDragMove, true); document.removeEventListener("pointerup", onDragEnd, true); if (root) clampIsland(root, true); } function setToolbarStatus(text, busy = true) { const root = document.getElementById(ROOT_ID) || ensureBase(); root.innerHTML = `
${busy ? '' : ""}
`; root.querySelector(".w2p-text").textContent = text; root.querySelector(".w2p-cancel").addEventListener("click", removePicker); root.addEventListener("pointerdown", onDragStart, true); clampIsland(root, false); } function showToolbar(settings) { removePicker(); currentSettings = settings || {}; mode = "toolbar"; const root = ensureBase(); root.innerHTML = `
`; root.addEventListener("pointerdown", onDragStart, true); root.querySelector('[data-action="close"]').addEventListener("click", removePicker); root.querySelector('[data-action="select"]').addEventListener("click", () => startElementPicker(currentSettings)); root.querySelector('[data-action="screen"]').addEventListener("click", () => startFullPageCapture(false)); root.querySelector('[data-action="clipboard"]').addEventListener("click", () => startFullPageCapture(true)); clampIsland(root, false); } async function copyText(text) { try { await navigator.clipboard.writeText(text); return true; } catch { const textarea = document.createElement("textarea"); textarea.value = text; textarea.style.cssText = "position:fixed;left:-9999px;top:0;opacity:0"; document.documentElement.appendChild(textarea); textarea.focus(); textarea.select(); const ok = document.execCommand("copy"); textarea.remove(); if (!ok) throw new Error("浏览器拒绝写入剪贴板"); return true; } } async function startFullPageCapture(copyToClipboard) { setToolbarStatus(copyToClipboard ? "正在将页面捕获到剪贴板" : "正在捕获整个页面"); try { const response = await chrome.runtime.sendMessage({ type: copyToClipboard ? "PIXSO_CAPTURE_CLIPBOARD" : "PIXSO_CAPTURE_CURRENT_TAB", options: currentSettings || {} }); if (!response?.ok) throw new Error(response?.error || "采集失败"); if (copyToClipboard) { await copyText(response.json); setToolbarStatus("已复制 JSON 到剪贴板", false); } else { setToolbarStatus("整页采集完成", false); } setTimeout(removePicker, 1100); } catch (error) { setToolbarStatus(error.message || String(error), false); setTimeout(showToolbar, 2200, currentSettings); } } function hideHighlight() { const box = document.getElementById(BOX_ID); const label = document.getElementById(LABEL_ID); if (box) box.style.display = "none"; if (label) label.style.display = "none"; } function updateHighlight(element) { const box = document.getElementById(BOX_ID); const label = document.getElementById(LABEL_ID); if (!box || !label || !element) return; const rect = element.getBoundingClientRect(); if (rect.width <= 0 || rect.height <= 0) return; box.style.display = "block"; box.style.left = `${Math.max(0, rect.left)}px`; box.style.top = `${Math.max(0, rect.top)}px`; box.style.width = `${rect.width}px`; box.style.height = `${rect.height}px`; label.style.display = "block"; label.textContent = elementName(element); label.style.left = `${Math.max(8, rect.left)}px`; label.style.top = `${Math.max(8, Math.min(window.innerHeight - 36, rect.bottom + 8))}px`; } function isPickerNode(element) { return Boolean(element?.closest?.(`#${ROOT_ID}, #${BOX_ID}, #${LABEL_ID}`)); } function onMouseMove(event) { if (mode !== "select") return; const element = event.target; if (!element || isPickerNode(element)) return; currentElement = element; updateHighlight(element); } function onKeyDown(event) { if (event.key === "Escape") { event.preventDefault(); event.stopPropagation(); removePicker(); } } async function onClick(event) { if (mode !== "select" || !currentElement || isPickerNode(event.target)) return; event.preventDefault(); event.stopPropagation(); const selected = currentElement; const rect = selected.getBoundingClientRect(); const selectionId = `w2p-${Date.now()}-${Math.random().toString(16).slice(2)}`; selected.setAttribute(ATTR, selectionId); setToolbarStatus("正在捕获所选元素"); try { const response = await chrome.runtime.sendMessage({ type: "PIXSO_CAPTURE_ELEMENT_START", options: { ...(currentSettings || {}), captureMode: "mixed", selectionId, selectionWidth: Math.max(1, Math.round(rect.width)) } }); if (!response?.ok) throw new Error(response?.error || "元素采集失败"); setToolbarStatus(`元素采集完成,宽度 ${response.selectionWidth || Math.round(rect.width)}px`, false); setTimeout(removePicker, 1100); } catch (error) { setToolbarStatus(error.message || String(error), false); setTimeout(() => startElementPicker(currentSettings), 2200); } finally { selected.removeAttribute(ATTR); hideHighlight(); } } function startElementPicker(settings) { removePicker(); currentSettings = settings || {}; mode = "select"; setToolbarStatus("选择要捕获的元素"); document.addEventListener("mousemove", onMouseMove, true); document.addEventListener("click", onClick, true); document.addEventListener("keydown", onKeyDown, true); } window.__webToPixsoStartElementPicker = startElementPicker; window.__webToPixsoShowCaptureToolbar = showToolbar; })();