// Popup logic const $ = (id) => document.getElementById(id); async function load() { const cfg = await chrome.runtime.sendMessage({ action: "getConfig" }); $("serverUrl").value = cfg.serverUrl || "http://localhost:8080"; $("token").value = cfg.token || ""; const sb = $("showButton"); if (sb) sb.checked = cfg.showButton !== false; } async function save() { const serverUrl = $("serverUrl").value.trim() || "http://localhost:8080"; const token = $("token").value.trim(); const showButton = $("showButton") ? $("showButton").checked : true; const cfg = await chrome.runtime.sendMessage({ action: "getConfig" }); cfg.serverUrl = serverUrl.replace(/\/$/, ""); cfg.token = token; cfg.showButton = showButton; await chrome.runtime.sendMessage({ action: "setConfig", config: cfg }); show("Saved ✓", "ok"); } async function toggleButton(show) { const cfg = await chrome.runtime.sendMessage({ action: "getConfig" }); cfg.showButton = show; await chrome.runtime.sendMessage({ action: "setConfig", config: cfg }); // Notify all tabs immediately for instant UX try { const tabs = await chrome.tabs.query({}); for (const t of tabs) { if (!t.id) continue; chrome.tabs.sendMessage(t.id, { action: "toggleButton", show }).catch(() => {}); } } catch (_e) {} } async function verify() { await save(); const res = await chrome.runtime.sendMessage({ action: "auth" }); if (res && res.authenticated) show(`Connected as ${res.user?.login || "user"} — ${res.devices} device(s)`, "ok"); else if (res && res.authenticated === false) show("Not authenticated — check token / server URL", "err"); else show(JSON.stringify(res).slice(0, 200), "warn"); } function show(msg, kind) { const el = $("status"); el.textContent = msg; el.className = "status " + kind; } async function doClip(type) { const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!tab) return; // Get page data via scripting const [{ result }] = await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: (clipType) => { const sel = window.getSelection(); const html = document.documentElement.outerHTML; const selectionHtml = (() => { if (!sel || sel.rangeCount === 0) return ""; const d = document.createElement("div"); d.appendChild(sel.getRangeAt(0).cloneContents()); return d.innerHTML; })(); return { url: location.href, title: document.title, html: html, content_type: sel && sel.toString().trim().length > 20 ? "selection" : clipType, selection_html: selectionHtml, metadata: { og_description: document.querySelector('meta[property="og:description"]')?.content || document.querySelector('meta[name="description"]')?.content || "" } }; }, args: [type] }); const resp = await chrome.runtime.sendMessage({ action: "clip", data: result }); if (resp && resp.status === "ok") show(`Clipped → page ${resp.page_id} ✓`, "ok"); else show(resp.detail || resp.error || "Clip failed", "err"); } $("save").addEventListener("click", save); $("verify").addEventListener("click", verify); $("clipArticle").addEventListener("click", () => doClip("article")); $("clipBookmark").addEventListener("click", () => doClip("bookmark")); $("clipSelection").addEventListener("click", () => doClip("selection")); $("openFlowDeck").addEventListener("click", (e) => { e.preventDefault(); chrome.tabs.create({ url: $("serverUrl").value || "http://localhost:8080" }); }); $("openExtensions").addEventListener("click", (e) => { e.preventDefault(); chrome.tabs.create({ url: ($("serverUrl").value || "http://localhost:8080") + "/extensions" }); }); const _sb = $("showButton"); if (_sb) _sb.addEventListener("change", (e) => toggleButton(e.target.checked)); load();