Skip to content

Commit bc0db77

Browse files
committed
DRAFT: Add support for saving full document
Most of the code is similar to the export functionality. The exception is that this document will encompass additional non-svg data. The `SerializeData` request accepts an `action` string that it opaquely passes through. The response handler can use the `action` string to decide if the serialization is for saving or auto-saving.
1 parent d3958f8 commit bc0db77

File tree

7 files changed

+46
-2
lines changed

7 files changed

+46
-2
lines changed

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@
214214
import { defineComponent } from "vue";
215215
216216
import { makeModifiersBitfield } from "@/utilities/input";
217-
import { ResponseType, registerResponseHandler, Response, UpdateCanvas, SetActiveTool, ExportDocument, SetCanvasZoom, SetCanvasRotation } from "@/utilities/response-handler";
217+
import { ResponseType, registerResponseHandler, Response, UpdateCanvas, SetActiveTool, ExportDocument, SetCanvasZoom, SetCanvasRotation, SerializeDocument } from "@/utilities/response-handler";
218218
import { SeparatorDirection, SeparatorType } from "@/components/widgets/widgets";
219219
import comingSoon from "@/utilities/coming-soon";
220220
@@ -329,6 +329,12 @@ export default defineComponent({
329329
const updateData = responseData as ExportDocument;
330330
if (updateData) this.download("canvas.svg", updateData.document);
331331
});
332+
registerResponseHandler(ResponseType.SerializeDocument, (responseData: Response) => {
333+
const data = responseData as SerializeDocument;
334+
if (data && data.action === "save") {
335+
this.download("canvas.gsvg", data.document);
336+
}
337+
});
332338
registerResponseHandler(ResponseType.SetActiveTool, (responseData: Response) => {
333339
const toolData = responseData as SetActiveTool;
334340
if (toolData) this.activeTool = toolData.tool_name;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const menuEntries: MenuListEntries = [
9090
{ label: "Close All", shortcut: ["Ctrl", "Alt", "W"], action: async () => (await wasm).close_all_documents_with_confirmation() },
9191
],
9292
[
93-
{ label: "Save", shortcut: ["Ctrl", "S"] },
93+
{ label: "Save", shortcut: ["Ctrl", "S"], action: async () => (await wasm).serialize_document("save") },
9494
{ label: "Save As…", shortcut: ["Ctrl", "", "S"] },
9595
{ label: "Save All", shortcut: ["Ctrl", "Alt", "S"] },
9696
{ label: "Auto-Save", checkbox: true, checked: true },

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export enum ResponseType {
2424
SetCanvasRotation = "SetCanvasRotation",
2525
DisplayConfirmationToCloseDocument = "DisplayConfirmationToCloseDocument",
2626
DisplayConfirmationToCloseAllDocuments = "DisplayConfirmationToCloseAllDocuments",
27+
SerializeDocument = "SerializeDocument",
2728
}
2829

2930
export function registerResponseHandler(responseType: ResponseType, callback: ResponseCallback) {
@@ -73,6 +74,8 @@ function parseResponse(responseType: string, data: any): Response {
7374
return newDisplayConfirmationToCloseDocument(data.DisplayConfirmationToCloseDocument);
7475
case "DisplayConfirmationToCloseAllDocuments":
7576
return newDisplayConfirmationToCloseAllDocuments(data.DisplayConfirmationToCloseAllDocuments);
77+
case "SerializeDocument":
78+
return newSerializeDocument(data.SerializeDocument);
7679
default:
7780
throw new Error(`Unrecognized origin/responseType pair: ${origin}, '${responseType}'`);
7881
}
@@ -158,6 +161,17 @@ function newExportDocument(input: any): UpdateCanvas {
158161
};
159162
}
160163

164+
export interface SerializeDocument {
165+
document: string;
166+
action: string;
167+
}
168+
function newSerializeDocument(input: any): SerializeDocument {
169+
return {
170+
document: input.document,
171+
action: input.action,
172+
};
173+
}
174+
161175
export type DocumentChanged = {};
162176
function newDocumentChanged(_: any): DocumentChanged {
163177
return {};

client/web/wasm/src/document.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,14 @@ pub fn export_document() -> Result<(), JsValue> {
256256
EDITOR_STATE.with(|editor| editor.borrow_mut().handle_message(DocumentMessage::ExportDocument)).map_err(convert_error)
257257
}
258258

259+
/// Serialize document
260+
#[wasm_bindgen]
261+
pub fn serialize_document(action: String) -> Result<(), JsValue> {
262+
EDITOR_STATE
263+
.with(|editor| editor.borrow_mut().handle_message(DocumentMessage::SerializeDocument(action)))
264+
.map_err(convert_error)
265+
}
266+
259267
/// Sets the zoom to the value
260268
#[wasm_bindgen]
261269
pub fn set_zoom(new_zoom: f64) -> Result<(), JsValue> {

core/document/src/document.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ impl Document {
6363
svg
6464
}
6565

66+
// Returns string that represents the full document (not just svg)
67+
pub fn serialize_document(&mut self) -> String {
68+
// Manually constructing JSON. Should switch to serde_json
69+
format!("{{\"version\": 0, \"svg\": \"{}\"}}", self.render_root())
70+
}
71+
6672
/// Checks whether each layer under `path` intersects with the provided `quad` and adds all intersection layers as paths to `intersections`.
6773
pub fn intersects_quad(&self, quad: [DVec2; 4], path: &mut Vec<LayerId>, intersections: &mut Vec<Vec<LayerId>>) {
6874
self.document_folder(path).unwrap().intersects_quad(quad, path, intersections);

core/editor/src/document/document_message_handler.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub enum DocumentMessage {
6464
MoveSelectedLayersTo { path: Vec<LayerId>, insert_index: isize },
6565
ReorderSelectedLayers(i32), // relative_position,
6666
SetLayerTranslation(Vec<LayerId>, Option<f64>, Option<f64>),
67+
SerializeDocument(String),
6768
}
6869

6970
#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
@@ -380,6 +381,13 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
380381
responses.push_back(DocumentOperation::SetLayerOpacity { path, opacity }.into());
381382
}
382383
}
384+
SerializeDocument(action) => responses.push_back(
385+
FrontendMessage::SerializeDocument {
386+
document: self.active_document_mut().document.serialize_document(),
387+
action,
388+
}
389+
.into(),
390+
),
383391
ToggleLayerVisibility(path) => {
384392
responses.push_back(DocumentOperation::ToggleVisibility { path }.into());
385393
}
@@ -826,6 +834,7 @@ impl MessageHandler<DocumentMessage, &InputPreprocessor> for DocumentMessageHand
826834
SetCanvasRotation,
827835
WheelCanvasZoom,
828836
WheelCanvasTranslate,
837+
SerializeDocument
829838
);
830839

831840
if self.active_document().layer_data.values().any(|data| data.selected) {

core/editor/src/frontend/frontend_message_handler.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ pub enum FrontendMessage {
2222
UpdateWorkingColors { primary: Color, secondary: Color },
2323
SetCanvasZoom { new_zoom: f64 },
2424
SetCanvasRotation { new_radians: f64 },
25+
SerializeDocument { document: String, action: String },
2526
}
2627

2728
pub struct FrontendMessageHandler {

0 commit comments

Comments
 (0)