mirror of
https://github.com/google/blockly.git
synced 2026-01-10 18:37:09 +01:00
Re-enable events even when an exception is thrown
This prevents a recoverable exception permanently disabling events. This could be caused by calling domToWorkspace() to load a corrupt program.
This commit is contained in:
@@ -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]);
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
51
core/xml.js
51
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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user