// FlowDeck Web Clipper — content script // Injected in every page: floating button + context menu + selection handling (function () { if (window.__fdClipperInjected) return; window.__fdClipperInjected = true; const BTN_ID = "fd-clipper-btn"; function createFloatButton() { if (document.getElementById(BTN_ID)) return; const btn = document.createElement("button"); btn.id = BTN_ID; btn.className = "fd-clipper-btn"; btn.textContent = "📌 Clip to FlowDeck"; btn.title = "Clip this page to FlowDeck"; btn.addEventListener("click", () => openClipper("article")); document.body.appendChild(btn); } function getSelectionHtml() { const sel = window.getSelection(); if (!sel || sel.rangeCount === 0 || sel.toString().trim().length < 3) return ""; const range = sel.getRangeAt(0); const div = document.createElement("div"); div.appendChild(range.cloneContents()); return div.innerHTML; } async function openClipper(type) { const html = document.documentElement.outerHTML; const selectionHtml = getSelectionHtml(); const selectionText = window.getSelection() ? window.getSelection().toString().trim() : ""; let clipType = type; if (selectionHtml && selectionText.length > 20) clipType = "selection"; const payload = { url: window.location.href, title: document.title, content: html, content_type: clipType, selection_html: selectionHtml, metadata: { og_title: document.querySelector('meta[property="og:title"]')?.content || "", og_description: document.querySelector('meta[property="og:description"]')?.content || document.querySelector('meta[name="description"]')?.content || "", author: document.querySelector('meta[name="author"]')?.content || "" } }; // Send to background try { const resp = await chrome.runtime.sendMessage({ action: "clip", data: payload }); if (resp && resp.error === "not_authenticated") { alert("FlowDeck: not authenticated. Open FlowDeck settings to connect the clipper."); } else if (resp && resp.status === "ok") { showToast("Clipped to FlowDeck ✓ — page " + resp.page_id); } else if (resp && resp.error) { showToast("Clip failed: " + resp.error, true); } } catch (e) { console.error("FlowDeck clipper", e); showToast("Clip failed: " + e.message, true); } } function showToast(msg, isError) { let t = document.getElementById("fd-clipper-toast"); if (!t) { t = document.createElement("div"); t.id = "fd-clipper-toast"; t.className = "fd-clipper-toast"; document.body.appendChild(t); } t.textContent = msg; t.style.background = isError ? "#e03e3e" : "#1a7f37"; t.classList.add("show"); setTimeout(() => t.classList.remove("show"), 3000); } // Context menu via right-click: if selection exists, inject inline menu document.addEventListener("mouseup", () => { // No heavy UI here; popup/background handles contextMenus API }); // Keyboard shortcut Ctrl+Shift+C document.addEventListener("keydown", (e) => { if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "c") { e.preventDefault(); openClipper("article"); } }); // Expose for popup window.__fdOpenClipper = openClipper; if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", createFloatButton); } else { createFloatButton(); } })();