From 057bc779907b4eca66791dbf03f107b2e735a473 Mon Sep 17 00:00:00 2001 From: a Date: Fri, 7 Aug 2020 12:25:18 +0200 Subject: [PATCH] Initial work on flashcards --- src/background/background.ts | 8 +-- src/background/database.ts | 59 +++++++++++++++++++++ src/background/gtranslate_content_script.ts | 1 - src/background/gtranslate_scraper.ts | 7 ++- src/background/gtranslate_types.ts | 5 -- src/content_script/custom_elements.ts | 50 ++++++++++++++++- src/types.d.ts | 14 ++++- 7 files changed, 128 insertions(+), 16 deletions(-) create mode 100644 src/background/database.ts delete mode 100644 src/background/gtranslate_types.ts diff --git a/src/background/background.ts b/src/background/background.ts index 39dcca3..78bc913 100644 --- a/src/background/background.ts +++ b/src/background/background.ts @@ -1,10 +1,10 @@ import { browser, Runtime, Tabs } from "webextension-polyfill-ts"; import { GTranslateScraper } from "./gtranslate_scraper"; - -console.log("Background script loaded"); +import { Flashcards } from "./database"; const scraper = new GTranslateScraper(); -console.log(scraper); +const db = new Flashcards(); +console.log(db); const getTab = async (s: Runtime.MessageSender): Promise => { if (s.tab) return s.tab; @@ -53,6 +53,8 @@ browser.runtime.onMessage.addListener( return getEnabledCommand(s); case commands.translate: return scraper.translate(c.toTranslate); + case commands.addFlashcard: + return db.addTranslation(c.translation); } } ); diff --git a/src/background/database.ts b/src/background/database.ts new file mode 100644 index 0000000..909e0ce --- /dev/null +++ b/src/background/database.ts @@ -0,0 +1,59 @@ +export interface flashcard { + id?: IDBValidKey; + src: string; + result: string; + dateAdded: Date; + exported: boolean; +} + +export class Flashcards { + db: IDBDatabase; + + constructor() { + const req = indexedDB.open("FlashCardDB", 1); + req.onupgradeneeded = () => { + let objectStore = req.result.createObjectStore("flashcards", { + keyPath: "id", + autoIncrement: true, + }); + objectStore.createIndex("src", "src", { unique: true }); + objectStore.createIndex("result", "result"); + objectStore.createIndex("dateAdded", "dateAdded"); + objectStore.createIndex("exported", "exported"); + }; + req.onsuccess = () => { + this.db = req.result; + }; + } + + addTranslation(t: Translation): Promise { + let card: flashcard = { + ...t, + dateAdded: new Date(), + exported: false, + }; + let req = this.db + .transaction(["flashcards"], "readwrite") + .objectStore("flashcards") + .add(card); + return new Promise((resolve, reject) => { + req.onsuccess = () => { + card.id = req.result; + resolve(card); + }; + req.onerror = () => reject(req.error); + }); + } + + async getAllCards(): Promise> { + let req = this.db + .transaction(["flashcards"], "readonly") + .objectStore("flashcards") + .getAll(); + + return new Promise((resolve, reject) => { + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + } +} diff --git a/src/background/gtranslate_content_script.ts b/src/background/gtranslate_content_script.ts index ee5d5b1..754ed19 100644 --- a/src/background/gtranslate_content_script.ts +++ b/src/background/gtranslate_content_script.ts @@ -1,5 +1,4 @@ import { browser } from "webextension-polyfill-ts"; -import "./gtranslate_types"; declare interface Window { hasRun: boolean; } diff --git a/src/background/gtranslate_scraper.ts b/src/background/gtranslate_scraper.ts index a884d6b..30e2134 100644 --- a/src/background/gtranslate_scraper.ts +++ b/src/background/gtranslate_scraper.ts @@ -1,10 +1,9 @@ -import "./gtranslate_types"; import { browser, WebRequest, Runtime } from "webextension-polyfill-ts"; export class GTranslateScraper { iframe: HTMLIFrameElement; conn?: Runtime.Port; - resolveFn?: (value: TranslationResponse) => void; + resolveFn?: (value: Translation) => void; rejectFn?: (reason: String) => void; constructor() { @@ -46,13 +45,13 @@ export class GTranslateScraper { document.body.appendChild(iframe); }); } - onTranslationRecieved(message: TranslationResponse) { + onTranslationRecieved(message: Translation) { this.resolveFn(message); this.resolveFn = null; this.rejectFn = null; } - translate(to_translate: string): Promise { + 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"); diff --git a/src/background/gtranslate_types.ts b/src/background/gtranslate_types.ts deleted file mode 100644 index 99c565f..0000000 --- a/src/background/gtranslate_types.ts +++ /dev/null @@ -1,5 +0,0 @@ -type TranslationRequest = string; -interface TranslationResponse { - src: string; - result: string; -} diff --git a/src/content_script/custom_elements.ts b/src/content_script/custom_elements.ts index a043217..8949ada 100644 --- a/src/content_script/custom_elements.ts +++ b/src/content_script/custom_elements.ts @@ -15,9 +15,14 @@ class LingoTranslate extends HTMLElement { commandKind: commands.translate, toTranslate: toTranslate, }); - translation.then((t: TranslationResponse) => { + translation.then((t: Translation) => { if (t.src == this.getAttribute("translate")) { - this.shadowRoot.textContent = t.result; + this.shadowRoot.innerHTML = ""; + + let translationElement = document.createElement("lingo-translation"); + translationElement.setAttribute("src", t.src); + translationElement.setAttribute("translation", t.result); + this.shadowRoot.appendChild(translationElement); this.dispatchEvent(new Event("translationFinished")); } }); @@ -48,3 +53,44 @@ class LingoLoading extends HTMLElement { } } customElements.define("lingo-loading", LingoLoading); + +class LingoTranslation extends HTMLElement { + srcElm: HTMLSpanElement; + translateElm: HTMLSpanElement; + addToCollection: HTMLButtonElement; + constructor() { + super(); + const shadow = this.attachShadow({ mode: "open" }); + + this.translateElm = document.createElement("span"); + this.srcElm = document.createElement("span"); + this.addToCollection = document.createElement("button"); + this.addToCollection.addEventListener("click", () => + browser.runtime.sendMessage({ + commandKind: commands.addFlashcard, + translation: { + src: this.getAttribute("src"), + translation: this.getAttribute("translation"), + }, + }) + ); + + shadow.appendChild(this.translateElm); + shadow.appendChild(this.srcElm); + shadow.appendChild(this.addToCollection); + } + + render = () => { + this.srcElm.textContent = this.getAttribute("src"); + this.translateElm.textContent = this.getAttribute("translation"); + }; + + attributeChangedCallback() { + this.render(); + } + + static get observedAttributes() { + return ["src", "translation"]; + } +} +customElements.define("lingo-translation", LingoTranslation); diff --git a/src/types.d.ts b/src/types.d.ts index 19bafd7..6f9e0dd 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -7,6 +7,7 @@ declare const enum commands { setEnabled = "setEnabled", getEnabled = "getEnabled", translate = "translate", + addFlashcard = "addFlashcard", } interface setEnabled { commandKind: commands.setEnabled; @@ -22,4 +23,15 @@ interface translate { toTranslate: string; } -type command = setEnabled | getEnabled | translate; +interface addFlashcard { + commandKind: commands.addFlashcard; + translation: Translation; +} + +type command = setEnabled | getEnabled | translate | addFlashcard; + +type TranslationRequest = string; +interface Translation { + src: string; + result: string; +}