Initial work on flashcards

This commit is contained in:
a 2020-08-07 12:25:18 +02:00
parent d94cfdf01d
commit 057bc77990
7 changed files with 128 additions and 16 deletions

View file

@ -1,10 +1,10 @@
import { browser, Runtime, Tabs } from "webextension-polyfill-ts"; import { browser, Runtime, Tabs } from "webextension-polyfill-ts";
import { GTranslateScraper } from "./gtranslate_scraper"; import { GTranslateScraper } from "./gtranslate_scraper";
import { Flashcards } from "./database";
console.log("Background script loaded");
const scraper = new GTranslateScraper(); const scraper = new GTranslateScraper();
console.log(scraper); const db = new Flashcards();
console.log(db);
const getTab = async (s: Runtime.MessageSender): Promise<Tabs.Tab> => { const getTab = async (s: Runtime.MessageSender): Promise<Tabs.Tab> => {
if (s.tab) return s.tab; if (s.tab) return s.tab;
@ -53,6 +53,8 @@ browser.runtime.onMessage.addListener(
return getEnabledCommand(s); return getEnabledCommand(s);
case commands.translate: case commands.translate:
return scraper.translate(c.toTranslate); return scraper.translate(c.toTranslate);
case commands.addFlashcard:
return db.addTranslation(c.translation);
} }
} }
); );

View file

@ -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<flashcard> {
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<Array<flashcard>> {
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);
});
}
}

View file

@ -1,5 +1,4 @@
import { browser } from "webextension-polyfill-ts"; import { browser } from "webextension-polyfill-ts";
import "./gtranslate_types";
declare interface Window { declare interface Window {
hasRun: boolean; hasRun: boolean;
} }

View file

@ -1,10 +1,9 @@
import "./gtranslate_types";
import { browser, WebRequest, Runtime } from "webextension-polyfill-ts"; import { browser, WebRequest, Runtime } from "webextension-polyfill-ts";
export class GTranslateScraper { export class GTranslateScraper {
iframe: HTMLIFrameElement; iframe: HTMLIFrameElement;
conn?: Runtime.Port; conn?: Runtime.Port;
resolveFn?: (value: TranslationResponse) => void; resolveFn?: (value: Translation) => void;
rejectFn?: (reason: String) => void; rejectFn?: (reason: String) => void;
constructor() { constructor() {
@ -46,13 +45,13 @@ export class GTranslateScraper {
document.body.appendChild(iframe); document.body.appendChild(iframe);
}); });
} }
onTranslationRecieved(message: TranslationResponse) { onTranslationRecieved(message: Translation) {
this.resolveFn(message); this.resolveFn(message);
this.resolveFn = null; this.resolveFn = null;
this.rejectFn = null; this.rejectFn = null;
} }
translate(to_translate: string): Promise<TranslationResponse> { translate(to_translate: string): Promise<Translation> {
if (this.rejectFn) this.rejectFn("Got a different translation request"); if (this.rejectFn) this.rejectFn("Got a different translation request");
if (!this.conn) return Promise.reject("The translator is not yet ready"); if (!this.conn) return Promise.reject("The translator is not yet ready");

View file

@ -1,5 +0,0 @@
type TranslationRequest = string;
interface TranslationResponse {
src: string;
result: string;
}

View file

@ -15,9 +15,14 @@ class LingoTranslate extends HTMLElement {
commandKind: commands.translate, commandKind: commands.translate,
toTranslate: toTranslate, toTranslate: toTranslate,
}); });
translation.then((t: TranslationResponse) => { translation.then((t: Translation) => {
if (t.src == this.getAttribute("translate")) { 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")); this.dispatchEvent(new Event("translationFinished"));
} }
}); });
@ -48,3 +53,44 @@ class LingoLoading extends HTMLElement {
} }
} }
customElements.define("lingo-loading", LingoLoading); 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);

14
src/types.d.ts vendored
View file

@ -7,6 +7,7 @@ declare const enum commands {
setEnabled = "setEnabled", setEnabled = "setEnabled",
getEnabled = "getEnabled", getEnabled = "getEnabled",
translate = "translate", translate = "translate",
addFlashcard = "addFlashcard",
} }
interface setEnabled { interface setEnabled {
commandKind: commands.setEnabled; commandKind: commands.setEnabled;
@ -22,4 +23,15 @@ interface translate {
toTranslate: string; 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;
}