diff --git a/demos/blocklyfactory/workspacefactory/wfactory_controller.js b/demos/blocklyfactory/workspacefactory/wfactory_controller.js index 46adc91c7..40af136e2 100644 --- a/demos/blocklyfactory/workspacefactory/wfactory_controller.js +++ b/demos/blocklyfactory/workspacefactory/wfactory_controller.js @@ -117,6 +117,8 @@ WorkspaceFactoryController.prototype.addCategory = function() { this.view.setCategoryTabSelection(id, true); // Allow user to use the default options for injecting with categories. this.allowToSetDefaultOptions(); + // Update preview here in case exit early. + this.updatePreview(); } } @@ -860,12 +862,62 @@ WorkspaceFactoryController.prototype.addShadow = function() { if (!Blockly.selected) { return; } - this.view.markShadowBlock(Blockly.selected); - this.model.addShadowBlock(Blockly.selected.id); + // Clear any previous warnings on the block (would only have warnings on + // a non-shadow block if it was nested inside another shadow block). + Blockly.selected.setWarningText(null); + // Set selected block and all children as shadow blocks. + this.addShadowForBlockAndChildren_(Blockly.selected); + + // Save and update the preview. this.saveStateFromWorkspace(); this.updatePreview(); }; +/** + * Sets a block and all of its children to be user-generated shadow blocks, + * both in the model and view. + * @private + * + * @param {!Blockly.Block} block The block to be converted to a user-generated + * shadow block. + */ +WorkspaceFactoryController.prototype.addShadowForBlockAndChildren_ = + function(block) { + // Convert to shadow block. + this.view.markShadowBlock(block); + this.model.addShadowBlock(block.id); + + if (this.hasVariableField(block)) { + block.setWarningText('Cannot make variable blocks shadow blocks.'); + } + + // Convert all children to shadow blocks recursively. + var children = block.getChildren(); + for (var i = 0; i < children.length; i++) { + this.addShadowForBlockAndChildren_(children[i]); + } +}; + +/** + * Checks if a block has a variable field. Blocks with variable fields cannot + * be shadow blocks. + * + * @param {Blockly.Block} block The block to check if a variable field exists. + * @return {boolean} True if the block has a variable field, false otherwise. + */ +WorkspaceFactoryController.prototype.hasVariableField = function(block) { + if (!block) { + return false; + } + for (var i = 0; i < block.inputList.length; i++) { + if (block.inputList[i].fieldRow.length > 0 && + block.inputList[i].fieldRow[0].name == 'VAR') { + return true; + } + } + return false; +}; + /** * If the currently selected block is a user-generated shadow block, this * function makes it a normal block again, removing it from the list of @@ -879,6 +931,10 @@ WorkspaceFactoryController.prototype.removeShadow = function() { } this.model.removeShadowBlock(Blockly.selected.id); this.view.unmarkShadowBlock(Blockly.selected); + + // If turning invalid shadow block back to normal block, remove warning. + Blockly.selected.setWarningText(null); + this.saveStateFromWorkspace(); this.updatePreview(); }; diff --git a/demos/blocklyfactory/workspacefactory/wfactory_init.js b/demos/blocklyfactory/workspacefactory/wfactory_init.js index dc73183da..96ca6f2f4 100644 --- a/demos/blocklyfactory/workspacefactory/wfactory_init.js +++ b/demos/blocklyfactory/workspacefactory/wfactory_init.js @@ -339,9 +339,8 @@ document.getElementById('button_import').addEventListener controller.removeShadow(); document.getElementById('dropdownDiv_editShadowRemove').classList. remove("show"); - // If turning invalid shadow block back to normal block, remove - // warning and disable block editing privileges. - Blockly.selected.setWarningText(null); + // Disable shadow editing button if turning invalid shadow block back + // to normal block. if (!Blockly.selected.getSurroundParent()) { document.getElementById('button_editShadow').disabled = true; } @@ -374,6 +373,16 @@ WorkspaceFactoryInit.addWorkspaceFactoryEventListeners_ = function(controller) { } }); + // Determines if a block breaks shadow block placement rules. + // Breaks rules if (1) a shadow block no longer has a valid + // parent, or (2) a normal block is inside of a shadow block. + var isInvalidBlockPlacement = function(block) { + return ((controller.isUserGenShadowBlock(block.id) && + !block.getSurroundParent()) || + (!controller.isUserGenShadowBlock(block.id) && block.getSurroundParent() + && controller.isUserGenShadowBlock(block.getSurroundParent().id))); + } + // Add change listeners for toolbox workspace in workspace factory. controller.toolboxWorkspace.addChangeListener(function(e) { // Listen for Blockly move and delete events to update preview. @@ -394,24 +403,48 @@ WorkspaceFactoryInit.addWorkspaceFactoryEventListeners_ = function(controller) { e.element == 'selected')) { var selected = Blockly.selected; - if (selected != null && selected.getSurroundParent() != null) { + if (selected != null && selected.getSurroundParent() != null && + !controller.isUserGenShadowBlock(selected.getSurroundParent().id)) { + // Selected block is a valid shadow block or could be a valid shadow + // block. - // A valid shadow block is selected. Enable block editing and remove - // warnings. + // Enable block editing and remove warnings if the block is not a + // variable user-generated shadow block. document.getElementById('button_editShadow').disabled = false; - Blockly.selected.setWarningText(null); + if (!controller.hasVariableField(selected)) { + selected.setWarningText(null); + } } else { - if (selected != null && controller.isUserGenShadowBlock(selected.id)) { + // Selected block cannot be a valid shadow block. - // Provide warning if shadow block is moved and is no longer a valid - // shadow block. - Blockly.selected.setWarningText('Shadow blocks must be nested' + - ' inside other blocks to be displayed.'); + if (selected != null && isInvalidBlockPlacement(selected)) { + // Selected block breaks shadow block rules. + // Invalid shadow block if (1) a shadow block no longer has a valid + // parent, or (2) a normal block is inside of a shadow block. + + if (!controller.isUserGenShadowBlock(selected.id)) { + // Warn if a non-shadow block is nested inside a shadow block. + selected.setWarningText('Only shadow blocks can be nested inside ' + + 'other shadow blocks.'); + } else if (!controller.hasVariableField(selected)) { + // Warn if a shadow block is invalid only if not replacing + // warning for variables. + selected.setWarningText('Shadow blocks must be nested inside other' + + ' blocks.') + } // Give editing options so that the user can make an invalid shadow // block a normal block. document.getElementById('button_editShadow').disabled = false; } else { + // Selected block does not break any shadow block rules, but cannot + // be a shadow block. + + // Remove possible 'invalid shadow block placement' warning. + if (selected != null && (!controller.hasVariableField(selected) || + !controller.isUserGenShadowBlock(selected.id))) { + selected.setWarningText(null); + } // No block selected that is a shadow block or could be a valid shadow // block. Disable block editing.