Skip to content

Commit 7261527

Browse files
authored
Frontend refactor to move response handler, key input handling, and more into new utilities folder (#260)
Part of #124
1 parent 9d34aa4 commit 7261527

File tree

14 files changed

+80
-66
lines changed

14 files changed

+80
-66
lines changed

client/web/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ module.exports = {
3131
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
3232
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
3333
"no-param-reassign": ["error", { props: false }],
34+
"import/prefer-default-export": "off",
3435
"max-len": ["error", { code: 200, tabWidth: 4 }],
3536
"@typescript-eslint/camelcase": "off",
3637
"@typescript-eslint/no-use-before-define": "off",

client/web/src/components/panels/Document.vue

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@
192192

193193
<script lang="ts">
194194
import { defineComponent } from "vue";
195-
import { ResponseType, registerResponseHandler, Response, UpdateCanvas, SetActiveTool, ExportDocument, SetCanvasZoom, SetRotation } from "../../response-handler";
195+
import { makeModifiersBitfield } from "@/utilities/input";
196+
import { ResponseType, registerResponseHandler, Response, UpdateCanvas, SetActiveTool, ExportDocument, SetCanvasZoom, SetRotation } from "../../utilities/response-handler";
196197
import LayoutRow from "../layout/LayoutRow.vue";
197198
import LayoutCol from "../layout/LayoutCol.vue";
198199
import WorkingColors from "../widgets/WorkingColors.vue";
@@ -217,26 +218,6 @@ const modeMenuEntries: SectionsOfMenuListEntries = [
217218
218219
const wasm = import("../../../wasm/pkg");
219220
220-
function redirectKeyboardEventToBackend(e: KeyboardEvent): boolean {
221-
// Don't redirect user input from text entry into HTML elements
222-
const target = e.target as HTMLElement;
223-
if (target.nodeName === "INPUT" || target.nodeName === "TEXTAREA" || target.isContentEditable) return false;
224-
225-
// Don't redirect a fullscreen request
226-
if (e.key.toLowerCase() === "f11") return false;
227-
228-
// Don't redirect debugging tools
229-
if (e.key.toLowerCase() === "f12") return false;
230-
if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "c") return false;
231-
232-
return true;
233-
}
234-
235-
function makeModifiersBitfield(control: boolean, shift: boolean, alt: boolean): number {
236-
// eslint-disable-next-line no-bitwise
237-
return Number(control) | (Number(shift) << 1) | (Number(alt) << 2);
238-
}
239-
240221
export default defineComponent({
241222
methods: {
242223
async viewportResize() {
@@ -273,28 +254,11 @@ export default defineComponent({
273254
const { set_rotation } = await wasm;
274255
set_rotation(newRotation * (Math.PI / 180));
275256
},
276-
async keyDown(e: KeyboardEvent) {
277-
if (redirectKeyboardEventToBackend(e)) {
278-
e.preventDefault();
279-
const { on_key_down } = await wasm;
280-
const modifiers = makeModifiersBitfield(e.ctrlKey, e.shiftKey, e.altKey);
281-
on_key_down(e.key, modifiers);
282-
}
283-
},
284-
async keyUp(e: KeyboardEvent) {
285-
if (redirectKeyboardEventToBackend(e)) {
286-
e.preventDefault();
287-
const { on_key_up } = await wasm;
288-
const modifiers = makeModifiersBitfield(e.ctrlKey, e.shiftKey, e.altKey);
289-
on_key_up(e.key, modifiers);
290-
}
291-
},
292257
async selectTool(toolName: string) {
293258
const { select_tool } = await wasm;
294259
select_tool(toolName);
295260
},
296261
async viewModeChanged(toolIndex: number) {
297-
console.log(toolIndex);
298262
function todo(_: number) {
299263
return _;
300264
}
@@ -341,10 +305,10 @@ export default defineComponent({
341305
}
342306
});
343307
344-
window.addEventListener("keyup", (e: KeyboardEvent) => this.keyUp(e));
308+
// TODO: Move event listeners to `main.ts`
345309
const canvas = this.$refs.canvas as HTMLDivElement;
346310
canvas.addEventListener("wheel", this.canvasMouseScroll, { passive: false });
347-
window.addEventListener("keydown", (e: KeyboardEvent) => this.keyDown(e));
311+
348312
window.addEventListener("resize", () => this.viewportResize());
349313
window.addEventListener("DOMContentLoaded", () => this.viewportResize());
350314

client/web/src/components/panels/LayerTree.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104

105105
<script lang="ts">
106106
import { defineComponent } from "vue";
107-
import { ResponseType, registerResponseHandler, Response, ExpandFolder, LayerPanelEntry } from "../../response-handler";
107+
import { ResponseType, registerResponseHandler, Response, ExpandFolder, LayerPanelEntry } from "../../utilities/response-handler";
108108
import LayoutRow from "../layout/LayoutRow.vue";
109109
import LayoutCol from "../layout/LayoutCol.vue";
110110
import Separator, { SeparatorType } from "../widgets/Separator.vue";

client/web/src/components/widgets/floating-menus/ColorPicker.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@
118118

119119
<script lang="ts">
120120
import { defineComponent } from "vue";
121-
import { clamp, hsvToRgb, rgbToHsv, isRGB } from "../../../lib/utils";
121+
import { hsvToRgb, rgbToHsv, isRGB } from "@/utilities/color";
122+
import { clamp } from "@/utilities/math";
122123
123124
const enum ColorPickerState {
124125
Idle = "Idle",

client/web/src/components/widgets/inputs/SwatchPairInput.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@
6666
</style>
6767

6868
<script lang="ts">
69-
import { rgbToDecimalRgb } from "@/lib/utils";
69+
import { rgbToDecimalRgb } from "@/utilities/color";
7070
import { defineComponent } from "vue";
7171
import ColorPicker from "../floating-menus/ColorPicker.vue";
7272
import FloatingMenu, { MenuDirection, MenuType } from "../floating-menus/FloatingMenu.vue";
73-
import { ResponseType, registerResponseHandler, Response, UpdateWorkingColors } from "../../../response-handler";
73+
import { ResponseType, registerResponseHandler, Response, UpdateWorkingColors } from "../../../utilities/response-handler";
7474
75-
const wasm = import("../../../../wasm/pkg");
75+
const wasm = import("@/../wasm/pkg");
7676
7777
export default defineComponent({
7878
components: {

client/web/src/components/workspace/Panel.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ import Minimap from "../panels/Minimap.vue";
150150
import IconButton from "../widgets/buttons/IconButton.vue";
151151
import PopoverButton, { PopoverButtonIcon } from "../widgets/buttons/PopoverButton.vue";
152152
import { MenuDirection } from "../widgets/floating-menus/FloatingMenu.vue";
153-
import { ResponseType, registerResponseHandler, Response } from "../../response-handler";
153+
import { ResponseType, registerResponseHandler, Response } from "../../utilities/response-handler";
154154
155155
const wasm = import("../../../wasm/pkg");
156156

client/web/src/components/workspace/Workspace.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646

4747
<script lang="ts">
4848
import { defineComponent } from "vue";
49-
import { ResponseType, registerResponseHandler, Response, SetActiveDocument, NewDocument, CloseDocument } from "../../response-handler";
49+
import { ResponseType, registerResponseHandler, Response, SetActiveDocument, NewDocument, CloseDocument } from "../../utilities/response-handler";
5050
import LayoutRow from "../layout/LayoutRow.vue";
5151
import LayoutCol from "../layout/LayoutCol.vue";
5252
import Panel from "./Panel.vue";

client/web/src/main.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { createApp } from "vue";
2+
import { handleKeyUp, handleKeyDown } from "@/utilities/input";
23
import App from "./App.vue";
3-
import { attachResponseHandlerToPage } from "./response-handler";
44

5+
// Bind global browser events
56
document.addEventListener("contextmenu", (e) => e.preventDefault());
7+
window.addEventListener("keyup", (e: KeyboardEvent) => handleKeyUp(e));
8+
window.addEventListener("keydown", (e: KeyboardEvent) => handleKeyDown(e));
69

7-
attachResponseHandlerToPage();
8-
10+
// Initialize the Vue application
911
createApp(App).mount("#app");

client/web/src/lib/utils.ts renamed to client/web/src/utilities/color.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ export function rgbToDecimalRgb(rgb: RGB) {
6363
return { r, g, b, a: rgb.a };
6464
}
6565

66-
export function clamp(value: number, min = 0, max = 1) {
67-
return Math.max(min, Math.min(value, max));
68-
}
69-
7066
// eslint-disable-next-line @typescript-eslint/no-explicit-any
7167
export function isRGB(data: any): data is RGB {
7268
if (typeof data !== "object" || data === null) return false;

client/web/src/utilities/input.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
const wasm = import("@/../wasm/pkg");
2+
3+
export function shouldRedirectKeyboardEventToBackend(e: KeyboardEvent): boolean {
4+
// Don't redirect user input from text entry into HTML elements
5+
const target = e.target as HTMLElement;
6+
if (target.nodeName === "INPUT" || target.nodeName === "TEXTAREA" || target.isContentEditable) return false;
7+
8+
// Don't redirect a fullscreen request
9+
if (e.key.toLowerCase() === "f11") return false;
10+
11+
// Don't redirect a reload request
12+
if (e.key.toLowerCase() === "f5") return false;
13+
14+
// Don't redirect debugging tools
15+
if (e.key.toLowerCase() === "f12") return false;
16+
if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "c") return false;
17+
if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "i") return false;
18+
if (e.ctrlKey && e.shiftKey && e.key.toLowerCase() === "j") return false;
19+
20+
// Redirect to the backend
21+
return true;
22+
}
23+
24+
export async function handleKeyDown(e: KeyboardEvent) {
25+
if (shouldRedirectKeyboardEventToBackend(e)) {
26+
e.preventDefault();
27+
const { on_key_down } = await wasm;
28+
const modifiers = makeModifiersBitfield(e.ctrlKey, e.shiftKey, e.altKey);
29+
on_key_down(e.key, modifiers);
30+
}
31+
}
32+
33+
export async function handleKeyUp(e: KeyboardEvent) {
34+
if (shouldRedirectKeyboardEventToBackend(e)) {
35+
e.preventDefault();
36+
const { on_key_up } = await wasm;
37+
const modifiers = makeModifiersBitfield(e.ctrlKey, e.shiftKey, e.altKey);
38+
on_key_up(e.key, modifiers);
39+
}
40+
}
41+
42+
export function makeModifiersBitfield(control: boolean, shift: boolean, alt: boolean): number {
43+
// eslint-disable-next-line no-bitwise
44+
return Number(control) | (Number(shift) << 1) | (Number(alt) << 2);
45+
}

client/web/src/utilities/math.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function clamp(value: number, min = 0, max = 1) {
2+
return Math.max(min, Math.min(value, max));
3+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// This file is instantiated by wasm-bindgen in `client\web\wasm\src\lib.rs` and re-exports the `handleResponse` function to
2+
// provide access to the global copy of `response-handler.ts` with its shared state, not an isolated duplicate with empty state
3+
4+
export { handleResponse } from "@/utilities/response-handler";

client/web/src/response-handler.ts renamed to client/web/src/utilities/response-handler.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
import { reactive } from "vue";
2+
13
/* eslint-disable @typescript-eslint/no-explicit-any */
24

35
type ResponseCallback = (responseData: Response) => void;
46
type ResponseMap = {
57
[response: string]: ResponseCallback | undefined;
68
};
7-
declare global {
8-
interface Window {
9-
responseMap: ResponseMap;
10-
}
11-
}
9+
10+
const state = reactive({
11+
responseMap: {} as ResponseMap,
12+
});
1213

1314
export enum ResponseType {
1415
UpdateCanvas = "UpdateCanvas",
@@ -25,17 +26,13 @@ export enum ResponseType {
2526
SetRotation = "SetRotation",
2627
}
2728

28-
export function attachResponseHandlerToPage() {
29-
window.responseMap = {};
30-
}
31-
3229
export function registerResponseHandler(responseType: ResponseType, callback: ResponseCallback) {
33-
window.responseMap[responseType] = callback;
30+
state.responseMap[responseType] = callback;
3431
}
3532

3633
// eslint-disable-next-line @typescript-eslint/no-explicit-any
3734
export function handleResponse(responseType: string, responseData: any) {
38-
const callback = window.responseMap[responseType];
35+
const callback = state.responseMap[responseType];
3936
const data = parseResponse(responseType, responseData);
4037

4138
if (callback && data) {
@@ -97,6 +94,7 @@ export interface Color {
9794
alpha: number;
9895
}
9996
function newColor(input: any): Color {
97+
// TODO: Possibly change this in the Rust side to avoid any pitfalls
10098
return { red: input.red * 255, green: input.green * 255, blue: input.blue * 255, alpha: input.alpha };
10199
}
102100

client/web/wasm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fn send_response(response_type: String, response_data: FrontendMessage) {
3030
let _ = handleResponse(response_type, response_data).map_err(|error| log::error!("javascript threw an error: {:?}", error));
3131
}
3232

33-
#[wasm_bindgen(module = "/../src/response-handler.ts")]
33+
#[wasm_bindgen(module = "/../src/utilities/response-handler-binding.ts")]
3434
extern "C" {
3535
#[wasm_bindgen(catch)]
3636
fn handleResponse(responseType: String, responseData: JsValue) -> Result<(), JsValue>;

0 commit comments

Comments
 (0)