diff --git a/src/background/background.ts b/src/background/background.ts index 27eba35..11d5733 100644 --- a/src/background/background.ts +++ b/src/background/background.ts @@ -7,7 +7,8 @@ import content_script from "../frontend/content_script/content_script.ts?file"; let com = new Communicator(); const scraper = new GTranslateScraper(); -com.translateCallback = (toTranslate) => scraper.translate(toTranslate); +com.translateCallback = (toTranslate, sender) => + scraper.translate(toTranslate, sender.tab?.id); const db = new Flashcards(); com.addFlashcardCallback = (c) => db.addFlashcard(c); diff --git a/src/background/gtranslate_scraper.ts b/src/background/gtranslate_scraper.ts index 720a8ed..cb8bf25 100644 --- a/src/background/gtranslate_scraper.ts +++ b/src/background/gtranslate_scraper.ts @@ -1,23 +1,29 @@ import { browser, WebRequest, Runtime } from "webextension-polyfill-ts"; import content_script from "./gtranslate_content_script.ts?file"; +interface TranslationRequest { + tabID?: number; + resolveFn: (value: Translation) => void; + rejectFn: (reason: String) => void; + toTranslate: string; +} + export class GTranslateScraper { - iframe: HTMLIFrameElement; - conn?: Runtime.Port; - resolveFn?: (value: Translation) => void; - rejectFn?: (reason: String) => void; + private conn?: Runtime.Port; + private current?: TranslationRequest; + private queue: Array = []; constructor() { browser.runtime.onConnect.addListener((p) => { if (p.name != "gtranslate_scraper_conn") return; this.conn = p; + this.processFromQueue(p); p.onMessage.addListener((m) => this.onTranslationRecieved(m)); }); //This allows us to create the google translate iframe by removing the x-frame-options header browser.webRequest.onHeadersReceived.addListener( allowIFrameAccess, - { urls: [""], types: ["sub_frame"], @@ -28,7 +34,6 @@ export class GTranslateScraper { //TODO make the language customizable iframe.src = "https://translate.google.com/?op=translate&sl=de&tl=en"; - this.iframe = iframe; //Registers a temp content script, because we cannot inject scripts into iframes created on the background html page, because they have no tabId const js = { @@ -46,21 +51,50 @@ export class GTranslateScraper { document.body.appendChild(iframe); }); } - onTranslationRecieved(message: Translation) { - if (this.resolveFn) this.resolveFn(message); - this.resolveFn = undefined; - this.rejectFn = undefined; + private onTranslationRecieved(message: Translation) { + if (this.current) this.current.resolveFn(message); + this.current = undefined; + this.processFromQueue(this.conn!); } - translate(to_translate: string): Promise { - if (this.rejectFn) this.rejectFn("Got a different translation request"); - if (!this.conn) return Promise.reject("The translator is not yet ready"); + private processTranslationRequest( + request: TranslationRequest, + conn: Runtime.Port + ) { + this.current = request; + conn.postMessage(request.toTranslate); + } - this.conn.postMessage(to_translate); - return new Promise((resolve, reject) => { - this.resolveFn = resolve; - this.rejectFn = reject; + private processFromQueue(conn: Runtime.Port) { + const next = this.queue.pop(); + if (next) this.processTranslationRequest(next, conn); + } + + translate(to_translate: string, tabID?: number): Promise { + if (to_translate == "") return Promise.resolve({ src: "", result: "" }); + + const p = new Promise((resolve: (value: Translation) => void, reject) => { + const req = { + toTranslate: to_translate, + resolveFn: resolve, + rejectFn: reject, + tabID: tabID, + }; + if (this.current || !this.conn) { + //Remove the requests from the same tab + if (tabID) + this.queue = this.queue.filter((r) => { + if (r.tabID !== tabID) { + r.rejectFn("Got another request from the same tab"); + return true; + } + }); + this.queue.push(req); + } else { + this.processTranslationRequest(req, this.conn); + } }); + return p; } }