From f9e0552c11cecb98605557710b241606f605cb66 Mon Sep 17 00:00:00 2001 From: Tim Dawborn Date: Wed, 28 Dec 2016 12:26:53 +1100 Subject: [PATCH 1/2] Add an `allInputsConnected` method to `Block` and `Workspace` to test whether all trees in the block forest have their inputs filled. An optional argument controls whether or not shadow blocks are counted as being filled. Recommitting changes off `develop` instead of `master` as per discussion in PR #791. --- core/block.js | 34 ++++++++++++++++++++++++++++++++++ core/workspace.js | 17 +++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/core/block.js b/core/block.js index 4730c1cd6..25f09ee14 100644 --- a/core/block.js +++ b/core/block.js @@ -1335,3 +1335,37 @@ Blockly.Block.prototype.moveBy = function(dx, dy) { Blockly.Block.prototype.makeConnection_ = function(type) { return new Blockly.Connection(this, type); }; + +/** + * Recursively checks whether all statement and value inputs are filled with + * blocks. Also checks all following statement blocks in this stack. + * @param {boolean=} opt_shadowBlocksAreFilled An optional argument controlling + * whether shadow blocks are counted as filled. Defaults to true. + * @return {boolean} True if all inputs are filled, false otherwise. + */ +Blockly.Block.prototype.allInputsFilled = function(opt_shadowBlocksAreFilled) { + // Handle the default value for the optional argument. + if (opt_shadowBlocksAreFilled === undefined) { + opt_shadowBlocksAreFilled = true; + } + + for (var i = 0, input; input = this.inputList[i]; i++) { + if (!input.connection) { + continue; + } + var target = input.connection.targetBlock(); + if (!target || !target.allInputsFilled(opt_shadowBlocksAreFilled)) { + return false; + } + if (!opt_shadowBlocksAreFilled && target.isShadow()) { + return false; + } + } + + var next = this.getNextBlock(); + if (next) { + return next.allInputsFilled(opt_shadowBlocksAreFilled); + } + + return true; +}; diff --git a/core/workspace.js b/core/workspace.js index 46661f532..95dc26c00 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -478,6 +478,23 @@ Blockly.Workspace.prototype.getBlockById = function(id) { return this.blockDB_[id] || null; }; +/** + * Checks whether all value and statement inputs in the workspace are filled + * with blocks. + * @param {boolean=} opt_shadowBlocksAreFilled An optional argument controlling + * whether shadow blocks are counted as filled. Defaults to true. + * @return {boolean} True if all inputs are filled, false otherwise. + */ +Blockly.Workspace.prototype.allInputsFilled = function(opt_shadowBlocksAreFilled) { + var blocks = this.getTopBlocks(false); + for (var i = 0, block; block = blocks[i]; i++) { + if (!block.allInputsFilled(opt_shadowBlocksAreFilled)) { + return false; + } + } + return true; +}; + /** * Database of all workspaces. * @private From 69df716ef53fad06251af84a6086e40412d0ca47 Mon Sep 17 00:00:00 2001 From: Tim Dawborn Date: Mon, 16 Jan 2017 08:48:11 +1100 Subject: [PATCH 2/2] Fixes as per code review on PR. --- core/block.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/block.js b/core/block.js index 25f09ee14..48181f9d8 100644 --- a/core/block.js +++ b/core/block.js @@ -1344,11 +1344,15 @@ Blockly.Block.prototype.makeConnection_ = function(type) { * @return {boolean} True if all inputs are filled, false otherwise. */ Blockly.Block.prototype.allInputsFilled = function(opt_shadowBlocksAreFilled) { - // Handle the default value for the optional argument. + // Account for the shadow block filledness toggle. if (opt_shadowBlocksAreFilled === undefined) { opt_shadowBlocksAreFilled = true; } + if (!opt_shadowBlocksAreFilled && this.isShadow()) { + return false; + } + // Recursively check each input block of the current block. for (var i = 0, input; input = this.inputList[i]; i++) { if (!input.connection) { continue; @@ -1357,11 +1361,9 @@ Blockly.Block.prototype.allInputsFilled = function(opt_shadowBlocksAreFilled) { if (!target || !target.allInputsFilled(opt_shadowBlocksAreFilled)) { return false; } - if (!opt_shadowBlocksAreFilled && target.isShadow()) { - return false; - } } + // Recursively check the next block after the current block. var next = this.getNextBlock(); if (next) { return next.allInputsFilled(opt_shadowBlocksAreFilled);