From 9264f30198cd549045e94aa783b215a3841ab14d Mon Sep 17 00:00:00 2001
From: Paul Kaplan <pkaplan@media.mit.edu>
Date: Wed, 30 Jan 2019 09:39:18 -0500
Subject: [PATCH] Make the toolbox xml reflect the costume, sound and backdrop
 name

This invalidates the toolbox XML when switching back to the code tab after e.g. renaming a costume, making the code tab
---
 src/containers/blocks.jsx   | 38 +++++++++++++++++++++++++----------
 src/lib/make-toolbox-xml.js | 40 ++++++++++++++++++++++++++-----------
 2 files changed, 56 insertions(+), 22 deletions(-)

diff --git a/src/containers/blocks.jsx b/src/containers/blocks.jsx
index e58337f53..98a01db1b 100644
--- a/src/containers/blocks.jsx
+++ b/src/containers/blocks.jsx
@@ -50,6 +50,7 @@ class Blocks extends React.Component {
         bindAll(this, [
             'attachVM',
             'detachVM',
+            'getToolboxXML',
             'handleCategorySelected',
             'handleConnectionModalStart',
             'handleDrop',
@@ -307,12 +308,32 @@ class Blocks extends React.Component {
     onVisualReport (data) {
         this.workspace.reportValue(data.id, data.value);
     }
+    getToolboxXML () {
+        // Use try/catch because this requires digging pretty deep into the VM
+        // Code inside intentionally ignores several error situations (no stage, etc.)
+        // Because they would get caught by this try/catch
+        try {
+            let {editingTarget: target, runtime} = this.props.vm;
+            const stage = runtime.getTargetForStage();
+            if (!target) target = stage; // If no editingTarget, use the stage
+
+            const stageCostumes = stage.getCostumes();
+            const targetCostumes = target.getCostumes();
+            const targetSounds = target.getSounds();
+            const dynamicBlocksXML = this.props.vm.runtime.getBlocksXML();
+            return makeToolboxXML(target.isStage, target.id, dynamicBlocksXML,
+                targetCostumes[0].name,
+                stageCostumes[0].name,
+                targetSounds.length > 0 ? targetSounds[0].name : ''
+            );
+        } catch {
+            return null;
+        }
+    }
     onWorkspaceUpdate (data) {
         // When we change sprites, update the toolbox to have the new sprite's blocks
-        if (this.props.vm.editingTarget) {
-            const target = this.props.vm.editingTarget;
-            const dynamicBlocksXML = this.props.vm.runtime.getBlocksXML();
-            const toolboxXML = makeToolboxXML(target.isStage, target.id, dynamicBlocksXML);
+        const toolboxXML = this.getToolboxXML();
+        if (toolboxXML) {
             this.props.updateToolboxState(toolboxXML);
         }
 
@@ -360,12 +381,9 @@ class Blocks extends React.Component {
         // this actually defines blocks and MUST run regardless of the UI state
         this.ScratchBlocks.defineBlocksWithJsonArray(blocksInfo.map(blockInfo => blockInfo.json).filter(x => x));
 
-        // update the toolbox view: this can be skipped if we're not looking at a target, etc.
-        const runtime = this.props.vm.runtime;
-        const target = runtime.getEditingTarget() || runtime.getTargetForStage();
-        if (target) {
-            const dynamicBlocksXML = runtime.getBlocksXML();
-            const toolboxXML = makeToolboxXML(target.isStage, target.id, dynamicBlocksXML);
+        // Update the toolbox with new blocks
+        const toolboxXML = this.getToolboxXML();
+        if (toolboxXML) {
             this.props.updateToolboxState(toolboxXML);
         }
     }
diff --git a/src/lib/make-toolbox-xml.js b/src/lib/make-toolbox-xml.js
index 936859666..4217b6e6b 100644
--- a/src/lib/make-toolbox-xml.js
+++ b/src/lib/make-toolbox-xml.js
@@ -138,7 +138,7 @@ const motion = function (isStage, targetId) {
     `;
 };
 
-const looks = function (isStage, targetId) {
+const looks = function (isStage, targetId, costumeName, backdropName) {
     const hello = ScratchBlocks.ScratchMsgs.translate('LOOKS_HELLO', 'Hello!');
     const hmm = ScratchBlocks.ScratchMsgs.translate('LOOKS_HMM', 'Hmm...');
     return `
@@ -187,25 +187,33 @@ const looks = function (isStage, targetId) {
         ${isStage ? `
             <block type="looks_switchbackdropto">
                 <value name="BACKDROP">
-                    <shadow type="looks_backdrops"/>
+                    <shadow type="looks_backdrops">
+                        <field name="BACKDROP">${backdropName}</field>
+                    </shadow>
                 </value>
             </block>
             <block type="looks_switchbackdroptoandwait">
                 <value name="BACKDROP">
-                    <shadow type="looks_backdrops"/>
+                    <shadow type="looks_backdrops">
+                        <field name="BACKDROP">${backdropName}</field>
+                    </shadow>
                 </value>
             </block>
             <block type="looks_nextbackdrop"/>
         ` : `
             <block id="${targetId}_switchcostumeto" type="looks_switchcostumeto">
                 <value name="COSTUME">
-                    <shadow type="looks_costume"/>
+                    <shadow type="looks_costume">
+                        <field name="COSTUME">${costumeName}</field>
+                    </shadow>
                 </value>
             </block>
             <block type="looks_nextcostume"/>
             <block type="looks_switchbackdropto">
                 <value name="BACKDROP">
-                    <shadow type="looks_backdrops"/>
+                    <shadow type="looks_backdrops">
+                        <field name="BACKDROP">${backdropName}</field>
+                    </shadow>
                 </value>
             </block>
             <block type="looks_nextbackdrop"/>
@@ -267,17 +275,21 @@ const looks = function (isStage, targetId) {
     `;
 };
 
-const sound = function (isStage, targetId) {
+const sound = function (isStage, targetId, soundName) {
     return `
     <category name="%{BKY_CATEGORY_SOUND}" id="sound" colour="#D65CD6" secondaryColour="#BD42BD">
         <block id="${targetId}_sound_playuntildone" type="sound_playuntildone">
             <value name="SOUND_MENU">
-                <shadow type="sound_sounds_menu"/>
+                <shadow type="sound_sounds_menu">
+                    <field name="SOUND_MENU">${soundName}</field>
+                </shadow>
             </value>
         </block>
         <block id="${targetId}_sound_play" type="sound_play">
             <value name="SOUND_MENU">
-                <shadow type="sound_sounds_menu"/>
+                <shadow type="sound_sounds_menu">
+                    <field name="SOUND_MENU">${soundName}</field>
+                </shadow>
             </value>
         </block>
         <block type="sound_stopallsounds"/>
@@ -692,17 +704,21 @@ const xmlClose = '</xml>';
 /**
  * @param {!boolean} isStage - Whether the toolbox is for a stage-type target.
  * @param {?string} targetId - The current editing target
- * @param {string?} categoriesXML - null for default toolbox, or an XML string with <category> elements.
+ * @param {?string} categoriesXML - null for default toolbox, or an XML string with <category> elements.
+ * @param {?string} costumeName - The name of the default selected costume dropdown.
+ * @param {?string} backdropName - The name of the default selected backdrop dropdown.
+ * @param {?string} soundName -  The name of the default selected sound dropdown.
  * @returns {string} - a ScratchBlocks-style XML document for the contents of the toolbox.
  */
-const makeToolboxXML = function (isStage, targetId, categoriesXML) {
+const makeToolboxXML = function (isStage, targetId, categoriesXML,
+    costumeName = '', backdropName = '', soundName = '') {
     const gap = [categorySeparator];
 
     const everything = [
         xmlOpen,
         motion(isStage, targetId), gap,
-        looks(isStage, targetId), gap,
-        sound(isStage, targetId), gap,
+        looks(isStage, targetId, costumeName, backdropName), gap,
+        sound(isStage, targetId, soundName), gap,
         events(isStage, targetId), gap,
         control(isStage, targetId), gap,
         sensing(isStage, targetId), gap,
-- 
GitLab