diff --git a/blocks/procedures.js b/blocks/procedures.js index f6b25bcd6..7eb785509 100644 --- a/blocks/procedures.js +++ b/blocks/procedures.js @@ -120,8 +120,11 @@ Blockly.Blocks['procedures_defnoreturn'] = { // The params field is deterministic based on the mutation, // no need to fire a change event. Blockly.Events.disable(); - this.setFieldValue(paramString, 'PARAMS'); - Blockly.Events.enable(); + try { + this.setFieldValue(paramString, 'PARAMS'); + } finally { + Blockly.Events.enable(); + } }, /** * Create XML to represent the argument inputs. @@ -589,8 +592,11 @@ Blockly.Blocks['procedures_callnoreturn'] = { // The argument name field is deterministic based on the mutation, // no need to fire a change event. Blockly.Events.disable(); - field.setValue(this.arguments_[i]); - Blockly.Events.enable(); + try { + field.setValue(this.arguments_[i]); + } finally { + Blockly.Events.enable(); + } } else { // Add new input. field = new Blockly.FieldLabel(this.arguments_[i]); diff --git a/core/block.js b/core/block.js index 92b533be8..d4640f275 100644 --- a/core/block.js +++ b/core/block.js @@ -204,39 +204,42 @@ Blockly.Block.prototype.dispose = function(healStack) { } Blockly.Events.disable(); - // This block is now at the top of the workspace. - // Remove this block from the workspace's list of top-most blocks. - if (this.workspace) { - this.workspace.removeTopBlock(this); - // Remove from block database. - delete this.workspace.blockDB_[this.id]; - this.workspace = null; - } - - // Just deleting this block from the DOM would result in a memory leak as - // well as corruption of the connection database. Therefore we must - // methodically step through the blocks and carefully disassemble them. - - // First, dispose of all my children. - for (var i = this.childBlocks_.length - 1; i >= 0; i--) { - this.childBlocks_[i].dispose(false); - } - // Then dispose of myself. - // Dispose of all inputs and their fields. - for (var i = 0, input; input = this.inputList[i]; i++) { - input.dispose(); - } - this.inputList.length = 0; - // Dispose of any remaining connections (next/previous/output). - var connections = this.getConnections_(true); - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.isConnected()) { - connection.disconnect(); + try { + // This block is now at the top of the workspace. + // Remove this block from the workspace's list of top-most blocks. + if (this.workspace) { + this.workspace.removeTopBlock(this); + // Remove from block database. + delete this.workspace.blockDB_[this.id]; + this.workspace = null; } - connections[i].dispose(); + + // Just deleting this block from the DOM would result in a memory leak as + // well as corruption of the connection database. Therefore we must + // methodically step through the blocks and carefully disassemble them. + + // First, dispose of all my children. + for (var i = this.childBlocks_.length - 1; i >= 0; i--) { + this.childBlocks_[i].dispose(false); + } + // Then dispose of myself. + // Dispose of all inputs and their fields. + for (var i = 0, input; input = this.inputList[i]; i++) { + input.dispose(); + } + this.inputList.length = 0; + // Dispose of any remaining connections (next/previous/output). + var connections = this.getConnections_(true); + for (var i = 0; i < connections.length; i++) { + var connection = connections[i]; + if (connection.isConnected()) { + connection.disconnect(); + } + connections[i].dispose(); + } + } finally { + Blockly.Events.enable(); } - Blockly.Events.enable(); }; /** diff --git a/core/block_svg.js b/core/block_svg.js index ee70a93d1..1e3024a50 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -156,8 +156,11 @@ Blockly.BlockSvg.prototype.select = function() { oldId = Blockly.selected.id; // Unselect any previously selected block. Blockly.Events.disable(); - Blockly.selected.unselect(); - Blockly.Events.enable(); + try { + Blockly.selected.unselect(); + } finally { + Blockly.Events.enable(); + } } var event = new Blockly.Events.Ui(null, 'selected', oldId, this.id); event.workspaceId = this.workspace.id; @@ -999,11 +1002,14 @@ Blockly.BlockSvg.prototype.dispose = function(healStack, animate) { this.rendered = false; Blockly.Events.disable(); - var icons = this.getIcons(); - for (var i = 0; i < icons.length; i++) { - icons[i].dispose(); + try { + var icons = this.getIcons(); + for (var i = 0; i < icons.length; i++) { + icons[i].dispose(); + } + } finally { + Blockly.Events.enable(); } - Blockly.Events.enable(); Blockly.BlockSvg.superClass_.dispose.call(this, healStack); goog.dom.removeNode(this.svgGroup_); diff --git a/core/contextmenu.js b/core/contextmenu.js index af92cf6e2..462ad0b2c 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -126,17 +126,20 @@ Blockly.ContextMenu.hide = function() { Blockly.ContextMenu.callbackFactory = function(block, xml) { return function() { Blockly.Events.disable(); - var newBlock = Blockly.Xml.domToBlock(xml, block.workspace); - // Move the new block next to the old block. - var xy = block.getRelativeToSurfaceXY(); - if (block.RTL) { - xy.x -= Blockly.SNAP_RADIUS; - } else { - xy.x += Blockly.SNAP_RADIUS; + try { + var newBlock = Blockly.Xml.domToBlock(xml, block.workspace); + // Move the new block next to the old block. + var xy = block.getRelativeToSurfaceXY(); + if (block.RTL) { + xy.x -= Blockly.SNAP_RADIUS; + } else { + xy.x += Blockly.SNAP_RADIUS; + } + xy.y += Blockly.SNAP_RADIUS * 2; + newBlock.moveBy(xy.x, xy.y); + } finally { + Blockly.Events.enable(); } - xy.y += Blockly.SNAP_RADIUS * 2; - newBlock.moveBy(xy.x, xy.y); - Blockly.Events.enable(); if (Blockly.Events.isEnabled() && !newBlock.isShadow()) { Blockly.Events.fire(new Blockly.Events.Create(newBlock)); } diff --git a/core/flyout.js b/core/flyout.js index e8aa2f872..52eebc7c1 100644 --- a/core/flyout.js +++ b/core/flyout.js @@ -844,8 +844,11 @@ Blockly.Flyout.prototype.createBlockFunc_ = function(originBlock) { return; } Blockly.Events.disable(); - var block = flyout.placeNewBlock_(originBlock); - Blockly.Events.enable(); + try { + var block = flyout.placeNewBlock_(originBlock); + } finally { + Blockly.Events.enable(); + } if (Blockly.Events.isEnabled()) { Blockly.Events.setGroup(true); Blockly.Events.fire(new Blockly.Events.Create(block)); diff --git a/core/workspace_svg.js b/core/workspace_svg.js index d857bdf21..251d5ef10 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -535,51 +535,54 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) { } Blockly.terminateDrag_(); // Dragging while pasting? No. Blockly.Events.disable(); - var block = Blockly.Xml.domToBlock(xmlBlock, this); - // Move the duplicate to original position. - var blockX = parseInt(xmlBlock.getAttribute('x'), 10); - var blockY = parseInt(xmlBlock.getAttribute('y'), 10); - if (!isNaN(blockX) && !isNaN(blockY)) { - if (this.RTL) { - blockX = -blockX; - } - // Offset block until not clobbering another block and not in connection - // distance with neighbouring blocks. - do { - var collide = false; - var allBlocks = this.getAllBlocks(); - for (var i = 0, otherBlock; otherBlock = allBlocks[i]; i++) { - var otherXY = otherBlock.getRelativeToSurfaceXY(); - if (Math.abs(blockX - otherXY.x) <= 1 && - Math.abs(blockY - otherXY.y) <= 1) { - collide = true; - break; - } + try { + var block = Blockly.Xml.domToBlock(xmlBlock, this); + // Move the duplicate to original position. + var blockX = parseInt(xmlBlock.getAttribute('x'), 10); + var blockY = parseInt(xmlBlock.getAttribute('y'), 10); + if (!isNaN(blockX) && !isNaN(blockY)) { + if (this.RTL) { + blockX = -blockX; } - if (!collide) { - // Check for blocks in snap range to any of its connections. - var connections = block.getConnections_(false); - for (var i = 0, connection; connection = connections[i]; i++) { - var neighbour = connection.closest(Blockly.SNAP_RADIUS, - new goog.math.Coordinate(blockX, blockY)); - if (neighbour.connection) { + // Offset block until not clobbering another block and not in connection + // distance with neighbouring blocks. + do { + var collide = false; + var allBlocks = this.getAllBlocks(); + for (var i = 0, otherBlock; otherBlock = allBlocks[i]; i++) { + var otherXY = otherBlock.getRelativeToSurfaceXY(); + if (Math.abs(blockX - otherXY.x) <= 1 && + Math.abs(blockY - otherXY.y) <= 1) { collide = true; break; } } - } - if (collide) { - if (this.RTL) { - blockX -= Blockly.SNAP_RADIUS; - } else { - blockX += Blockly.SNAP_RADIUS; + if (!collide) { + // Check for blocks in snap range to any of its connections. + var connections = block.getConnections_(false); + for (var i = 0, connection; connection = connections[i]; i++) { + var neighbour = connection.closest(Blockly.SNAP_RADIUS, + new goog.math.Coordinate(blockX, blockY)); + if (neighbour.connection) { + collide = true; + break; + } + } } - blockY += Blockly.SNAP_RADIUS * 2; - } - } while (collide); - block.moveBy(blockX, blockY); + if (collide) { + if (this.RTL) { + blockX -= Blockly.SNAP_RADIUS; + } else { + blockX += Blockly.SNAP_RADIUS; + } + blockY += Blockly.SNAP_RADIUS * 2; + } + } while (collide); + block.moveBy(blockX, blockY); + } + } finally { + Blockly.Events.enable(); } - Blockly.Events.enable(); if (Blockly.Events.isEnabled() && !block.isShadow()) { Blockly.Events.fire(new Blockly.Events.Create(block)); } diff --git a/core/xml.js b/core/xml.js index 70fd915a5..7f096956a 100644 --- a/core/xml.js +++ b/core/xml.js @@ -332,32 +332,35 @@ Blockly.Xml.domToBlock = function(xmlBlock, workspace) { } // Create top-level block. Blockly.Events.disable(); - var topBlock = Blockly.Xml.domToBlockHeadless_(xmlBlock, workspace); - if (workspace.rendered) { - // Hide connections to speed up assembly. - topBlock.setConnectionsHidden(true); - // Generate list of all blocks. - var blocks = topBlock.getDescendants(); - // Render each block. - for (var i = blocks.length - 1; i >= 0; i--) { - blocks[i].initSvg(); - } - for (var i = blocks.length - 1; i >= 0; i--) { - blocks[i].render(false); - } - // Populating the connection database may be defered until after the blocks - // have renderend. - setTimeout(function() { - if (topBlock.workspace) { // Check that the block hasn't been deleted. - topBlock.setConnectionsHidden(false); + try { + var topBlock = Blockly.Xml.domToBlockHeadless_(xmlBlock, workspace); + if (workspace.rendered) { + // Hide connections to speed up assembly. + topBlock.setConnectionsHidden(true); + // Generate list of all blocks. + var blocks = topBlock.getDescendants(); + // Render each block. + for (var i = blocks.length - 1; i >= 0; i--) { + blocks[i].initSvg(); } - }, 1); - topBlock.updateDisabled(); - // Allow the scrollbars to resize and move based on the new contents. - // TODO(@picklesrus): #387. Remove when domToBlock avoids resizing. - Blockly.resizeSvgContents(workspace); + for (var i = blocks.length - 1; i >= 0; i--) { + blocks[i].render(false); + } + // Populating the connection database may be defered until after the + // blocks have rendered. + setTimeout(function() { + if (topBlock.workspace) { // Check that the block hasn't been deleted. + topBlock.setConnectionsHidden(false); + } + }, 1); + topBlock.updateDisabled(); + // Allow the scrollbars to resize and move based on the new contents. + // TODO(@picklesrus): #387. Remove when domToBlock avoids resizing. + Blockly.resizeSvgContents(workspace); + } + } finally { + Blockly.Events.enable(); } - Blockly.Events.enable(); if (Blockly.Events.isEnabled()) { Blockly.Events.fire(new Blockly.Events.Create(topBlock)); }