From b43f78fc0c646db7077f65b83bdf3d0ea9d00d1a Mon Sep 17 00:00:00 2001 From: Isaac Corbrey Date: Wed, 21 Jan 2026 10:17:00 -0500 Subject: [PATCH] firefox: Fix highlight context menu Fixes the highlight option in the context menu doing nothing in Firefox. The call to the service worker wasn't being handled, and the API call the extension would have made wasn't being authenticated. --- extension/background/service-worker.js | 115 +++++++++++-------------- extension/content/content.js | 14 +++ 2 files changed, 66 insertions(+), 63 deletions(-) diff --git a/extension/background/service-worker.js b/extension/background/service-worker.js index 09e0ef4..4951a87 100644 --- a/extension/background/service-worker.js +++ b/extension/background/service-worker.js @@ -39,6 +39,38 @@ function showNotification(title, message) { } } +async function createHighlight(payload) { + if (!API_BASE) { + throw new Error("API URL not configured"); + } + + const cookie = await chrome.cookies.get({ + url: API_BASE, + name: "margin_session", + }); + + if (!cookie) { + throw new Error("Not authenticated"); + } + + const res = await fetch(`${API_BASE}/api/highlights`, { + method: "POST", + headers: { + "Content-Type": "application/json", + "X-Session-Token": cookie.value, + }, + credentials: "include", + body: JSON.stringify(payload), + }); + + if (!res.ok) { + const errText = await res.text(); + throw new Error(`Failed to create highlight: ${res.status} ${errText}`); + } + + return res.json(); +} + async function openAnnotationUI(tabId, windowId) { if (hasSidePanel) { try { @@ -218,50 +250,35 @@ chrome.contextMenus.onClicked.addListener(async (info, tab) => { type: "GET_SELECTOR_FOR_HIGHLIGHT", selectionText: info.selectionText, }); + if (response?.selector) { + selector = response.selector; + } if (response && response.success) return; } catch { /* ignore */ } - if (info.selectionText) { + if (!selector && info.selectionText) { selector = { type: "TextQuoteSelector", exact: info.selectionText, }; + } + if (selector) { try { - const cookie = await chrome.cookies.get({ - url: API_BASE, - name: "margin_session", + await createHighlight({ + url: tab.url, + title: tab.title, + selector: selector, }); - - if (!cookie) { + showNotification("Margin", "Text highlighted!"); + } catch (err) { + console.error("Highlight API error:", err); + if (err?.message === "Not authenticated") { showNotification("Margin", "Please sign in to create highlights"); return; } - - const res = await fetch(`${API_BASE}/api/highlights`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - credentials: "include", - body: JSON.stringify({ - url: tab.url, - title: tab.title, - selector: selector, - }), - }); - - if (res.ok) { - showNotification("Margin", "Text highlighted!"); - } else { - const errText = await res.text(); - console.error("Highlight API error:", res.status, errText); - showNotification("Margin", "Failed to create highlight"); - } - } catch (err) { - console.error("Highlight API error:", err); showNotification("Margin", "Error creating highlight"); } } else { @@ -490,45 +507,17 @@ async function handleMessage(request, sender, sendResponse) { } case "CREATE_HIGHLIGHT": { - if (!API_BASE) { - sendResponse({ success: false, error: "API URL not configured" }); - return; - } - - const cookie = await chrome.cookies.get({ - url: API_BASE, - name: "margin_session", - }); - - if (!cookie) { - sendResponse({ success: false, error: "Not authenticated" }); - return; - } - - const highlightRes = await fetch(`${API_BASE}/api/highlights`, { - method: "POST", - credentials: "include", - headers: { - "Content-Type": "application/json", - "X-Session-Token": cookie.value, - }, - body: JSON.stringify({ + try { + const highlightData = await createHighlight({ url: request.data.url, title: request.data.title, selector: request.data.selector, color: request.data.color || "yellow", - }), - }); - - if (!highlightRes.ok) { - const errorText = await highlightRes.text(); - throw new Error( - `Failed to create highlight: ${highlightRes.status} ${errorText}`, - ); + }); + sendResponse({ success: true, data: highlightData }); + } catch (error) { + sendResponse({ success: false, error: error.message }); } - - const highlightData = await highlightRes.json(); - sendResponse({ success: true, data: highlightData }); break; } diff --git a/extension/content/content.js b/extension/content/content.js index 2848951..94bae60 100644 --- a/extension/content/content.js +++ b/extension/content/content.js @@ -972,6 +972,20 @@ return true; } + if (request.type === "GET_SELECTOR_FOR_HIGHLIGHT") { + const sel = window.getSelection(); + if (!sel || !sel.toString().trim()) { + sendResponse({ success: false, selector: null }); + return true; + } + const exact = sel.toString().trim(); + sendResponse({ + success: false, + selector: { type: "TextQuoteSelector", exact }, + }); + return true; + } + if (request.type === "UPDATE_OVERLAY_VISIBILITY") { if (sidebarHost) { sidebarHost.style.display = request.show ? "block" : "none"; -- 2.51.2