From df7f534ad6ed287ecc8d13c4e159138b71ed1e88 Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Thu, 17 May 2018 11:05:18 -0700 Subject: [PATCH] Performance improvements for workspace clear and load --- core/block_svg.js | 30 +++++++++++++++++++++--------- core/workspace.js | 44 ++++++++++++++++++++++++++++---------------- core/xml.js | 15 +++++++++++++++ 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/core/block_svg.js b/core/block_svg.js index 313103794..a073aacf0 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -252,28 +252,40 @@ Blockly.BlockSvg.prototype.getIcons = function() { * @param {Blockly.BlockSvg} newParent New parent block. */ Blockly.BlockSvg.prototype.setParent = function(newParent) { - if (newParent == this.parentBlock_) { + var oldParent = this.parentBlock_; + if (newParent == oldParent) { return; } - var svgRoot = this.getSvgRoot(); - if (this.parentBlock_ && svgRoot) { - // Move this block up the DOM. Keep track of x/y translations. - var xy = this.getRelativeToSurfaceXY(); - this.workspace.getCanvas().appendChild(svgRoot); - svgRoot.setAttribute('transform', 'translate(' + xy.x + ',' + xy.y + ')'); - } Blockly.Field.startCache(); Blockly.BlockSvg.superClass_.setParent.call(this, newParent); Blockly.Field.stopCache(); + var svgRoot = this.getSvgRoot(); + + // Bail early if workspace is clearing, or we aren't rendered. + // We won't need to reattach ourselves anywhere. + if (this.workspace.isClearing || !svgRoot) { + return; + } + + var oldXY = this.getRelativeToSurfaceXY(); if (newParent) { - var oldXY = this.getRelativeToSurfaceXY(); newParent.getSvgRoot().appendChild(svgRoot); var newXY = this.getRelativeToSurfaceXY(); // Move the connections to match the child's new position. this.moveConnections_(newXY.x - oldXY.x, newXY.y - oldXY.y); } + // If we are losing a parent, we want to move our DOM element to the + // root of the workspace. + else if (oldParent) { + // Avoid moving a block up the DOM if it's currently selected/dragging, + // so as to avoid taking things off the drag surface. + if (Blockly.selected != this) { + this.workspace.getCanvas().appendChild(svgRoot); + this.translate(oldXY.x, oldXY.y); + } + } }; /** diff --git a/core/workspace.js b/core/workspace.js index 13815f7d2..2bb088c52 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -115,6 +115,13 @@ Blockly.Workspace = function(opt_options) { */ Blockly.Workspace.prototype.rendered = false; +/** + * Returns `true` if the workspace is currently in the process of a bulk clear. + * @type {boolean} + * @package + */ +Blockly.Workspace.prototype.isClearing = false; + /** * Maximum number of undo events in stack. `0` turns off undo, `Infinity` sets it to unlimited. * @type {number} @@ -264,22 +271,27 @@ Blockly.Workspace.prototype.getAllBlocks = function(ordered) { * Dispose of all blocks and comments in workspace. */ Blockly.Workspace.prototype.clear = function() { - var existingGroup = Blockly.Events.getGroup(); - if (!existingGroup) { - Blockly.Events.setGroup(true); - } - while (this.topBlocks_.length) { - this.topBlocks_[0].dispose(); - } - while (this.topComments_.length) { - this.topComments_[this.topComments_.length - 1].dispose(); - } - if (!existingGroup) { - Blockly.Events.setGroup(false); - } - this.variableMap_.clear(); - if (this.potentialVariableMap_) { - this.potentialVariableMap_.clear(); + this.isClearing = true; + try { + var existingGroup = Blockly.Events.getGroup(); + if (!existingGroup) { + Blockly.Events.setGroup(true); + } + while (this.topBlocks_.length) { + this.topBlocks_[0].dispose(); + } + while (this.topComments_.length) { + this.topComments_[this.topComments_.length - 1].dispose(); + } + if (!existingGroup) { + Blockly.Events.setGroup(false); + } + this.variableMap_.clear(); + if (this.potentialVariableMap_) { + this.potentialVariableMap_.clear(); + } + } finally { + this.isClearing = false; } }; diff --git a/core/xml.js b/core/xml.js index 15199c1ac..744274629 100644 --- a/core/xml.js +++ b/core/xml.js @@ -364,6 +364,21 @@ Blockly.Xml.textToDom = function(text) { return dom.firstChild; }; +/** + * Clear the given workspace then decode an XML DOM and + * create blocks on the workspace. + * @param {!Element} xml XML DOM. + * @param {!Blockly.Workspace} workspace The workspace. + * @return {Array.} An array containing new block ids. + */ +Blockly.Xml.clearWorkspaceAndLoadFromXml = function(xml, workspace) { + workspace.setResizesEnabled(false); + workspace.clear(); + var blockIds = Blockly.Xml.domToWorkspace(xml, workspace); + workspace.setResizesEnabled(true); + return blockIds; +}; + /** * Decode an XML DOM and create blocks on the workspace. * @param {!Element} xml XML DOM.