diff --git a/core/block.js b/core/block.js index 0e92d660a..16c8604a3 100644 --- a/core/block.js +++ b/core/block.js @@ -511,6 +511,7 @@ Blockly.Block.prototype.setShadow = function(shadow) { } this.isShadow_ = shadow; if (Blockly.Events.isEnabled() && !shadow) { + Blockly.Events.group = Blockly.genUid(); // Fire a creation event. var xmlBlock = Blockly.Xml.blockToDom(this); Blockly.Events.fire(new Blockly.Events.Create(this.workspace, xmlBlock)); @@ -521,6 +522,7 @@ Blockly.Block.prototype.setShadow = function(shadow) { moveEvent.oldCoordinate = new goog.math.Coordinate(0, 0); moveEvent.recordNew(); Blockly.Events.fire(moveEvent); + Blockly.Events.group = ''; } }; diff --git a/core/block_svg.js b/core/block_svg.js index aab5cffa0..70db3bbbe 100644 --- a/core/block_svg.js +++ b/core/block_svg.js @@ -460,6 +460,7 @@ Blockly.BlockSvg.prototype.onMouseDown_ = function(e) { // dragged instead. return; } else { + Blockly.Events.group = Blockly.genUid(); // Left-click (or middle click) Blockly.removeAllRanges(); Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED); @@ -528,6 +529,7 @@ Blockly.BlockSvg.prototype.onMouseUp_ = function(e) { Blockly.highlightedConnection_ = null; } Blockly.Css.setCursor(Blockly.Css.Cursor.OPEN); + Blockly.Events.group = ''; }; /** diff --git a/core/events.js b/core/events.js index ddef12665..222737f1c 100644 --- a/core/events.js +++ b/core/events.js @@ -27,6 +27,12 @@ goog.provide('Blockly.Events'); +/** + * Group ID for new events. Grouped events are indivisible. + * @type {string} + */ +Blockly.Events.group = ''; + /** * Allow change events to be created and fired. * @type {number} @@ -159,10 +165,14 @@ Blockly.Events.isEnabled = function() { }; /** - * Abstract class for a change event. + * Abstract class for an event. + * @param {!Blockly.Workspace} workspace The workspace. * @constructor */ -Blockly.Events.Abstract = function() {}; +Blockly.Events.Abstract = function(workspace) { + this.workspaceId = workspace.id; + this.group = Blockly.Events.group; +}; /** * Does this event record any change of state? @@ -180,12 +190,17 @@ Blockly.Events.Abstract.prototype.isNull = function() { * @constructor */ Blockly.Events.Create = function(workspace, xml) { - this.type = Blockly.Events.CREATE; - this.workspaceId = workspace.id; + Blockly.Events.Create.superClass_.constructor.call(this, workspace); this.xml = xml; }; goog.inherits(Blockly.Events.Create, Blockly.Events.Abstract); +/** + * Type of this event. + * @type {string} + */ +Blockly.Events.Create.prototype.type = Blockly.Events.CREATE; + /** * Class for a block deletion event. * @param {!Blockly.Block} block The deleted block. @@ -196,13 +211,18 @@ Blockly.Events.Delete = function(block) { if (block.getParent()) { throw 'Connected blocks cannot be deleted.'; } - this.type = Blockly.Events.DELETE; - this.workspaceId = block.workspace.id; + Blockly.Events.Delete.superClass_.constructor.call(this, block.workspace); this.blockId = block.id; this.oldXml = Blockly.Xml.blockToDomWithXY(block); }; goog.inherits(Blockly.Events.Delete, Blockly.Events.Abstract); +/** + * Type of this event. + * @type {string} + */ +Blockly.Events.Delete.prototype.type = Blockly.Events.DELETE; + /** * Class for a block change event. * @param {!Blockly.Block} block The deleted block. @@ -214,15 +234,20 @@ goog.inherits(Blockly.Events.Delete, Blockly.Events.Abstract); * @constructor */ Blockly.Events.Change = function(block, element, name, oldValue, newValue) { - this.type = Blockly.Events.CHANGE; - this.workspaceId = block.workspace.id; + Blockly.Events.Change.superClass_.constructor.call(this, block.workspace); this.blockId = block.id; this.element = element; this.name = name; this.oldValue = oldValue; this.newValue = newValue; }; -goog.inherits(Blockly.Events.Create, Blockly.Events.Abstract); +goog.inherits(Blockly.Events.Change, Blockly.Events.Abstract); + +/** + * Type of this event. + * @type {string} + */ +Blockly.Events.Change.prototype.type = Blockly.Events.CHANGE; /** * Does this event record any change of state? @@ -239,8 +264,7 @@ Blockly.Events.Change.prototype.isNull = function() { * @constructor */ Blockly.Events.Move = function(block) { - this.type = Blockly.Events.MOVE; - this.workspaceId = block.workspace.id; + Blockly.Events.Move.superClass_.constructor.call(this, block.workspace); this.blockId = block.id; var location = this.currentLocation_(); @@ -250,6 +274,12 @@ Blockly.Events.Move = function(block) { }; goog.inherits(Blockly.Events.Move, Blockly.Events.Abstract); +/** + * Type of this event. + * @type {string} + */ +Blockly.Events.Move.prototype.type = Blockly.Events.MOVE; + /** * Record the block's new location. Called after the move. */ diff --git a/tests/playground.html b/tests/playground.html index d8fadd60e..2f3d98167 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -81,6 +81,15 @@ function start() { scaleSpeed: 1.1 }, }); + // Restore previously displayed text. + var text = sessionStorage.getItem('textarea'); + if (text) { + document.getElementById('importExport').value = text; + } + taChange(); + // Restore event logging state. + var state = sessionStorage.getItem('logEvents'); + logEvents(Boolean(state)); } function toXml() { @@ -89,17 +98,49 @@ function toXml() { output.value = Blockly.Xml.domToPrettyText(xml); output.focus(); output.select(); + taChange(); } function fromXml() { var input = document.getElementById('importExport'); var xml = Blockly.Xml.textToDom(input.value); Blockly.Xml.domToWorkspace(workspace, xml); + taChange(); } function toCode(lang) { var output = document.getElementById('importExport'); output.value = Blockly[lang].workspaceToCode(workspace); + taChange(); +} + +// Disable the "Import from XML" button if the XML is invalid. +// Preserve text between page reloads. +function taChange() { + var textarea = document.getElementById('importExport'); + sessionStorage.setItem('textarea', textarea.value) + var valid = true; + try { + Blockly.Xml.textToDom(textarea.value); + } catch (e) { + valid = false; + } + document.getElementById('import').disabled = !valid; +} + +function logEvents(state) { + var checkbox = document.getElementById('logCheck'); + checkbox.checked = state; + sessionStorage.setItem('logEvents', Number(state)); + if (state) { + workspace.addChangeListener(logger); + } else { + workspace.removeChangeListener(logger); + } +} + +function logger(e) { + console.log(e); } function airstrike(n) { @@ -526,7 +567,7 @@ h1 {
-
+
@@ -536,15 +577,19 @@ h1 {
-
+
- Stress test: + Stress test:
++ Log events: + +