mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-03 21:08:18 +00:00
Clean up JS message dispatcher and fix a bug thrown on empty-data messages
Fixes bug in #394
This commit is contained in:
parent
1cf90bde9a
commit
d4e3684744
5 changed files with 44 additions and 46 deletions
|
@ -220,6 +220,7 @@ img {
|
|||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
|
||||
// State providers
|
||||
import dialog from "@/utilities/dialog";
|
||||
import documents from "@/utilities/documents";
|
||||
import fullscreen from "@/utilities/fullscreen";
|
||||
|
|
|
@ -424,14 +424,14 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
subscribeJsMessage(UpdateLayer, (updateLayer) => {
|
||||
const responsePath = updateLayer.data.path;
|
||||
const responseLayer = updateLayer.data;
|
||||
const targetPath = updateLayer.data.path;
|
||||
const targetLayer = updateLayer.data;
|
||||
|
||||
const layer = this.layerCache.get(responsePath.toString());
|
||||
const layer = this.layerCache.get(targetPath.toString());
|
||||
if (layer) {
|
||||
Object.assign(this.layerCache.get(responsePath.toString()), responseLayer);
|
||||
Object.assign(this.layerCache.get(targetPath.toString()), targetLayer);
|
||||
} else {
|
||||
this.layerCache.set(responsePath.toString(), responseLayer);
|
||||
this.layerCache.set(targetPath.toString(), targetLayer);
|
||||
}
|
||||
this.setBlendModeForSelectedLayers();
|
||||
this.setOpacityForSelectedLayers();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { createDialog, dismissDialog } from "@/utilities/dialog";
|
||||
import { TextButtonWidget } from "@/components/widgets/widgets";
|
||||
import { subscribeJsMessage } from "@/utilities/js-message-dispatcher";
|
||||
import { DisplayError, DisplayPanic } from "./js-messages";
|
||||
import { DisplayError, DisplayPanic } from "@/utilities/js-messages";
|
||||
|
||||
// Coming soon dialog
|
||||
export function comingSoon(issueNumber?: number) {
|
||||
|
@ -139,8 +139,7 @@ function browserVersion(): string {
|
|||
|
||||
function operatingSystem(): string {
|
||||
const osTable: Record<string, string> = {
|
||||
"Windows NT 11": "Windows 11",
|
||||
"Windows NT 10": "Windows 10",
|
||||
"Windows NT 10": "Windows 10 or 11",
|
||||
"Windows NT 6.3": "Windows 8.1",
|
||||
"Windows NT 6.2": "Windows 8",
|
||||
"Windows NT 6.1": "Windows 7",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { toggleFullscreen } from "@/utilities/fullscreen";
|
||||
import { dialogIsVisible, dismissDialog, submitDialog } from "@/utilities/dialog";
|
||||
import { panicProxy } from "@/utilities/panic-proxy";
|
||||
import documents from "./documents";
|
||||
import documents from "@/utilities/documents";
|
||||
|
||||
const wasm = import("@/../wasm/pkg").then(panicProxy);
|
||||
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
import { reactive } from "vue";
|
||||
import { plainToInstance } from "class-transformer";
|
||||
|
||||
import {
|
||||
JsMessage,
|
||||
DisplayConfirmationToCloseAllDocuments,
|
||||
DisplayConfirmationToCloseDocument,
|
||||
DisplayError,
|
||||
DisplayPanic,
|
||||
ExportDocument,
|
||||
newDisplayFolderTreeStructure,
|
||||
newDisplayFolderTreeStructure as DisplayFolderTreeStructure,
|
||||
OpenDocumentBrowse,
|
||||
SaveDocument,
|
||||
SetActiveDocument,
|
||||
|
@ -22,29 +21,16 @@ import {
|
|||
UpdateScrollbars,
|
||||
UpdateWorkingColors,
|
||||
UpdateLayer,
|
||||
JsMessage,
|
||||
} from "./js-messages";
|
||||
} from "@/utilities/js-messages";
|
||||
|
||||
type JsMessageCallback<T extends JsMessage> = (responseData: T) => void;
|
||||
type JsMessageCallbackMap = {
|
||||
[response: string]: JsMessageCallback<any> | undefined;
|
||||
};
|
||||
|
||||
const state = reactive({
|
||||
responseMap: {} as JsMessageCallbackMap,
|
||||
});
|
||||
|
||||
type Constructs<T> = new (...args: any[]) => T;
|
||||
type ConstructsJsMessage = Constructs<JsMessage> & typeof JsMessage;
|
||||
|
||||
const responseMap = {
|
||||
const messageConstructors = {
|
||||
UpdateCanvas,
|
||||
UpdateScrollbars,
|
||||
UpdateRulers,
|
||||
ExportDocument,
|
||||
SaveDocument,
|
||||
OpenDocumentBrowse,
|
||||
DisplayFolderTreeStructure: newDisplayFolderTreeStructure,
|
||||
DisplayFolderTreeStructure,
|
||||
UpdateLayer,
|
||||
SetActiveTool,
|
||||
SetActiveDocument,
|
||||
|
@ -57,39 +43,51 @@ const responseMap = {
|
|||
DisplayConfirmationToCloseDocument,
|
||||
DisplayConfirmationToCloseAllDocuments,
|
||||
} as const;
|
||||
type JsMessageType = keyof typeof messageConstructors;
|
||||
|
||||
export type JsMessageType = keyof typeof responseMap;
|
||||
type JsMessageCallback<T extends JsMessage> = (messageData: T) => void;
|
||||
type JsMessageCallbackMap = {
|
||||
[message: string]: JsMessageCallback<any> | undefined;
|
||||
};
|
||||
|
||||
function isJsMessageConstructor(fn: ConstructsJsMessage | ((data: any) => JsMessage)): fn is ConstructsJsMessage {
|
||||
return (fn as ConstructsJsMessage).jsMessageMarker !== undefined;
|
||||
type Constructs<T> = new (...args: any[]) => T;
|
||||
type ConstructsJsMessage = Constructs<JsMessage> & typeof JsMessage;
|
||||
|
||||
const subscriptions = {} as JsMessageCallbackMap;
|
||||
|
||||
export function subscribeJsMessage<T extends JsMessage>(messageType: Constructs<T>, callback: JsMessageCallback<T>) {
|
||||
subscriptions[messageType.name] = callback;
|
||||
}
|
||||
|
||||
export function handleJsMessage(responseType: JsMessageType, responseData: any) {
|
||||
const messageMaker = responseMap[responseType];
|
||||
let message: JsMessage;
|
||||
|
||||
if (!messageMaker) {
|
||||
export function handleJsMessage(messageType: JsMessageType, messageData: any) {
|
||||
const messageConstructor = messageConstructors[messageType];
|
||||
if (!messageConstructor) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Received a Response of type "${responseType}" but but was not able to parse the data.`);
|
||||
console.error(`Received a frontend message of type "${messageType}" but but was not able to parse the data.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJsMessageConstructor(messageMaker)) {
|
||||
message = plainToInstance(messageMaker, responseData[responseType]);
|
||||
// Messages with non-empty data are provided by wasm-bindgen as an object with one key as the message name, like: { NameOfThisMessage: { ... } }
|
||||
// Messages with empty data are provided by wasm-bindgen as a string with the message name, like: "NameOfThisMessage"
|
||||
const unwrappedMessageData = messageData[messageType] || {};
|
||||
|
||||
const isJsMessageConstructor = (fn: ConstructsJsMessage | ((data: any) => JsMessage)): fn is ConstructsJsMessage => {
|
||||
return (fn as ConstructsJsMessage).jsMessageMarker !== undefined;
|
||||
};
|
||||
let message: JsMessage;
|
||||
if (isJsMessageConstructor(messageConstructor)) {
|
||||
message = plainToInstance(messageConstructor, unwrappedMessageData);
|
||||
} else {
|
||||
message = messageMaker(responseData[responseType]);
|
||||
message = messageConstructor(unwrappedMessageData);
|
||||
}
|
||||
|
||||
// It is ok to use constructor.name even with minification since it is used consistently with registerHandler
|
||||
const callback = state.responseMap[message.constructor.name];
|
||||
const callback = subscriptions[message.constructor.name];
|
||||
|
||||
if (callback && message) {
|
||||
callback(message);
|
||||
} else if (message) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Received a Response of type "${responseType}" but no handler was registered for it from the client.`);
|
||||
console.error(`Received a frontend message of type "${messageType}" but no handler was registered for it from the client.`);
|
||||
}
|
||||
}
|
||||
|
||||
export function subscribeJsMessage<T extends JsMessage>(responseType: Constructs<T>, callback: JsMessageCallback<T>) {
|
||||
state.responseMap[responseType.name] = callback;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue