Skip to content

Commit 98b81c8

Browse files
ttop32claude
andcommitted
0.1.235: Firefox web PDF viewer + collapse newlines in selection translation
- Firefox: intercept http(s) .pdf main_frame navigations via blocking webRequest and redirect to the bundled pdf.js viewer, so mouseover translation works (Firefox's built-in viewer is a privileged page extensions can't inject into, bugzilla 1454760). Firefox-only guard; Chrome keeps the MV3 embed-swap path. local file:// PDFs are out of reach of webRequest and still use the built-in viewer. - Selection translation: collapse whitespace/newline runs to a single space before translating, so a sentence dragged across wrapped lines (esp. in the PDF viewer) is translated and read aloud as one sentence instead of being split at the line breaks. (review: DeeTho) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 48673c8 commit 98b81c8

5 files changed

Lines changed: 44 additions & 2 deletions

File tree

doc/description.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ Mouseover Translate Any Language At Once
1919
English, Russian, Japanese, Chinese and so on
2020

2121
# Change Log
22+
- 0.1.235
23+
- Firefox: web (http/https) PDFs now open in the extension's own PDF viewer so mouseover translation works, instead of Firefox's built-in viewer which extensions can't add features to (local file:// PDFs still use the built-in viewer)
24+
- Selecting text across multiple lines (e.g. a PDF sentence that wraps) no longer splits the sentence at the line breaks: newlines are collapsed to spaces so it is translated and read aloud as one sentence
2225
- 0.1.234
2326
- Fix broken menus and pop-ups on sites that use Tippy.js for their own UI (e.g. zulip.com): the extension's tooltip styles no longer leak onto the page's own tooltips
2427
- Scroll the settings tab bar sideways with the mouse wheel (no more clicking the arrow buttons when tabs overflow)

public/manifest.firefox.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"128": "icons/icon_128.png"
1212
},
1313
"content_security_policy": "script-src 'self' 'wasm-unsafe-eval' ; object-src 'none'",
14-
"permissions": ["storage", "tabs", "scripting", "contextMenus", "search", "<all_urls>"],
14+
"permissions": ["storage", "tabs", "scripting", "contextMenus", "search", "webRequest", "webRequestBlocking", "<all_urls>"],
1515

1616

1717

src/background.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ var recentRecord = {};
3030
addCopyRequestListener(); // listen copy / save context menus and shortcut key
3131
addTabSwitchEventListener(); // listen tab switch for kill tts
3232
addPdfFileTabListener(); //listen drag and drop pdf
33+
addFirefoxPdfRedirectListener(); //firefox: redirect web pdf to our viewer
3334
addSearchBarListener(); // listen url search bar for translate omnibox
3435
addMessageListener(); // listen message from content script for handle translate & tts
3536
} catch (error) {
@@ -352,6 +353,34 @@ function checkIsLocalPdfUrl(url) {
352353
return /^(file:\/\/).*(\.pdf)$/.test(url?.toLowerCase());
353354
}
354355

356+
// Firefox only: its built-in pdf.js viewer is a privileged page we can't inject
357+
// our tooltip/translation into (bugzilla 1454760, unfixed 7+ yrs). So intercept
358+
// http(s) PDF navigations BEFORE the built-in viewer loads and redirect them to
359+
// our own bundled viewer (a normal extension page where the content script
360+
// runs). Chrome (MV3) can't use blocking webRequest and keeps the embed-swap
361+
// path in contentScript.detectPDF instead.
362+
// Limitation: Firefox webRequest can't intercept file:// requests, so local PDFs
363+
// still open in the built-in viewer.
364+
function addFirefoxPdfRedirectListener() {
365+
if (!util.isFirefox() || !browser.webRequest?.onBeforeRequest) {
366+
return;
367+
}
368+
browser.webRequest.onBeforeRequest.addListener(
369+
function (details) {
370+
if (setting?.detectPDF === "false") {
371+
return {};
372+
}
373+
// never touch our own viewer (it loads the pdf via ?file=) -> no loop
374+
if (details.url.includes("/pdfjs/web/viewer.html")) {
375+
return {};
376+
}
377+
return { redirectUrl: util.getPDFUrl(details.url) };
378+
},
379+
{ urls: ["*://*/*.pdf", "*://*/*.pdf?*"], types: ["main_frame"] },
380+
["blocking"]
381+
);
382+
}
383+
355384
//search bar================================================
356385
function addSearchBarListener() {
357386
browser.omnibox.setDefaultSuggestion({

src/contentScript.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,13 @@ function stageTooltipTextSelect(event, useEvent = true) {
159159
) {
160160
prevSelected = selectedText;
161161
selectedText = useEvent ? event?.selectedText : selectedText;
162-
stageTooltipText(selectedText, "select");
162+
// A sentence dragged across multiple lines (especially in the PDF viewer,
163+
// where getSelection() inserts a newline at every line/span boundary) was
164+
// sent to the translator split by newlines and came back as two fragments.
165+
// Collapse whitespace runs (incl. newlines) to a single space so a wrapped
166+
// sentence is translated — and read aloud — as one flowing sentence.
167+
var selectText = selectedText?.replace(/\s+/g, " ").trim();
168+
stageTooltipText(selectText, "select");
163169
}
164170
}
165171

src/util/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,10 @@ function checkFirefox() {
571571
return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
572572
}
573573

574+
export function isFirefox() {
575+
return checkFirefox();
576+
}
577+
574578
function getOffscreenIframe() {
575579
return document.querySelector('iframe[src="offscreen.html"]');
576580
}

0 commit comments

Comments
 (0)