Strict ts mode

This commit is contained in:
a 2020-08-07 21:52:32 +02:00
parent fdf8cbe0ff
commit 2f8d94bb1a
10 changed files with 98 additions and 85 deletions

View file

@ -9,16 +9,17 @@ const scraper = new GTranslateScraper();
com.translateCallback = (toTranslate) => scraper.translate(toTranslate); com.translateCallback = (toTranslate) => scraper.translate(toTranslate);
const db = new Flashcards(); const db = new Flashcards();
com.addFlashcardCallback = (card) => db.addFlashcard(card); com.addFlashcardCallback = db.addFlashcard;
com.removeFlashcardCallback = (card) => console.log(db); com.removeFlashcardCallback = db.removeFlashcard;
console.log(db);
const getTab = async (s: Runtime.MessageSender): Promise<Tabs.Tab> => { const getTabID = async (s: Runtime.MessageSender): Promise<number> => {
if (s.tab) return s.tab; if (s.tab?.id) return s.tab.id;
let tabs = await browser.tabs.query({ let tabs = await browser.tabs.query({
active: true, active: true,
currentWindow: true, currentWindow: true,
}); });
return tabs[0]; return tabs[0].id!;
}; };
const isEnabledSession = async (tabID: number): Promise<boolean> => const isEnabledSession = async (tabID: number): Promise<boolean> =>
@ -39,15 +40,15 @@ const injectScript = async (tabID: number, enabled?: boolean) => {
}; };
com.setEnabledCallback = async (v: boolean, s: Runtime.MessageSender) => { com.setEnabledCallback = async (v: boolean, s: Runtime.MessageSender) => {
const tab = await getTab(s); const tab = await getTabID(s);
injectScript(tab.id); injectScript(tab);
await setEnabledSession(tab.id, v); await setEnabledSession(tab, v);
}; };
com.getEnabledCallback = async (s: Runtime.MessageSender): Promise<boolean> => { com.getEnabledCallback = async (s: Runtime.MessageSender): Promise<boolean> => {
const tab = await getTab(s); const tab = await getTabID(s);
return isEnabledSession(tab.id); return isEnabledSession(tab);
}; };
browser.tabs.onUpdated.addListener(async (tabID, changeInfo) => { browser.tabs.onUpdated.addListener(async (tabID, changeInfo) => {

View file

@ -1,5 +1,5 @@
export class Flashcards { export class Flashcards {
db: IDBDatabase; db!: IDBDatabase;
constructor() { constructor() {
const req = indexedDB.open("FlashCardDB", 1); const req = indexedDB.open("FlashCardDB", 1);
@ -16,6 +16,11 @@ export class Flashcards {
req.onsuccess = () => { req.onsuccess = () => {
this.db = req.result; this.db = req.result;
}; };
req.onerror = () => {
throw new Error(
`Error initializing the database backend, ${req.error}. This shouldn't ever happen`
);
};
} }
addFlashcard(t: Translation | Flashcard): Promise<Flashcard> { addFlashcard(t: Translation | Flashcard): Promise<Flashcard> {
@ -43,14 +48,16 @@ export class Flashcards {
} }
removeFlashcard(card: Flashcard): Promise<void> { removeFlashcard(card: Flashcard): Promise<void> {
let req = this.db if (card.id) {
.transaction(["flashcards"], "readwrite") let req = this.db
.objectStore("flashcards") .transaction(["flashcards"], "readwrite")
.delete(card.id); .objectStore("flashcards")
return new Promise((resolve, reject) => { .delete(card.id);
req.onsuccess = () => resolve(); return new Promise((resolve, reject) => {
req.onerror = () => reject(req.error); req.onsuccess = () => resolve();
}); req.onerror = () => reject(req.error);
});
} else return Promise.reject("Undefined ID");
} }
async getAllCards(): Promise<Array<Flashcard>> { async getAllCards(): Promise<Array<Flashcard>> {

View file

@ -22,7 +22,7 @@ declare interface Window {
const observer = new MutationObserver((mutations) => { const observer = new MutationObserver((mutations) => {
console.log(mutations); console.log(mutations);
const wasTranslating = mutations.some((m) => const wasTranslating = mutations.some((m) =>
m.oldValue.split(" ").some((c) => c == "translating") m.oldValue!.split(" ").some((c) => c == "translating")
); );
if (wasTranslating && !isTranslating()) { if (wasTranslating && !isTranslating()) {
sendTranslation(); sendTranslation();

View file

@ -46,9 +46,9 @@ export class GTranslateScraper {
}); });
} }
onTranslationRecieved(message: Translation) { onTranslationRecieved(message: Translation) {
this.resolveFn(message); if (this.resolveFn) this.resolveFn(message);
this.resolveFn = null; this.resolveFn = undefined;
this.rejectFn = null; this.rejectFn = undefined;
} }
translate(to_translate: string): Promise<Translation> { translate(to_translate: string): Promise<Translation> {
@ -68,7 +68,7 @@ const allowIFrameAccess = (info: WebRequest.OnHeadersReceivedDetailsType) => {
if (info.documentUrl != document.URL) return; if (info.documentUrl != document.URL) return;
let headers = info.responseHeaders; let headers = info.responseHeaders;
headers = headers.filter((header) => { headers = headers?.filter((header) => {
let h = header.name.toString().toLowerCase(); let h = header.name.toString().toLowerCase();
h != "x-frame-options" && h != "frame-options"; h != "x-frame-options" && h != "frame-options";
}); });

View file

@ -2,36 +2,41 @@
import { browser, Runtime } from "webextension-polyfill-ts"; import { browser, Runtime } from "webextension-polyfill-ts";
export class Communicator { export class Communicator {
setEnabledCallback: (value: boolean, sender: Runtime.MessageSender) => void; setEnabledCallback?: (value: boolean, sender: Runtime.MessageSender) => void;
getEnabledCallback: (sender: Runtime.MessageSender) => Promise<boolean>; getEnabledCallback?: (sender: Runtime.MessageSender) => Promise<boolean>;
translateCallback: ( translateCallback?: (
toTranslate: string, toTranslate: string,
sender: Runtime.MessageSender sender: Runtime.MessageSender
) => Promise<Translation>; ) => Promise<Translation>;
addFlashcardCallback?: (
addFlashcardCallback: (
value: Translation | Flashcard, value: Translation | Flashcard,
sender: Runtime.MessageSender sender: Runtime.MessageSender
) => Promise<Flashcard>; ) => Promise<Flashcard>;
removeFlashcardCallback: ( removeFlashcardCallback?: (
value: Flashcard, value: Flashcard,
sender: Runtime.MessageSender sender: Runtime.MessageSender
) => Promise<Flashcard>; ) => Promise<void>;
constructor() { constructor() {
browser.runtime.onMessage.addListener( browser.runtime.onMessage.addListener(
(c: command, s: Runtime.MessageSender) => { (c: command, s: Runtime.MessageSender) => {
switch (c.commandKind) { try {
case commandKinds.setEnabled: switch (c.commandKind) {
return this.setEnabledCallback(c.value, s); case commandKinds.setEnabled:
case commandKinds.getEnabled: return this.setEnabledCallback!(c.value, s);
return this.getEnabledCallback(s); case commandKinds.getEnabled:
case commandKinds.translate: return this.getEnabledCallback!(s);
return this.translateCallback(c.toTranslate, s); case commandKinds.translate:
case commandKinds.addFlashcard: return this.translateCallback!(c.toTranslate, s);
return this.addFlashcardCallback(c.card, s); case commandKinds.addFlashcard:
case commandKinds.removeFlashcard: return this.addFlashcardCallback!(c.card, s);
return this.removeFlashcardCallback(c.card, s); case commandKinds.removeFlashcard:
return this.removeFlashcardCallback!(c.card, s);
}
} catch (e) {
if (e instanceof ReferenceError)
console.warn(`Unimplemented command ${c.commandKind}`);
else throw e;
} }
} }
); );
@ -46,12 +51,10 @@ export class Communicator {
commandKind: commandKinds.translate, commandKind: commandKinds.translate,
toTranslate: toTranslate, toTranslate: toTranslate,
}); });
static addFlashcard = (card: Flashcard | Translation) => { static addFlashcard = (card: Flashcard | Translation): Promise<Flashcard> =>
sendMessage({ commandKind: commandKinds.addFlashcard, card: card }); sendMessage({ commandKind: commandKinds.addFlashcard, card: card });
}; static removeFlashcard = (card: Flashcard) =>
static removeFlashcard = (card: Flashcard) => {
sendMessage({ commandKind: commandKinds.removeFlashcard, card: card }); sendMessage({ commandKind: commandKinds.removeFlashcard, card: card });
};
} }
const sendMessage = (m: command) => browser.runtime.sendMessage(m); const sendMessage = (m: command) => browser.runtime.sendMessage(m);

View file

@ -29,7 +29,7 @@ declare global {
const onSelectionChange = () => { const onSelectionChange = () => {
tippyInstance.hide(); tippyInstance.hide();
clearTimeout(timeoutID); clearTimeout(timeoutID);
if (document.getSelection().type == "Range") if (document.getSelection()?.type == "Range")
timeoutID = window.setTimeout(tippyInstance.show, 500); timeoutID = window.setTimeout(tippyInstance.show, 500);
}; };
@ -41,16 +41,16 @@ declare global {
trigger: "manual", trigger: "manual",
interactive: true, interactive: true,
getReferenceClientRect: () => getReferenceClientRect: () =>
document.getSelection().getRangeAt(0).getBoundingClientRect(), document.getSelection()!.getRangeAt(0).getBoundingClientRect(),
onCreate: (instance) => { onCreate: (instance) => {
translateElement.addEventListener("translationFinished", () => translateElement.addEventListener("translationFinished", () =>
instance.popperInstance.update() instance.popperInstance!.update()
); );
}, },
onShow: () => { onShow: () => {
translateElement.setAttribute( translateElement.setAttribute(
"translate", "translate",
document.getSelection().toString() document.getSelection()?.toString() ?? ""
); );
}, },
}); });

View file

@ -7,10 +7,12 @@ class LingoTranslate extends HTMLElement {
translationElm: LingoTranslation; translationElm: LingoTranslation;
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: "open" }); const shadow = this.attachShadow({ mode: "open" });
this.shadowRoot.innerHTML = `<lingo-loading></lingo-loading> <lingo-translation></lingo-translation>`; shadow.innerHTML = `<lingo-loading></lingo-loading> <lingo-translation></lingo-translation>`;
this.loadingElm = this.shadowRoot.querySelector("lingo-loading"); this.loadingElm = <LingoLoading>shadow.querySelector("lingo-loading");
this.translationElm = this.shadowRoot.querySelector("lingo-translation"); this.translationElm = <LingoTranslation>(
shadow.querySelector("lingo-translation")
);
} }
render = () => { render = () => {
@ -25,8 +27,7 @@ class LingoTranslate extends HTMLElement {
this.loadingElm.hidden = true; this.loadingElm.hidden = true;
this.translationElm.hidden = false; this.translationElm.hidden = false;
this.translationElm.setAttribute("src", t.src); this.translationElm.translation = t;
this.translationElm.setAttribute("translation", t.result);
this.dispatchEvent(new Event("translationFinished")); this.dispatchEvent(new Event("translationFinished"));
} }
}); });
@ -62,44 +63,46 @@ class LingoTranslation extends HTMLElement {
srcElm: HTMLSpanElement; srcElm: HTMLSpanElement;
translateElm: HTMLSpanElement; translateElm: HTMLSpanElement;
addToCollection: HTMLButtonElement; addToCollection: HTMLButtonElement;
private _translation?: Translation;
constructor() { constructor() {
super(); super();
this.attachShadow({ mode: "open" }); const shadow = this.attachShadow({ mode: "open" });
let style = document.createElement("style"); let style = document.createElement("style");
style.textContent = translationCSS; style.textContent = translationCSS;
this.shadowRoot.appendChild(style); shadow.appendChild(style);
this.shadowRoot.innerHTML = ` shadow.innerHTML = `
<div id="translation"> <div id="translation">
<span id="src"></span> - <span id="translated"></span> <span id="src"></span> - <span id="translated"></span>
</div> </div>
<button is="toggleButton"> Add to collection </button> <button is="toggleButton"> Add to collection </button>
`; `;
this.srcElm = this.shadowRoot.querySelector("#src"); this.srcElm = <HTMLSpanElement>shadow.querySelector("#src");
this.translateElm = this.shadowRoot.querySelector("#translated"); this.translateElm = <HTMLSpanElement>shadow.querySelector("#translated");
this.addToCollection = <HTMLButtonElement>shadow.querySelector("button");
this.addToCollection = this.shadowRoot.querySelector("button");
this.addToCollection.addEventListener("click", () => this.addToCollection.addEventListener("click", () =>
Communicator.addFlashcard({ Communicator.addFlashcard(this.translation)
src: this.getAttribute("src"),
result: this.getAttribute("translation"),
})
); );
} }
render = () => { public set translation(v: Translation) {
this.srcElm.textContent = this.getAttribute("src"); this._translation = v;
this.translateElm.textContent = this.getAttribute("translation");
};
attributeChangedCallback() {
this.render(); this.render();
} }
static get observedAttributes() { public get translation(): Translation {
return ["src", "translation"]; if (this._translation == null)
throw new Error("No translation object provided");
return this._translation;
} }
render = () => {
this.srcElm.textContent = this.translation.src;
this.translateElm.textContent = this.translation.result;
};
} }
customElements.define("lingo-translation", LingoTranslation); customElements.define("lingo-translation", LingoTranslation);

View file

@ -5,6 +5,6 @@
<title></title> <title></title>
</head> </head>
<body> <body>
<button is="extension-toggle"></button> <button is="lingo-toggle"></button>
</body> </body>
</html> </html>

View file

@ -3,7 +3,7 @@ import "./popup.scss";
const con = new Communicator(); const con = new Communicator();
class ExtensionToggle extends HTMLButtonElement { class Toggle extends HTMLButtonElement {
isON: boolean = false; isON: boolean = false;
textContent: string = "OFF"; textContent: string = "OFF";
@ -27,23 +27,21 @@ class ExtensionToggle extends HTMLButtonElement {
this.addEventListener("click", () => { this.addEventListener("click", () => {
this.on = !this.on; this.on = !this.on;
const toggleEvent = new CustomEvent("extensionToggled", { const toggleEvent = new CustomEvent("toggled", {
detail: this.on, detail: this.on,
}); });
this.dispatchEvent(toggleEvent); this.dispatchEvent(toggleEvent);
}); });
} }
} }
customElements.define("extension-toggle", ExtensionToggle, { customElements.define("lingo-toggle", Toggle, {
extends: "button", extends: "button",
}); });
const toggle = <ExtensionToggle>( const toggle = <Toggle>document.querySelector("button[is=extension-toggle]");
document.querySelector("button[is=extension-toggle]") toggle.addEventListener("toggled", ((e: CustomEvent) => {
); Communicator.setEnabled(e.detail);
toggle.addEventListener("extensionToggled", (e: CustomEvent) => }) as EventListener); //Hate to do this but ts forced me
Communicator.setEnabled(e.detail)
);
con.setEnabledCallback = (v) => (toggle.on = v); con.setEnabledCallback = (v) => (toggle.on = v);
Communicator.getEnabled().then((v) => (toggle.on = v)); Communicator.getEnabled().then((v) => (toggle.on = v));

View file

@ -6,6 +6,7 @@
"target": "es6", "target": "es6",
"allowJs": true, "allowJs": true,
"sourceMap": true, "sourceMap": true,
"esModuleInterop": true "esModuleInterop": true,
"strict": true
} }
} }