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);
const db = new Flashcards();
com.addFlashcardCallback = (card) => db.addFlashcard(card);
com.removeFlashcardCallback = (card) => console.log(db);
com.addFlashcardCallback = db.addFlashcard;
com.removeFlashcardCallback = db.removeFlashcard;
console.log(db);
const getTab = async (s: Runtime.MessageSender): Promise<Tabs.Tab> => {
if (s.tab) return s.tab;
const getTabID = async (s: Runtime.MessageSender): Promise<number> => {
if (s.tab?.id) return s.tab.id;
let tabs = await browser.tabs.query({
active: true,
currentWindow: true,
});
return tabs[0];
return tabs[0].id!;
};
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) => {
const tab = await getTab(s);
const tab = await getTabID(s);
injectScript(tab.id);
await setEnabledSession(tab.id, v);
injectScript(tab);
await setEnabledSession(tab, v);
};
com.getEnabledCallback = async (s: Runtime.MessageSender): Promise<boolean> => {
const tab = await getTab(s);
return isEnabledSession(tab.id);
const tab = await getTabID(s);
return isEnabledSession(tab);
};
browser.tabs.onUpdated.addListener(async (tabID, changeInfo) => {

View file

@ -1,5 +1,5 @@
export class Flashcards {
db: IDBDatabase;
db!: IDBDatabase;
constructor() {
const req = indexedDB.open("FlashCardDB", 1);
@ -16,6 +16,11 @@ export class Flashcards {
req.onsuccess = () => {
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> {
@ -43,14 +48,16 @@ export class Flashcards {
}
removeFlashcard(card: Flashcard): Promise<void> {
let req = this.db
.transaction(["flashcards"], "readwrite")
.objectStore("flashcards")
.delete(card.id);
return new Promise((resolve, reject) => {
req.onsuccess = () => resolve();
req.onerror = () => reject(req.error);
});
if (card.id) {
let req = this.db
.transaction(["flashcards"], "readwrite")
.objectStore("flashcards")
.delete(card.id);
return new Promise((resolve, reject) => {
req.onsuccess = () => resolve();
req.onerror = () => reject(req.error);
});
} else return Promise.reject("Undefined ID");
}
async getAllCards(): Promise<Array<Flashcard>> {

View file

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

View file

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

View file

@ -2,36 +2,41 @@
import { browser, Runtime } from "webextension-polyfill-ts";
export class Communicator {
setEnabledCallback: (value: boolean, sender: Runtime.MessageSender) => void;
getEnabledCallback: (sender: Runtime.MessageSender) => Promise<boolean>;
translateCallback: (
setEnabledCallback?: (value: boolean, sender: Runtime.MessageSender) => void;
getEnabledCallback?: (sender: Runtime.MessageSender) => Promise<boolean>;
translateCallback?: (
toTranslate: string,
sender: Runtime.MessageSender
) => Promise<Translation>;
addFlashcardCallback: (
addFlashcardCallback?: (
value: Translation | Flashcard,
sender: Runtime.MessageSender
) => Promise<Flashcard>;
removeFlashcardCallback: (
removeFlashcardCallback?: (
value: Flashcard,
sender: Runtime.MessageSender
) => Promise<Flashcard>;
) => Promise<void>;
constructor() {
browser.runtime.onMessage.addListener(
(c: command, s: Runtime.MessageSender) => {
switch (c.commandKind) {
case commandKinds.setEnabled:
return this.setEnabledCallback(c.value, s);
case commandKinds.getEnabled:
return this.getEnabledCallback(s);
case commandKinds.translate:
return this.translateCallback(c.toTranslate, s);
case commandKinds.addFlashcard:
return this.addFlashcardCallback(c.card, s);
case commandKinds.removeFlashcard:
return this.removeFlashcardCallback(c.card, s);
try {
switch (c.commandKind) {
case commandKinds.setEnabled:
return this.setEnabledCallback!(c.value, s);
case commandKinds.getEnabled:
return this.getEnabledCallback!(s);
case commandKinds.translate:
return this.translateCallback!(c.toTranslate, s);
case commandKinds.addFlashcard:
return this.addFlashcardCallback!(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,
toTranslate: toTranslate,
});
static addFlashcard = (card: Flashcard | Translation) => {
static addFlashcard = (card: Flashcard | Translation): Promise<Flashcard> =>
sendMessage({ commandKind: commandKinds.addFlashcard, card: card });
};
static removeFlashcard = (card: Flashcard) => {
static removeFlashcard = (card: Flashcard) =>
sendMessage({ commandKind: commandKinds.removeFlashcard, card: card });
};
}
const sendMessage = (m: command) => browser.runtime.sendMessage(m);

View file

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

View file

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

View file

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

View file

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

View file

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