From 7516866804177d0b14982da411684ba168184dd9 Mon Sep 17 00:00:00 2001 From: Tina Quach Date: Mon, 22 Aug 2016 18:07:52 -0700 Subject: [PATCH] Blockly Factory: Select Used Blocks for Export (#565) * addAllUsedBlocks in exporter works when you hand set the instance variable. added click handler for export button (which got lost in refactor). saveStateFromWorkspace on tab switch fixed bug in deselect block in exporter; added warning alert for add all used blocks * nit line * not warning for standard block types --- demos/blocklyfactory/app_controller.js | 18 +++++- .../block_exporter_controller.js | 61 ++++++++++++++++++- .../block_library_controller.js | 3 +- demos/blocklyfactory/block_library_storage.js | 11 ++++ demos/blocklyfactory/factory_utils.js | 1 + .../workspacefactory/wfactory_controller.js | 9 +++ .../workspacefactory/wfactory_model.js | 10 +-- 7 files changed, 103 insertions(+), 10 deletions(-) diff --git a/demos/blocklyfactory/app_controller.js b/demos/blocklyfactory/app_controller.js index 58477cb41..c698ad785 100644 --- a/demos/blocklyfactory/app_controller.js +++ b/demos/blocklyfactory/app_controller.js @@ -294,6 +294,14 @@ AppController.prototype.onTab = function() { // Update toolbox to reflect current block library. this.exporter.updateToolbox(); + // Need accurate state in order to know which blocks are used in workspace + // factory. + this.workspaceFactoryController.saveStateFromWorkspace(); + + // Update exporter's list of the types of blocks used in workspace factory. + var usedBlockTypes = this.workspaceFactoryController.getAllUsedBlockTypes(); + this.exporter.setUsedBlockTypes(usedBlockTypes); + // Show container of exporter. FactoryUtils.show('blockLibraryExporter'); FactoryUtils.hide('workspaceFactoryContent'); @@ -336,7 +344,7 @@ AppController.prototype.styleTabs_ = function() { */ AppController.prototype.assignExporterClickHandlers = function() { var self = this; - // Export blocks when the user submits the export settings. + document.getElementById('button_setBlocks').addEventListener('click', function() { document.getElementById('dropdownDiv_setBlocks').classList.toggle("show"); @@ -344,7 +352,7 @@ AppController.prototype.assignExporterClickHandlers = function() { document.getElementById('dropdown_addAllUsed').addEventListener('click', function() { - self.exporter.export(); + self.exporter.addUsedBlocksToWorkspace(); document.getElementById('dropdownDiv_setBlocks').classList.remove("show"); }); @@ -359,6 +367,12 @@ AppController.prototype.assignExporterClickHandlers = function() { self.exporter.addAllBlocksToWorkspace(); document.getElementById('dropdownDiv_setBlocks').classList.remove("show"); }); + + // Export blocks when the user submits the export settings. + document.getElementById('exporterSubmitButton').addEventListener('click', + function() { + self.exporter.export(); + }); }; /** diff --git a/demos/blocklyfactory/block_exporter_controller.js b/demos/blocklyfactory/block_exporter_controller.js index d6c6fd649..ec1d82449 100644 --- a/demos/blocklyfactory/block_exporter_controller.js +++ b/demos/blocklyfactory/block_exporter_controller.js @@ -51,6 +51,8 @@ BlockExporterController = function(blockLibStorage) { this.view = new BlockExporterView( //Xml representation of the toolbox this.tools.generateToolboxFromLibrary(this.blockLibStorage)); + // Array to hold the block types used in workspace factory. + this.usedBlockTypes = []; }; /** @@ -283,7 +285,7 @@ BlockExporterController.prototype.onDeselectBlockForExport_ = function(event) { var deletedBlockXml = event.oldXml; var blockType = deletedBlockXml.getAttribute('type'); // Do not try to enable any blocks deleted from the block library. - if (this.blockLibStorage[blockType]) { + if (this.blockLibStorage.has(blockType)) { // Enable the deselected block. this.setBlockEnabled(blockType, true); } @@ -332,3 +334,60 @@ BlockExporterController.prototype.addAllBlocksToWorkspace = function() { BlockExporterController.prototype.getBlockLibCategory = function() { return this.tools.generateCategoryFromBlockLib(this.blockLibStorage); }; + +/** + * Tied to the 'Add All Stored Blocks' button in the Block Exporter. + * Adds all blocks stored in block library to the selector workspace. + */ +BlockExporterController.prototype.addUsedBlocksToWorkspace = function() { + // Clear selector workspace. + this.view.clearSelectorWorkspace(); + + // Get list of block types that are in block library and used in workspace + // factory. + var storedBlockTypes = this.blockLibStorage.getBlockTypes(); + var sharedBlockTypes = []; + // Keep list of custom block types used but not in library. + var unstoredCustomBlockTypes = []; + + for (var i = 0, blockType; blockType = this.usedBlockTypes[i]; i++) { + if (storedBlockTypes.indexOf(blockType) != -1) { + sharedBlockTypes.push(blockType); + } else if (BlockFactory.standardBlockTypes.indexOf(blockType) == -1) { + unstoredCustomBlockTypes.push(blockType); + } + } + + // Add and evaluate the shared blocks' definitions. + var blockXmlMap = this.blockLibStorage.getBlockXmlMap(sharedBlockTypes); + this.tools.addBlockDefinitions(blockXmlMap); + + // For every block, render in selector workspace. + for (var i = 0, blockType; blockType = sharedBlockTypes[i]; i++) { + this.view.addBlock(blockType); + } + + // Clean up workspace. + this.view.cleanUpSelectorWorkspace(); + + if (unstoredCustomBlockTypes.length > 0){ + // Warn user to import block definitions and generator code for blocks + // not in their Block Library nor Blockly's standard library. + var blockTypesText = unstoredCustomBlockTypes.join(', '); + var customWarning = 'Custom blocks used in workspace factory but not ' + + 'stored in block library:\n ' + blockTypesText + + '\n\nDon\'t forget to include block definitions and generator code ' + + 'for these blocks.'; + alert(customWarning); + } +}; + +/** + * Set the array that holds the block types used in workspace factory. + * + * @param {!Array.} usedBlockTypes - Block types used in + */ +BlockExporterController.prototype.setUsedBlockTypes = + function(usedBlockTypes) { + this.usedBlockTypes = usedBlockTypes; +}; diff --git a/demos/blocklyfactory/block_library_controller.js b/demos/blocklyfactory/block_library_controller.js index 514eeaaeb..62a3a747a 100644 --- a/demos/blocklyfactory/block_library_controller.js +++ b/demos/blocklyfactory/block_library_controller.js @@ -208,8 +208,7 @@ BlockLibraryController.prototype.setBlockLibStorage * @return {!BlockLibraryStorage} blockLibStorage - Block Library Storage object * that stores the blocks. */ -BlockLibraryController.prototype.getBlockLibStorage = - function(blockLibStorage) { +BlockLibraryController.prototype.getBlockLibStorage = function() { return this.blockLibStorage; }; diff --git a/demos/blocklyfactory/block_library_storage.js b/demos/blocklyfactory/block_library_storage.js index 4bca70242..c4361959e 100644 --- a/demos/blocklyfactory/block_library_storage.js +++ b/demos/blocklyfactory/block_library_storage.js @@ -165,3 +165,14 @@ BlockLibraryStorage.prototype.isEmpty = function() { BlockLibraryStorage.prototype.getBlockXmlTextMap = function() { return this.blocks; }; + +/** + * Returns boolean of whether or not a given blockType is stored in block + * library. + * + * @param {string} blockType - Type of block. + * @return {boolean} Whether or not blockType is stored in block library. + */ +BlockLibraryStorage.prototype.has = function(blockType) { + return this.blocks[blockType] ? true : false; +}; diff --git a/demos/blocklyfactory/factory_utils.js b/demos/blocklyfactory/factory_utils.js index 35a677d68..c167f7136 100644 --- a/demos/blocklyfactory/factory_utils.js +++ b/demos/blocklyfactory/factory_utils.js @@ -872,3 +872,4 @@ FactoryUtils.defineAndGetBlockTypes = function(blockDefsString, format) { return blockTypes; }; + diff --git a/demos/blocklyfactory/workspacefactory/wfactory_controller.js b/demos/blocklyfactory/workspacefactory/wfactory_controller.js index 2c42b865f..da5749921 100644 --- a/demos/blocklyfactory/workspacefactory/wfactory_controller.js +++ b/demos/blocklyfactory/workspacefactory/wfactory_controller.js @@ -1192,3 +1192,12 @@ WorkspaceFactoryController.prototype.setBlockLibCategory = this.toolboxWorkspace.updateToolbox(this.toolbox); }; +/** + * Return the block types used in the custom toolbox and pre-loaded workspace. + * + * @return {!Array.} Block types used in the custom toolbox and + * pre-loaded workspace. + */ +WorkspaceFactoryController.prototype.getAllUsedBlockTypes = function() { + return this.model.getAllUsedBlockTypes(); +}; diff --git a/demos/blocklyfactory/workspacefactory/wfactory_model.js b/demos/blocklyfactory/workspacefactory/wfactory_model.js index 13154c11d..bcb622a11 100644 --- a/demos/blocklyfactory/workspacefactory/wfactory_model.js +++ b/demos/blocklyfactory/workspacefactory/wfactory_model.js @@ -436,7 +436,7 @@ WorkspaceFactoryModel.prototype.getAllUsedBlockTypes = function() { // Given XML for the workspace, adds all block types included in the XML // to the list, not including duplicates. - var pushBlockTypesToList = function (xml, list) { + var pushBlockTypesToList = function(xml, list) { // Get all block XML nodes. var blocks = xml.getElementsByTagName('block'); @@ -451,22 +451,22 @@ WorkspaceFactoryModel.prototype.getAllUsedBlockTypes = function() { if (this.flyout) { // If has a single flyout, add block types for the single flyout. - this.pushBlockTypesToList(this.getSelectedXml(), blockTypeList); + pushBlockTypesToList(this.getSelectedXml(), blockTypeList); } else { // If has categories, add block types for each category. for (var i = 0, category; category = this.toolboxList[i]; i++) { if (category.type == ListElement.TYPE_CATEGORY) { - this.pushBlockTypesToList(category.xml, blockTypeList); + pushBlockTypesToList(category.xml, blockTypeList); } } } // Add the block types from any pre-loaded blocks. - this.pushBlockTypesToList(this.getPreloadXml(), blockTypeList); + pushBlockTypesToList(this.getPreloadXml(), blockTypeList); return blockTypeList; -} +}; /** * Class for a ListElement.