diff --git a/demos/blocklyfactory/index.html b/demos/blocklyfactory/index.html index 2a0139e2b..0f5af9e71 100644 --- a/demos/blocklyfactory/index.html +++ b/demos/blocklyfactory/index.html @@ -158,9 +158,9 @@ @@ -194,6 +194,7 @@ New Category Standard Category Separator + Standard Toolbox @@ -220,7 +221,7 @@

Configure the options for your Blockly inject call.

- +
Read Only
diff --git a/demos/blocklyfactory/workspacefactory/wfactory_controller.js b/demos/blocklyfactory/workspacefactory/wfactory_controller.js index af2f9b695..5f9d45e70 100644 --- a/demos/blocklyfactory/workspacefactory/wfactory_controller.js +++ b/demos/blocklyfactory/workspacefactory/wfactory_controller.js @@ -98,37 +98,8 @@ WorkspaceFactoryController.MODE_PRELOAD = 'preload'; * before), and then creates a tab and switches to it. */ WorkspaceFactoryController.prototype.addCategory = function() { - this.allowToTransferFlyoutBlocksToCategory(); - // Check if it's the first category added. - var isFirstCategory = !this.model.hasElements(); - // Give the option to save blocks if their workspace is not empty and they - // are creating their first category. - if (isFirstCategory && this.toolboxWorkspace.getAllBlocks().length > 0) { - var confirmCreate = confirm('Do you want to save your work in another ' - + 'category? If you don\'t, the blocks in your workspace will be ' + - 'deleted.'); - - // Create a new category for current blocks. - if (confirmCreate) { - var name = prompt('Enter the name of the category for your ' + - 'current blocks: '); - if (!name) { // Exit if cancelled. - return; - } - - // Create the new category. - this.createCategory(name, true); - // Set the new category as selected. - var id = this.model.getCategoryIdByName(name); - this.model.setSelectedById(id); - this.view.setCategoryTabSelection(id, true); - // Set default options if switching from single flyout to categories. - this.view.setCategoryOptions(this.model.hasElements()); - this.generateNewOptions(); - // Update preview here in case exit early. - this.updatePreview(); - } - } + // Transfers the user's blocks to a flyout if it's the first category created. + this.transferFlyoutBlocksToCategory(); // After possibly creating a category, check again if it's the first category. var isFirstCategory = !this.model.hasElements(); @@ -188,40 +159,28 @@ WorkspaceFactoryController.prototype.addClickToSwitch = function(tab, id) { }; /** - * Allows the user to transfer blocks in their flyout to a new category if + * Transfers the blocks in the user's flyout to a new category if * the user is creating their first category and their workspace is not * empty. Should be called whenever it is possible to switch from single flyout * to categories (not including importing). */ -WorkspaceFactoryController.prototype.allowToTransferFlyoutBlocksToCategory = +WorkspaceFactoryController.prototype.transferFlyoutBlocksToCategory = function() { - // Give the option to save blocks if their workspace is not empty and they - // are creating their first category. + // Saves the user's blocks from the flyout in a category if there is no + // toolbox and the user has dragged in blocks. if (!this.model.hasElements() && this.toolboxWorkspace.getAllBlocks().length > 0) { - var confirmCreate = confirm('Do you want to save your work in another ' - + 'category? If you don\'t, the blocks in your workspace will be ' + - 'deleted.'); - - // Create a new category for current blocks. - if (confirmCreate) { - var name = prompt('Enter the name of the category for your ' + - 'current blocks: '); - if (!name) { // Exit if cancelled. - return; - } - - // Create the new category. - this.createCategory(name, true); - // Set the new category as selected. - var id = this.model.getCategoryIdByName(name); - this.model.setSelectedById(id); - 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(); - } + // Create the new category. + this.createCategory('Category 1', true); + // Set the new category as selected. + var id = this.model.getCategoryIdByName('Category 1'); + this.model.setSelectedById(id); + this.view.setCategoryTabSelection(id, true); + // Allow user to use the default options for injecting with categories. + this.view.setCategoryOptions(this.model.hasElements()); + this.generateNewOptions(); + // Update preview here in case exit early. + this.updatePreview(); } }; @@ -391,15 +350,15 @@ WorkspaceFactoryController.prototype.exportXmlFile = function(exportMode) { * Export the options object to be used for the Blockly inject call. Gets a * file name from the user and downloads the options object to that file. */ -WorkspaceFactoryController.prototype.exportOptionsFile = function() { - var fileName = prompt('File Name for options object for injecting: '); +WorkspaceFactoryController.prototype.exportInjectFile = function() { + var fileName = prompt('File Name for starter Blockly workspace code: '); if (!fileName) { // If cancelled. return; } // Generate new options to remove toolbox XML from options object (if // necessary). this.generateNewOptions(); - var printableOptions = this.generator.generateOptionsString() + var printableOptions = this.generator.generateInjectString() var data = new Blob([printableOptions], {type: 'text/javascript'}); this.view.createAndDownloadFile(fileName, data); }; @@ -632,8 +591,9 @@ WorkspaceFactoryController.prototype.loadCategoryByName = function(name) { + '. Rename your category and try again.'); return; } - // Allow user to transfer current flyout blocks to a category. - this.allowToTransferFlyoutBlocksToCategory(); + // Transfers current flyout blocks to a category if it's the first category + // created. + this.transferFlyoutBlocksToCategory(); var isFirstCategory = !this.model.hasElements(); // Copy the standard category in the model. @@ -665,6 +625,22 @@ WorkspaceFactoryController.prototype.loadCategoryByName = function(name) { this.updatePreview(); }; +/** + * Loads the standard Blockly toolbox into the editing space. Should only + * be called when the mode is set to toolbox. + */ +WorkspaceFactoryController.prototype.loadStandardToolbox = function() { + this.loadCategoryByName('Logic'); + this.loadCategoryByName('Loops'); + this.loadCategoryByName('Math'); + this.loadCategoryByName('Text'); + this.loadCategoryByName('Lists'); + this.loadCategoryByName('Colour'); + this.addSeparator(); + this.loadCategoryByName('Variables'); + this.loadCategoryByName('Functions'); +} + /** * Given the name of a category, determines if it's the name of a standard * category (case insensitive). @@ -688,9 +664,9 @@ WorkspaceFactoryController.prototype.isStandardCategoryName = function(name) { * the separator, and updates the preview. */ WorkspaceFactoryController.prototype.addSeparator = function() { - // If adding the first element in the toolbox, allow the user to transfer - // their flyout blocks to a category. - this.allowToTransferFlyoutBlocksToCategory(); + // If adding the first element in the toolbox, transfers the user's blocks + // in a flyout to a category. + this.transferFlyoutBlocksToCategory(); // Create the separator in the model. var separator = new ListElement(ListElement.TYPE_SEPARATOR); this.model.addElementToList(separator); @@ -734,12 +710,32 @@ WorkspaceFactoryController.prototype.importFile = function(file, importMode) { try { var tree = Blockly.Xml.textToDom(reader.result); if (importMode == WorkspaceFactoryController.MODE_TOOLBOX) { - // Switch mode and import toolbox XML. + // Switch mode. controller.setMode(WorkspaceFactoryController.MODE_TOOLBOX); + + // Confirm that the user wants to override their current toolbox. + var hasToolboxElements = controller.model.hasElements() || + controller.getAllBlocks().length > 0; + if (hasToolboxElements && + !confirm('Are you sure you want to import? You will lose your ' + + 'current toolbox. ')) { + return; + } + // Import toolbox XML. controller.importToolboxFromTree_(tree); + } else if (importMode == WorkspaceFactoryController.MODE_PRELOAD) { - // Switch mode and import pre-loaded workspace XML. + // Switch mode. controller.setMode(WorkspaceFactoryController.MODE_PRELOAD); + + // Confirm that the user wants to override their current blocks. + if (controller.toolboxWorkspace.getAllBlocks().length > 0 && + !confirm('Are you sure you want to import? You will lose your ' + + 'current workspace blocks. ')) { + return; + } + + // Import pre-loaded workspace XML. controller.importPreloadFromTree_(tree); } else { // Throw error if invalid mode. @@ -883,6 +879,10 @@ WorkspaceFactoryController.prototype.importPreloadFromTree_ = function(tree) { * "Clear" button. */ WorkspaceFactoryController.prototype.clearAll = function() { + if (!confirm('Are you sure you want to clear all of your work in Workspace' + + ' Factory?')) { + return; + } var hasCategories = this.model.hasElements(); this.model.clearToolboxList(); this.view.clearToolboxTabs(); @@ -1196,8 +1196,17 @@ WorkspaceFactoryController.prototype.importBlocks = // Define blocks using block types from file. var blockTypes = FactoryUtils.defineAndGetBlockTypes(reader.result, format); - var blocks = controller.generator.getDefinedBlocks(blockTypes); + // If an imported block type is already defined, check if the user wants + // to override the current block definition. + if (controller.model.hasDefinedBlockTypes(blockTypes) && + !confirm('An imported block uses the same name as a block ' + + 'already in your toolbox. Are you sure you want to override the ' + + 'currently defined block?')) { + return; + } + + var blocks = controller.generator.getDefinedBlocks(blockTypes); // Generate category XML and append to toolbox. var categoryXml = FactoryUtils.generateCategoryXml(blocks, categoryName); // Get random color for category between 0 and 360. Gives each imported @@ -1207,9 +1216,10 @@ WorkspaceFactoryController.prototype.importBlocks = controller.toolbox.appendChild(categoryXml); controller.toolboxWorkspace.updateToolbox(controller.toolbox); // Update imported block types. - this.model.addImportedBlocks(blockTypes); + controller.model.addImportedBlockTypes(blockTypes); // Reload current category to possibly reflect any newly defined blocks. - this.clearAndLoadXml_(Blockly.Xml.workspaceToDom(this.toolboxWorkspace)); + controller.clearAndLoadXml_ + (Blockly.Xml.workspaceToDom(controller.toolboxWorkspace)); } catch (e) { alert('Cannot read blocks from file.'); window.console.log(e); diff --git a/demos/blocklyfactory/workspacefactory/wfactory_generator.js b/demos/blocklyfactory/workspacefactory/wfactory_generator.js index 8c2fa91d7..01d578f78 100644 --- a/demos/blocklyfactory/workspacefactory/wfactory_generator.js +++ b/demos/blocklyfactory/workspacefactory/wfactory_generator.js @@ -130,18 +130,18 @@ WorkspaceFactoryGenerator.prototype.generateWorkspaceXml = function() { // Generate XML and set attributes. var generatedXml = Blockly.Xml.workspaceToDom(this.hiddenWorkspace); - generatedXml.setAttribute('id', 'preload_blocks'); + generatedXml.setAttribute('id', 'workspaceBlocks'); generatedXml.setAttribute('style', 'display:none'); return generatedXml; }; /** * Generates a string representation of the options object for injecting the - * workspace. + * workspace and starter code. * - * @return {!string} String representation of options object. + * @return {!string} String representation of starter code for injecting. */ -WorkspaceFactoryGenerator.prototype.generateOptionsString = function() { +WorkspaceFactoryGenerator.prototype.generateInjectString = function() { var addAttributes = function(obj, tabChar) { if (!obj) { @@ -157,14 +157,28 @@ WorkspaceFactoryGenerator.prototype.generateOptionsString = function() { } else { var temp = tabChar + key + ' : ' + obj[key] + ', \n'; } - str = str.concat(temp); + str += temp; } var lastCommaIndex = str.lastIndexOf(','); str = str.slice(0, lastCommaIndex) + '\n'; return str; }; - return 'var options = { \n' + addAttributes(this.model.options, '\t') + '};'; + var attributes = addAttributes(this.model.options, '\t'); + if (!this.model.options['readOnly']) { + attributes = '\ttoolbox : toolbox, /* TODO: Change toolbox XML ID if ' + + 'necessary. Can export toolbox XML from Workspace Factory. */\n' + + attributes; + } + var finalStr = 'var options = { \n' + attributes + '};'; + finalStr += '\n\n/* Inject your workspace */ \nvar workspace = Blockly.' + + 'inject(/* TODO: Add ID of div to inject Blockly into */, options);'; + finalStr += '\n\n/* Load Workspace Blocks from XML to workspace. ' + + 'Remove if no blocks to load */' + + '\nBlockly.Xml.domToWorkspace(workspace, workspaceBlocks/*' + + ' TODO: Change workspace blocks XML ID if necessary. Can export' + + ' workspace blocks XML from Workspace Factory. */);'; + return finalStr; } /** diff --git a/demos/blocklyfactory/workspacefactory/wfactory_init.js b/demos/blocklyfactory/workspacefactory/wfactory_init.js index 212c3e04f..3a37eae38 100644 --- a/demos/blocklyfactory/workspacefactory/wfactory_init.js +++ b/demos/blocklyfactory/workspacefactory/wfactory_init.js @@ -193,6 +193,13 @@ WorkspaceFactoryInit.assignWorkspaceFactoryClickHandlers_ = document.getElementById('dropdownDiv_add').classList.remove("show"); }); + document.getElementById('dropdown_loadStandardToolbox').addEventListener + ('click', + function() { + controller.loadStandardToolbox(); + document.getElementById('dropdownDiv_add').classList.remove("show"); + }); + document.getElementById('button_remove').addEventListener ('click', function() { @@ -216,16 +223,16 @@ WorkspaceFactoryInit.assignWorkspaceFactoryClickHandlers_ = document.getElementById('dropdown_exportOptions').addEventListener ('click', function() { - controller.exportOptionsFile(); + controller.exportInjectFile(); document.getElementById('dropdownDiv_export').classList.remove("show"); }); document.getElementById('dropdown_exportAll').addEventListener ('click', function() { + controller.exportInjectFile(); controller.exportXmlFile(WorkspaceFactoryController.MODE_TOOLBOX); controller.exportXmlFile(WorkspaceFactoryController.MODE_PRELOAD); - controller.exportOptionsFile(); document.getElementById('dropdownDiv_export').classList.remove("show"); }); diff --git a/demos/blocklyfactory/workspacefactory/wfactory_model.js b/demos/blocklyfactory/workspacefactory/wfactory_model.js index ec059354c..a03fb86ea 100644 --- a/demos/blocklyfactory/workspacefactory/wfactory_model.js +++ b/demos/blocklyfactory/workspacefactory/wfactory_model.js @@ -495,6 +495,22 @@ WorkspaceFactoryModel.prototype.isDefinedBlockType = function(blockType) { var isLibBlock = this.libBlockTypes.indexOf(blockType) != -1; var isImportedBlock = this.importedBlockTypes.indexOf(blockType) != -1; return (isStandardBlock || isLibBlock || isImportedBlock); +}; + +/** + * Checks if any of the block types are already defined. + * + * @param {!Array} blockTypes Array of block types. + * @return {boolean} True if a block type in the array is already defined, + * false if none of the blocks are already defined. + */ +WorkspaceFactoryModel.prototype.hasDefinedBlockTypes = function(blockTypes) { + for (var i = 0, blockType; blockType = blockTypes[i]; i++) { + if (this.isDefinedBlockType(blockType)) { + return true; + } + } + return false; } /**