From 243e9d30f0dd845b4336bf8bf217fefbf7db9b06 Mon Sep 17 00:00:00 2001 From: a Date: Thu, 13 Aug 2020 10:49:43 +0200 Subject: [PATCH] Language selection --- package.json | 1 + src/background/background.ts | 1 + src/background/gtranslate_content_script.ts | 37 +++++++++- src/background/gtranslate_scraper.ts | 15 +++- src/communication.ts | 17 ++++- src/frontend/popup/LanguageOption.svelte | 36 ++++++++++ src/frontend/popup/LanguageSelection.svelte | 79 +++++++++++++++++++++ src/frontend/popup/Popup.svelte | 19 ++++- src/types.d.ts | 5 ++ yarn.lock | 5 ++ 10 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 src/frontend/popup/LanguageOption.svelte create mode 100644 src/frontend/popup/LanguageSelection.svelte diff --git a/package.json b/package.json index bb259e1..699c4bb 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Lingo is a small browser extension to help you learn languages", "main": "webpack.config.js", "dependencies": { + "svelte-select": "^3.11.0", "tippy.js": "^6.2.5" }, "devDependencies": { diff --git a/src/background/background.ts b/src/background/background.ts index 11d5733..c871b96 100644 --- a/src/background/background.ts +++ b/src/background/background.ts @@ -9,6 +9,7 @@ let com = new Communicator(); const scraper = new GTranslateScraper(); com.translateCallback = (toTranslate, sender) => scraper.translate(toTranslate, sender.tab?.id); +com.getLanguagesCallback = () => scraper.languages; const db = new Flashcards(); com.addFlashcardCallback = (c) => db.addFlashcard(c); diff --git a/src/background/gtranslate_content_script.ts b/src/background/gtranslate_content_script.ts index 0a771e6..07d5683 100644 --- a/src/background/gtranslate_content_script.ts +++ b/src/background/gtranslate_content_script.ts @@ -1,5 +1,19 @@ import { browser } from "webextension-polyfill-ts"; +export enum MessageKinds { + translationFinished = "translation", + languageList = "languages", +} +interface TranslationMessage { + messageKind: MessageKinds.translationFinished; + translation: Translation; +} +interface LanguageListMessage { + messageKind: MessageKinds.languageList; + languages: Array; +} +export type Message = TranslationMessage | LanguageListMessage; + (async () => { if (window.location.host != "translate.google.com" || window.hasRun) return; window.hasRun = true; @@ -8,6 +22,8 @@ import { browser } from "webextension-polyfill-ts"; name: "gtranslate_scraper_conn", }); + const sendMessage = (m: Message) => conn.postMessage(m); + const src = document.querySelector("textarea#source"); const result = ( @@ -32,11 +48,30 @@ import { browser } from "webextension-polyfill-ts"; }); const sendTranslation = () => { - conn.postMessage({ src: src.value, result: result.innerText.trim() }); + sendMessage({ + messageKind: MessageKinds.translationFinished, + translation: { src: src.value, result: result.innerText.trim() }, + }); }; conn.onMessage.addListener((to_translate: string) => { if (src.value == to_translate && !isTranslating()) sendTranslation(); else src.value = to_translate; }); + + const getLanguages = () => { + const langs = document.querySelectorAll( + "div.language_list_section:nth-child(3) > .language_list_item_wrapper" + ); + return Array.from(langs).map((l) => { + const code = l.classList[1].split("-").pop(); + const name = l.querySelector(".language_list_item_language_name")! + .textContent; + return { code: code!, name: name! }; + }); + }; + sendMessage({ + messageKind: MessageKinds.languageList, + languages: getLanguages(), + }); })(); diff --git a/src/background/gtranslate_scraper.ts b/src/background/gtranslate_scraper.ts index cb8bf25..0e48303 100644 --- a/src/background/gtranslate_scraper.ts +++ b/src/background/gtranslate_scraper.ts @@ -1,5 +1,6 @@ import { browser, WebRequest, Runtime } from "webextension-polyfill-ts"; import content_script from "./gtranslate_content_script.ts?file"; +import { Message, MessageKinds } from "./gtranslate_content_script"; interface TranslationRequest { tabID?: number; @@ -12,13 +13,25 @@ export class GTranslateScraper { private conn?: Runtime.Port; private current?: TranslationRequest; private queue: Array = []; + languages: Promise>; constructor() { + let languagesResolve: (value: Array) => void; + this.languages = new Promise((resolv) => (languagesResolve = resolv)); + 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)); + p.onMessage.addListener((m: Message) => { + switch (m.messageKind) { + case MessageKinds.languageList: + languagesResolve(m.languages); + return; + case MessageKinds.translationFinished: + this.onTranslationRecieved(m.translation); + } + }); }); //This allows us to create the google translate iframe by removing the x-frame-options header diff --git a/src/communication.ts b/src/communication.ts index 52470ff..5e8dc21 100644 --- a/src/communication.ts +++ b/src/communication.ts @@ -16,6 +16,9 @@ export class Communicator { value: Flashcard, sender: Runtime.MessageSender ) => Promise; + getLanguagesCallback?: ( + sender: Runtime.MessageSender + ) => Promise>; constructor() { browser.runtime.onMessage.addListener( @@ -32,6 +35,8 @@ export class Communicator { return this.addFlashcardCallback!(c.card, s); case commandKinds.removeFlashcard: return this.removeFlashcardCallback!(c.card, s); + case commandKinds.getLanguages: + return this.getLanguagesCallback!(s); default: console.warn(`Unimplemented command ${c}`); } @@ -63,6 +68,10 @@ export class Communicator { commandKind: commandKinds.removeFlashcard, card: card, }); + static getLanguages = (): Promise> => + sendMessage({ + commandKind: commandKinds.getLanguages, + }); } const sendMessage = (m: command) => browser.runtime.sendMessage(m); @@ -73,6 +82,7 @@ export enum commandKinds { translate = "translate", addFlashcard = "addFlashcard", removeFlashcard = "removeFlashcard", + getLanguages = "getLanguages", } interface setEnabled { commandKind: commandKinds.setEnabled; @@ -98,9 +108,14 @@ interface removeFlashcard { card: Flashcard; } +interface getLanguages { + commandKind: commandKinds.getLanguages; +} + export type command = | setEnabled | getEnabled | translate | addFlashcard - | removeFlashcard; + | removeFlashcard + | getLanguages; diff --git a/src/frontend/popup/LanguageOption.svelte b/src/frontend/popup/LanguageOption.svelte new file mode 100644 index 0000000..f54ebd0 --- /dev/null +++ b/src/frontend/popup/LanguageOption.svelte @@ -0,0 +1,36 @@ + + + + + + diff --git a/src/frontend/popup/LanguageSelection.svelte b/src/frontend/popup/LanguageSelection.svelte new file mode 100644 index 0000000..20078c3 --- /dev/null +++ b/src/frontend/popup/LanguageSelection.svelte @@ -0,0 +1,79 @@ + + + + +
+ (focused = true)} + on:blur={onBlur} /> + {#if focused} +
+ {#each searched_langs as l} + + {/each} +
+ {/if} +
diff --git a/src/frontend/popup/Popup.svelte b/src/frontend/popup/Popup.svelte index 1811943..d25170c 100644 --- a/src/frontend/popup/Popup.svelte +++ b/src/frontend/popup/Popup.svelte @@ -1,5 +1,7 @@