From bbada0937bf93e1d698f3b57a2023b3e025f1d46 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Tue, 29 Jul 2025 13:55:12 -0700 Subject: [PATCH] fix: fix deserialization of local/cloud variables --- src/index.ts | 1 + src/xml.ts | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 src/xml.ts diff --git a/src/index.ts b/src/index.ts index b57312ec98..f86ffef276 100644 --- a/src/index.ts +++ b/src/index.ts @@ -80,6 +80,7 @@ export { StatusIndicatorLabel, StatusButtonState, } from "./status_indicator_label"; +export * from "./xml"; export function inject(container: Element, options: Blockly.BlocklyOptions) { registerScratchFieldAngle(); diff --git a/src/xml.ts b/src/xml.ts new file mode 100644 index 0000000000..6ab4fb00ba --- /dev/null +++ b/src/xml.ts @@ -0,0 +1,57 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as Blockly from "blockly/core"; +import { ScratchVariableModel } from "./scratch_variable_model"; + +/** + * Clears the workspace and loads the given serialized state. + * + * @param xml XML representation of a Blockly workspace. + * @param workspace The workspace to load the serialized data onto. + */ +export function clearWorkspaceAndLoadFromXml( + xml: Element, + workspace: Blockly.WorkspaceSvg +): string[] { + workspace.setResizesEnabled(false); + Blockly.Events.setGroup(true); + workspace.clear(); + + // Manually load variables to include the cloud and local properties that core + // Blockly is unaware of. + for (const variable of xml.querySelectorAll("variables variable")) { + const id = variable.getAttribute("id"); + if (!id) continue; + const type = variable.getAttribute("type"); + const name = variable.textContent; + const isLocal = variable.getAttribute("islocal") === "true"; + const isCloud = variable.getAttribute("iscloud") === "true"; + + const variableModel = new ScratchVariableModel( + workspace, + name, + type, + id, + isLocal, + isCloud + ); + Blockly.Events.fire( + new (Blockly.Events.get(Blockly.Events.VAR_CREATE))(variableModel) + ); + workspace.getVariableMap().addVariable(variableModel); + } + + // Remove the `variables` element from the XML to prevent Blockly from + // throwing or stomping on the variables we created. + xml.querySelector("variables").remove(); + + // Defer to core for the rest of the deserialization. + const blockIds = Blockly.Xml.domToWorkspace(xml, workspace); + + workspace.setResizesEnabled(true); + return blockIds; +}