New communicator
This commit is contained in:
parent
74fe885fd0
commit
72568aa9b5
8 changed files with 181 additions and 179 deletions
|
@ -1,20 +1,21 @@
|
||||||
import { browser, Runtime } from "webextension-polyfill-ts";
|
import { browser, Runtime } from "webextension-polyfill-ts";
|
||||||
import { GTranslateScraper } from "./gtranslate_scraper";
|
import { GTranslateScraper } from "./gtranslate_scraper";
|
||||||
import { Flashcards } from "./database";
|
import { Flashcards } from "./database";
|
||||||
import { Communicator, commandKinds } from "../communication";
|
import { BackgroundMessenger } from "../background_frontend_commands";
|
||||||
import content_script from "../frontend/content_script/content_script.ts?file";
|
import content_script from "../frontend/content_script/content_script.ts?file";
|
||||||
|
|
||||||
let com = new Communicator();
|
let con = new BackgroundMessenger();
|
||||||
|
|
||||||
const scraper = new GTranslateScraper();
|
const scraper = new GTranslateScraper();
|
||||||
com.translateCallback = async (toTranslate, sender) =>
|
con.addMessageListener("translate", async (toTranslate, sender) =>
|
||||||
scraper.translate(toTranslate, await getCurrentLanguages(), sender.tab?.id);
|
scraper.translate(toTranslate, await getCurrentLanguages(), sender.tab?.id)
|
||||||
|
);
|
||||||
|
|
||||||
com.getLanguagesCallback = () => scraper.languages;
|
con.addMessageListener("getLanguages", () => scraper.languages);
|
||||||
|
|
||||||
const db = new Flashcards();
|
const db = new Flashcards();
|
||||||
com.addFlashcardCallback = (c) => db.addFlashcard(c);
|
con.addMessageListener("addFlashcard", (c) => db.addFlashcard(c));
|
||||||
com.removeFlashcardCallback = (c) => db.removeFlashcard(c);
|
con.addMessageListener("removeFlashcard", (c) => db.removeFlashcard(c));
|
||||||
|
|
||||||
const getCurrentLanguages = async () => {
|
const getCurrentLanguages = async () => {
|
||||||
const langs = await scraper.languages;
|
const langs = await scraper.languages;
|
||||||
|
@ -33,8 +34,8 @@ const setCurrentLanguages = async (l: Partial<LanguagePair>) => {
|
||||||
if (l.dstLang) await browser.storage.local.set({ dstLang: l.dstLang.code });
|
if (l.dstLang) await browser.storage.local.set({ dstLang: l.dstLang.code });
|
||||||
};
|
};
|
||||||
|
|
||||||
com.getCurrentLanguagesCallback = getCurrentLanguages;
|
con.addMessageListener("getCurrentLanguages", getCurrentLanguages);
|
||||||
com.setCurrentLanguagesCallback = setCurrentLanguages;
|
con.addMessageListener("setCurrentLanguages", setCurrentLanguages);
|
||||||
|
|
||||||
const getTabID = async (s: Runtime.MessageSender): Promise<number> => {
|
const getTabID = async (s: Runtime.MessageSender): Promise<number> => {
|
||||||
if (s.tab?.id) return s.tab.id;
|
if (s.tab?.id) return s.tab.id;
|
||||||
|
@ -56,24 +57,24 @@ const injectScript = async (tabID: number, enabled?: boolean) => {
|
||||||
file: content_script,
|
file: content_script,
|
||||||
});
|
});
|
||||||
if (enabled === undefined) enabled = await isEnabledSession(tabID);
|
if (enabled === undefined) enabled = await isEnabledSession(tabID);
|
||||||
browser.tabs.sendMessage(tabID, {
|
con.runCommand("setEnabled", enabled, tabID);
|
||||||
commandKind: commandKinds.setEnabled,
|
|
||||||
value: enabled,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
com.setEnabledCallback = async (v: boolean, s: Runtime.MessageSender) => {
|
con.addMessageListener(
|
||||||
const tab = await getTabID(s);
|
"setEnabled",
|
||||||
if ((await isEnabledSession(tab)) == v) return;
|
async (v: boolean, s: Runtime.MessageSender) => {
|
||||||
|
const tab = await getTabID(s);
|
||||||
|
if ((await isEnabledSession(tab)) == v) return;
|
||||||
|
|
||||||
injectScript(tab);
|
injectScript(tab);
|
||||||
await setEnabledSession(tab, v);
|
await setEnabledSession(tab, v);
|
||||||
};
|
}
|
||||||
|
);
|
||||||
|
|
||||||
com.getEnabledCallback = async (s: Runtime.MessageSender): Promise<boolean> => {
|
con.addMessageListener("getEnabled", async (s: Runtime.MessageSender) => {
|
||||||
const tab = await getTabID(s);
|
const tab = await getTabID(s);
|
||||||
return isEnabledSession(tab);
|
return isEnabledSession(tab);
|
||||||
};
|
});
|
||||||
|
|
||||||
browser.tabs.onUpdated.addListener(async (tabID, changeInfo) => {
|
browser.tabs.onUpdated.addListener(async (tabID, changeInfo) => {
|
||||||
if (changeInfo.status == "complete") {
|
if (changeInfo.status == "complete") {
|
||||||
|
|
77
src/background_frontend_commands.ts
Normal file
77
src/background_frontend_commands.ts
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import { Communicator, commandFunction, commandList } from "./communicator";
|
||||||
|
import { browser } from "webextension-polyfill-ts";
|
||||||
|
|
||||||
|
export interface commands extends commandList {
|
||||||
|
setEnabled: setEnabled;
|
||||||
|
getEnabled: getEnabled;
|
||||||
|
translate: translate;
|
||||||
|
addFlashcard: addFlashcard;
|
||||||
|
removeFlashcard: removeFlashcard;
|
||||||
|
getLanguages: getLanguages;
|
||||||
|
getCurrentLanguages: getCurrentLanguages;
|
||||||
|
setCurrentLanguages: setCurrentLanguages;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface setEnabled extends commandFunction {
|
||||||
|
args: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface getEnabled extends commandFunction {
|
||||||
|
return: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface getLanguages extends commandFunction {
|
||||||
|
return: Array<Language>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface translate extends commandFunction {
|
||||||
|
args: string;
|
||||||
|
return: Translation;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface getCurrentLanguages extends commandFunction {
|
||||||
|
return: LanguagePair;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface addFlashcard extends commandFunction {
|
||||||
|
args: Translation | Flashcard;
|
||||||
|
return: Flashcard;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface removeFlashcard extends commandFunction {
|
||||||
|
args: Flashcard;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface setCurrentLanguages extends commandFunction {
|
||||||
|
args: Partial<LanguagePair>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BackgroundMessenger extends Communicator<commands> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
browser.runtime.onMessage.addListener((m, s) => this.onMessage(m, s));
|
||||||
|
}
|
||||||
|
runCommand<K extends keyof commands>(
|
||||||
|
command: K,
|
||||||
|
args: commands[K]["args"],
|
||||||
|
tabID: number
|
||||||
|
) {
|
||||||
|
const msg = this.getCommandMessage(command, args);
|
||||||
|
return browser.tabs.sendMessage(tabID, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FrontendMessenger extends Communicator<commands> {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
browser.runtime.onMessage.addListener((m, s) => this.onMessage(m, s));
|
||||||
|
}
|
||||||
|
|
||||||
|
runCommand<K extends keyof commands>(
|
||||||
|
command: K,
|
||||||
|
args: commands[K]["args"]
|
||||||
|
): commands[K]["return"] {
|
||||||
|
const message = this.getCommandMessage(command, args);
|
||||||
|
return browser.runtime.sendMessage(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,138 +0,0 @@
|
||||||
//There has to be a better way to do this while remaining type safe...
|
|
||||||
import { browser, Runtime } from "webextension-polyfill-ts";
|
|
||||||
|
|
||||||
export class Communicator {
|
|
||||||
setEnabledCallback?: (value: boolean, sender: Runtime.MessageSender) => void;
|
|
||||||
getEnabledCallback?: (sender: Runtime.MessageSender) => Promise<boolean>;
|
|
||||||
translateCallback?: (
|
|
||||||
toTranslate: string,
|
|
||||||
sender: Runtime.MessageSender
|
|
||||||
) => Promise<Translation>;
|
|
||||||
addFlashcardCallback?: (
|
|
||||||
value: Translation | Flashcard,
|
|
||||||
sender: Runtime.MessageSender
|
|
||||||
) => Promise<Flashcard>;
|
|
||||||
removeFlashcardCallback?: (
|
|
||||||
value: Flashcard,
|
|
||||||
sender: Runtime.MessageSender
|
|
||||||
) => Promise<void>;
|
|
||||||
getLanguagesCallback?: (
|
|
||||||
sender: Runtime.MessageSender
|
|
||||||
) => Promise<Array<Language>>;
|
|
||||||
getCurrentLanguagesCallback?: (
|
|
||||||
sender: Runtime.MessageSender
|
|
||||||
) => Promise<LanguagePair>;
|
|
||||||
setCurrentLanguagesCallback?: (
|
|
||||||
value: Partial<LanguagePair>,
|
|
||||||
sender: Runtime.MessageSender
|
|
||||||
) => 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);
|
|
||||||
case commandKinds.getLanguages:
|
|
||||||
return this.getLanguagesCallback!(s);
|
|
||||||
case commandKinds.getCurrentLanguages:
|
|
||||||
return this.getCurrentLanguagesCallback!(s);
|
|
||||||
case commandKinds.setCurrentLanguages:
|
|
||||||
return this.setCurrentLanguagesCallback!(c.value, s);
|
|
||||||
default:
|
|
||||||
console.warn(`Unimplemented command ${c}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static setEnabled = (v: boolean) =>
|
|
||||||
sendMessage({ commandKind: commandKinds.setEnabled, value: v });
|
|
||||||
static getEnabled = (): Promise<boolean> =>
|
|
||||||
sendMessage({ commandKind: commandKinds.getEnabled });
|
|
||||||
static translate = (toTranslate: string): Promise<Translation> =>
|
|
||||||
sendMessage({
|
|
||||||
commandKind: commandKinds.translate,
|
|
||||||
toTranslate: toTranslate,
|
|
||||||
});
|
|
||||||
static addFlashcard = (card: Flashcard | Translation): Promise<Flashcard> =>
|
|
||||||
sendMessage({
|
|
||||||
commandKind: commandKinds.addFlashcard,
|
|
||||||
card: card,
|
|
||||||
});
|
|
||||||
static removeFlashcard = (card: Flashcard) =>
|
|
||||||
sendMessage({
|
|
||||||
commandKind: commandKinds.removeFlashcard,
|
|
||||||
card: card,
|
|
||||||
});
|
|
||||||
static getLanguages = (): Promise<Array<Language>> =>
|
|
||||||
sendMessage({
|
|
||||||
commandKind: commandKinds.getLanguages,
|
|
||||||
});
|
|
||||||
static getCurrentLanguages = (): Promise<LanguagePair> =>
|
|
||||||
sendMessage({
|
|
||||||
commandKind: commandKinds.getCurrentLanguages,
|
|
||||||
});
|
|
||||||
static setCurrentLanguages = (v: Partial<LanguagePair>) =>
|
|
||||||
sendMessage({ commandKind: commandKinds.setCurrentLanguages, value: v });
|
|
||||||
}
|
|
||||||
|
|
||||||
const sendMessage = (m: command) => browser.runtime.sendMessage(m);
|
|
||||||
|
|
||||||
export enum commandKinds {
|
|
||||||
setEnabled = "setEnabled",
|
|
||||||
getEnabled = "getEnabled",
|
|
||||||
translate = "translate",
|
|
||||||
addFlashcard = "addFlashcard",
|
|
||||||
removeFlashcard = "removeFlashcard",
|
|
||||||
getLanguages = "getLanguages",
|
|
||||||
getCurrentLanguages = "getCurrentLanguage",
|
|
||||||
setCurrentLanguages = "setCurrentLanguages",
|
|
||||||
}
|
|
||||||
interface setEnabled {
|
|
||||||
commandKind: commandKinds.setEnabled;
|
|
||||||
value: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface getCommand {
|
|
||||||
commandKind:
|
|
||||||
| commandKinds.getEnabled
|
|
||||||
| commandKinds.getLanguages
|
|
||||||
| commandKinds.getCurrentLanguages;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface translateCommand {
|
|
||||||
commandKind: commandKinds.translate;
|
|
||||||
toTranslate: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface addFlashcard {
|
|
||||||
commandKind: commandKinds.addFlashcard;
|
|
||||||
card: Translation | Flashcard;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface removeFlashcard {
|
|
||||||
commandKind: commandKinds.removeFlashcard;
|
|
||||||
card: Flashcard;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface setCurrentLanguages {
|
|
||||||
commandKind: commandKinds.setCurrentLanguages;
|
|
||||||
value: Partial<LanguagePair>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type command =
|
|
||||||
| setEnabled
|
|
||||||
| getCommand
|
|
||||||
| translateCommand
|
|
||||||
| addFlashcard
|
|
||||||
| removeFlashcard
|
|
||||||
| setCurrentLanguages;
|
|
52
src/communicator.ts
Normal file
52
src/communicator.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import type { Runtime } from "webextension-polyfill-ts";
|
||||||
|
|
||||||
|
export interface commandFunction {
|
||||||
|
args: any;
|
||||||
|
return: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface commandList {
|
||||||
|
[functionName: string]: commandFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface commandMessage<T extends commandList, K extends keyof T> {
|
||||||
|
name: K;
|
||||||
|
args: T[K]["args"];
|
||||||
|
}
|
||||||
|
|
||||||
|
declare type listener<T extends commandList, K extends keyof T> = (
|
||||||
|
args: T[K]["args"],
|
||||||
|
s: Runtime.MessageSender
|
||||||
|
) => Promise<T[K]["return"]>;
|
||||||
|
|
||||||
|
export abstract class Communicator<T extends commandList> {
|
||||||
|
private listeners = new Map<keyof T, listener<T, keyof T>>();
|
||||||
|
|
||||||
|
abstract runCommand<K extends keyof T>(
|
||||||
|
command: K,
|
||||||
|
args: T[K]["args"],
|
||||||
|
...rest: any[]
|
||||||
|
): Promise<T[K]["return"]>;
|
||||||
|
|
||||||
|
addMessageListener<K extends keyof T>(command: K, callback: listener<T, K>) {
|
||||||
|
this.listeners.set(command, <any>callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCommandMessage<K extends keyof T>(
|
||||||
|
command: K,
|
||||||
|
...args: T[K]["args"]
|
||||||
|
): commandMessage<T, K> {
|
||||||
|
return { name: command, args: args };
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessage<K extends keyof T>(
|
||||||
|
m: commandMessage<T, K>,
|
||||||
|
s: Runtime.MessageSender
|
||||||
|
) {
|
||||||
|
let listener = this.listeners.get(m.name);
|
||||||
|
let args: [T[keyof T]["args"], Runtime.MessageSender] = m.args;
|
||||||
|
if (args[0] === undefined) args.pop();
|
||||||
|
args.push(s);
|
||||||
|
if (listener) return listener.apply(null, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +1,23 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Spinner from "./Spinner.svelte";
|
import Spinner from "./Spinner.svelte";
|
||||||
import Translated from "./Translated.svelte";
|
import Translated from "./Translated.svelte";
|
||||||
import { Communicator } from "../../communication";
|
import { createEventDispatcher, tick, setContext } from "svelte";
|
||||||
import { createEventDispatcher, tick } from "svelte";
|
import type { FrontendMessenger } from "../../background_frontend_commands";
|
||||||
|
|
||||||
export let toTranslate: string;
|
export let toTranslate: string;
|
||||||
|
export let connection: FrontendMessenger;
|
||||||
|
setContext("connection", connection);
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
let trans_promise: Promise<Translation>;
|
let trans_promise: Promise<Translation>;
|
||||||
$: {
|
$: {
|
||||||
trans_promise = Communicator.translate(toTranslate).then((r) => {
|
trans_promise = connection
|
||||||
tick().then(() => dispatch("translationFinished"));
|
.runCommand("translate", toTranslate)
|
||||||
return r;
|
.then((r) => {
|
||||||
});
|
tick().then(() => dispatch("translationFinished"));
|
||||||
|
return r;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -21,4 +25,6 @@
|
||||||
<Spinner />
|
<Spinner />
|
||||||
{:then trans}
|
{:then trans}
|
||||||
<Translated {trans} />
|
<Translated {trans} />
|
||||||
|
{:catch}
|
||||||
|
Error
|
||||||
{/await}
|
{/await}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Communicator } from "../../communication";
|
import { getContext } from "svelte";
|
||||||
|
import type { FrontendMessenger } from "../../background_frontend_commands";
|
||||||
|
|
||||||
|
let connection = getContext("connection") as FrontendMessenger;
|
||||||
export let trans: Translation;
|
export let trans: Translation;
|
||||||
let card: Flashcard | undefined;
|
let card: Flashcard | undefined;
|
||||||
|
|
||||||
const addFlashcard = async () => {
|
const addFlashcard = async () => {
|
||||||
card = await Communicator.addFlashcard(trans);
|
card = await connection.runCommand("addFlashcard", trans);
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeFlashcard = async () => {
|
const removeFlashcard = async () => {
|
||||||
if (card) await Communicator.removeFlashcard(card);
|
if (card) await connection.runCommand("removeFlashcard", card);
|
||||||
card = undefined;
|
card = undefined;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import { Communicator } from "../../communication";
|
|
||||||
import tippy, { roundArrow } from "tippy.js";
|
import tippy, { roundArrow } from "tippy.js";
|
||||||
import App from "./Translate.svelte";
|
import App from "./Translate.svelte";
|
||||||
import "./tippy.scss";
|
import "./tippy.scss";
|
||||||
|
import { FrontendMessenger } from "../../background_frontend_commands";
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
//Make sure our script only runs once
|
//Make sure our script only runs once
|
||||||
if (window.hasRun) return;
|
if (window.hasRun) return;
|
||||||
window.hasRun = true;
|
window.hasRun = true;
|
||||||
|
|
||||||
|
let con = new FrontendMessenger();
|
||||||
|
|
||||||
const tippyInstance = setupTippy();
|
const tippyInstance = setupTippy();
|
||||||
|
|
||||||
let timeoutID: number;
|
let timeoutID: number;
|
||||||
|
@ -18,20 +20,19 @@ import "./tippy.scss";
|
||||||
timeoutID = window.setTimeout(tippyInstance.show, 500);
|
timeoutID = window.setTimeout(tippyInstance.show, 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
let con = new Communicator();
|
con.addMessageListener("setEnabled", async (v: boolean) => {
|
||||||
con.setEnabledCallback = (v: boolean) => {
|
|
||||||
document.removeEventListener("selectionchange", onSelectionChange); //Always remove it avoid duplicate event listeners
|
document.removeEventListener("selectionchange", onSelectionChange); //Always remove it avoid duplicate event listeners
|
||||||
if (v) {
|
if (v) {
|
||||||
onSelectionChange(); // Call it since selection may have changed since it was enabled
|
onSelectionChange(); // Call it since selection may have changed since it was enabled
|
||||||
document.addEventListener("selectionchange", onSelectionChange);
|
document.addEventListener("selectionchange", onSelectionChange);
|
||||||
} else tippyInstance.hide();
|
} else tippyInstance.hide();
|
||||||
};
|
});
|
||||||
|
|
||||||
function setupTippy() {
|
function setupTippy() {
|
||||||
const svelteElement = document.createElement("div");
|
const svelteElement = document.createElement("div");
|
||||||
const sveleteApp = new App({
|
const sveleteApp = new App({
|
||||||
target: svelteElement,
|
target: svelteElement,
|
||||||
props: { toTranslate: "" },
|
props: { toTranslate: "", connection: con },
|
||||||
});
|
});
|
||||||
return tippy(document.body, {
|
return tippy(document.body, {
|
||||||
content: svelteElement,
|
content: svelteElement,
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Communicator } from "../../communication";
|
|
||||||
import LanguageSelection from "./LanguageSelection.svelte";
|
import LanguageSelection from "./LanguageSelection.svelte";
|
||||||
|
import { FrontendMessenger } from "../../background_frontend_commands";
|
||||||
|
|
||||||
Communicator.getEnabled().then((v) => (enabled = v));
|
const conn = new FrontendMessenger();
|
||||||
|
conn.runCommand("getEnabled", undefined).then((v) => (enabled = v));
|
||||||
|
|
||||||
const languages = Communicator.getLanguages();
|
const languages = conn.runCommand("getLanguages", undefined);
|
||||||
|
|
||||||
let enabled: boolean;
|
let enabled: boolean;
|
||||||
$: if (enabled !== undefined) Communicator.setEnabled(enabled);
|
$: if (enabled !== undefined) conn.runCommand("setEnabled", enabled);
|
||||||
|
|
||||||
let selected: LanguagePair;
|
let selected: LanguagePair;
|
||||||
Communicator.getCurrentLanguages().then((l) => (selected = l));
|
conn.runCommand("getCurrentLanguages", undefined).then((l) => (selected = l));
|
||||||
$: if (selected) Communicator.setCurrentLanguages(selected);
|
$: if (selected) conn.runCommand("setCurrentLanguages", selected);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div id="container">
|
<div id="container">
|
||||||
|
|
Loading…
Reference in a new issue