From ea89be63d99bb26d68a1e1af37aa79944bbbd430 Mon Sep 17 00:00:00 2001
From: Paul Kaplan <pkaplan@media.mit.edu>
Date: Wed, 26 Jul 2017 15:21:50 -0400
Subject: [PATCH 1/2] Add shadow dom ID uniquifier to 'Duplicate' code path

---
 core/block_svg.js | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/core/block_svg.js b/core/block_svg.js
index d5984299..f0cfd812 100644
--- a/core/block_svg.js
+++ b/core/block_svg.js
@@ -684,6 +684,23 @@ Blockly.BlockSvg.prototype.duplicateAndDragCallback_ = function() {
       // Using domToBlock instead of domToWorkspace means that the new block
       // will be placed at position (0, 0) in main workspace units.
       var newBlock = Blockly.Xml.domToBlock(xml, ws);
+
+      // Scratch-specific: Give shadow dom new IDs to prevent duplicating on paste
+      var blocks = newBlock.getDescendants();
+      for (var i = blocks.length - 1; i >= 0; i--) {
+        var descendant = blocks[i];
+        for (var j = 0; j < descendant.inputList.length; j++) {
+          var connection = descendant.inputList[j].connection;
+          if (connection) {
+            var shadowDom = connection.getShadowDom();
+            if (shadowDom) {
+              shadowDom.setAttribute('id', Blockly.utils.genUid());
+              connection.setShadowDom(shadowDom);
+            }
+          }
+        }
+      }
+
       var svgRootNew = newBlock.getSvgRoot();
       if (!svgRootNew) {
         throw new Error('newBlock is not rendered.');

From 3efae4ce3f419d4b54028a67794626332f56fa69 Mon Sep 17 00:00:00 2001
From: Paul Kaplan <pkaplan@media.mit.edu>
Date: Sat, 5 Aug 2017 13:37:10 -0400
Subject: [PATCH 2/2] Move function into helper

---
 core/block_svg.js     | 15 +--------------
 core/utils.js         | 23 +++++++++++++++++++++++
 core/workspace_svg.js | 16 +++-------------
 3 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/core/block_svg.js b/core/block_svg.js
index f0cfd812..43c8ef8d 100644
--- a/core/block_svg.js
+++ b/core/block_svg.js
@@ -686,20 +686,7 @@ Blockly.BlockSvg.prototype.duplicateAndDragCallback_ = function() {
       var newBlock = Blockly.Xml.domToBlock(xml, ws);
 
       // Scratch-specific: Give shadow dom new IDs to prevent duplicating on paste
-      var blocks = newBlock.getDescendants();
-      for (var i = blocks.length - 1; i >= 0; i--) {
-        var descendant = blocks[i];
-        for (var j = 0; j < descendant.inputList.length; j++) {
-          var connection = descendant.inputList[j].connection;
-          if (connection) {
-            var shadowDom = connection.getShadowDom();
-            if (shadowDom) {
-              shadowDom.setAttribute('id', Blockly.utils.genUid());
-              connection.setShadowDom(shadowDom);
-            }
-          }
-        }
-      }
+      Blockly.utils.changeObscuredShadowIds(newBlock);
 
       var svgRootNew = newBlock.getSvgRoot();
       if (!svgRootNew) {
diff --git a/core/utils.js b/core/utils.js
index 9b088977..4669ea2c 100644
--- a/core/utils.js
+++ b/core/utils.js
@@ -931,3 +931,26 @@ Blockly.utils.setCssTransform = function(node, transform) {
   node.style['transform'] = transform;
   node.style['-webkit-transform'] = transform;
 };
+
+
+/**
+ * Re-assign obscured shadow blocks new IDs to prevent collisions
+ * Scratch specific to help the VM handle deleting obscured shadows.
+ * @param {Blockly.Block} block the root block to be processed.
+ */
+Blockly.utils.changeObscuredShadowIds = function(block) {
+  var blocks = block.getDescendants();
+  for (var i = blocks.length - 1; i >= 0; i--) {
+    var descendant = blocks[i];
+    for (var j = 0; j < descendant.inputList.length; j++) {
+      var connection = descendant.inputList[j].connection;
+      if (connection) {
+        var shadowDom = connection.getShadowDom();
+        if (shadowDom) {
+          shadowDom.setAttribute('id', Blockly.utils.genUid());
+          connection.setShadowDom(shadowDom);
+        }
+      }
+    }
+  }
+};
diff --git a/core/workspace_svg.js b/core/workspace_svg.js
index 69d58eba..985dcf78 100644
--- a/core/workspace_svg.js
+++ b/core/workspace_svg.js
@@ -945,22 +945,12 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) {
   try {
     var block = Blockly.Xml.domToBlock(xmlBlock, this);
 
+    // Scratch-specific: Give shadow dom new IDs to prevent duplicating on paste
+    Blockly.utils.changeObscuredShadowIds(block);
+
     var blocks = block.getDescendants();
     for (var i = blocks.length - 1; i >= 0; i--) {
       var descendant = blocks[i];
-
-      // Scratch-specific: Give shadow dom new IDs to prevent duplicating on paste
-      for (var j = 0; j < descendant.inputList.length; j++) {
-        var connection = descendant.inputList[j].connection;
-        if (connection) {
-          var shadowDom = connection.getShadowDom();
-          if (shadowDom) {
-            shadowDom.setAttribute('id', Blockly.utils.genUid());
-            connection.setShadowDom(shadowDom);
-          }
-        }
-      }
-
       // Rerender to get around problem with IE and Edge not measuring text
       // correctly when it is hidden.
       if (goog.userAgent.IE || goog.userAgent.EDGE) {