Refactor document tab management from Panel.vue into utilities/documents.ts

This commit is contained in:
Keavon Chambers 2021-08-04 12:39:18 -07:00
parent 7cc3a44527
commit 4d90d70220
6 changed files with 110 additions and 137 deletions

View File

@ -217,7 +217,7 @@ img {
<script lang="ts"> <script lang="ts">
import { defineComponent } from "vue"; import { defineComponent } from "vue";
import dialog from "@/utilities/dialog"; import dialog from "@/utilities/dialog";
import document from "@/utilities/document"; import documents from "@/utilities/documents";
import fullscreen from "@/utilities/fullscreen"; import fullscreen from "@/utilities/fullscreen";
import MainWindow from "@/components/window/MainWindow.vue"; import MainWindow from "@/components/window/MainWindow.vue";
import LayoutRow from "@/components/layout/LayoutRow.vue"; import LayoutRow from "@/components/layout/LayoutRow.vue";
@ -225,7 +225,7 @@ import LayoutRow from "@/components/layout/LayoutRow.vue";
export default defineComponent({ export default defineComponent({
provide: { provide: {
dialog, dialog,
document, documents,
fullscreen, fullscreen,
}, },
data() { data() {

View File

@ -4,7 +4,7 @@
<MenuBarInput v-if="platform !== ApplicationPlatform.Mac" /> <MenuBarInput v-if="platform !== ApplicationPlatform.Mac" />
</div> </div>
<div class="header-third"> <div class="header-third">
<WindowTitle :title="`${document.title}${document.unsaved ? '*' : ''} - Graphite`" /> <WindowTitle :title="`${documents.title}${documents.unsaved ? '*' : ''} - Graphite`" />
</div> </div>
<div class="header-third"> <div class="header-third">
<WindowButtonsWindows :maximized="maximized" v-if="platform === ApplicationPlatform.Windows || platform === ApplicationPlatform.Linux" /> <WindowButtonsWindows :maximized="maximized" v-if="platform === ApplicationPlatform.Windows || platform === ApplicationPlatform.Linux" />
@ -41,7 +41,7 @@ import MenuBarInput from "@/components/widgets/inputs/MenuBarInput.vue";
import { ApplicationPlatform } from "@/components/window/MainWindow.vue"; import { ApplicationPlatform } from "@/components/window/MainWindow.vue";
export default defineComponent({ export default defineComponent({
inject: ["document"], inject: ["documents"],
props: { props: {
platform: { type: String, required: true }, platform: { type: String, required: true },
maximized: { type: Boolean, required: true }, maximized: { type: Boolean, required: true },

View File

@ -7,11 +7,11 @@
:class="{ active: tabIndex === tabActiveIndex }" :class="{ active: tabIndex === tabActiveIndex }"
v-for="(tabLabel, tabIndex) in tabLabels" v-for="(tabLabel, tabIndex) in tabLabels"
:key="tabIndex" :key="tabIndex"
@click.middle="handleTabClose(tabIndex)" @click.middle="closeDocumentWithConfirmation(tabIndex)"
@click="handleTabClick(tabIndex)" @click="selectDocument(tabIndex)"
> >
<span>{{ tabLabel }}</span> <span>{{ tabLabel }}</span>
<IconButton :action="() => handleTabClose(tabIndex)" :icon="'CloseX'" :size="16" v-if="tabCloseButtons" /> <IconButton :action="() => closeDocumentWithConfirmation(tabIndex)" :icon="'CloseX'" :size="16" v-if="tabCloseButtons" />
</div> </div>
</div> </div>
<PopoverButton :icon="PopoverButtonIcon.VerticalEllipsis"> <PopoverButton :icon="PopoverButtonIcon.VerticalEllipsis">
@ -144,7 +144,7 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, PropType } from "vue"; import { defineComponent, PropType } from "vue";
import { createDialog, dismissDialog } from "@/utilities/dialog"; import { selectDocument, closeDocumentWithConfirmation } from "@/utilities/documents";
import Document from "@/components/panels/Document.vue"; import Document from "@/components/panels/Document.vue";
import Properties from "@/components/panels/Properties.vue"; import Properties from "@/components/panels/Properties.vue";
@ -153,12 +153,8 @@ import Minimap from "@/components/panels/Minimap.vue";
import IconButton from "@/components/widgets/buttons/IconButton.vue"; import IconButton from "@/components/widgets/buttons/IconButton.vue";
import PopoverButton, { PopoverButtonIcon } from "@/components/widgets/buttons/PopoverButton.vue"; import PopoverButton, { PopoverButtonIcon } from "@/components/widgets/buttons/PopoverButton.vue";
import { MenuDirection } from "@/components/widgets/floating-menus/FloatingMenu.vue"; import { MenuDirection } from "@/components/widgets/floating-menus/FloatingMenu.vue";
import { ResponseType, registerResponseHandler, Response, DisplayConfirmationToCloseDocument } from "@/utilities/response-handler";
const wasm = import("@/../wasm/pkg");
export default defineComponent({ export default defineComponent({
inject: ["dialog"],
components: { components: {
Document, Document,
Properties, Properties,
@ -167,78 +163,6 @@ export default defineComponent({
IconButton, IconButton,
PopoverButton, PopoverButton,
}, },
methods: {
handleTabClick(tabIndex: number) {
if (this.panelType === "Document") this.selectDocument(tabIndex);
},
handleTabClose(tabIndex: number) {
if (this.panelType === "Document") this.closeDocumentWithConfirmation(tabIndex);
},
async selectDocument(tabIndex: number) {
const { select_document } = await wasm;
select_document(tabIndex);
},
async closeDocumentWithConfirmation(tabIndex: number) {
this.selectDocument(tabIndex);
const tabLabel = this.tabLabels[tabIndex];
// TODO: Rename to "Save changes before closing?" when we can actually save documents somewhere, not just export SVGs
createDialog("File", "Close without exporting SVG?", tabLabel, [
{
kind: "TextButton",
callback: async () => {
(await wasm).export_document();
dismissDialog();
},
props: { label: "Export", emphasized: true, minWidth: 96 },
},
{
kind: "TextButton",
callback: async () => {
(await wasm).close_document(tabIndex);
dismissDialog();
},
props: { label: "Discard", minWidth: 96 },
},
{
kind: "TextButton",
callback: async () => {
dismissDialog();
},
props: { label: "Cancel", minWidth: 96 },
},
]);
},
async closeAllDocumentsWithConfirmation() {
createDialog("Copy", "Close all documents?", "Unsaved work will be lost!", [
{
kind: "TextButton",
callback: async () => {
(await wasm).close_all_documents();
dismissDialog();
},
props: { label: "Discard All", minWidth: 96 },
},
{
kind: "TextButton",
callback: async () => {
dismissDialog();
},
props: { label: "Cancel", minWidth: 96 },
},
]);
},
},
mounted() {
// TODO: Move these somewhere more appropriate to act upon all panels
registerResponseHandler(ResponseType.DisplayConfirmationToCloseDocument, (responseData: Response) => {
const data = responseData as DisplayConfirmationToCloseDocument;
this.closeDocumentWithConfirmation(data.document_index);
});
registerResponseHandler(ResponseType.DisplayConfirmationToCloseAllDocuments, (_responseData: Response) => {
this.closeAllDocumentsWithConfirmation();
});
},
props: { props: {
tabMinWidths: { type: Boolean, default: false }, tabMinWidths: { type: Boolean, default: false },
tabCloseButtons: { type: Boolean, default: false }, tabCloseButtons: { type: Boolean, default: false },
@ -248,6 +172,8 @@ export default defineComponent({
}, },
data() { data() {
return { return {
selectDocument,
closeDocumentWithConfirmation,
PopoverButtonIcon, PopoverButtonIcon,
MenuDirection, MenuDirection,
}; };

View File

@ -1,7 +1,7 @@
<template> <template>
<LayoutRow class="workspace-grid-subdivision"> <LayoutRow class="workspace-grid-subdivision">
<LayoutCol class="workspace-grid-subdivision" style="flex-grow: 1597"> <LayoutCol class="workspace-grid-subdivision" style="flex-grow: 1597">
<Panel :panelType="'Document'" :tabCloseButtons="true" :tabMinWidths="true" :tabLabels="documents" :tabActiveIndex="activeDocument" /> <Panel :panelType="'Document'" :tabCloseButtons="true" :tabMinWidths="true" :tabLabels="documents.documents" :tabActiveIndex="documents.activeDocumentIndex" />
</LayoutCol> </LayoutCol>
<LayoutCol class="workspace-grid-resize-gutter"></LayoutCol> <LayoutCol class="workspace-grid-resize-gutter"></LayoutCol>
<LayoutCol class="workspace-grid-subdivision" style="flex-grow: 319"> <LayoutCol class="workspace-grid-subdivision" style="flex-grow: 319">
@ -48,47 +48,21 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from "vue"; import { defineComponent } from "vue";
import { setDocumentTitle } from "@/utilities/document";
import Panel from "@/components/workspace/Panel.vue"; import Panel from "@/components/workspace/Panel.vue";
import { ResponseType, registerResponseHandler, Response, SetActiveDocument, UpdateOpenDocumentsList } from "@/utilities/response-handler";
import LayoutRow from "@/components/layout/LayoutRow.vue"; import LayoutRow from "@/components/layout/LayoutRow.vue";
import LayoutCol from "@/components/layout/LayoutCol.vue"; import LayoutCol from "@/components/layout/LayoutCol.vue";
import DialogModal from "@/components/widgets/floating-menus/DialogModal.vue"; import DialogModal from "@/components/widgets/floating-menus/DialogModal.vue";
const wasm = import("@/../wasm/pkg");
export default defineComponent({ export default defineComponent({
inject: ["dialog"], inject: ["documents", "dialog"],
components: { components: {
LayoutRow, LayoutRow,
LayoutCol, LayoutCol,
Panel, Panel,
DialogModal, DialogModal,
}, },
mounted() {
registerResponseHandler(ResponseType.UpdateOpenDocumentsList, (responseData: Response) => {
const documentListData = responseData as UpdateOpenDocumentsList;
if (documentListData) {
this.documents = documentListData.open_documents;
setDocumentTitle(this.documents[this.activeDocument]);
}
});
registerResponseHandler(ResponseType.SetActiveDocument, (responseData: Response) => {
const documentData = responseData as SetActiveDocument;
if (documentData) {
this.activeDocument = documentData.document_index;
setDocumentTitle(this.documents[this.activeDocument]);
}
});
(async () => (await wasm).get_open_documents_list())();
},
data() { data() {
return { return {};
activeDocument: 0,
documents: [] as Array<string>,
};
}, },
}); });
</script> </script>

View File

@ -1,24 +0,0 @@
import { reactive, readonly } from "vue";
const state = reactive({
title: "",
unsaved: false,
});
export function setDocumentTitle(title: string) {
state.title = title;
}
export function setUnsavedState(isUnsaved: boolean) {
state.unsaved = isUnsaved;
}
export function documentTitle(): string {
return state.title;
}
export function documentIsUnsaved(): boolean {
return state.unsaved;
}
export default readonly(state);

View File

@ -0,0 +1,97 @@
import { reactive, readonly } from "vue";
import { createDialog, dismissDialog } from "@/utilities/dialog";
import { ResponseType, registerResponseHandler, Response, SetActiveDocument, UpdateOpenDocumentsList, DisplayConfirmationToCloseDocument } from "@/utilities/response-handler";
const wasm = import("@/../wasm/pkg");
const state = reactive({
title: "",
unsaved: false,
documents: [] as Array<string>,
activeDocumentIndex: 0,
});
export async function selectDocument(tabIndex: number) {
const { select_document } = await wasm;
select_document(tabIndex);
}
export async function closeDocumentWithConfirmation(tabIndex: number) {
selectDocument(tabIndex);
const tabLabel = state.documents[tabIndex];
// TODO: Rename to "Save changes before closing?" when we can actually save documents somewhere, not just export SVGs
createDialog("File", "Close without exporting SVG?", tabLabel, [
{
kind: "TextButton",
callback: async () => {
(await wasm).export_document();
dismissDialog();
},
props: { label: "Export", emphasized: true, minWidth: 96 },
},
{
kind: "TextButton",
callback: async () => {
(await wasm).close_document(tabIndex);
dismissDialog();
},
props: { label: "Discard", minWidth: 96 },
},
{
kind: "TextButton",
callback: async () => {
dismissDialog();
},
props: { label: "Cancel", minWidth: 96 },
},
]);
}
export async function closeAllDocumentsWithConfirmation() {
createDialog("Copy", "Close all documents?", "Unsaved work will be lost!", [
{
kind: "TextButton",
callback: async () => {
(await wasm).close_all_documents();
dismissDialog();
},
props: { label: "Discard All", minWidth: 96 },
},
{
kind: "TextButton",
callback: async () => {
dismissDialog();
},
props: { label: "Cancel", minWidth: 96 },
},
]);
}
export default readonly(state);
registerResponseHandler(ResponseType.UpdateOpenDocumentsList, (responseData: Response) => {
const documentListData = responseData as UpdateOpenDocumentsList;
if (documentListData) {
state.documents = documentListData.open_documents;
state.title = state.documents[state.activeDocumentIndex];
}
});
registerResponseHandler(ResponseType.SetActiveDocument, (responseData: Response) => {
const documentData = responseData as SetActiveDocument;
if (documentData) {
state.activeDocumentIndex = documentData.document_index;
state.title = state.documents[state.activeDocumentIndex];
}
});
registerResponseHandler(ResponseType.DisplayConfirmationToCloseDocument, (responseData: Response) => {
const data = responseData as DisplayConfirmationToCloseDocument;
closeDocumentWithConfirmation(data.document_index);
});
registerResponseHandler(ResponseType.DisplayConfirmationToCloseAllDocuments, (_responseData: Response) => {
closeAllDocumentsWithConfirmation();
});
(async () => (await wasm).get_open_documents_list())();