mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-01-06 01:52:50 +00:00
feat: improvements
This commit is contained in:
@@ -70,6 +70,9 @@ actions:
|
||||
title: Primary Keymap
|
||||
icon: counter_1
|
||||
variant: left
|
||||
description: |
|
||||
Acts as a toggle if the same action is not assigned
|
||||
to the target layer
|
||||
549:
|
||||
variantOf: 548
|
||||
<<: *primary_keymap
|
||||
@@ -80,6 +83,9 @@ actions:
|
||||
title: Numeric Layer
|
||||
icon: counter_2
|
||||
variant: left
|
||||
description: |
|
||||
Acts as a toggle if the same action is not assigned
|
||||
to the target layer
|
||||
551:
|
||||
variantOf: 550
|
||||
<<: *secondary_keymap
|
||||
@@ -90,6 +96,9 @@ actions:
|
||||
title: Function Layer
|
||||
icon: counter_3
|
||||
variant: left
|
||||
description: |
|
||||
Acts as a toggle if the same action is not assigned
|
||||
to the target layer
|
||||
553:
|
||||
variationOf: 552
|
||||
<<: *tertiary_keymap
|
||||
|
||||
@@ -422,8 +422,8 @@ actions:
|
||||
title: Keyboard Non-US \ and | (US English)
|
||||
357:
|
||||
id: "COMPOSE"
|
||||
icon: menu
|
||||
title: Keyboard Application
|
||||
description: Officially supported by Win, Unix, and Boot
|
||||
358:
|
||||
id: "POWER"
|
||||
keyCode: "Power"
|
||||
@@ -944,99 +944,99 @@ actions:
|
||||
title: Keyboard Right GUI
|
||||
488:
|
||||
id: "KSC_E8"
|
||||
icon: play_pause
|
||||
keyCode: "MediaPlayPause"
|
||||
title: Media Play Pause
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
489:
|
||||
id: "KSC_E9"
|
||||
icon: stop
|
||||
keyCode: "MediaStop"
|
||||
title: Media Stop CD
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
490:
|
||||
id: "KSC_EA"
|
||||
icon: skip_previous
|
||||
keyCode: "MediaTrackPrevious"
|
||||
title: Media Previous Song
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
491:
|
||||
id: "KSC_EB"
|
||||
icon: skip_next
|
||||
keyCode: "MediaTrackNext"
|
||||
title: Media Next Song
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
492:
|
||||
id: "KSC_EC"
|
||||
icon: eject
|
||||
keyCode: "Eject"
|
||||
title: Media Eject CD
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
description: MacOS only
|
||||
493:
|
||||
id: "KSC_ED"
|
||||
icon: volume_up
|
||||
keyCode: "AudioVolumeUp"
|
||||
title: Media Volume Up
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
494:
|
||||
id: "KSC_EE"
|
||||
icon: volume_down
|
||||
keyCode: "AudioVolumeDown"
|
||||
title: Media Volume Down
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
495:
|
||||
id: "KSC_EF"
|
||||
icon: volume_off
|
||||
keyCode: "AudioVolumeMute"
|
||||
title: Media Mute
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
496:
|
||||
id: "KSC_F0"
|
||||
title: Media www
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
icon: language
|
||||
title: Media Browser
|
||||
497:
|
||||
id: "KSC_F1"
|
||||
keyCode: "BrowserBack"
|
||||
title: Media Back
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
title: Media Browser Back
|
||||
498:
|
||||
id: "KSC_F2"
|
||||
keyCode: "BrowserForward"
|
||||
title: Media Forward
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
title: Media Browser Forward
|
||||
499:
|
||||
id: "KSC_F3"
|
||||
keyCode: "BrowserStop"
|
||||
title: Media Stop
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
title: Media Browser Stop
|
||||
description: Not supported on MacOS
|
||||
500:
|
||||
id: "KSC_F4"
|
||||
icon: search
|
||||
keyCode: "BrowserSearch"
|
||||
title: Media Find
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
title: Media Browser Search
|
||||
501:
|
||||
id: "KSC_F5"
|
||||
title: Media Scroll Up
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
icon: brightness_high
|
||||
title: Media Brightness Up
|
||||
502:
|
||||
id: "KSC_F6"
|
||||
title: Media Scroll Down
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
icon: brightness_low
|
||||
title: Media Brightness Down
|
||||
503:
|
||||
id: "KSC_F7"
|
||||
title: Media Edit
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
504:
|
||||
id: "KSC_F8"
|
||||
icon: bedtime
|
||||
keyCode: "Sleep"
|
||||
title: Media Sleep
|
||||
title: Media System Sleep
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
505:
|
||||
id: "KSC_F9"
|
||||
icon: routine
|
||||
keyCode: "WakeUp"
|
||||
title: Media Coffee
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
title: Media System Wake
|
||||
description: Not supported on Windows
|
||||
506:
|
||||
id: "KSC_FA"
|
||||
keyCode: "BrowserRefresh"
|
||||
title: Media Refresh
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
title: Media Browser Refresh
|
||||
507:
|
||||
id: "KSC_FB"
|
||||
title: Media Calc
|
||||
description: Not required to be supported by any OS. Possibly deprecated.
|
||||
title: Media Calculator
|
||||
description: Not supported on MacOS
|
||||
508:
|
||||
id: "KSC_FC"
|
||||
description: Not required to be supported by any OS.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import type { KeyInfo } from "$lib/serial/keymap-codes";
|
||||
import { action as title } from "$lib/title";
|
||||
import { osLayout } from "$lib/os-layout";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
|
||||
export let action: number | KeyInfo;
|
||||
export let display: "inline-keys" | "keys" = "inline-keys";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { KEYMAP_CODES } from "$lib/serial/keymap-codes";
|
||||
import type { KeyInfo } from "$lib/serial/keymap-codes";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import Action from "$lib/components/Action.svelte";
|
||||
|
||||
export let id: number | KeyInfo;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import FlexSearch from "flexsearch";
|
||||
import { createEventDispatcher, onMount } from "svelte";
|
||||
import ActionListItem from "$lib/components/ActionListItem.svelte";
|
||||
import LL from "../../../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import { action } from "$lib/title";
|
||||
|
||||
export let currentAction: number | undefined = undefined;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
} from "$lib/undo-redo";
|
||||
import { ChangeType, chords } from "$lib/undo-redo";
|
||||
import ActionString from "$lib/components/ActionString.svelte";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import { KEYMAP_IDS } from "$lib/serial/keymap-codes";
|
||||
|
||||
export let changes: Change[] = [
|
||||
|
||||
@@ -20,10 +20,10 @@
|
||||
import "tippy.js/dist/tippy.css";
|
||||
import tippy from "tippy.js";
|
||||
import { theme, userPreferences } from "$lib/preferences.js";
|
||||
import { LL, setLocale } from "../i18n/i18n-svelte";
|
||||
import { loadLocale } from "../i18n/i18n-util.sync";
|
||||
import { detectLocale } from "../i18n/i18n-util";
|
||||
import type { Locales } from "../i18n/i18n-types";
|
||||
import { LL, setLocale } from "$i18n/i18n-svelte";
|
||||
import { loadLocale } from "$i18n/i18n-util.sync";
|
||||
import { detectLocale } from "$i18n/i18n-util";
|
||||
import type { Locales } from "$i18n/i18n-types";
|
||||
import Footer from "./Footer.svelte";
|
||||
import { osLayout, runLayoutDetection } from "$lib/os-layout.js";
|
||||
import PageTransition from "./PageTransition.svelte";
|
||||
13
src/routes/(app)/+layout.ts
Normal file
13
src/routes/(app)/+layout.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { LayoutLoad } from "./$types";
|
||||
import { browser } from "$app/environment";
|
||||
import { charaFileFromUriComponent } from "$lib/share/share-url";
|
||||
|
||||
export const load = (async ({ url, data, fetch }) => {
|
||||
const importFile = browser && new URLSearchParams(url.search).get("import");
|
||||
return {
|
||||
...data,
|
||||
importFile: importFile
|
||||
? await charaFileFromUriComponent(importFile, fetch)
|
||||
: undefined,
|
||||
};
|
||||
}) satisfies LayoutLoad;
|
||||
@@ -2,5 +2,5 @@ import { redirect } from "@sveltejs/kit";
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export const load = (() => {
|
||||
throw redirect(302, "/config/");
|
||||
redirect(302, "/config/");
|
||||
}) satisfies PageLoad;
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { preference } from "$lib/preferences";
|
||||
import LL from "../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import {
|
||||
createChordBackup,
|
||||
createLayoutBackup,
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import LL from "../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
</script>
|
||||
|
||||
<dialog open>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { page } from "$app/stores";
|
||||
import LL from "../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
|
||||
$: paths = [
|
||||
{
|
||||
@@ -3,7 +3,7 @@
|
||||
import { browser } from "$app/environment";
|
||||
import { slide, fade } from "svelte/transition";
|
||||
import { preference } from "$lib/preferences";
|
||||
import LL from "../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import { downloadBackup } from "$lib/backup/backup";
|
||||
|
||||
function reboot() {
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import LL from "../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import {
|
||||
changes,
|
||||
ChangeType,
|
||||
@@ -1,11 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { browser, version } from "$app/environment";
|
||||
import { action } from "$lib/title";
|
||||
import LL, { setLocale } from "../i18n/i18n-svelte";
|
||||
import LL, { setLocale } from "$i18n/i18n-svelte";
|
||||
import { theme } from "$lib/preferences.js";
|
||||
import type { Locales } from "../i18n/i18n-types";
|
||||
import { detectLocale, locales } from "../i18n/i18n-util";
|
||||
import { loadLocaleAsync } from "../i18n/i18n-util.async";
|
||||
import type { Locales } from "$i18n/i18n-types";
|
||||
import { detectLocale, locales } from "$i18n/i18n-util";
|
||||
import { loadLocaleAsync } from "$i18n/i18n-util.async";
|
||||
import { tick } from "svelte";
|
||||
import SyncOverlay from "./SyncOverlay.svelte";
|
||||
import { serialPort } from "$lib/serial/connection";
|
||||
@@ -8,7 +8,7 @@
|
||||
import { browser } from "$app/environment";
|
||||
import { userPreferences } from "$lib/preferences";
|
||||
import { action } from "$lib/title";
|
||||
import LL from "../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import ConfigTabs from "./ConfigTabs.svelte";
|
||||
import EditActions from "./EditActions.svelte";
|
||||
import { onMount } from "svelte";
|
||||
@@ -5,7 +5,7 @@
|
||||
syncStatus,
|
||||
sync,
|
||||
} from "$lib/serial/connection";
|
||||
import LL from "../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import { slide } from "svelte/transition";
|
||||
</script>
|
||||
|
||||
@@ -2,5 +2,5 @@ import { redirect } from "@sveltejs/kit";
|
||||
import type { PageLoad } from "./$types";
|
||||
|
||||
export const load = (() => {
|
||||
throw redirect(302, "/config/layout/");
|
||||
redirect(302, "/config/layout/");
|
||||
}) satisfies PageLoad;
|
||||
@@ -1,5 +1,5 @@
|
||||
<script>
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
</script>
|
||||
|
||||
{$LL.share.URL_COPIED()}
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { KEYMAP_CATEGORIES, KEYMAP_CODES } from "$lib/serial/keymap-codes";
|
||||
import { KEYMAP_CODES } from "$lib/serial/keymap-codes";
|
||||
import FlexSearch from "flexsearch";
|
||||
import LL from "../../../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import { action } from "$lib/title";
|
||||
import { onDestroy, onMount, setContext, tick } from "svelte";
|
||||
import { changes, ChangeType, chords } from "$lib/undo-redo";
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { ChordInfo } from "$lib/undo-redo";
|
||||
import { changes, ChangeType } from "$lib/undo-redo";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import LL from "../../../i18n/i18n-svelte";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import ActionString from "$lib/components/ActionString.svelte";
|
||||
import { selectAction } from "./action-selector";
|
||||
import { serialPort } from "$lib/serial/connection";
|
||||
@@ -7,11 +7,16 @@
|
||||
import { keymap } from "@codemirror/view";
|
||||
import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
||||
import { tags } from "@lezer/highlight";
|
||||
import LL from "../../i18n/i18n-svelte";
|
||||
import type { CompletionContext } from "@codemirror/autocomplete";
|
||||
import LL from "$i18n/i18n-svelte";
|
||||
import type { CompletionContext, Completion } from "@codemirror/autocomplete";
|
||||
import { syntaxTree } from "@codemirror/language";
|
||||
import { serialPort } from "$lib/serial/connection";
|
||||
import type { CharaDevice } from "$lib/serial/device";
|
||||
import examplePlugin from "./example-plugin.js?raw";
|
||||
import {
|
||||
charaMethods,
|
||||
type ChannelCharaEventData,
|
||||
type ChannelResponseEventData,
|
||||
} from "./plugin-types";
|
||||
|
||||
let theme = EditorView.baseTheme({
|
||||
".cm-editor .cm-content": {
|
||||
@@ -40,6 +45,18 @@
|
||||
background: "transparent !important",
|
||||
backdropFilter: "invert(0.3)",
|
||||
},
|
||||
".cm-tooltip": {
|
||||
backgroundColor: "var(--md-sys-color-background) !important",
|
||||
color: "var(--md-sys-color-on-background)",
|
||||
borderColor: "var(--md-sys-color-outline)",
|
||||
},
|
||||
".cm-tooltip-autocomplete ul li[aria-selected]": {
|
||||
backgroundColor: "var(--md-sys-color-primary) !important",
|
||||
color: "var(--md-sys-color-on-primary) !important",
|
||||
},
|
||||
".cm-completionIcon.cm-completionIcon-keyword::after": {
|
||||
content: "'🗝'",
|
||||
},
|
||||
});
|
||||
const highlightStyle = HighlightStyle.define(
|
||||
[
|
||||
@@ -56,11 +73,74 @@
|
||||
all: { fontFamily: '"Noto Sans Mono", monospace', fontSize: "14px" },
|
||||
},
|
||||
);
|
||||
|
||||
const globalsCompletion: Completion[] = [
|
||||
{ label: "Chara", type: "class", boost: 90 },
|
||||
{ label: "Actions", type: "class", boost: 90 },
|
||||
];
|
||||
|
||||
const actionsCompletion: Completion[] = Array.from(
|
||||
KEYMAP_CODES,
|
||||
([id, info]) => {
|
||||
const isValidIdentifier =
|
||||
info.id && /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(info.id);
|
||||
return {
|
||||
label: info.id
|
||||
? isValidIdentifier
|
||||
? info.id
|
||||
: `["${info.id}"]`
|
||||
: info.id!,
|
||||
displayLabel: info.id,
|
||||
detail: [info.title, `(0x${id.toString(16)})`, info.description]
|
||||
.filter((it) => !!it)
|
||||
.join(" "),
|
||||
section: info.category,
|
||||
boost: isValidIdentifier ? Math.min(info.id?.length ?? 0, 10) + 50 : 40,
|
||||
type: "property",
|
||||
};
|
||||
},
|
||||
).filter((it) => it.label !== undefined);
|
||||
|
||||
const completion = javascriptLanguage.data.of({
|
||||
autocomplete: function completeGlobals(context: CompletionContext) {
|
||||
if (context.matchBefore(/Chara\./)) {
|
||||
// TODO
|
||||
let nodeBefore = syntaxTree(context.state).resolveInner(context.pos, -1);
|
||||
if (nodeBefore.name === "VariableName") {
|
||||
return {
|
||||
from: nodeBefore.from,
|
||||
options: globalsCompletion,
|
||||
};
|
||||
} else if (nodeBefore.name === "Script") {
|
||||
return {
|
||||
from: context.pos,
|
||||
options: globalsCompletion,
|
||||
};
|
||||
} else if (
|
||||
(nodeBefore.name === "PropertyName" || nodeBefore.name === ".") &&
|
||||
nodeBefore.parent?.name === "MemberExpression" &&
|
||||
nodeBefore.parent.firstChild
|
||||
) {
|
||||
const variable = nodeBefore.parent.firstChild;
|
||||
const variableName = context.state.sliceDoc(variable.from, variable.to);
|
||||
if (variableName === "Actions") {
|
||||
return {
|
||||
from:
|
||||
nodeBefore.name === "PropertyName"
|
||||
? nodeBefore.from
|
||||
: nodeBefore.to,
|
||||
options: actionsCompletion,
|
||||
};
|
||||
}
|
||||
let parent = nodeBefore.prevSibling;
|
||||
while (parent !== null && parent?.name !== "VariableName") {
|
||||
parent = parent.prevSibling;
|
||||
}
|
||||
if (parent) {
|
||||
}
|
||||
}
|
||||
console.log(nodeBefore);
|
||||
|
||||
console.log(context);
|
||||
return null;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -78,22 +158,6 @@
|
||||
doc: examplePlugin,
|
||||
});
|
||||
});
|
||||
|
||||
const charaMethods = [
|
||||
"reboot",
|
||||
"bootloader",
|
||||
"getRamBytesAvailable",
|
||||
"getSetting",
|
||||
"setSetting",
|
||||
"getLayoutKey",
|
||||
"setLayoutKey",
|
||||
"deleteChord",
|
||||
"setChord",
|
||||
"getChordPhrase",
|
||||
"getChordCount",
|
||||
"getChord",
|
||||
"send",
|
||||
] satisfies Array<keyof CharaDevice>;
|
||||
$: channels = $serialPort
|
||||
? ({
|
||||
getVersion: async (..._args: unknown[]) => $serialPort.version,
|
||||
@@ -122,7 +186,10 @@
|
||||
|
||||
const [channel, params] = event.data;
|
||||
const response = channels[channel as keyof typeof channels](...params);
|
||||
frame.contentWindow!.postMessage({ response: await response }, "*");
|
||||
frame.contentWindow!.postMessage(
|
||||
{ response: await response } satisfies ChannelResponseEventData,
|
||||
"*",
|
||||
);
|
||||
}
|
||||
|
||||
function runPlugin() {
|
||||
@@ -131,7 +198,7 @@
|
||||
actionCodes: KEYMAP_CODES,
|
||||
script: editorView.state.doc.toString(),
|
||||
charaChannels: Object.keys(channels),
|
||||
},
|
||||
} satisfies ChannelCharaEventData,
|
||||
"*",
|
||||
);
|
||||
}
|
||||
30
src/routes/(app)/plugin/plugin-types.ts
Normal file
30
src/routes/(app)/plugin/plugin-types.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { CharaDevice } from "$lib/serial/device";
|
||||
import type { KeyInfo } from "$lib/serial/keymap-codes";
|
||||
|
||||
export const charaMethods = [
|
||||
"reboot",
|
||||
"bootloader",
|
||||
"getRamBytesAvailable",
|
||||
"getSetting",
|
||||
"setSetting",
|
||||
"getLayoutKey",
|
||||
"setLayoutKey",
|
||||
"deleteChord",
|
||||
"setChord",
|
||||
"getChordPhrase",
|
||||
"getChordCount",
|
||||
"getChord",
|
||||
"send",
|
||||
] as const satisfies Array<keyof CharaDevice>;
|
||||
|
||||
export interface ChannelResponseEventData {
|
||||
response: unknown;
|
||||
}
|
||||
|
||||
export interface ChannelCharaEventData {
|
||||
charaChannels: string[];
|
||||
script: string;
|
||||
actionCodes: Map<number, KeyInfo>;
|
||||
}
|
||||
|
||||
export type ChannelEventData = ChannelResponseEventData | ChannelCharaEventData;
|
||||
@@ -1,16 +1,2 @@
|
||||
import type { LayoutLoad } from "./$types";
|
||||
import { browser } from "$app/environment";
|
||||
import { charaFileFromUriComponent } from "$lib/share/share-url";
|
||||
|
||||
export const prerender = true;
|
||||
export const trailingSlash = "always";
|
||||
|
||||
export const load = (async ({ url, data, fetch }) => {
|
||||
const importFile = browser && new URLSearchParams(url.search).get("import");
|
||||
return {
|
||||
...data,
|
||||
importFile: importFile
|
||||
? await charaFileFromUriComponent(importFile, fetch)
|
||||
: undefined,
|
||||
};
|
||||
}) satisfies LayoutLoad;
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
<script>
|
||||
// @ts-nocheck
|
||||
let ongoingRequest;
|
||||
let resolveRequest;
|
||||
let source;
|
||||
async function post(channel, args) {
|
||||
<script lang="ts">
|
||||
import type { ChannelEventData } from "../(app)/plugin/plugin-types";
|
||||
|
||||
let ongoingRequest: Promise<unknown> | undefined = undefined;
|
||||
let resolveRequest: ((data: unknown) => void) | undefined = undefined;
|
||||
let source: MessageEventSource | undefined = undefined;
|
||||
|
||||
async function post(channel: string, args: unknown[]) {
|
||||
while (ongoingRequest) {
|
||||
await ongoingRequest;
|
||||
}
|
||||
ongoingRequest = new Promise((resolve) => {
|
||||
resolveRequest = resolve;
|
||||
source.postMessage([channel, args], "*");
|
||||
source?.postMessage([channel, args], { targetOrigin: "*" });
|
||||
});
|
||||
ongoingRequest.then(() => {
|
||||
ongoingRequest = undefined;
|
||||
@@ -17,13 +19,13 @@
|
||||
return ongoingRequest;
|
||||
}
|
||||
|
||||
window.addEventListener("message", (event) => {
|
||||
function onMessage(event: MessageEvent<ChannelEventData>) {
|
||||
if ("response" in event.data) {
|
||||
resolveRequest(event.data.response);
|
||||
resolveRequest?.(event.data.response);
|
||||
} else {
|
||||
source = event.source;
|
||||
source = event.source ?? undefined;
|
||||
|
||||
var Action = event.data.actionCodes;
|
||||
const Action = event.data.actionCodes;
|
||||
Object.assign(
|
||||
Action,
|
||||
Object.fromEntries(
|
||||
@@ -33,12 +35,17 @@
|
||||
),
|
||||
);
|
||||
|
||||
var Chara = {};
|
||||
for (const fn of event.data.charaChannels) {
|
||||
Chara[fn] = (...args) => post(fn, args);
|
||||
}
|
||||
|
||||
eval(`(async function(){${event.data.script}})()`);
|
||||
new Function("Action", "Chara", event.data.script)(
|
||||
Action,
|
||||
Object.fromEntries(
|
||||
event.data.charaChannels.map((name) => [
|
||||
name,
|
||||
(...args: unknown[]) => post(name, args),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:message={onMessage} />
|
||||
|
||||
Reference in New Issue
Block a user