diff --git a/frontend/src/components/window/title-bar/TitleBar.vue b/frontend/src/components/window/title-bar/TitleBar.vue
index 40bc480d..28f74f61 100644
--- a/frontend/src/components/window/title-bar/TitleBar.vue
+++ b/frontend/src/components/window/title-bar/TitleBar.vue
@@ -4,7 +4,7 @@
diff --git a/frontend/src/components/workspace/Workspace.vue b/frontend/src/components/workspace/Workspace.vue
index c3a2c65d..3d7ac0e8 100644
--- a/frontend/src/components/workspace/Workspace.vue
+++ b/frontend/src/components/workspace/Workspace.vue
@@ -1,7 +1,13 @@
-
+
diff --git a/frontend/src/main.ts b/frontend/src/main.ts
index 17a7eb54..9256cc7f 100644
--- a/frontend/src/main.ts
+++ b/frontend/src/main.ts
@@ -1,7 +1,7 @@
import { createApp } from "vue";
import { fullscreenModeChanged } from "@/utilities/fullscreen";
-import { onKeyUp, onKeyDown, onMouseMove, onMouseDown, onMouseUp, onMouseScroll, onWindowResize } from "@/utilities/input";
+import { onKeyUp, onKeyDown, onMouseMove, onMouseDown, onMouseUp, onMouseScroll, onWindowResize, onBeforeUnload } from "@/utilities/input";
import "@/utilities/errors";
import App from "@/App.vue";
import { panicProxy } from "@/utilities/panic-proxy";
@@ -21,6 +21,8 @@ const wasm = import("@/../wasm/pkg").then(panicProxy);
window.addEventListener("resize", onWindowResize);
onWindowResize();
+ window.addEventListener("beforeunload", onBeforeUnload);
+
document.addEventListener("contextmenu", (e) => e.preventDefault());
document.addEventListener("fullscreenchange", () => fullscreenModeChanged());
diff --git a/frontend/src/utilities/documents.ts b/frontend/src/utilities/documents.ts
index 1cc5a3ee..7750fa36 100644
--- a/frontend/src/utilities/documents.ts
+++ b/frontend/src/utilities/documents.ts
@@ -16,12 +16,17 @@ import { panicProxy } from "@/utilities/panic-proxy";
const wasm = import("@/../wasm/pkg").then(panicProxy);
+class DocumentState {
+ readonly displayName: string;
+
+ constructor(readonly name: string, readonly isSaved: boolean) {
+ this.displayName = `${name}${isSaved ? "" : "*"}`;
+ }
+}
+
const state = reactive({
- documents: [] as string[],
+ documents: [] as DocumentState[],
activeDocumentIndex: 0,
- get activeDocument() {
- return this.documents[this.activeDocumentIndex];
- },
});
export async function selectDocument(tabIndex: number) {
@@ -29,9 +34,16 @@ export async function selectDocument(tabIndex: number) {
}
export async function closeDocumentWithConfirmation(tabIndex: number) {
- selectDocument(tabIndex);
+ const targetDocument = state.documents[tabIndex];
+ if (targetDocument.isSaved) {
+ (await wasm).close_document(tabIndex);
+ return;
+ }
- const tabLabel = state.documents[tabIndex];
+ // Show the document is being prompted to close
+ await selectDocument(tabIndex);
+
+ const tabLabel = targetDocument.displayName;
createDialog("File", "Save changes before closing?", tabLabel, [
{
@@ -84,7 +96,7 @@ export default readonly(state);
registerResponseHandler(ResponseType.UpdateOpenDocumentsList, (responseData: Response) => {
const documentListData = responseData as UpdateOpenDocumentsList;
- state.documents = documentListData.open_documents.map(({ name, isSaved }) => `${name}${isSaved ? "" : "*"}`);
+ state.documents = documentListData.open_documents.map(({ name, isSaved }) => new DocumentState(name, isSaved));
});
registerResponseHandler(ResponseType.SetActiveDocument, (responseData: Response) => {
diff --git a/frontend/src/utilities/input.ts b/frontend/src/utilities/input.ts
index 61135913..ed31656f 100644
--- a/frontend/src/utilities/input.ts
+++ b/frontend/src/utilities/input.ts
@@ -1,6 +1,7 @@
import { toggleFullscreen } from "@/utilities/fullscreen";
import { dialogIsVisible, dismissDialog, submitDialog } from "@/utilities/dialog";
import { panicProxy } from "@/utilities/panic-proxy";
+import documents from "./documents";
const wasm = import("@/../wasm/pkg").then(panicProxy);
@@ -125,6 +126,14 @@ export async function onWindowResize() {
if (boundsOfViewports.length > 0) (await wasm).bounds_of_viewports(data);
}
+export function onBeforeUnload(event: BeforeUnloadEvent) {
+ const allDocumentsSaved = documents.documents.reduce((acc, doc) => doc.isSaved && acc, true);
+ if (!allDocumentsSaved) {
+ event.returnValue = "Unsaved work will be lost if the web browser tab is closed. Close anyway?";
+ event.preventDefault();
+ }
+}
+
export function makeModifiersBitfield(e: MouseEvent | KeyboardEvent): number {
return Number(e.ctrlKey) | (Number(e.shiftKey) << 1) | (Number(e.altKey) << 2);
}