diff --git a/core/connection.js b/core/connection.js index 427a6ed68..a144e1b8c 100644 --- a/core/connection.js +++ b/core/connection.js @@ -108,7 +108,7 @@ Blockly.Connection.prototype.connect_ = function(childConnection) { var orphanBlock = parentConnection.targetBlock(); var shadowDom = parentConnection.getShadowDom(); // Temporarily set the shadow DOM to null so it does not respawn. - parentConnection.setShadowDom(null); + parentConnection.shadowDom_ = null; // Displaced shadow blocks dissolve rather than reattaching or bumping. if (orphanBlock.isShadow()) { // Save the shadow block so that field values are preserved. @@ -175,7 +175,7 @@ Blockly.Connection.prototype.connect_ = function(childConnection) { } } // Restore the shadow DOM. - parentConnection.setShadowDom(shadowDom); + parentConnection.shadowDom_ = shadowDom; } var event; @@ -200,12 +200,11 @@ Blockly.Connection.prototype.dispose = function() { // isConnected returns true for shadows and non-shadows. if (this.isConnected()) { + // Destroy the attached shadow block & its children (if it exists). this.setShadowDom(null); + var targetBlock = this.targetBlock(); - if (targetBlock.isShadow()) { - // Destroy the attached shadow block & its children. - targetBlock.dispose(false); - } else { + if (targetBlock) { // Disconnect the attached normal block. targetBlock.unplug(); } @@ -672,15 +671,22 @@ Blockly.Connection.prototype.getCheck = function() { }; /** - * Change a connection's shadow block. + * Changes the connection's shadow block. * @param {Element} shadow DOM representation of a block or null. */ Blockly.Connection.prototype.setShadowDom = function(shadow) { this.shadowDom_ = shadow; + var target = this.targetBlock(); + if (!target) { + this.respawnShadow_(); + } else if (target.isShadow()) { + // The disconnect from dispose will automatically generate the new shadow. + target.dispose(false); + } }; /** - * Return a connection's shadow block. + * Returns the xml representation of the connection's shadow block. * @return {Element} Shadow DOM representation of a block or null. */ Blockly.Connection.prototype.getShadowDom = function() { diff --git a/core/input.js b/core/input.js index aeb60a9de..dd56adf6a 100644 --- a/core/input.js +++ b/core/input.js @@ -231,6 +231,30 @@ Blockly.Input.prototype.setAlign = function(align) { return this; }; +/** + * Changes the connection's shadow block. + * @param {Element} shadow DOM representation of a block or null. + * @return {Blockly.Input} The input being modified (to allow chaining). + */ +Blockly.Input.prototype.setShadowDom = function(shadow) { + if (!this.connection) { + throw Error('This input does not have a connection.'); + } + this.connection.setShadowDom(shadow); + return this; +}; + +/** + * Returns the xml representation of the connection's shadow block. + * @return {Element} Shadow DOM representation of a block or null. + */ +Blockly.Input.prototype.getShadowDom = function() { + if (!this.connection) { + throw Error('This input does not have a connection.'); + } + return this.connection.getShadowDom(); +}; + /** * Initialize the fields on this input. */ diff --git a/core/xml.js b/core/xml.js index 45b3e0ca6..e2ce6974e 100644 --- a/core/xml.js +++ b/core/xml.js @@ -661,10 +661,6 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { } } } - // Use the shadow block if there is no child block. - if (!childBlockElement && childShadowElement) { - childBlockElement = childShadowElement; - } var name = xmlChild.getAttribute('name'); var xmlChildElement = /** @type {!Element} */ (xmlChild); @@ -719,9 +715,6 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { prototypeName); break; } - if (childShadowElement) { - input.connection.setShadowDom(childShadowElement); - } if (childBlockElement) { blockChild = Blockly.Xml.domToBlockHeadless_(childBlockElement, workspace); @@ -734,11 +727,12 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { 'Child block does not have output or previous statement.'); } } + // Set shadow after so we don't create a shadow we delete immediately. + if (childShadowElement) { + input.connection.setShadowDom(childShadowElement); + } break; case 'next': - if (childShadowElement && block.nextConnection) { - block.nextConnection.setShadowDom(childShadowElement); - } if (childBlockElement) { if (!block.nextConnection) { throw TypeError('Next statement does not exist.'); @@ -754,6 +748,10 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { } block.nextConnection.connect(blockChild.previousConnection); } + // Set shadow after so we don't create a shadow we delete immediately. + if (childShadowElement && block.nextConnection) { + block.nextConnection.setShadowDom(childShadowElement); + } break; default: // Unknown tag; ignore. Same principle as HTML parsers. diff --git a/tests/mocha/connection_test.js b/tests/mocha/connection_test.js index f78584cfa..33f785756 100644 --- a/tests/mocha/connection_test.js +++ b/tests/mocha/connection_test.js @@ -184,4 +184,1027 @@ suite('Connections', function() { chai.assert.isFalse(this.con1.checkType((this.con2))); }); }); + suite('Set Shadow Dom', function() { + setup(function() { + Blockly.defineBlocksWithJsonArray([ + { + "type": "stack_block", + "message0": "", + "previousStatement": null, + "nextStatement": null + }, + { + "type": "row_block", + "message0": "%1", + "args0": [ + { + "type": "input_value", + "name": "INPUT" + } + ], + "output": null + }, + { + "type": "statement_block", + "message0": "%1", + "args0": [ + { + "type": "input_statement", + "name": "STATEMENT" + } + ], + "previousStatement": null, + "nextStatement": null + }]); + + this.runHeadlessAndRendered = function(func, context) { + var workspace = new Blockly.Workspace(); + func.call(context, workspace); + workspace.clear(); + workspace.dispose(); + + workspace = Blockly.inject('blocklyDiv'); + func.call(context, workspace); + workspace.clear(); + workspace.dispose(); + }; + }); + teardown(function() { + delete this.runHeadlessAndRendered; + delete Blockly.Blocks['stack_block']; + delete Blockly.Blocks['row_block']; + delete Blockly.Blocks['statement_block']; + }); + suite('Add - No Block Connected', function() { + setup(function() { + // These are defined separately in each suite. + this.createRowBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), workspace); + return block; + }; + + this.createStatementBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), workspace); + return block; + }; + + this.createStackBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), workspace); + return block; + }; + }); + teardown(function() { + delete this.createRowBlock; + delete this.createStatementBlock; + delete this.createStackBlock; + }); + test('Value', function() { + var func = function(workspace) { + var parent = this.createRowBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Value', function() { + var func = function(workspace) { + var parent = this.createRowBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Next', function() { + var func = function(workspace) { + var parent = this.createStackBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Next', function() { + var func = function(workspace) { + var parent = this.createStackBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getNextBlock(); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + }); + suite('Add - With Block Connected', function() { + setup(function() { + // These are defined separately in each suite. + this.createRowBlocks = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ), workspace); + return block; + }; + + this.createStatementBlocks = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ), workspace); + return block; + }; + + this.createStackBlocks = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ), workspace); + return block; + }; + }); + teardown(function() { + delete this.createRowBlocks; + delete this.createStatementBlock; + delete this.createStackBlock; + }); + test('Value', function() { + var func = function(workspace) { + var parent = this.createRowBlocks(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.getInput('INPUT').connection.disconnect(); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Value', function() { + var func = function(workspace) { + var parent = this.createRowBlocks(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + var target2 = target.getInputTargetBlock('INPUT'); + chai.assert.isNull(target2); + + parent.getInput('INPUT').connection.disconnect(); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlocks(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.getInput('STATEMENT').connection.disconnect(); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlocks(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + var target2 = target.getInputTargetBlock('STATEMENT'); + chai.assert.isNull(target2); + + parent.getInput('STATEMENT').connection.disconnect(); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Next', function() { + var func = function(workspace) { + var parent = this.createStackBlocks(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.nextConnection.disconnect(); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Next', function() { + var func = function(workspace) { + var parent = this.createStackBlocks(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + var target2 = target.getNextBlock(); + chai.assert.isNull(target2); + + parent.nextConnection.disconnect(); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getNextBlock(); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + }; + this.runHeadlessAndRendered(func, this); + }); + }); + suite('Add - With Shadow Connected', function() { + setup(function() { + // These are defined separately in each suite. + this.createRowBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), workspace); + return block; + }; + + this.createStatementBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), workspace); + return block; + }; + + this.createStackBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), workspace); + return block; + }; + }); + teardown(function() { + delete this.createRowBlock; + delete this.createStatementBlock; + delete this.createStackBlock; + }); + test('Value', function() { + var func = function(workspace) { + var parent = this.createRowBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '1'); + + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target2 = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + chai.assert.equal(target2.id, '2'); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Value', function() { + var func = function(workspace) { + var parent = this.createRowBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '1'); + var target2 = target.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + chai.assert.equal(target2.id, 'a'); + + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '2'); + var target2 = target.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + chai.assert.equal(target2.id, 'b'); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '1'); + + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '2'); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '1'); + var target2 = target.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + chai.assert.equal(target2.id, 'a'); + + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '2'); + var target2 = target.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + chai.assert.equal(target2.id, 'b'); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Next', function() { + var func = function(workspace) { + var parent = this.createStackBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '1'); + + var xml = Blockly.Xml.textToDom( + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '2'); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Next', function() { + var func = function(workspace) { + var parent = this.createStackBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '1'); + var target2 = target.getNextBlock(); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + chai.assert.equal(target2.id, 'a'); + + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + chai.assert.equal(target.id, '2'); + var target2 = target.getNextBlock(); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + chai.assert.equal(target2.id, 'b'); + }; + this.runHeadlessAndRendered(func, this); + }); + }); + suite('Remove - No Block Connected', function() { + setup(function() { + // These are defined separately in each suite. + this.createRowBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ), workspace); + return block; + }; + + this.createStatementBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ), workspace); + return block; + }; + + this.createStackBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ), workspace); + return block; + }; + }); + teardown(function() { + delete this.createRowBlock; + delete this.createStatementBlock; + delete this.createStackBlock; + }); + test('Value', function() { + var func = function(workspace) { + var parent = this.createRowBlock(workspace); + parent.getInput('INPUT').connection.setShadowDom(null); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlock(workspace); + parent.getInput('STATEMENT').connection.setShadowDom(null); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Next', function() { + var func = function(workspace) { + var parent = this.createStackBlock(workspace); + parent.nextConnection.setShadowDom(null); + + var target = parent.getNextBlock(); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + }); + suite('Remove - Block Connected', function() { + setup(function() { + // These are defined separately in each suite. + this.createRowBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), workspace); + return block; + }; + + this.createStatementBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), workspace); + return block; + }; + + this.createStackBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + ), workspace); + return block; + }; + }); + teardown(function() { + delete this.createRowBlock; + delete this.createStatementBlock; + delete this.createStackBlock; + }); + test('Value', function() { + var func = function(workspace) { + var parent = this.createRowBlock(workspace); + parent.getInput('INPUT').connection.setShadowDom(null); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.getInput('INPUT').connection.disconnect(); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlock(workspace); + parent.getInput('STATEMENT').connection.setShadowDom(null); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.getInput('STATEMENT').connection.disconnect(); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Next', function() { + var func = function(workspace) { + var parent = this.createStackBlock(workspace); + parent.nextConnection.setShadowDom(null); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.nextConnection.disconnect(); + + var target = parent.getNextBlock(); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + }); + suite('Add - Connect & Disconnect - Remove', function() { + setup(function() { + // These are defined separately in each suite. + this.createRowBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), workspace); + return block; + }; + + this.createStatementBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), workspace); + return block; + }; + + this.createStackBlock = function(workspace) { + var block = Blockly.Xml.domToBlock(Blockly.Xml.textToDom( + '' + ), workspace); + return block; + }; + }); + teardown(function() { + delete this.createRowBlock; + delete this.createStatementBlock; + delete this.createStackBlock; + }); + test('Value', function() { + var func = function(workspace) { + var parent = this.createRowBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + + var child = this.createRowBlock(workspace); + parent.getInput('INPUT').connection.connect(child.outputConnection); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.getInput('INPUT').connection.disconnect(); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + + parent.getInput('INPUT').connection.setShadowDom(null); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Value', function() { + var func = function(workspace) { + var parent = this.createRowBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('INPUT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + + var child = this.createRowBlock(workspace); + parent.getInput('INPUT').connection.connect(child.outputConnection); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.getInput('INPUT').connection.disconnect(); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getInputTargetBlock('INPUT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + + parent.getInput('INPUT').connection.setShadowDom(null); + + var target = parent.getInputTargetBlock('INPUT'); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + + var child = this.createStatementBlock(workspace); + parent.getInput('STATEMENT').connection + .connect(child.previousConnection); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.getInput('STATEMENT').connection.disconnect(); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + + parent.getInput('STATEMENT').connection.setShadowDom(null); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Statement', function() { + var func = function(workspace) { + var parent = this.createStatementBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.getInput('STATEMENT').connection.setShadowDom(xml); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + + var child = this.createStatementBlock(workspace); + parent.getInput('STATEMENT').connection + .connect(child.previousConnection); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.getInput('STATEMENT').connection.disconnect(); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getInputTargetBlock('STATEMENT'); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + + parent.getInput('STATEMENT').connection.setShadowDom(null); + + var target = parent.getInputTargetBlock('STATEMENT'); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Next', function() { + var func = function(workspace) { + var parent = this.createStackBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + + var child = this.createStatementBlock(workspace); + parent.nextConnection.connect(child.previousConnection); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.nextConnection.disconnect(); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + + parent.nextConnection.setShadowDom(null); + + var target = parent.getNextBlock(); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + test('Multiple Next', function() { + var func = function(workspace) { + var parent = this.createStackBlock(workspace); + var xml = Blockly.Xml.textToDom( + '' + + ' ' + + ' ' + + ' ' + + '' + ); + parent.nextConnection.setShadowDom(xml); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getNextBlock(); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + + var child = this.createStatementBlock(workspace); + parent.nextConnection.connect(child.previousConnection); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isFalse(target.isShadow()); + + parent.nextConnection.disconnect(); + + var target = parent.getNextBlock(); + chai.assert.isNotNull(target); + chai.assert.isTrue(target.isShadow()); + var target2 = target.getNextBlock(); + chai.assert.isNotNull(target2); + chai.assert.isTrue(target2.isShadow()); + + parent.nextConnection.setShadowDom(null); + + var target = parent.getNextBlock(); + chai.assert.isNull(target); + }; + this.runHeadlessAndRendered(func, this); + }); + }); + }); });