diff --git a/core/events/block_events.js b/core/events/block_events.js
deleted file mode 100644
index 8be1dae302e..00000000000
--- a/core/events/block_events.js
+++ /dev/null
@@ -1,573 +0,0 @@
-/**
- * @license
- * Copyright 2018 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-/**
- * @fileoverview Classes for all types of block events.
- * @author fenichel@google.com (Rachel Fenichel)
- */
-'use strict';
-
-goog.provide('Blockly.Events.BlockBase');
-goog.provide('Blockly.Events.BlockChange');
-goog.provide('Blockly.Events.BlockCreate');
-goog.provide('Blockly.Events.BlockDelete');
-goog.provide('Blockly.Events.BlockMove');
-goog.provide('Blockly.Events.Change'); // Deprecated.
-goog.provide('Blockly.Events.Create'); // Deprecated.
-goog.provide('Blockly.Events.Delete'); // Deprecated.
-goog.provide('Blockly.Events.Move'); // Deprecated.
-
-goog.require('Blockly.connectionTypes');
-goog.require('Blockly.Events');
-goog.require('Blockly.Events.Abstract');
-goog.require('Blockly.registry');
-goog.require('Blockly.utils.Coordinate');
-goog.require('Blockly.utils.object');
-goog.require('Blockly.utils.xml');
-goog.require('Blockly.Xml');
-
-goog.requireType('Blockly.Block');
-
-
-/**
- * Abstract class for a block event.
- * @param {!Blockly.Block=} opt_block The block this event corresponds to.
- * Undefined for a blank event.
- * @extends {Blockly.Events.Abstract}
- * @constructor
- */
-Blockly.Events.BlockBase = function(opt_block) {
- Blockly.Events.BlockBase.superClass_.constructor.call(this);
- this.isBlank = typeof opt_block == 'undefined';
-
- /**
- * The block ID for the block this event pertains to
- * @type {string}
- */
- this.blockId = this.isBlank ? '' : opt_block.id;
-
- /**
- * The workspace identifier for this event.
- * @type {string}
- */
- this.workspaceId = this.isBlank ? '' : opt_block.workspace.id;
-};
-Blockly.utils.object.inherits(Blockly.Events.BlockBase,
- Blockly.Events.Abstract);
-
-/**
- * Encode the event as JSON.
- * @return {!Object} JSON representation.
- */
-Blockly.Events.BlockBase.prototype.toJson = function() {
- var json = Blockly.Events.BlockBase.superClass_.toJson.call(this);
- json['blockId'] = this.blockId;
- return json;
-};
-
-/**
- * Decode the JSON event.
- * @param {!Object} json JSON representation.
- */
-Blockly.Events.BlockBase.prototype.fromJson = function(json) {
- Blockly.Events.BlockBase.superClass_.fromJson.call(this, json);
- this.blockId = json['blockId'];
-};
-
-/**
- * Class for a block change event.
- * @param {!Blockly.Block=} opt_block The changed block. Undefined for a blank
- * event.
- * @param {string=} opt_element One of 'field', 'comment', 'disabled', etc.
- * @param {?string=} opt_name Name of input or field affected, or null.
- * @param {*=} opt_oldValue Previous value of element.
- * @param {*=} opt_newValue New value of element.
- * @extends {Blockly.Events.BlockBase}
- * @constructor
- */
-Blockly.Events.BlockChange = function(opt_block, opt_element, opt_name, opt_oldValue,
- opt_newValue) {
- Blockly.Events.Change.superClass_.constructor.call(this, opt_block);
- if (!opt_block) {
- return; // Blank event to be populated by fromJson.
- }
- this.element = typeof opt_element == 'undefined' ? '' : opt_element;
- this.name = typeof opt_name == 'undefined' ? '' : opt_name;
- this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue;
- this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue;
-};
-Blockly.utils.object.inherits(Blockly.Events.BlockChange, Blockly.Events.BlockBase);
-
-/**
- * Class for a block change event.
- * @param {!Blockly.Block=} opt_block The changed block. Undefined for a blank
- * event.
- * @param {string=} opt_element One of 'field', 'comment', 'disabled', etc.
- * @param {?string=} opt_name Name of input or field affected, or null.
- * @param {*=} opt_oldValue Previous value of element.
- * @param {*=} opt_newValue New value of element.
- * @extends {Blockly.Events.BlockBase}
- * @constructor
- */
-Blockly.Events.Change = Blockly.Events.BlockChange;
-
-/**
- * Type of this event.
- * @type {string}
- */
-Blockly.Events.BlockChange.prototype.type = Blockly.Events.CHANGE;
-
-/**
- * Encode the event as JSON.
- * @return {!Object} JSON representation.
- */
-Blockly.Events.BlockChange.prototype.toJson = function() {
- var json = Blockly.Events.BlockChange.superClass_.toJson.call(this);
- json['element'] = this.element;
- if (this.name) {
- json['name'] = this.name;
- }
- json['oldValue'] = this.oldValue;
- json['newValue'] = this.newValue;
- return json;
-};
-
-/**
- * Decode the JSON event.
- * @param {!Object} json JSON representation.
- */
-Blockly.Events.BlockChange.prototype.fromJson = function(json) {
- Blockly.Events.BlockChange.superClass_.fromJson.call(this, json);
- this.element = json['element'];
- this.name = json['name'];
- this.oldValue = json['oldValue'];
- this.newValue = json['newValue'];
-};
-
-/**
- * Does this event record any change of state?
- * @return {boolean} False if something changed.
- */
-Blockly.Events.BlockChange.prototype.isNull = function() {
- return this.oldValue == this.newValue;
-};
-
-/**
- * Run a change event.
- * @param {boolean} forward True if run forward, false if run backward (undo).
- */
-Blockly.Events.BlockChange.prototype.run = function(forward) {
- var workspace = this.getEventWorkspace_();
- var block = workspace.getBlockById(this.blockId);
- if (!block) {
- console.warn("Can't change non-existent block: " + this.blockId);
- return;
- }
- if (block.mutator) {
- // Close the mutator (if open) since we don't want to update it.
- block.mutator.setVisible(false);
- }
- var value = forward ? this.newValue : this.oldValue;
- switch (this.element) {
- case 'field':
- var field = block.getField(this.name);
- if (field) {
- field.setValue(value);
- } else {
- console.warn("Can't set non-existent field: " + this.name);
- }
- break;
- case 'comment':
- block.setCommentText(/** @type {string} */ (value) || null);
- break;
- case 'collapsed':
- block.setCollapsed(!!value);
- break;
- case 'disabled':
- block.setEnabled(!value);
- break;
- case 'inline':
- block.setInputsInline(!!value);
- break;
- case 'mutation':
- var oldMutation = '';
- if (block.mutationToDom) {
- var oldMutationDom = block.mutationToDom();
- oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom);
- }
- if (block.domToMutation) {
- var dom = Blockly.Xml.textToDom(/** @type {string} */ (value) || '');
- block.domToMutation(dom);
- }
- Blockly.Events.fire(new Blockly.Events.BlockChange(
- block, 'mutation', null, oldMutation, value));
- break;
- default:
- console.warn('Unknown change type: ' + this.element);
- }
-};
-
-/**
- * Class for a block creation event.
- * @param {!Blockly.Block=} opt_block The created block. Undefined for a blank
- * event.
- * @extends {Blockly.Events.BlockBase}
- * @constructor
- */
-Blockly.Events.Create = function(opt_block) {
- Blockly.Events.Create.superClass_.constructor.call(this, opt_block);
- if (!opt_block) {
- return; // Blank event to be populated by fromJson.
- }
- if (opt_block.isShadow()) {
- // Moving shadow blocks is handled via disconnection.
- this.recordUndo = false;
- }
-
- if (opt_block.workspace.rendered) {
- this.xml = Blockly.Xml.blockToDomWithXY(opt_block);
- } else {
- this.xml = Blockly.Xml.blockToDom(opt_block);
- }
- this.ids = Blockly.Events.getDescendantIds(opt_block);
-};
-Blockly.utils.object.inherits(Blockly.Events.Create, Blockly.Events.BlockBase);
-
-/**
- * Class for a block creation event.
- * @param {!Blockly.Block=} block The created block. Undefined for a blank
- * event.
- * @extends {Blockly.Events.BlockBase}
- * @constructor
- */
-Blockly.Events.BlockCreate = Blockly.Events.Create;
-
-/**
- * Type of this event.
- * @type {string}
- */
-Blockly.Events.Create.prototype.type = Blockly.Events.CREATE;
-
-/**
- * Encode the event as JSON.
- * @return {!Object} JSON representation.
- */
-Blockly.Events.Create.prototype.toJson = function() {
- var json = Blockly.Events.Create.superClass_.toJson.call(this);
- json['xml'] = Blockly.Xml.domToText(this.xml);
- json['ids'] = this.ids;
- if (!this.recordUndo) {
- json['recordUndo'] = this.recordUndo;
- }
- return json;
-};
-
-/**
- * Decode the JSON event.
- * @param {!Object} json JSON representation.
- */
-Blockly.Events.Create.prototype.fromJson = function(json) {
- Blockly.Events.Create.superClass_.fromJson.call(this, json);
- this.xml = Blockly.Xml.textToDom(json['xml']);
- this.ids = json['ids'];
- if (json['recordUndo'] !== undefined) {
- this.recordUndo = json['recordUndo'];
- }
-};
-
-/**
- * Run a creation event.
- * @param {boolean} forward True if run forward, false if run backward (undo).
- */
-Blockly.Events.Create.prototype.run = function(forward) {
- var workspace = this.getEventWorkspace_();
- if (forward) {
- var xml = Blockly.utils.xml.createElement('xml');
- xml.appendChild(this.xml);
- Blockly.Xml.domToWorkspace(xml, workspace);
- } else {
- for (var i = 0, id; (id = this.ids[i]); i++) {
- var block = workspace.getBlockById(id);
- if (block) {
- block.dispose(false);
- } else if (id == this.blockId) {
- // Only complain about root-level block.
- console.warn("Can't uncreate non-existent block: " + id);
- }
- }
- }
-};
-
-/**
- * Class for a block deletion event.
- * @param {!Blockly.Block=} opt_block The deleted block. Undefined for a blank
- * event.
- * @extends {Blockly.Events.BlockBase}
- * @constructor
- */
-Blockly.Events.Delete = function(opt_block) {
- Blockly.Events.Delete.superClass_.constructor.call(this, opt_block);
- if (!opt_block) {
- return; // Blank event to be populated by fromJson.
- }
- if (opt_block.getParent()) {
- throw Error('Connected blocks cannot be deleted.');
- }
- if (opt_block.isShadow()) {
- // Respawning shadow blocks is handled via disconnection.
- this.recordUndo = false;
- }
-
- if (opt_block.workspace.rendered) {
- this.oldXml = Blockly.Xml.blockToDomWithXY(opt_block);
- } else {
- this.oldXml = Blockly.Xml.blockToDom(opt_block);
- }
- this.ids = Blockly.Events.getDescendantIds(opt_block);
-};
-Blockly.utils.object.inherits(Blockly.Events.Delete, Blockly.Events.BlockBase);
-
-/**
- * Class for a block deletion event.
- * @param {?Blockly.Block} block The deleted block. Null for a blank event.
- * @extends {Blockly.Events.BlockBase}
- * @constructor
- */
-Blockly.Events.BlockDelete = Blockly.Events.Delete;
-
-/**
- * Type of this event.
- * @type {string}
- */
-Blockly.Events.Delete.prototype.type = Blockly.Events.DELETE;
-
-/**
- * Encode the event as JSON.
- * @return {!Object} JSON representation.
- */
-Blockly.Events.Delete.prototype.toJson = function() {
- var json = Blockly.Events.Delete.superClass_.toJson.call(this);
- json['oldXml'] = Blockly.Xml.domToText(this.oldXml);
- json['ids'] = this.ids;
- if (!this.recordUndo) {
- json['recordUndo'] = this.recordUndo;
- }
- return json;
-};
-
-/**
- * Decode the JSON event.
- * @param {!Object} json JSON representation.
- */
-Blockly.Events.Delete.prototype.fromJson = function(json) {
- Blockly.Events.Delete.superClass_.fromJson.call(this, json);
- this.oldXml = Blockly.Xml.textToDom(json['oldXml']);
- this.ids = json['ids'];
- if (json['recordUndo'] !== undefined) {
- this.recordUndo = json['recordUndo'];
- }
-};
-
-/**
- * Run a deletion event.
- * @param {boolean} forward True if run forward, false if run backward (undo).
- */
-Blockly.Events.Delete.prototype.run = function(forward) {
- var workspace = this.getEventWorkspace_();
- if (forward) {
- for (var i = 0, id; (id = this.ids[i]); i++) {
- var block = workspace.getBlockById(id);
- if (block) {
- block.dispose(false);
- } else if (id == this.blockId) {
- // Only complain about root-level block.
- console.warn("Can't delete non-existent block: " + id);
- }
- }
- } else {
- var xml = Blockly.utils.xml.createElement('xml');
- xml.appendChild(this.oldXml);
- Blockly.Xml.domToWorkspace(xml, workspace);
- }
-};
-
-/**
- * Class for a block move event. Created before the move.
- * @param {!Blockly.Block=} opt_block The moved block. Undefined for a blank
- * event.
- * @extends {Blockly.Events.BlockBase}
- * @constructor
- */
-Blockly.Events.Move = function(opt_block) {
- Blockly.Events.Move.superClass_.constructor.call(this, opt_block);
- if (!opt_block) {
- return; // Blank event to be populated by fromJson.
- }
- if (opt_block.isShadow()) {
- // Moving shadow blocks is handled via disconnection.
- this.recordUndo = false;
- }
-
- var location = this.currentLocation_();
- this.oldParentId = location.parentId;
- this.oldInputName = location.inputName;
- this.oldCoordinate = location.coordinate;
-};
-Blockly.utils.object.inherits(Blockly.Events.Move, Blockly.Events.BlockBase);
-
-/**
- * Class for a block move event. Created before the move.
- * @param {?Blockly.Block} block The moved block. Null for a blank event.
- * @extends {Blockly.Events.BlockBase}
- * @constructor
- */
-Blockly.Events.BlockMove = Blockly.Events.Move;
-
-/**
- * Type of this event.
- * @type {string}
- */
-Blockly.Events.Move.prototype.type = Blockly.Events.MOVE;
-
-/**
- * Encode the event as JSON.
- * @return {!Object} JSON representation.
- */
-Blockly.Events.Move.prototype.toJson = function() {
- var json = Blockly.Events.Move.superClass_.toJson.call(this);
- if (this.newParentId) {
- json['newParentId'] = this.newParentId;
- }
- if (this.newInputName) {
- json['newInputName'] = this.newInputName;
- }
- if (this.newCoordinate) {
- json['newCoordinate'] = Math.round(this.newCoordinate.x) + ',' +
- Math.round(this.newCoordinate.y);
- }
- if (!this.recordUndo) {
- json['recordUndo'] = this.recordUndo;
- }
- return json;
-};
-
-/**
- * Decode the JSON event.
- * @param {!Object} json JSON representation.
- */
-Blockly.Events.Move.prototype.fromJson = function(json) {
- Blockly.Events.Move.superClass_.fromJson.call(this, json);
- this.newParentId = json['newParentId'];
- this.newInputName = json['newInputName'];
- if (json['newCoordinate']) {
- var xy = json['newCoordinate'].split(',');
- this.newCoordinate =
- new Blockly.utils.Coordinate(Number(xy[0]), Number(xy[1]));
- }
- if (json['recordUndo'] !== undefined) {
- this.recordUndo = json['recordUndo'];
- }
-};
-
-/**
- * Record the block's new location. Called after the move.
- */
-Blockly.Events.Move.prototype.recordNew = function() {
- var location = this.currentLocation_();
- this.newParentId = location.parentId;
- this.newInputName = location.inputName;
- this.newCoordinate = location.coordinate;
-};
-
-/**
- * Returns the parentId and input if the block is connected,
- * or the XY location if disconnected.
- * @return {!Object} Collection of location info.
- * @private
- */
-Blockly.Events.Move.prototype.currentLocation_ = function() {
- var workspace = this.getEventWorkspace_();
- var block = workspace.getBlockById(this.blockId);
- var location = {};
- var parent = block.getParent();
- if (parent) {
- location.parentId = parent.id;
- var input = parent.getInputWithBlock(block);
- if (input) {
- location.inputName = input.name;
- }
- } else {
- location.coordinate = block.getRelativeToSurfaceXY();
- }
- return location;
-};
-
-/**
- * Does this event record any change of state?
- * @return {boolean} False if something changed.
- */
-Blockly.Events.Move.prototype.isNull = function() {
- return this.oldParentId == this.newParentId &&
- this.oldInputName == this.newInputName &&
- Blockly.utils.Coordinate.equals(this.oldCoordinate, this.newCoordinate);
-};
-
-/**
- * Run a move event.
- * @param {boolean} forward True if run forward, false if run backward (undo).
- */
-Blockly.Events.Move.prototype.run = function(forward) {
- var workspace = this.getEventWorkspace_();
- var block = workspace.getBlockById(this.blockId);
- if (!block) {
- console.warn("Can't move non-existent block: " + this.blockId);
- return;
- }
- var parentId = forward ? this.newParentId : this.oldParentId;
- var inputName = forward ? this.newInputName : this.oldInputName;
- var coordinate = forward ? this.newCoordinate : this.oldCoordinate;
- var parentBlock = null;
- if (parentId) {
- parentBlock = workspace.getBlockById(parentId);
- if (!parentBlock) {
- console.warn("Can't connect to non-existent block: " + parentId);
- return;
- }
- }
- if (block.getParent()) {
- block.unplug();
- }
- if (coordinate) {
- var xy = block.getRelativeToSurfaceXY();
- block.moveBy(coordinate.x - xy.x, coordinate.y - xy.y);
- } else {
- var blockConnection = block.outputConnection || block.previousConnection;
- var parentConnection;
- var connectionType = blockConnection.type;
- if (inputName) {
- var input = parentBlock.getInput(inputName);
- if (input) {
- parentConnection = input.connection;
- }
- } else if (connectionType == Blockly.connectionTypes.PREVIOUS_STATEMENT) {
- parentConnection = parentBlock.nextConnection;
- }
- if (parentConnection) {
- blockConnection.connect(parentConnection);
- } else {
- console.warn("Can't connect to non-existent input: " + inputName);
- }
- }
-};
-
-Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.CREATE,
- Blockly.Events.Create);
-Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.DELETE,
- Blockly.Events.Delete);
-Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.CHANGE,
- Blockly.Events.BlockChange);
-Blockly.registry.register(Blockly.registry.Type.EVENT, Blockly.Events.MOVE,
- Blockly.Events.Move);
diff --git a/core/events/events_block_base.js b/core/events/events_block_base.js
new file mode 100644
index 00000000000..1f22a4ed86d
--- /dev/null
+++ b/core/events/events_block_base.js
@@ -0,0 +1,66 @@
+/**
+ * @license
+ * Copyright 2018 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @fileoverview Base class for all types of block events.
+ * @author fenichel@google.com (Rachel Fenichel)
+ */
+'use strict';
+
+goog.module('Blockly.Events.BlockBase');
+goog.module.declareLegacyNamespace();
+
+const Abstract = goog.require('Blockly.Events.Abstract');
+/* eslint-disable-next-line no-unused-vars */
+const Block = goog.requireType('Blockly.Block');
+const object = goog.require('Blockly.utils.object');
+
+
+/**
+ * Abstract class for a block event.
+ * @param {!Block=} opt_block The block this event corresponds to.
+ * Undefined for a blank event.
+ * @extends {Abstract}
+ * @constructor
+ */
+const BlockBase = function(opt_block) {
+ BlockBase.superClass_.constructor.call(this);
+ this.isBlank = typeof opt_block == 'undefined';
+
+ /**
+ * The block ID for the block this event pertains to
+ * @type {string}
+ */
+ this.blockId = this.isBlank ? '' : opt_block.id;
+
+ /**
+ * The workspace identifier for this event.
+ * @type {string}
+ */
+ this.workspaceId = this.isBlank ? '' : opt_block.workspace.id;
+};
+object.inherits(BlockBase, Abstract);
+
+/**
+ * Encode the event as JSON.
+ * @return {!Object} JSON representation.
+ */
+BlockBase.prototype.toJson = function() {
+ const json = BlockBase.superClass_.toJson.call(this);
+ json['blockId'] = this.blockId;
+ return json;
+};
+
+/**
+ * Decode the JSON event.
+ * @param {!Object} json JSON representation.
+ */
+BlockBase.prototype.fromJson = function(json) {
+ BlockBase.superClass_.fromJson.call(this, json);
+ this.blockId = json['blockId'];
+};
+
+exports = BlockBase;
diff --git a/core/events/events_block_change.js b/core/events/events_block_change.js
new file mode 100644
index 00000000000..3814a0d27ea
--- /dev/null
+++ b/core/events/events_block_change.js
@@ -0,0 +1,148 @@
+/**
+ * @license
+ * Copyright 2018 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @fileoverview Class for a block change event.
+ * @author fenichel@google.com (Rachel Fenichel)
+ */
+'use strict';
+
+goog.module('Blockly.Events.BlockChange');
+goog.module.declareLegacyNamespace();
+
+/* eslint-disable-next-line no-unused-vars */
+const Block = goog.requireType('Blockly.Block');
+const Events = goog.require('Blockly.Events');
+const Xml = goog.require('Blockly.Xml');
+const object = goog.require('Blockly.utils.object');
+const registry = goog.require('Blockly.registry');
+
+
+/**
+ * Class for a block change event.
+ * @param {!Block=} opt_block The changed block. Undefined for a blank
+ * event.
+ * @param {string=} opt_element One of 'field', 'comment', 'disabled', etc.
+ * @param {?string=} opt_name Name of input or field affected, or null.
+ * @param {*=} opt_oldValue Previous value of element.
+ * @param {*=} opt_newValue New value of element.
+ * @extends {Events.BlockBase}
+ * @constructor
+ */
+const BlockChange = function(
+ opt_block, opt_element, opt_name, opt_oldValue, opt_newValue) {
+ BlockChange.superClass_.constructor.call(this, opt_block);
+ if (!opt_block) {
+ return; // Blank event to be populated by fromJson.
+ }
+ this.element = typeof opt_element == 'undefined' ? '' : opt_element;
+ this.name = typeof opt_name == 'undefined' ? '' : opt_name;
+ this.oldValue = typeof opt_oldValue == 'undefined' ? '' : opt_oldValue;
+ this.newValue = typeof opt_newValue == 'undefined' ? '' : opt_newValue;
+};
+object.inherits(BlockChange, Events.BlockBase);
+
+/**
+ * Type of this event.
+ * @type {string}
+ */
+BlockChange.prototype.type = Events.BLOCK_CHANGE;
+
+/**
+ * Encode the event as JSON.
+ * @return {!Object} JSON representation.
+ */
+BlockChange.prototype.toJson = function() {
+ const json = BlockChange.superClass_.toJson.call(this);
+ json['element'] = this.element;
+ if (this.name) {
+ json['name'] = this.name;
+ }
+ json['oldValue'] = this.oldValue;
+ json['newValue'] = this.newValue;
+ return json;
+};
+
+/**
+ * Decode the JSON event.
+ * @param {!Object} json JSON representation.
+ */
+BlockChange.prototype.fromJson = function(json) {
+ BlockChange.superClass_.fromJson.call(this, json);
+ this.element = json['element'];
+ this.name = json['name'];
+ this.oldValue = json['oldValue'];
+ this.newValue = json['newValue'];
+};
+
+/**
+ * Does this event record any change of state?
+ * @return {boolean} False if something changed.
+ */
+BlockChange.prototype.isNull = function() {
+ return this.oldValue == this.newValue;
+};
+
+/**
+ * Run a change event.
+ * @param {boolean} forward True if run forward, false if run backward (undo).
+ */
+BlockChange.prototype.run = function(forward) {
+ const workspace = this.getEventWorkspace_();
+ const block = workspace.getBlockById(this.blockId);
+ if (!block) {
+ console.warn('Can\'t change non-existent block: ' + this.blockId);
+ return;
+ }
+ if (block.mutator) {
+ // Close the mutator (if open) since we don't want to update it.
+ block.mutator.setVisible(false);
+ }
+ const value = forward ? this.newValue : this.oldValue;
+ switch (this.element) {
+ case 'field': {
+ const field = block.getField(this.name);
+ if (field) {
+ field.setValue(value);
+ } else {
+ console.warn('Can\'t set non-existent field: ' + this.name);
+ }
+ break;
+ }
+ case 'comment':
+ block.setCommentText(/** @type {string} */ (value) || null);
+ break;
+ case 'collapsed':
+ block.setCollapsed(!!value);
+ break;
+ case 'disabled':
+ block.setEnabled(!value);
+ break;
+ case 'inline':
+ block.setInputsInline(!!value);
+ break;
+ case 'mutation': {
+ let oldMutation = '';
+ if (block.mutationToDom) {
+ const oldMutationDom = block.mutationToDom();
+ oldMutation = oldMutationDom && Xml.domToText(oldMutationDom);
+ }
+ if (block.domToMutation) {
+ const dom = Xml.textToDom(/** @type {string} */
+ (value) || '');
+ block.domToMutation(dom);
+ }
+ Events.fire(new BlockChange(block, 'mutation', null, oldMutation, value));
+ break;
+ }
+ default:
+ console.warn('Unknown change type: ' + this.element);
+ }
+};
+
+registry.register(registry.Type.EVENT, Events.CHANGE, BlockChange);
+
+exports = BlockChange;
diff --git a/core/events/events_block_create.js b/core/events/events_block_create.js
new file mode 100644
index 00000000000..2a6afb003fc
--- /dev/null
+++ b/core/events/events_block_create.js
@@ -0,0 +1,111 @@
+/**
+ * @license
+ * Copyright 2018 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @fileoverview Class for a block creation event.
+ * @author fenichel@google.com (Rachel Fenichel)
+ */
+'use strict';
+
+goog.module('Blockly.Events.BlockCreate');
+goog.module.declareLegacyNamespace();
+
+/* eslint-disable-next-line no-unused-vars */
+const Block = goog.requireType('Blockly.Block');
+const BlockBase = goog.require('Blockly.Events.BlockBase');
+const Events = goog.require('Blockly.Events');
+const Xml = goog.require('Blockly.Xml');
+const object = goog.require('Blockly.utils.object');
+const registry = goog.require('Blockly.registry');
+const xml = goog.require('Blockly.utils.xml');
+
+
+/**
+ * Class for a block creation event.
+ * @param {!Block=} opt_block The created block. Undefined for a blank
+ * event.
+ * @extends {BlockBase}
+ * @constructor
+ */
+const BlockCreate = function(opt_block) {
+ BlockCreate.superClass_.constructor.call(this, opt_block);
+ if (!opt_block) {
+ return; // Blank event to be populated by fromJson.
+ }
+ if (opt_block.isShadow()) {
+ // Moving shadow blocks is handled via disconnection.
+ this.recordUndo = false;
+ }
+
+ if (opt_block.workspace.rendered) {
+ this.xml = Xml.blockToDomWithXY(opt_block);
+ } else {
+ this.xml = Xml.blockToDom(opt_block);
+ }
+ this.ids = Events.getDescendantIds(opt_block);
+};
+object.inherits(BlockCreate, BlockBase);
+
+/**
+ * Type of this event.
+ * @type {string}
+ */
+BlockCreate.prototype.type = Events.BLOCK_CREATE;
+
+/**
+ * Encode the event as JSON.
+ * @return {!Object} JSON representation.
+ */
+BlockCreate.prototype.toJson = function() {
+ const json = BlockCreate.superClass_.toJson.call(this);
+ json['xml'] = Xml.domToText(this.xml);
+ json['ids'] = this.ids;
+ if (!this.recordUndo) {
+ json['recordUndo'] = this.recordUndo;
+ }
+ return json;
+};
+
+/**
+ * Decode the JSON event.
+ * @param {!Object} json JSON representation.
+ */
+BlockCreate.prototype.fromJson = function(json) {
+ BlockCreate.superClass_.fromJson.call(this, json);
+ this.xml = Xml.textToDom(json['xml']);
+ this.ids = json['ids'];
+ if (json['recordUndo'] !== undefined) {
+ this.recordUndo = json['recordUndo'];
+ }
+};
+
+/**
+ * Run a creation event.
+ * @param {boolean} forward True if run forward, false if run backward (undo).
+ */
+BlockCreate.prototype.run = function(forward) {
+ const workspace = this.getEventWorkspace_();
+ if (forward) {
+ const xmlEl = xml.createElement('xml');
+ xmlEl.appendChild(this.xml);
+ Xml.domToWorkspace(xmlEl, workspace);
+ } else {
+ for (let i = 0; i < this.ids.length; i++) {
+ const id = this.ids[i];
+ const block = workspace.getBlockById(id);
+ if (block) {
+ block.dispose(false);
+ } else if (id == this.blockId) {
+ // Only complain about root-level block.
+ console.warn('Can\'t uncreate non-existent block: ' + id);
+ }
+ }
+ }
+};
+
+registry.register(registry.Type.EVENT, Events.CREATE, BlockCreate);
+
+exports = BlockCreate;
diff --git a/core/events/events_block_delete.js b/core/events/events_block_delete.js
new file mode 100644
index 00000000000..f44caa7f019
--- /dev/null
+++ b/core/events/events_block_delete.js
@@ -0,0 +1,114 @@
+/**
+ * @license
+ * Copyright 2018 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @fileoverview Class for a block delete event.
+ * @author fenichel@google.com (Rachel Fenichel)
+ */
+'use strict';
+
+goog.module('Blockly.Events.BlockDelete');
+goog.module.declareLegacyNamespace();
+
+/* eslint-disable-next-line no-unused-vars */
+const Block = goog.requireType('Blockly.Block');
+const BlockBase = goog.require('Blockly.Events.BlockBase');
+const Events = goog.require('Blockly.Events');
+const Xml = goog.require('Blockly.Xml');
+const object = goog.require('Blockly.utils.object');
+const registry = goog.require('Blockly.registry');
+const xml = goog.require('Blockly.utils.xml');
+
+
+/**
+ * Class for a block deletion event.
+ * @param {!Block=} opt_block The deleted block. Undefined for a blank
+ * event.
+ * @extends {BlockBase}
+ * @constructor
+ */
+const BlockDelete = function(opt_block) {
+ BlockDelete.superClass_.constructor.call(this, opt_block);
+ if (!opt_block) {
+ return; // Blank event to be populated by fromJson.
+ }
+ if (opt_block.getParent()) {
+ throw Error('Connected blocks cannot be deleted.');
+ }
+ if (opt_block.isShadow()) {
+ // Respawning shadow blocks is handled via disconnection.
+ this.recordUndo = false;
+ }
+
+ if (opt_block.workspace.rendered) {
+ this.oldXml = Xml.blockToDomWithXY(opt_block);
+ } else {
+ this.oldXml = Xml.blockToDom(opt_block);
+ }
+ this.ids = Events.getDescendantIds(opt_block);
+};
+object.inherits(BlockDelete, BlockBase);
+
+/**
+ * Type of this event.
+ * @type {string}
+ */
+BlockDelete.prototype.type = Events.BLOCK_DELETE;
+
+/**
+ * Encode the event as JSON.
+ * @return {!Object} JSON representation.
+ */
+BlockDelete.prototype.toJson = function() {
+ const json = BlockDelete.superClass_.toJson.call(this);
+ json['oldXml'] = Xml.domToText(this.oldXml);
+ json['ids'] = this.ids;
+ if (!this.recordUndo) {
+ json['recordUndo'] = this.recordUndo;
+ }
+ return json;
+};
+
+/**
+ * Decode the JSON event.
+ * @param {!Object} json JSON representation.
+ */
+BlockDelete.prototype.fromJson = function(json) {
+ BlockDelete.superClass_.fromJson.call(this, json);
+ this.oldXml = Xml.textToDom(json['oldXml']);
+ this.ids = json['ids'];
+ if (json['recordUndo'] !== undefined) {
+ this.recordUndo = json['recordUndo'];
+ }
+};
+
+/**
+ * Run a deletion event.
+ * @param {boolean} forward True if run forward, false if run backward (undo).
+ */
+BlockDelete.prototype.run = function(forward) {
+ const workspace = this.getEventWorkspace_();
+ if (forward) {
+ for (let i = 0; i < this.ids.length; i++) {
+ const id = this.ids[i];
+ const block = workspace.getBlockById(id);
+ if (block) {
+ block.dispose(false);
+ } else if (id == this.blockId) {
+ // Only complain about root-level block.
+ console.warn('Can\'t delete non-existent block: ' + id);
+ }
+ }
+ } else {
+ const xmlEl = xml.createElement('xml');
+ xmlEl.appendChild(this.oldXml);
+ Xml.domToWorkspace(xmlEl, workspace);
+ }
+};
+
+registry.register(registry.Type.EVENT, Events.DELETE, BlockDelete);
+
+exports = BlockDelete;
diff --git a/core/events/events_block_move.js b/core/events/events_block_move.js
new file mode 100644
index 00000000000..f026c080b2b
--- /dev/null
+++ b/core/events/events_block_move.js
@@ -0,0 +1,188 @@
+/**
+ * @license
+ * Copyright 2018 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/**
+ * @fileoverview Class for a block move event.
+ * @author fenichel@google.com (Rachel Fenichel)
+ */
+'use strict';
+
+goog.module('Blockly.Events.BlockMove');
+goog.module.declareLegacyNamespace();
+
+/* eslint-disable-next-line no-unused-vars */
+const Block = goog.requireType('Blockly.Block');
+const BlockBase = goog.require('Blockly.Events.BlockBase');
+const Coordinate = goog.require('Blockly.utils.Coordinate');
+const Events = goog.require('Blockly.Events');
+const connectionTypes = goog.require('Blockly.connectionTypes');
+const object = goog.require('Blockly.utils.object');
+const registry = goog.require('Blockly.registry');
+
+
+/**
+ * Class for a block move event. Created before the move.
+ * @param {!Block=} opt_block The moved block. Undefined for a blank
+ * event.
+ * @extends {BlockBase}
+ * @constructor
+ */
+const BlockMove = function(opt_block) {
+ BlockMove.superClass_.constructor.call(this, opt_block);
+ if (!opt_block) {
+ return; // Blank event to be populated by fromJson.
+ }
+ if (opt_block.isShadow()) {
+ // Moving shadow blocks is handled via disconnection.
+ this.recordUndo = false;
+ }
+
+ const location = this.currentLocation_();
+ this.oldParentId = location.parentId;
+ this.oldInputName = location.inputName;
+ this.oldCoordinate = location.coordinate;
+};
+object.inherits(BlockMove, BlockBase);
+
+/**
+ * Type of this event.
+ * @type {string}
+ */
+BlockMove.prototype.type = Events.BLOCK_MOVE;
+
+/**
+ * Encode the event as JSON.
+ * @return {!Object} JSON representation.
+ */
+BlockMove.prototype.toJson = function() {
+ const json = BlockMove.superClass_.toJson.call(this);
+ if (this.newParentId) {
+ json['newParentId'] = this.newParentId;
+ }
+ if (this.newInputName) {
+ json['newInputName'] = this.newInputName;
+ }
+ if (this.newCoordinate) {
+ json['newCoordinate'] = Math.round(this.newCoordinate.x) + ',' +
+ Math.round(this.newCoordinate.y);
+ }
+ if (!this.recordUndo) {
+ json['recordUndo'] = this.recordUndo;
+ }
+ return json;
+};
+
+/**
+ * Decode the JSON event.
+ * @param {!Object} json JSON representation.
+ */
+BlockMove.prototype.fromJson = function(json) {
+ BlockMove.superClass_.fromJson.call(this, json);
+ this.newParentId = json['newParentId'];
+ this.newInputName = json['newInputName'];
+ if (json['newCoordinate']) {
+ const xy = json['newCoordinate'].split(',');
+ this.newCoordinate = new Coordinate(Number(xy[0]), Number(xy[1]));
+ }
+ if (json['recordUndo'] !== undefined) {
+ this.recordUndo = json['recordUndo'];
+ }
+};
+
+/**
+ * Record the block's new location. Called after the move.
+ */
+BlockMove.prototype.recordNew = function() {
+ const location = this.currentLocation_();
+ this.newParentId = location.parentId;
+ this.newInputName = location.inputName;
+ this.newCoordinate = location.coordinate;
+};
+
+/**
+ * Returns the parentId and input if the block is connected,
+ * or the XY location if disconnected.
+ * @return {!Object} Collection of location info.
+ * @private
+ */
+BlockMove.prototype.currentLocation_ = function() {
+ const workspace = this.getEventWorkspace_();
+ const block = workspace.getBlockById(this.blockId);
+ const location = {};
+ const parent = block.getParent();
+ if (parent) {
+ location.parentId = parent.id;
+ const input = parent.getInputWithBlock(block);
+ if (input) {
+ location.inputName = input.name;
+ }
+ } else {
+ location.coordinate = block.getRelativeToSurfaceXY();
+ }
+ return location;
+};
+
+/**
+ * Does this event record any change of state?
+ * @return {boolean} False if something changed.
+ */
+BlockMove.prototype.isNull = function() {
+ return this.oldParentId == this.newParentId &&
+ this.oldInputName == this.newInputName &&
+ Coordinate.equals(this.oldCoordinate, this.newCoordinate);
+};
+
+/**
+ * Run a move event.
+ * @param {boolean} forward True if run forward, false if run backward (undo).
+ */
+BlockMove.prototype.run = function(forward) {
+ const workspace = this.getEventWorkspace_();
+ const block = workspace.getBlockById(this.blockId);
+ if (!block) {
+ console.warn('Can\'t move non-existent block: ' + this.blockId);
+ return;
+ }
+ const parentId = forward ? this.newParentId : this.oldParentId;
+ const inputName = forward ? this.newInputName : this.oldInputName;
+ const coordinate = forward ? this.newCoordinate : this.oldCoordinate;
+ let parentBlock;
+ if (parentId) {
+ parentBlock = workspace.getBlockById(parentId);
+ if (!parentBlock) {
+ console.warn('Can\'t connect to non-existent block: ' + parentId);
+ return;
+ }
+ }
+ if (block.getParent()) {
+ block.unplug();
+ }
+ if (coordinate) {
+ const xy = block.getRelativeToSurfaceXY();
+ block.moveBy(coordinate.x - xy.x, coordinate.y - xy.y);
+ } else {
+ const blockConnection = block.outputConnection || block.previousConnection;
+ let parentConnection;
+ const connectionType = blockConnection.type;
+ if (inputName) {
+ const input = parentBlock.getInput(inputName);
+ if (input) {
+ parentConnection = input.connection;
+ }
+ } else if (connectionType == connectionTypes.PREVIOUS_STATEMENT) {
+ parentConnection = parentBlock.nextConnection;
+ }
+ if (parentConnection) {
+ blockConnection.connect(parentConnection);
+ } else {
+ console.warn('Can\'t connect to non-existent input: ' + inputName);
+ }
+ }
+};
+
+registry.register(registry.Type.EVENT, Events.MOVE, BlockMove);
+
+exports = BlockMove;
diff --git a/tests/deps.js b/tests/deps.js
index 9a432a8ee98..d81b13de24f 100644
--- a/tests/deps.js
+++ b/tests/deps.js
@@ -34,10 +34,14 @@ goog.addDependency('../../core/css.js', ['Blockly.Css'], [], {'lang': 'es6', 'mo
goog.addDependency('../../core/delete_area.js', ['Blockly.DeleteArea'], ['Blockly.BlockSvg', 'Blockly.DragTarget', 'Blockly.IDeleteArea', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/drag_target.js', ['Blockly.DragTarget'], ['Blockly.IDragTarget'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/dropdowndiv.js', ['Blockly.DropDownDiv'], ['Blockly.common', 'Blockly.utils.Rect', 'Blockly.utils.dom', 'Blockly.utils.math', 'Blockly.utils.style']);
-goog.addDependency('../../core/events/block_events.js', ['Blockly.Events.BlockBase', 'Blockly.Events.BlockChange', 'Blockly.Events.BlockCreate', 'Blockly.Events.BlockDelete', 'Blockly.Events.BlockMove', 'Blockly.Events.Change', 'Blockly.Events.Create', 'Blockly.Events.Delete', 'Blockly.Events.Move'], ['Blockly.Events', 'Blockly.Events.Abstract', 'Blockly.Xml', 'Blockly.connectionTypes', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object', 'Blockly.utils.xml']);
goog.addDependency('../../core/events/events.js', ['Blockly.Events'], ['Blockly.registry', 'Blockly.utils']);
goog.addDependency('../../core/events/events_abstract.js', ['Blockly.Events.Abstract'], ['Blockly.Events'], {'lang': 'es6', 'module': 'goog'});
+goog.addDependency('../../core/events/events_block_base.js', ['Blockly.Events.BlockBase'], ['Blockly.Events.Abstract', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
+goog.addDependency('../../core/events/events_block_change.js', ['Blockly.Events.BlockChange'], ['Blockly.Events', 'Blockly.Xml', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
+goog.addDependency('../../core/events/events_block_create.js', ['Blockly.Events.BlockCreate'], ['Blockly.Events', 'Blockly.Events.BlockBase', 'Blockly.Xml', 'Blockly.registry', 'Blockly.utils.object', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'});
+goog.addDependency('../../core/events/events_block_delete.js', ['Blockly.Events.BlockDelete'], ['Blockly.Events', 'Blockly.Events.BlockBase', 'Blockly.Xml', 'Blockly.registry', 'Blockly.utils.object', 'Blockly.utils.xml'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/events/events_block_drag.js', ['Blockly.Events.BlockDrag'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object']);
+goog.addDependency('../../core/events/events_block_move.js', ['Blockly.Events.BlockMove'], ['Blockly.Events', 'Blockly.Events.BlockBase', 'Blockly.connectionTypes', 'Blockly.registry', 'Blockly.utils.Coordinate', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/events/events_bubble_open.js', ['Blockly.Events.BubbleOpen'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/events/events_click.js', ['Blockly.Events.Click'], ['Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/events/events_marker_move.js', ['Blockly.Events.MarkerMove'], ['Blockly.ASTNode', 'Blockly.Events', 'Blockly.Events.UiBase', 'Blockly.registry', 'Blockly.utils.object'], {'lang': 'es6', 'module': 'goog'});
diff --git a/tests/mocha/event_test.js b/tests/mocha/event_test.js
index 81ab69519d4..febcaf1c389 100644
--- a/tests/mocha/event_test.js
+++ b/tests/mocha/event_test.js
@@ -109,32 +109,10 @@ suite('Events', function() {
});
});
- test('Create', function() {
- var event = new Blockly.Events.Create(this.block);
- sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.CREATE,
- this.workspace.id, this.TEST_BLOCK_ID,
- {
- 'recordUndo': true,
- 'group': '',
- });
- });
-
test('Block create', function() {
var event = new Blockly.Events.BlockCreate(this.block);
sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.CREATE,
- this.workspace.id, this.TEST_BLOCK_ID,
- {
- 'recordUndo': true,
- 'group': '',
- });
- });
-
- test('Delete', function() {
- var event = new Blockly.Events.Delete(this.block);
- sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.DELETE,
+ assertEventEquals(event, Blockly.Events.BLOCK_CREATE,
this.workspace.id, this.TEST_BLOCK_ID,
{
'recordUndo': true,
@@ -145,7 +123,7 @@ suite('Events', function() {
test('Block delete', function() {
var event = new Blockly.Events.BlockDelete(this.block);
sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.DELETE,
+ assertEventEquals(event, Blockly.Events.BLOCK_DELETE,
this.workspace.id, this.TEST_BLOCK_ID,
{
'recordUndo': true,
@@ -181,30 +159,14 @@ suite('Events', function() {
}, true);
});
- suite('Move', function() {
- test('Move by coordinate', function() {
- var coordinate = new Blockly.utils.Coordinate(3, 4);
- this.block.xy_ = coordinate;
-
- var event = new Blockly.Events.Move(this.block);
- sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
- this.TEST_BLOCK_ID, {
- 'oldParentId': undefined,
- 'oldInputName': undefined,
- 'oldCoordinate': coordinate,
- 'recordUndo': true,
- 'group': ''
- });
- });
-
- test('Block move by coordinate', function() {
+ suite('Block Move', function() {
+ test('by coordinate', function() {
var coordinate = new Blockly.utils.Coordinate(3, 4);
this.block.xy_ = coordinate;
var event = new Blockly.Events.BlockMove(this.block);
sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
+ assertEventEquals(event, Blockly.Events.BLOCK_MOVE, this.workspace.id,
this.TEST_BLOCK_ID, {
'oldParentId': undefined,
'oldInputName': undefined,
@@ -214,44 +176,25 @@ suite('Events', function() {
});
});
- suite('Move by parent', function() {
- setup(function() {
+ test('by parent', function() {
+ try {
this.parentBlock = createSimpleTestBlock(this.workspace);
-
this.block.parentBlock_ = this.parentBlock;
this.block.xy_ = new Blockly.utils.Coordinate(3, 4);
- });
- teardown(function() {
- // This needs to be cleared, otherwise workspace.dispose will fail.
- this.block.parentBlock_ = null;
- });
-
- test('Move by parent', function() {
- var event = new Blockly.Events.Move(this.block);
- sinon.assert.calledTwice(this.genUidStub);
- assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
- this.TEST_BLOCK_ID, {
- 'oldParentId': this.TEST_PARENT_ID,
- 'oldInputName': undefined,
- 'oldCoordinate': undefined,
- 'recordUndo': true,
- 'group': ''
- });
- });
-
- test('Block move by parent', function() {
var event = new Blockly.Events.BlockMove(this.block);
sinon.assert.calledTwice(this.genUidStub);
- assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
- this.TEST_BLOCK_ID,
- {
+ assertEventEquals(event, Blockly.Events.BLOCK_MOVE, this.workspace.id,
+ this.TEST_BLOCK_ID, {
'oldParentId': this.TEST_PARENT_ID,
'oldInputName': undefined,
'oldCoordinate': undefined,
'recordUndo': true,
'group': ''
});
- });
+ } finally {
+ // This needs to be cleared, otherwise workspace.dispose will fail.
+ this.block.parentBlock_ = null;
+ }
});
});
});
@@ -279,28 +222,11 @@ suite('Events', function() {
});
});
- test('Change', function() {
- var event = new Blockly.Events.Change(
- this.block, 'field', 'FIELD_NAME', 'old', 'new');
- sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.CHANGE,
- this.workspace.id, this.TEST_BLOCK_ID,
- {
- 'varId': undefined,
- 'element': 'field',
- 'name': 'FIELD_NAME',
- 'oldValue': 'old',
- 'newValue': 'new',
- 'recordUndo': true,
- 'group': '',
- });
- });
-
test('Block change', function() {
var event = new Blockly.Events.BlockChange(
this.block, 'field', 'FIELD_NAME', 'old', 'new');
sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.CHANGE,
+ assertEventEquals(event, Blockly.Events.BLOCK_CHANGE,
this.workspace.id, this.TEST_BLOCK_ID,
{
'varId': undefined,
@@ -313,32 +239,10 @@ suite('Events', function() {
});
});
- test('Create', function() {
- var event = new Blockly.Events.Create(this.block);
- sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.CREATE,
- this.workspace.id, this.TEST_BLOCK_ID,
- {
- 'recordUndo': false,
- 'group': '',
- });
- });
-
test('Block create', function() {
var event = new Blockly.Events.BlockCreate(this.block);
sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.CREATE,
- this.workspace.id, this.TEST_BLOCK_ID,
- {
- 'recordUndo': false,
- 'group': '',
- });
- });
-
- test('Delete', function() {
- var event = new Blockly.Events.Delete(this.block);
- sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.DELETE,
+ assertEventEquals(event, Blockly.Events.BLOCK_CREATE,
this.workspace.id, this.TEST_BLOCK_ID,
{
'recordUndo': false,
@@ -349,7 +253,7 @@ suite('Events', function() {
test('Block delete', function() {
var event = new Blockly.Events.BlockDelete(this.block);
sinon.assert.calledOnce(this.genUidStub);
- assertEventEquals(event, Blockly.Events.DELETE,
+ assertEventEquals(event, Blockly.Events.BLOCK_DELETE,
this.workspace.id, this.TEST_BLOCK_ID,
{
'recordUndo': false,
@@ -357,35 +261,14 @@ suite('Events', function() {
});
});
- suite('Move', function() {
- setup(function() {
+ test('Block move', function() {
+ try {
this.parentBlock = createSimpleTestBlock(this.workspace);
this.block.parentBlock_ = this.parentBlock;
this.block.xy_ = new Blockly.utils.Coordinate(3, 4);
- });
-
- teardown(function() {
- // This needs to be cleared, otherwise workspace.dispose will fail.
- this.block.parentBlock_ = null;
- });
-
- test('Move', function() {
- var event = new Blockly.Events.Move(this.block);
- sinon.assert.calledTwice(this.genUidStub);
- assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
- this.TEST_BLOCK_ID, {
- 'oldParentId': this.TEST_PARENT_ID,
- 'oldInputName': undefined,
- 'oldCoordinate': undefined,
- 'recordUndo': false,
- 'group': ''
- });
- });
-
- test('Block move', function() {
var event = new Blockly.Events.BlockMove(this.block);
sinon.assert.calledTwice(this.genUidStub);
- assertEventEquals(event, Blockly.Events.MOVE, this.workspace.id,
+ assertEventEquals(event, Blockly.Events.BLOCK_MOVE, this.workspace.id,
this.TEST_BLOCK_ID,
{
'oldParentId': this.TEST_PARENT_ID,
@@ -394,7 +277,10 @@ suite('Events', function() {
'recordUndo': false,
'group': ''
});
- });
+ } finally {
+ // This needs to be cleared, otherwise workspace.dispose will fail.
+ this.block.parentBlock_ = null;
+ }
});
});
@@ -408,25 +294,10 @@ suite('Events', function() {
this.workspace, 'field_variable_test_block');
});
- test('Change', function() {
- var event = new Blockly.Events.Change(
- this.block, 'field', 'VAR', 'id1', 'id2');
- assertEventEquals(event, Blockly.Events.CHANGE, this.workspace.id,
- this.TEST_BLOCK_ID,
- {
- 'element': 'field',
- 'name': 'VAR',
- 'oldValue': 'id1',
- 'newValue': 'id2',
- 'recordUndo': true,
- 'group': ''
- });
- });
-
test('Block change', function() {
var event = new Blockly.Events.BlockChange(
this.block, 'field', 'VAR', 'id1', 'id2');
- assertEventEquals(event, Blockly.Events.CHANGE, this.workspace.id,
+ assertEventEquals(event, Blockly.Events.BLOCK_CHANGE, this.workspace.id,
this.TEST_BLOCK_ID,
{
'element': 'field',
@@ -889,7 +760,7 @@ suite('Events', function() {
chai.assert.equal(filteredEvents[1].newCoordinate.y, 1);
});
- test('Merge move events', function() {
+ test('Merge block move events', function() {
var block = this.workspace.newBlock('field_variable_test_block', '1');
var events = [];
addMoveEvent(events, block, 0, 0);
@@ -900,11 +771,11 @@ suite('Events', function() {
chai.assert.equal(filteredEvents[0].newCoordinate.y, 1);
});
- test('Merge change events', function() {
+ test('Merge block change events', function() {
var block1 = this.workspace.newBlock('field_variable_test_block', '1');
var events = [
- new Blockly.Events.Change(block1, 'field', 'VAR', 'item', 'item1'),
- new Blockly.Events.Change(block1, 'field', 'VAR', 'item1', 'item2')
+ new Blockly.Events.BlockChange(block1, 'field', 'VAR', 'item', 'item1'),
+ new Blockly.Events.BlockChange(block1, 'field', 'VAR', 'item1', 'item2')
];
var filteredEvents = Blockly.Events.filter(events, true);
chai.assert.equal(filteredEvents.length, 1); // second change event merged into first
@@ -1042,11 +913,11 @@ suite('Events', function() {
sinon.assert.calledTwice(genUidStub);
assertNthCallEventArgEquals(
- this.eventsFireSpy, 0, Blockly.Events.Delete,
+ this.eventsFireSpy, 0, Blockly.Events.BlockDelete,
{oldXml: expectedOldXml, group: ''},
workspaceSvg.id, expectedId);
assertNthCallEventArgEquals(
- changeListenerSpy, 0, Blockly.Events.Delete,
+ changeListenerSpy, 0, Blockly.Events.BlockDelete,
{oldXml: expectedOldXml, group: ''},
workspaceSvg.id, expectedId);
@@ -1086,7 +957,7 @@ suite('Events', function() {
{group: TEST_GROUP_ID, varId: TEST_VAR_ID, varName: TEST_VAR_NAME},
this.workspace.id, undefined);
assertNthCallEventArgEquals(
- this.changeListenerSpy, 1, Blockly.Events.Create,
+ this.changeListenerSpy, 1, Blockly.Events.BlockCreate,
{group: TEST_GROUP_ID}, this.workspace.id, TEST_BLOCK_ID);
// Expect the workspace to have a variable with ID 'test_var_id'.
@@ -1131,7 +1002,7 @@ suite('Events', function() {
{group: TEST_GROUP_ID, varId: TEST_VAR_ID, varName: TEST_VAR_NAME},
this.workspace.id, undefined);
assertNthCallEventArgEquals(
- this.changeListenerSpy, 1, Blockly.Events.Create,
+ this.changeListenerSpy, 1, Blockly.Events.BlockCreate,
{group: TEST_GROUP_ID}, this.workspace.id, TEST_BLOCK_ID);
// Finished loading event should not be part of event group.
diff --git a/tests/mocha/trashcan_test.js b/tests/mocha/trashcan_test.js
index 9e0122d71ee..3a8bed2455b 100644
--- a/tests/mocha/trashcan_test.js
+++ b/tests/mocha/trashcan_test.js
@@ -10,7 +10,7 @@ suite("Trashcan", function() {
'' +
xmlString + '');
xml = xml.children[0];
- var event = new Blockly.Events.Delete();
+ var event = new Blockly.Events.BlockDelete();
event.oldXml = xml;
event.workspaceId = workspace.id;
Blockly.Events.fire(event);