diff --git a/trunk/web/blockly/demos/accessible/icon.png b/trunk/web/blockly/demos/accessible/icon.png deleted file mode 100644 index 3ea238c448b..00000000000 Binary files a/trunk/web/blockly/demos/accessible/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/accessible/index.html b/trunk/web/blockly/demos/accessible/index.html deleted file mode 100644 index 127628d4150..00000000000 --- a/trunk/web/blockly/demos/accessible/index.html +++ /dev/null @@ -1,354 +0,0 @@ - - - - - Accessible Blockly Demo - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- Blockly > - Demos > Accessible Blockly -

- -

- This is a demo of a version of Blockly designed for screen readers, - optimized for NVDA on Firefox. It allows users to create programs in a - workspace by manipulating groups of blocks. -

-

- - - - - - - - - - - diff --git a/trunk/web/blockly/demos/blockfactory/app_controller.js b/trunk/web/blockly/demos/blockfactory/app_controller.js deleted file mode 100644 index ac69780b264..00000000000 --- a/trunk/web/blockly/demos/blockfactory/app_controller.js +++ /dev/null @@ -1,735 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview The AppController Class brings together the Block - * Factory, Block Library, and Block Exporter functionality into a single web - * app. - * - * @author quachtina96 (Tina Quach) - */ -goog.provide('AppController'); - -goog.require('BlockFactory'); -goog.require('FactoryUtils'); -goog.require('BlockLibraryController'); -goog.require('BlockExporterController'); -goog.require('goog.dom.classlist'); -goog.require('goog.ui.PopupColorPicker'); -goog.require('goog.ui.ColorPicker'); - - -/** - * Controller for the Blockly Factory - * @constructor - */ -AppController = function() { - // Initialize Block Library - this.blockLibraryName = 'blockLibrary'; - this.blockLibraryController = - new BlockLibraryController(this.blockLibraryName); - this.blockLibraryController.populateBlockLibrary(); - - // Construct Workspace Factory Controller. - this.workspaceFactoryController = new WorkspaceFactoryController - ('workspacefactory_toolbox', 'toolbox_blocks', 'preview_blocks'); - - // Initialize Block Exporter - this.exporter = - new BlockExporterController(this.blockLibraryController.storage); - - // Map of tab type to the div element for the tab. - this.tabMap = Object.create(null); - this.tabMap[AppController.BLOCK_FACTORY] = - document.getElementById('blockFactory_tab'); - this.tabMap[AppController.WORKSPACE_FACTORY] = - document.getElementById('workspaceFactory_tab'); - this.tabMap[AppController.EXPORTER] = - document.getElementById('blocklibraryExporter_tab'); - - // Last selected tab. - this.lastSelectedTab = null; - // Selected tab. - this.selectedTab = AppController.BLOCK_FACTORY; -}; - -// Constant values representing the three tabs in the controller. -AppController.BLOCK_FACTORY = 'BLOCK_FACTORY'; -AppController.WORKSPACE_FACTORY = 'WORKSPACE_FACTORY'; -AppController.EXPORTER = 'EXPORTER'; - -/** - * Tied to the 'Import Block Library' button. Imports block library from file to - * Block Factory. Expects user to upload a single file of JSON mapping each - * block type to its XML text representation. - */ -AppController.prototype.importBlockLibraryFromFile = function() { - var self = this; - var files = document.getElementById('files'); - // If the file list is empty, the user likely canceled in the dialog. - if (files.files.length > 0) { - // The input tag doesn't have the "multiple" attribute - // so the user can only choose 1 file. - var file = files.files[0]; - var fileReader = new FileReader(); - - // Create a map of block type to XML text from the file when it has been - // read. - fileReader.addEventListener('load', function(event) { - var fileContents = event.target.result; - // Create empty object to hold the read block library information. - var blockXmlTextMap = Object.create(null); - try { - // Parse the file to get map of block type to XML text. - blockXmlTextMap = self.formatBlockLibraryForImport_(fileContents); - } catch (e) { - var message = 'Could not load your block library file.\n' - window.alert(message + '\nFile Name: ' + file.name); - return; - } - - // Create a new block library storage object with inputted block library. - var blockLibStorage = new BlockLibraryStorage( - self.blockLibraryName, blockXmlTextMap); - - // Update block library controller with the new block library - // storage. - self.blockLibraryController.setBlockLibraryStorage(blockLibStorage); - // Update the block library dropdown. - self.blockLibraryController.populateBlockLibrary(); - // Update the exporter's block library storage. - self.exporter.setBlockLibraryStorage(blockLibStorage); - }); - // Read the file. - fileReader.readAsText(file); - } -}; - -/** - * Tied to the 'Export Block Library' button. Exports block library to file that - * contains JSON mapping each block type to its XML text representation. - */ -AppController.prototype.exportBlockLibraryToFile = function() { - // Get map of block type to XML. - var blockLib = this.blockLibraryController.getBlockLibrary(); - // Concatenate the XMLs, each separated by a blank line. - var blockLibText = this.formatBlockLibraryForExport_(blockLib); - // Get file name. - var filename = prompt('Enter the file name under which to save your block ' + - 'library.', 'library.xml'); - // Download file if all necessary parameters are provided. - if (filename) { - FactoryUtils.createAndDownloadFile(blockLibText, filename, 'xml'); - } else { - alert('Could not export Block Library without file name under which to ' + - 'save library.'); - } -}; - -/** - * Converts an object mapping block type to XML to text file for output. - * @param {!Object} blockXmlMap Object mapping block type to XML. - * @return {string} XML text containing the block XMLs. - * @private - */ -AppController.prototype.formatBlockLibraryForExport_ = function(blockXmlMap) { - // Create DOM for XML. - var xmlDom = goog.dom.createDom('xml', { - 'xmlns':"http://www.w3.org/1999/xhtml" - }); - - // Append each block node to XML DOM. - for (var blockType in blockXmlMap) { - var blockXmlDom = Blockly.Xml.textToDom(blockXmlMap[blockType]); - var blockNode = blockXmlDom.firstElementChild; - xmlDom.appendChild(blockNode); - } - - // Return the XML text. - return Blockly.Xml.domToText(xmlDom); -}; - -/** - * Converts imported block library to an object mapping block type to block XML. - * @param {string} xmlText String representation of an XML with each block as - * a child node. - * @return {!Object} Object mapping block type to XML text. - * @private - */ -AppController.prototype.formatBlockLibraryForImport_ = function(xmlText) { - var xmlDom = Blockly.Xml.textToDom(xmlText); - - // Get array of XMLs. Use an asterisk (*) instead of a tag name for the XPath - // selector, to match all elements at that level and get all factory_base - // blocks. - var blockNodes = goog.dom.xml.selectNodes(xmlDom, '*'); - - // Create empty map. The line below creates a truly empy object. It doesn't - // have built-in attributes/functions such as length or toString. - var blockXmlTextMap = Object.create(null); - - // Populate map. - for (var i = 0, blockNode; blockNode = blockNodes[i]; i++) { - - // Add outer XML tag to the block for proper injection in to the - // main workspace. - // Create DOM for XML. - var xmlDom = goog.dom.createDom('xml', { - 'xmlns':"http://www.w3.org/1999/xhtml" - }); - xmlDom.appendChild(blockNode); - - xmlText = Blockly.Xml.domToText(xmlDom); - // All block types should be lowercase. - var blockType = this.getBlockTypeFromXml_(xmlText).toLowerCase(); - // Some names are invalid so fix them up. - blockType = FactoryUtils.cleanBlockType(blockType); - - blockXmlTextMap[blockType] = xmlText; - } - - return blockXmlTextMap; -}; - -/** - * Extracts out block type from XML text, the kind that is saved in block - * library storage. - * @param {string} xmlText A block's XML text. - * @return {string} The block type that corresponds to the provided XML text. - * @private - */ -AppController.prototype.getBlockTypeFromXml_ = function(xmlText) { - var xmlDom = Blockly.Xml.textToDom(xmlText); - // Find factory base block. - var factoryBaseBlockXml = xmlDom.getElementsByTagName('block')[0]; - // Get field elements from factory base. - var fields = factoryBaseBlockXml.getElementsByTagName('field'); - for (var i = 0; i < fields.length; i++) { - // The field whose name is 'NAME' holds the block type as its value. - if (fields[i].getAttribute('name') == 'NAME') { - return fields[i].childNodes[0].nodeValue; - } - } -}; - -/** - * Add click handlers to each tab to allow switching between the Block Factory, - * Workspace Factory, and Block Exporter tab. - * @param {!Object} tabMap Map of tab name to div element that is the tab. - */ -AppController.prototype.addTabHandlers = function(tabMap) { - var self = this; - for (var tabName in tabMap) { - var tab = tabMap[tabName]; - // Use an additional closure to correctly assign the tab callback. - tab.addEventListener('click', self.makeTabClickHandler_(tabName)); - } -}; - -/** - * Set the selected tab. - * @param {string} tabName AppController.BLOCK_FACTORY, - * AppController.WORKSPACE_FACTORY, or AppController.EXPORTER - * @private - */ -AppController.prototype.setSelected_ = function(tabName) { - this.lastSelectedTab = this.selectedTab; - this.selectedTab = tabName; -}; - -/** - * Creates the tab click handler specific to the tab specified. - * @param {string} tabName AppController.BLOCK_FACTORY, - * AppController.WORKSPACE_FACTORY, or AppController.EXPORTER - * @return {!Function} The tab click handler. - * @private - */ -AppController.prototype.makeTabClickHandler_ = function(tabName) { - var self = this; - return function() { - self.setSelected_(tabName); - self.onTab(); - }; -}; - -/** - * Called on each tab click. Hides and shows specific content based on which tab - * (Block Factory, Workspace Factory, or Exporter) is selected. - */ -AppController.prototype.onTab = function() { - // Get tab div elements. - var blockFactoryTab = this.tabMap[AppController.BLOCK_FACTORY]; - var exporterTab = this.tabMap[AppController.EXPORTER]; - var workspaceFactoryTab = this.tabMap[AppController.WORKSPACE_FACTORY]; - - // Warn user if they have unsaved changes when leaving Block Factory. - if (this.lastSelectedTab == AppController.BLOCK_FACTORY && - this.selectedTab != AppController.BLOCK_FACTORY) { - - var hasUnsavedChanges = - !FactoryUtils.savedBlockChanges(this.blockLibraryController); - if (hasUnsavedChanges && - !confirm('You have unsaved changes in Block Factory.')) { - // If the user doesn't want to switch tabs with unsaved changes, - // stay on Block Factory Tab. - this.setSelected_(AppController.BLOCK_FACTORY); - this.lastSelectedTab = AppController.BLOCK_FACTORY; - return; - } - } - - // Only enable key events in workspace factory if workspace factory tab is - // selected. - this.workspaceFactoryController.keyEventsEnabled = - this.selectedTab == AppController.WORKSPACE_FACTORY; - - // Turn selected tab on and other tabs off. - this.styleTabs_(); - - if (this.selectedTab == AppController.EXPORTER) { - // Hide other tabs. - FactoryUtils.hide('workspaceFactoryContent'); - FactoryUtils.hide('blockFactoryContent'); - // Show exporter tab. - FactoryUtils.show('blockLibraryExporter'); - - // 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); - - // Update exporter's block selector to reflect current block library. - this.exporter.updateSelector(); - - // Update the exporter's preview to reflect any changes made to the blocks. - this.exporter.updatePreview(); - - } else if (this.selectedTab == AppController.BLOCK_FACTORY) { - // Hide other tabs. - FactoryUtils.hide('blockLibraryExporter'); - FactoryUtils.hide('workspaceFactoryContent'); - // Show Block Factory. - FactoryUtils.show('blockFactoryContent'); - - } else if (this.selectedTab == AppController.WORKSPACE_FACTORY) { - // Hide other tabs. - FactoryUtils.hide('blockLibraryExporter'); - FactoryUtils.hide('blockFactoryContent'); - // Show workspace factory container. - FactoryUtils.show('workspaceFactoryContent'); - // Update block library category. - var categoryXml = this.exporter.getBlockLibraryCategory(); - var blockTypes = this.blockLibraryController.getStoredBlockTypes(); - this.workspaceFactoryController.setBlockLibCategory(categoryXml, - blockTypes); - } - - // Resize to render workspaces' toolboxes correctly for all tabs. - window.dispatchEvent(new Event('resize')); -}; - -/** - * Called on each tab click. Styles the tabs to reflect which tab is selected. - * @private - */ -AppController.prototype.styleTabs_ = function() { - for (var tabName in this.tabMap) { - if (this.selectedTab == tabName) { - goog.dom.classlist.addRemove(this.tabMap[tabName], 'taboff', 'tabon'); - } else { - goog.dom.classlist.addRemove(this.tabMap[tabName], 'tabon', 'taboff'); - } - } -}; - -/** - * Assign button click handlers for the exporter. - */ -AppController.prototype.assignExporterClickHandlers = function() { - var self = this; - document.getElementById('button_setBlocks').addEventListener('click', - function() { - self.openModal('dropdownDiv_setBlocks'); - }); - - document.getElementById('dropdown_addAllUsed').addEventListener('click', - function() { - self.exporter.selectUsedBlocks(); - self.exporter.updatePreview(); - self.closeModal(); - }); - - document.getElementById('dropdown_addAllFromLib').addEventListener('click', - function() { - self.exporter.selectAllBlocks(); - self.exporter.updatePreview(); - self.closeModal(); - }); - - document.getElementById('clearSelectedButton').addEventListener('click', - function() { - self.exporter.clearSelectedBlocks(); - self.exporter.updatePreview(); - }); - - // Export blocks when the user submits the export settings. - document.getElementById('exporterSubmitButton').addEventListener('click', - function() { - self.exporter.export(); - }); -}; - -/** - * Assign change listeners for the exporter. These allow for the dynamic update - * of the exporter preview. - */ -AppController.prototype.assignExporterChangeListeners = function() { - var self = this; - - var blockDefCheck = document.getElementById('blockDefCheck'); - var genStubCheck = document.getElementById('genStubCheck'); - - // Select the block definitions and generator stubs on default. - blockDefCheck.checked = true; - genStubCheck.checked = true; - - // Checking the block definitions checkbox displays preview of code to export. - document.getElementById('blockDefCheck').addEventListener('change', - function(e) { - self.ifCheckedEnable(blockDefCheck.checked, - ['blockDefs', 'blockDefSettings']); - }); - - // Preview updates when user selects different block definition format. - document.getElementById('exportFormat').addEventListener('change', - function(e) { - self.exporter.updatePreview(); - }); - - // Checking the generator stub checkbox displays preview of code to export. - document.getElementById('genStubCheck').addEventListener('change', - function(e) { - self.ifCheckedEnable(genStubCheck.checked, - ['genStubs', 'genStubSettings']); - }); - - // Preview updates when user selects different generator stub language. - document.getElementById('exportLanguage').addEventListener('change', - function(e) { - self.exporter.updatePreview(); - }); -}; - -/** - * If given checkbox is checked, enable the given elements. Otherwise, disable. - * @param {boolean} enabled True if enabled, false otherwise. - * @param {!Array.} idArray Array of element IDs to enable when - * checkbox is checked. - */ -AppController.prototype.ifCheckedEnable = function(enabled, idArray) { - for (var i = 0, id; id = idArray[i]; i++) { - var element = document.getElementById(id); - if (enabled) { - element.classList.remove('disabled'); - } else { - element.classList.add('disabled'); - } - var fields = element.querySelectorAll('input, textarea, select'); - for (var j = 0, field; field = fields[j]; j++) { - field.disabled = !enabled; - } - } -}; - -/** - * Assign button click handlers for the block library. - */ -AppController.prototype.assignLibraryClickHandlers = function() { - var self = this; - - // Button for saving block to library. - document.getElementById('saveToBlockLibraryButton').addEventListener('click', - function() { - self.blockLibraryController.saveToBlockLibrary(); - }); - - // Button for removing selected block from library. - document.getElementById('removeBlockFromLibraryButton').addEventListener( - 'click', - function() { - self.blockLibraryController.removeFromBlockLibrary(); - }); - - // Button for clearing the block library. - document.getElementById('clearBlockLibraryButton').addEventListener('click', - function() { - self.blockLibraryController.clearBlockLibrary(); - }); - - // Hide and show the block library dropdown. - document.getElementById('button_blockLib').addEventListener('click', - function() { - self.openModal('dropdownDiv_blockLib'); - }); -}; - -/** - * Assign button click handlers for the block factory. - */ -AppController.prototype.assignBlockFactoryClickHandlers = function() { - var self = this; - // Assign button event handlers for Block Factory. - document.getElementById('localSaveButton') - .addEventListener('click', function() { - self.exportBlockLibraryToFile(); - }); - - document.getElementById('helpButton').addEventListener('click', - function() { - open('https://developers.google.com/blockly/custom-blocks/block-factory', - 'BlockFactoryHelp'); - }); - - document.getElementById('files').addEventListener('change', - function() { - // Warn user. - var replace = confirm('This imported block library will ' + - 'replace your current block library.'); - if (replace) { - self.importBlockLibraryFromFile(); - // Clear this so that the change event still fires even if the - // same file is chosen again. If the user re-imports a file, we - // want to reload the workspace with its contents. - this.value = null; - } - }); - - document.getElementById('createNewBlockButton') - .addEventListener('click', function() { - // If there are unsaved changes warn user, check if they'd like to - // proceed with unsaved changes, and act accordingly. - var proceedWithUnsavedChanges = - self.blockLibraryController.warnIfUnsavedChanges(); - if (!proceedWithUnsavedChanges) { - return; - } - - BlockFactory.showStarterBlock(); - self.blockLibraryController.setNoneSelected(); - - // Close the Block Library Dropdown. - self.closeModal(); - }); -}; - -/** - * Add event listeners for the block factory. - */ -AppController.prototype.addBlockFactoryEventListeners = function() { - // Update code on changes to block being edited. - BlockFactory.mainWorkspace.addChangeListener(BlockFactory.updateLanguage); - - // Disable blocks not attached to the factory_base block. - BlockFactory.mainWorkspace.addChangeListener(Blockly.Events.disableOrphans); - - // Update the buttons on the screen based on whether - // changes have been saved. - var self = this; - BlockFactory.mainWorkspace.addChangeListener(function() { - self.blockLibraryController.updateButtons(FactoryUtils.savedBlockChanges( - self.blockLibraryController)); - }); - - document.getElementById('direction') - .addEventListener('change', BlockFactory.updatePreview); - document.getElementById('languageTA') - .addEventListener('change', BlockFactory.updatePreview); - document.getElementById('languageTA') - .addEventListener('keyup', BlockFactory.updatePreview); - document.getElementById('format') - .addEventListener('change', BlockFactory.formatChange); - document.getElementById('language') - .addEventListener('change', BlockFactory.updatePreview); -}; - -/** - * Handle Blockly Storage with App Engine. - */ -AppController.prototype.initializeBlocklyStorage = function() { - BlocklyStorage.HTTPREQUEST_ERROR = - 'There was a problem with the request.\n'; - BlocklyStorage.LINK_ALERT = - 'Share your blocks with this link:\n\n%1'; - BlocklyStorage.HASH_ERROR = - 'Sorry, "%1" doesn\'t correspond with any saved Blockly file.'; - BlocklyStorage.XML_ERROR = 'Could not load your saved file.\n' + - 'Perhaps it was created with a different version of Blockly?'; - var linkButton = document.getElementById('linkButton'); - linkButton.style.display = 'inline-block'; - linkButton.addEventListener('click', - function() { - BlocklyStorage.link(BlockFactory.mainWorkspace);}); - BlockFactory.disableEnableLink(); -}; - -/** - * Handle resizing of elements. - */ -AppController.prototype.onresize = function(event) { - if (this.selectedTab == AppController.BLOCK_FACTORY) { - // Handle resizing of Block Factory elements. - var expandList = [ - document.getElementById('blocklyPreviewContainer'), - document.getElementById('blockly'), - document.getElementById('blocklyMask'), - document.getElementById('preview'), - document.getElementById('languagePre'), - document.getElementById('languageTA'), - document.getElementById('generatorPre'), - ]; - for (var i = 0, expand; expand = expandList[i]; i++) { - expand.style.width = (expand.parentNode.offsetWidth - 2) + 'px'; - expand.style.height = (expand.parentNode.offsetHeight - 2) + 'px'; - } - } else if (this.selectedTab == AppController.EXPORTER) { - // Handle resize of Exporter block options. - this.exporter.view.centerPreviewBlocks(); - } -}; - -/** - * Handler for the window's 'beforeunload' event. When a user has unsaved - * changes and refreshes or leaves the page, confirm that they want to do so - * before actually refreshing. - * @param {!Event} e beforeunload event. - */ -AppController.prototype.confirmLeavePage = function(e) { - if ((!BlockFactory.isStarterBlock() && - !FactoryUtils.savedBlockChanges(blocklyFactory.blockLibraryController)) || - blocklyFactory.workspaceFactoryController.hasUnsavedChanges()) { - - var confirmationMessage = 'You will lose any unsaved changes. ' + - 'Are you sure you want to exit this page?'; - e.returnValue = confirmationMessage; - return confirmationMessage; - } -}; - -/** - * Show a modal element, usually a dropdown list. - * @param {string} id ID of element to show. - */ -AppController.prototype.openModal = function(id) { - Blockly.hideChaff(); - this.modalName_ = id; - document.getElementById(id).style.display = 'block'; - document.getElementById('modalShadow').style.display = 'block'; -}; - -/** - * Hide a previously shown modal element. - */ -AppController.prototype.closeModal = function() { - var id = this.modalName_; - if (!id) { - return; - } - document.getElementById(id).style.display = 'none'; - document.getElementById('modalShadow').style.display = 'none'; - this.modalName_ = null; -}; - -/** - * Name of currently open modal. - * @type {string?} - * @private - */ -AppController.prototype.modalName_ = null; - -/** - * Initialize Blockly and layout. Called on page load. - */ -AppController.prototype.init = function() { - // Block Factory has a dependency on bits of Closure that core Blockly - // doesn't have. When you run this from file:// without a copy of Closure, - // it breaks it non-obvious ways. Warning about this for now until the - // dependency is broken. - // TODO: #668. - if (!window.goog.dom.xml) { - alert('Sorry: Closure dependency not found. We are working on removing ' + - 'this dependency. In the meantime, you can use our hosted demo\n ' + - 'https://blockly-demo.appspot.com/static/demos/blockfactory/index.html' + - '\nor use these instructions to continue running locally:\n' + - 'https://developers.google.com/blockly/guides/modify/web/closure'); - return; - } - - var self = this; - // Handle Blockly Storage with App Engine. - if ('BlocklyStorage' in window) { - this.initializeBlocklyStorage(); - } - - // Assign click handlers. - this.assignExporterClickHandlers(); - this.assignLibraryClickHandlers(); - this.assignBlockFactoryClickHandlers(); - // Hide and show the block library dropdown. - document.getElementById('modalShadow').addEventListener('click', - function() { - self.closeModal(); - }); - - this.onresize(); - window.addEventListener('resize', function() { - self.onresize(); - }); - - // Inject Block Factory Main Workspace. - var toolbox = document.getElementById('blockfactory_toolbox'); - BlockFactory.mainWorkspace = Blockly.inject('blockly', - {collapse: false, - toolbox: toolbox, - media: '../../media/'}); - - // Add tab handlers for switching between Block Factory and Block Exporter. - this.addTabHandlers(this.tabMap); - - // Assign exporter change listeners. - this.assignExporterChangeListeners(); - - // Create the root block on Block Factory main workspace. - if ('BlocklyStorage' in window && window.location.hash.length > 1) { - BlocklyStorage.retrieveXml(window.location.hash.substring(1), - BlockFactory.mainWorkspace); - } else { - BlockFactory.showStarterBlock(); - } - BlockFactory.mainWorkspace.clearUndo(); - - // Add Block Factory event listeners. - this.addBlockFactoryEventListeners(); - - // Workspace Factory init. - WorkspaceFactoryInit.initWorkspaceFactory(this.workspaceFactoryController); -}; diff --git a/trunk/web/blockly/demos/blockfactory/block_exporter_controller.js b/trunk/web/blockly/demos/blockfactory/block_exporter_controller.js deleted file mode 100644 index b237f48a70f..00000000000 --- a/trunk/web/blockly/demos/blockfactory/block_exporter_controller.js +++ /dev/null @@ -1,323 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Javascript for the Block Exporter Controller class. Allows - * users to export block definitions and generator stubs of their saved blocks - * easily using a visual interface. Depends on Block Exporter View and Block - * Exporter Tools classes. Interacts with Export Settings in the index.html. - * - * @author quachtina96 (Tina Quach) - */ - -'use strict'; - -goog.provide('BlockExporterController'); - -goog.require('FactoryUtils'); -goog.require('StandardCategories'); -goog.require('BlockExporterView'); -goog.require('BlockExporterTools'); -goog.require('goog.dom.xml'); - - -/** - * BlockExporter Controller Class - * @param {!BlockLibrary.Storage} blockLibStorage Block Library Storage. - * @constructor - */ -BlockExporterController = function(blockLibStorage) { - // BlockLibrary.Storage object containing user's saved blocks. - this.blockLibStorage = blockLibStorage; - // Utils for generating code to export. - this.tools = new BlockExporterTools(); - // The ID of the block selector, a div element that will be populated with the - // block options. - this.selectorID = 'blockSelector'; - // Map of block types stored in block library to their corresponding Block - // Option objects. - this.blockOptions = this.tools.createBlockSelectorFromLib( - this.blockLibStorage, this.selectorID); - // View provides the block selector and export settings UI. - this.view = new BlockExporterView(this.blockOptions); -}; - -/** - * Set the block library storage object from which exporter exports. - * @param {!BlockLibraryStorage} blockLibStorage Block Library Storage object - * that stores the blocks. - */ -BlockExporterController.prototype.setBlockLibraryStorage = - function(blockLibStorage) { - this.blockLibStorage = blockLibStorage; -}; - -/** - * Get the block library storage object from which exporter exports. - * @return {!BlockLibraryStorage} blockLibStorage Block Library Storage object - * that stores the blocks. - */ -BlockExporterController.prototype.getBlockLibraryStorage = - function(blockLibStorage) { - return this.blockLibStorage; -}; - -/** - * Get selected blocks from block selector, pulls info from the Export - * Settings form in Block Exporter, and downloads code accordingly. - */ -BlockExporterController.prototype.export = function() { - // Get selected blocks' information. - var blockTypes = this.view.getSelectedBlockTypes(); - var blockXmlMap = this.blockLibStorage.getBlockXmlMap(blockTypes); - - // Pull block definition(s) settings from the Export Settings form. - var wantBlockDef = document.getElementById('blockDefCheck').checked; - var definitionFormat = document.getElementById('exportFormat').value; - var blockDef_filename = document.getElementById('blockDef_filename').value; - - // Pull block generator stub(s) settings from the Export Settings form. - var wantGenStub = document.getElementById('genStubCheck').checked; - var language = document.getElementById('exportLanguage').value; - var generatorStub_filename = document.getElementById( - 'generatorStub_filename').value; - - if (wantBlockDef) { - // User wants to export selected blocks' definitions. - if (!blockDef_filename) { - // User needs to enter filename. - alert('Please enter a filename for your block definition(s) download.'); - } else { - // Get block definition code in the selected format for the blocks. - var blockDefs = this.tools.getBlockDefinitions(blockXmlMap, - definitionFormat); - // Download the file, using .js file ending for JSON or Javascript. - FactoryUtils.createAndDownloadFile( - blockDefs, blockDef_filename, 'javascript'); - } - } - - if (wantGenStub) { - // User wants to export selected blocks' generator stubs. - if (!generatorStub_filename) { - // User needs to enter filename. - alert('Please enter a filename for your generator stub(s) download.'); - } else { - // Get generator stub code in the selected language for the blocks. - var genStubs = this.tools.getGeneratorCode(blockXmlMap, - language); - // Get the correct file extension. - var fileType = (language == 'JavaScript') ? 'javascript' : 'plain'; - // Download the file. - FactoryUtils.createAndDownloadFile( - genStubs, generatorStub_filename, fileType); - } - } - -}; - -/** - * Update the Exporter's block selector with block options generated from blocks - * stored in block library. - */ -BlockExporterController.prototype.updateSelector = function() { - // Get previously selected block types. - var oldSelectedTypes = this.view.getSelectedBlockTypes(); - - // Generate options from block library and assign to view. - this.blockOptions = this.tools.createBlockSelectorFromLib( - this.blockLibStorage, this.selectorID); - this.addBlockOptionSelectHandlers(); - this.view.setBlockOptions(this.blockOptions); - - // Select all previously selected blocks. - for (var i = 0, blockType; blockType = oldSelectedTypes[i]; i++) { - if (this.blockOptions[blockType]) { - this.view.select(blockType); - } - } - - this.view.listSelectedBlocks(); -}; - -/** - * Tied to the 'Clear Selected Blocks' button in the Block Exporter. - * Deselects all blocks in the selector and updates text accordingly. - */ -BlockExporterController.prototype.clearSelectedBlocks = function() { - this.view.deselectAllBlocks(); - this.view.listSelectedBlocks(); -}; - -/** - * Tied to the 'All Stored' button in the Block Exporter 'Select' dropdown. - * Selects all blocks stored in block library for export. - */ -BlockExporterController.prototype.selectAllBlocks = function() { - var allBlockTypes = this.blockLibStorage.getBlockTypes(); - for (var i = 0, blockType; blockType = allBlockTypes[i]; i++) { - this.view.select(blockType); - } - this.view.listSelectedBlocks(); -}; - -/** - * Returns the category XML containing all blocks in the block library. - * @return {Element} XML for a category to be used in toolbox. - */ -BlockExporterController.prototype.getBlockLibraryCategory = function() { - return this.tools.generateCategoryFromBlockLib(this.blockLibStorage); -}; - -/** - * Add select handlers to each block option to update the view and the selected - * blocks accordingly. - */ -BlockExporterController.prototype.addBlockOptionSelectHandlers = function() { - var self = this; - - // Click handler for a block option. Toggles whether or not it's selected and - // updates helper text accordingly. - var updateSelectedBlockTypes_ = function(blockOption) { - // Toggle selected. - blockOption.setSelected(!blockOption.isSelected()); - - // Show currently selected blocks in helper text. - self.view.listSelectedBlocks(); - }; - - // Returns a block option select handler. - var makeBlockOptionSelectHandler_ = function(blockOption) { - return function() { - updateSelectedBlockTypes_(blockOption); - self.updatePreview(); - }; - }; - - // Assign a click handler to each block option. - for (var blockType in this.blockOptions) { - var blockOption = this.blockOptions[blockType]; - // Use an additional closure to correctly assign the tab callback. - blockOption.dom.addEventListener( - 'click', makeBlockOptionSelectHandler_(blockOption)); - } -}; - -/** - * Tied to the 'All Used' button in the Block Exporter's 'Select' button. - * Selects all blocks stored in block library and used in workspace factory. - */ -BlockExporterController.prototype.selectUsedBlocks = function() { - // Deselect all blocks. - this.view.deselectAllBlocks(); - - // 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 (StandardCategories.coreBlockTypes.indexOf(blockType) == -1) { - unstoredCustomBlockTypes.push(blockType); - } - } - - // Select each shared block type. - for (var i = 0, blockType; blockType = sharedBlockTypes[i]; i++) { - this.view.select(blockType); - } - this.view.listSelectedBlocks(); - - if (unstoredCustomBlockTypes.length > 0){ - // Warn user to import block defifnitions 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; -}; - -/** - * Updates preview code (block definitions and generator stubs) in the exporter - * preview to reflect selected blocks. - */ -BlockExporterController.prototype.updatePreview = function() { - // Generate preview code for selected blocks. - var blockDefs = this.getBlockDefinitionsOfSelected(); - var genStubs = this.getGeneratorStubsOfSelected(); - - // Update the text areas containing the code. - FactoryUtils.injectCode(blockDefs, 'blockDefs_textArea'); - FactoryUtils.injectCode(genStubs, 'genStubs_textArea'); -}; - -/** - * Returns a map of each selected block's type to its corresponding XML. - * @return {!Object} A map of each selected block's type (a string) to its - * corresponding XML element. - */ -BlockExporterController.prototype.getSelectedBlockXmlMap = function() { - var blockTypes = this.view.getSelectedBlockTypes(); - return this.blockLibStorage.getBlockXmlMap(blockTypes); -}; - -/** - * Get block definition code in the selected format for selected blocks. - * @return {string} The concatenation of each selected block's language code - * in the format specified in export settings. - */ -BlockExporterController.prototype.getBlockDefinitionsOfSelected = function() { - // Get selected blocks' information. - var blockXmlMap = this.getSelectedBlockXmlMap(); - - // Get block definition code in the selected format for the blocks. - var definitionFormat = document.getElementById('exportFormat').value; - return this.tools.getBlockDefinitions(blockXmlMap, definitionFormat); -}; - -/** - * Get generator stubs in the selected language for selected blocks. - * @return {string} The concatenation of each selected block's generator stub - * in the language specified in export settings. - */ -BlockExporterController.prototype.getGeneratorStubsOfSelected = function() { - // Get selected blocks' information. - var blockXmlMap = this.getSelectedBlockXmlMap(); - - // Get generator stub code in the selected language for the blocks. - var language = document.getElementById('exportLanguage').value; - return this.tools.getGeneratorCode(blockXmlMap, language); -}; diff --git a/trunk/web/blockly/demos/blockfactory/block_exporter_tools.js b/trunk/web/blockly/demos/blockfactory/block_exporter_tools.js deleted file mode 100644 index 4d6d9bec65a..00000000000 --- a/trunk/web/blockly/demos/blockfactory/block_exporter_tools.js +++ /dev/null @@ -1,277 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Javascript for the BlockExporter Tools class, which generates - * block definitions and generator stubs for given block types. Also generates - * toolbox XML for the exporter's workspace. Depends on the FactoryUtils for - * its code generation functions. - * - * @author quachtina96 (Tina Quach) - */ -'use strict'; - -goog.provide('BlockExporterTools'); - -goog.require('FactoryUtils'); -goog.require('BlockOption'); -goog.require('goog.dom'); -goog.require('goog.dom.xml'); - - -/** -* Block Exporter Tools Class -* @constructor -*/ -BlockExporterTools = function() { - // Create container for hidden workspace. - this.container = goog.dom.createDom('div', { - 'id': 'blockExporterTools_hiddenWorkspace' - }, ''); // Empty quotes for empty div. - // Hide hidden workspace. - this.container.style.display = 'none'; - document.body.appendChild(this.container); - /** - * Hidden workspace for the Block Exporter that holds pieces that make - * up the block - * @type {Blockly.Workspace} - */ - this.hiddenWorkspace = Blockly.inject(this.container.id, - {collapse: false, - media: '../../media/'}); -}; - -/** - * Get Blockly Block object from XML that encodes the blocks used to design - * the block. - * @param {!Element} xml XML element that encodes the blocks used to design - * the block. For example, the block XMLs saved in block library. - * @return {!Blockly.Block} Root block (factory_base block) which contains - * all information needed to generate block definition or null. - * @private - */ -BlockExporterTools.prototype.getRootBlockFromXml_ = function(xml) { - // Render XML in hidden workspace. - this.hiddenWorkspace.clear(); - Blockly.Xml.domToWorkspace(xml, this.hiddenWorkspace); - // Get root block. - var rootBlock = this.hiddenWorkspace.getTopBlocks()[0] || null; - return rootBlock; -}; - -/** - * Return the given language code of each block type in an array. - * @param {!Object} blockXmlMap Map of block type to XML. - * @param {string} definitionFormat 'JSON' or 'JavaScript' - * @return {string} The concatenation of each block's language code in the - * desired format. - */ -BlockExporterTools.prototype.getBlockDefinitions = - function(blockXmlMap, definitionFormat) { - var blockCode = []; - for (var blockType in blockXmlMap) { - var xml = blockXmlMap[blockType]; - if (xml) { - // Render and get block from hidden workspace. - var rootBlock = this.getRootBlockFromXml_(xml); - if (rootBlock) { - // Generate the block's definition. - var code = FactoryUtils.getBlockDefinition(blockType, rootBlock, - definitionFormat, this.hiddenWorkspace); - // Add block's definition to the definitions to return. - } else { - // Append warning comment and write to console. - var code = '// No block definition generated for ' + blockType + - '. Could not find root block in XML stored for this block.'; - console.log('No block definition generated for ' + blockType + - '. Could not find root block in XML stored for this block.'); - } - } else { - // Append warning comment and write to console. - var code = '// No block definition generated for ' + blockType + - '. Block was not found in Block Library Storage.'; - console.log('No block definition generated for ' + blockType + - '. Block was not found in Block Library Storage.'); - } - blockCode.push(code); - } - - // Surround json with [] and comma separate items. - if (definitionFormat == "JSON") { - return "[" + blockCode.join(",\n") + "]"; - } - return blockCode.join("\n\n"); -}; - -/** - * Return the generator code of each block type in an array in a given language. - * @param {!Object} blockXmlMap Map of block type to XML. - * @param {string} generatorLanguage E.g. 'JavaScript', 'Python', 'PHP', 'Lua', - * 'Dart' - * @return {string} The concatenation of each block's generator code in the - * desired format. - */ -BlockExporterTools.prototype.getGeneratorCode = - function(blockXmlMap, generatorLanguage) { - var multiblockCode = []; - // Define the custom blocks in order to be able to create instances of - // them in the exporter workspace. - this.addBlockDefinitions(blockXmlMap); - - for (var blockType in blockXmlMap) { - var xml = blockXmlMap[blockType]; - if (xml) { - // Render the preview block in the hidden workspace. - var tempBlock = - FactoryUtils.getDefinedBlock(blockType, this.hiddenWorkspace); - // Get generator stub for the given block and add to generator code. - var blockGenCode = - FactoryUtils.getGeneratorStub(tempBlock, generatorLanguage); - } else { - // Append warning comment and write to console. - var blockGenCode = '// No generator stub generated for ' + blockType + - '. Block was not found in Block Library Storage.'; - console.log('No block generator stub generated for ' + blockType + - '. Block was not found in Block Library Storage.'); - } - multiblockCode.push(blockGenCode); - } - return multiblockCode.join("\n\n"); -}; - -/** - * Evaluates block definition code of each block in given object mapping - * block type to XML. Called in order to be able to create instances of the - * blocks in the exporter workspace. - * @param {!Object} blockXmlMap Map of block type to XML. - */ -BlockExporterTools.prototype.addBlockDefinitions = function(blockXmlMap) { - var blockDefs = this.getBlockDefinitions(blockXmlMap, 'JavaScript'); - eval(blockDefs); -}; - -/** - * Pulls information about all blocks in the block library to generate XML - * for the selector workpace's toolbox. - * @param {!BlockLibraryStorage} blockLibStorage Block Library Storage object. - * @return {!Element} XML representation of the toolbox. - */ -BlockExporterTools.prototype.generateToolboxFromLibrary - = function(blockLibStorage) { - // Create DOM for XML. - var xmlDom = goog.dom.createDom('xml', { - 'id' : 'blockExporterTools_toolbox', - 'style' : 'display:none' - }); - - var allBlockTypes = blockLibStorage.getBlockTypes(); - // Object mapping block type to XML. - var blockXmlMap = blockLibStorage.getBlockXmlMap(allBlockTypes); - - // Define the custom blocks in order to be able to create instances of - // them in the exporter workspace. - this.addBlockDefinitions(blockXmlMap); - - for (var blockType in blockXmlMap) { - // Get block. - var block = FactoryUtils.getDefinedBlock(blockType, this.hiddenWorkspace); - var category = FactoryUtils.generateCategoryXml([block], blockType); - xmlDom.appendChild(category); - } - - // If there are no blocks in library and the map is empty, append dummy - // category. - if (Object.keys(blockXmlMap).length == 0) { - var category = goog.dom.createDom('category'); - category.setAttribute('name','Next Saved Block'); - xmlDom.appendChild(category); - } - return xmlDom; -}; - -/** - * Generate XML for the workspace factory's category from imported block - * definitions. - * @param {!BlockLibraryStorage} blockLibStorage Block Library Storage object. - * @return {!Element} XML representation of a category. - */ -BlockExporterTools.prototype.generateCategoryFromBlockLib = - function(blockLibStorage) { - var allBlockTypes = blockLibStorage.getBlockTypes(); - // Object mapping block type to XML. - var blockXmlMap = blockLibStorage.getBlockXmlMap(allBlockTypes); - - // Define the custom blocks in order to be able to create instances of - // them in the exporter workspace. - this.addBlockDefinitions(blockXmlMap); - - // Get array of defined blocks. - var blocks = []; - for (var blockType in blockXmlMap) { - var block = FactoryUtils.getDefinedBlock(blockType, this.hiddenWorkspace); - blocks.push(block); - } - - return FactoryUtils.generateCategoryXml(blocks,'Block Library'); -}; - -/** - * Generate selector dom from block library storage. For each block in the - * library, it has a block option, which consists of a checkbox, a label, - * and a fixed size preview workspace. - * @param {!BlockLibraryStorage} blockLibStorage Block Library Storage object. - * @param {string} blockSelectorId ID of the div element that will contain - * the block options. - * @return {!Object} Map of block type to Block Option object. - */ -BlockExporterTools.prototype.createBlockSelectorFromLib = - function(blockLibStorage, blockSelectorId) { - // Object mapping each stored block type to XML. - var allBlockTypes = blockLibStorage.getBlockTypes(); - var blockXmlMap = blockLibStorage.getBlockXmlMap(allBlockTypes); - - // Define the custom blocks in order to be able to create instances of - // them in the exporter workspace. - this.addBlockDefinitions(blockXmlMap); - - var blockSelector = document.getElementById(blockSelectorId); - // Clear the block selector. - var child; - while ((child = blockSelector.firstChild)) { - blockSelector.removeChild(child); - } - - // Append each block option's dom to the selector. - var blockOptions = Object.create(null); - for (var blockType in blockXmlMap) { - // Get preview block's XML. - var block = FactoryUtils.getDefinedBlock(blockType, this.hiddenWorkspace); - var previewBlockXml = Blockly.Xml.workspaceToDom(this.hiddenWorkspace); - - // Create block option, inject block into preview workspace, and append - // option to block selector. - var blockOpt = new BlockOption(blockSelector, blockType, previewBlockXml); - blockOpt.createDom(); - blockSelector.appendChild(blockOpt.dom); - blockOpt.showPreviewBlock(); - blockOptions[blockType] = blockOpt; - } - return blockOptions; -}; diff --git a/trunk/web/blockly/demos/blockfactory/block_exporter_view.js b/trunk/web/blockly/demos/blockfactory/block_exporter_view.js deleted file mode 100644 index 198598c1418..00000000000 --- a/trunk/web/blockly/demos/blockfactory/block_exporter_view.js +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Javascript for the Block Exporter View class. Reads from and - * manages a block selector through which users select blocks to export. - * - * @author quachtina96 (Tina Quach) - */ - -'use strict'; - -goog.provide('BlockExporterView'); - -goog.require('BlockExporterTools'); -goog.require('BlockOption'); -goog.require('goog.dom'); - - -/** - * BlockExporter View Class - * @param {!Object} blockOptions Map of block types to BlockOption objects. - * @constructor - */ -BlockExporterView = function(blockOptions) { - // Map of block types to BlockOption objects to select from. - this.blockOptions = blockOptions; -}; - -/** - * Set the block options in the selector of this instance of - * BlockExporterView. - * @param {!Object} blockOptions Map of block types to BlockOption objects. - */ -BlockExporterView.prototype.setBlockOptions = function(blockOptions) { - this.blockOptions = blockOptions; -}; - -/** - * Updates the helper text to show list of currently selected blocks. - */ -BlockExporterView.prototype.listSelectedBlocks = function() { - - var selectedBlocksText = this.getSelectedBlockTypes().join(",\n "); - document.getElementById('selectedBlocksText').textContent = selectedBlocksText; -}; - -/** - * Selects a given block type in the selector. - * @param {string} blockType Type of block to selector. - */ -BlockExporterView.prototype.select = function(blockType) { - this.blockOptions[blockType].setSelected(true); -}; - -/** - * Deselects a block in the selector. - * @param {!Blockly.Block} block Type of block to add to selector workspce. - */ -BlockExporterView.prototype.deselect = function(blockType) { - this.blockOptions[blockType].setSelected(false); -}; - - -/** - * Deselects all blocks. - */ -BlockExporterView.prototype.deselectAllBlocks = function() { - for (var blockType in this.blockOptions) { - this.deselect(blockType); - } -}; - -/** - * Given an array of selected blocks, selects these blocks in the view, marking - * the checkboxes accordingly. - * @param {Array.} blockTypes Array of block types to select. - */ -BlockExporterView.prototype.setSelectedBlockTypes = function(blockTypes) { - for (var i = 0, blockType; blockType = blockTypes[i]; i++) { - this.select(blockType); - } -}; - -/** - * Returns array of selected blocks. - * @return {!Array.} Array of all selected block types. - */ -BlockExporterView.prototype.getSelectedBlockTypes = function() { - var selectedTypes = []; - for (var blockType in this.blockOptions) { - var blockOption = this.blockOptions[blockType]; - if (blockOption.isSelected()) { - selectedTypes.push(blockType); - } - } - return selectedTypes; -}; - -/** - * Centers the preview block of each block option in the exporter selector. - */ -BlockExporterView.prototype.centerPreviewBlocks = function() { - for (var blockType in this.blockOptions) { - this.blockOptions[blockType].centerBlock(); - } -}; diff --git a/trunk/web/blockly/demos/blockfactory/block_library_controller.js b/trunk/web/blockly/demos/blockfactory/block_library_controller.js deleted file mode 100644 index 1066ab127d7..00000000000 --- a/trunk/web/blockly/demos/blockfactory/block_library_controller.js +++ /dev/null @@ -1,321 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Contains the code for Block Library Controller, which - * depends on Block Library Storage and Block Library UI. Provides the - * interfaces for the user to - * - save their blocks to the browser - * - re-open and edit saved blocks - * - delete blocks - * - clear their block library - * Depends on BlockFactory functions defined in factory.js. - * - * @author quachtina96 (Tina Quach) - */ -'use strict'; - -goog.provide('BlockLibraryController'); - -goog.require('BlockLibraryStorage'); -goog.require('BlockLibraryView'); -goog.require('BlockFactory'); - - -/** - * Block Library Controller Class - * @param {string} blockLibraryName Desired name of Block Library, also used - * to create the key for where it's stored in local storage. - * @param {!BlockLibraryStorage} opt_blockLibraryStorage Optional storage - * object that allows user to import a block library. - * @constructor - */ -BlockLibraryController = function(blockLibraryName, opt_blockLibraryStorage) { - this.name = blockLibraryName; - // Create a new, empty Block Library Storage object, or load existing one. - this.storage = opt_blockLibraryStorage || new BlockLibraryStorage(this.name); - // The BlockLibraryView object handles the proper updating and formatting of - // the block library dropdown. - this.view = new BlockLibraryView(); -}; - -/** - * Returns the block type of the block the user is building. - * @return {string} The current block's type. - * @private - */ -BlockLibraryController.prototype.getCurrentBlockType = function() { - var rootBlock = FactoryUtils.getRootBlock(BlockFactory.mainWorkspace); - var blockType = rootBlock.getFieldValue('NAME').trim().toLowerCase(); - // Replace invalid characters. - return FactoryUtils.cleanBlockType(blockType); -}; - -/** - * Removes current block from Block Library and updates the save and delete - * buttons so that user may save block to library and but not delete. - * @param {string} blockType Type of block. - */ -BlockLibraryController.prototype.removeFromBlockLibrary = function() { - var blockType = this.getCurrentBlockType(); - this.storage.removeBlock(blockType); - this.storage.saveToLocalStorage(); - this.populateBlockLibrary(); - this.view.updateButtons(blockType, false, false); -}; - -/** - * Updates the workspace to show the block user selected from library - * @param {string} blockType Block to edit on block factory. - */ -BlockLibraryController.prototype.openBlock = function(blockType) { - if (blockType) { - var xml = this.storage.getBlockXml(blockType); - BlockFactory.mainWorkspace.clear(); - Blockly.Xml.domToWorkspace(xml, BlockFactory.mainWorkspace); - BlockFactory.mainWorkspace.clearUndo(); - } else { - BlockFactory.showStarterBlock(); - this.view.setSelectedBlockType(null); - } -}; - -/** - * Returns type of block selected from library. - * @return {string} Type of block selected. - */ -BlockLibraryController.prototype.getSelectedBlockType = function() { - return this.view.getSelectedBlockType(); -}; - -/** - * Confirms with user before clearing the block library in local storage and - * updating the dropdown and displaying the starter block (factory_base). - */ -BlockLibraryController.prototype.clearBlockLibrary = function() { - var check = confirm('Delete all blocks from library?'); - if (check) { - // Clear Block Library Storage. - this.storage.clear(); - this.storage.saveToLocalStorage(); - // Update dropdown. - this.view.clearOptions(); - // Show default block. - BlockFactory.showStarterBlock(); - // User may not save the starter block, but will get explicit instructions - // upon clicking the red save button. - this.view.updateButtons(null); - } -}; - -/** - * Saves current block to local storage and updates dropdown. - */ -BlockLibraryController.prototype.saveToBlockLibrary = function() { - var blockType = this.getCurrentBlockType(); - // If user has not changed the name of the starter block. - if (blockType == 'block_type') { - // Do not save block if it has the default type, 'block_type'. - alert('You cannot save a block under the name "block_type". Try changing ' + - 'the name before saving. Then, click on the "Block Library" button ' + - 'to view your saved blocks.'); - return; - } - - // Create block XML. - var xmlElement = goog.dom.createDom('xml'); - var block = FactoryUtils.getRootBlock(BlockFactory.mainWorkspace); - xmlElement.appendChild(Blockly.Xml.blockToDomWithXY(block)); - - // Do not add option again if block type is already in library. - if (!this.has(blockType)) { - this.view.addOption(blockType, true, true); - } - - // Save block. - this.storage.addBlock(blockType, xmlElement); - this.storage.saveToLocalStorage(); - - // Show saved block without other stray blocks sitting in Block Factory's - // main workspace. - this.openBlock(blockType); - - // Add select handler to the new option. - this.addOptionSelectHandler(blockType); -}; - -/** - * Checks to see if the given blockType is already in Block Library - * @param {string} blockType Type of block. - * @return {boolean} Boolean indicating whether or not block is in the library. - */ -BlockLibraryController.prototype.has = function(blockType) { - var blockLibrary = this.storage.blocks; - return (blockType in blockLibrary && blockLibrary[blockType] != null); -}; - -/** - * Populates the dropdown menu. - */ -BlockLibraryController.prototype.populateBlockLibrary = function() { - this.view.clearOptions(); - // Add an unselected option for each saved block. - var blockLibrary = this.storage.blocks; - for (var blockType in blockLibrary) { - this.view.addOption(blockType, false); - } - this.addOptionSelectHandlers(); -}; - -/** - * Return block library mapping block type to XML. - * @return {Object} Object mapping block type to XML text. - */ -BlockLibraryController.prototype.getBlockLibrary = function() { - return this.storage.getBlockXmlTextMap(); -}; - -/** - * Return stored XML of a given block type. - * @param {string} blockType The type of block. - * @return {!Element} XML element of a given block type or null. - */ -BlockLibraryController.prototype.getBlockXml = function(blockType) { - return this.storage.getBlockXml(blockType); -}; - -/** - * Set the block library storage object from which exporter exports. - * @param {!BlockLibraryStorage} blockLibStorage Block Library Storage object. - */ -BlockLibraryController.prototype.setBlockLibraryStorage - = function(blockLibStorage) { - this.storage = blockLibStorage; -}; - -/** - * Get the block library storage object from which exporter exports. - * @return {!BlockLibraryStorage} blockLibStorage Block Library Storage object - * that stores the blocks. - */ -BlockLibraryController.prototype.getBlockLibraryStorage = function() { - return this.blockLibStorage; -}; - -/** - * Get the block library storage object from which exporter exports. - * @return {boolean} True if the Block Library is empty, false otherwise. - */ -BlockLibraryController.prototype.hasEmptyBlockLibrary = function() { - return this.storage.isEmpty(); -}; - -/** - * Get all block types stored in block library. - * @return {!Array.} Array of block types. - */ -BlockLibraryController.prototype.getStoredBlockTypes = function() { - return this.storage.getBlockTypes(); -}; - -/** - * Sets the currently selected block option to none. - */ -BlockLibraryController.prototype.setNoneSelected = function() { - this.view.setSelectedBlockType(null); -}; - -/** - * If there are unsaved changes to the block in open in Block Factory - * and the block is not the starter block, check if user wants to proceed, - * knowing that it will cause them to lose their changes. - * @return {boolean} Whether or not to proceed. - */ -BlockLibraryController.prototype.warnIfUnsavedChanges = function() { - if (!FactoryUtils.savedBlockChanges(this)) { - return confirm('You have unsaved changes. By proceeding without saving ' + - ' your block first, you will lose these changes.'); - } - return true; -}; - -/** - * Add select handler for an option of a given block type. The handler will to - * update the view and the selected block accordingly. - * @param {string} blockType The type of block represented by the option is for. - */ -BlockLibraryController.prototype.addOptionSelectHandler = function(blockType) { - var self = this; - - // Click handler for a block option. Sets the block option as the selected - // option and opens the block for edit in Block Factory. - var setSelectedAndOpen_ = function(blockOption) { - var blockType = blockOption.textContent; - self.view.setSelectedBlockType(blockType); - self.openBlock(blockType); - // The block is saved in the block library and all changes have been saved - // when the user opens a block from the block library dropdown. - // Thus, the buttons show up as a disabled update button and an enabled - // delete. - self.view.updateButtons(blockType, true, true); - blocklyFactory.closeModal(); - }; - - // Returns a block option select handler. - var makeOptionSelectHandler_ = function(blockOption) { - return function() { - // If there are unsaved changes warn user, check if they'd like to - // proceed with unsaved changes, and act accordingly. - var proceedWithUnsavedChanges = self.warnIfUnsavedChanges(); - if (!proceedWithUnsavedChanges) { - return; - } - setSelectedAndOpen_(blockOption); - }; - }; - - // Assign a click handler to the block option. - var blockOption = this.view.optionMap[blockType]; - // Use an additional closure to correctly assign the tab callback. - blockOption.addEventListener( - 'click', makeOptionSelectHandler_(blockOption)); -}; - -/** - * Add select handlers to each option to update the view and the selected - * blocks accordingly. - */ -BlockLibraryController.prototype.addOptionSelectHandlers = function() { - // Assign a click handler to each block option. - for (var blockType in this.view.optionMap) { - this.addOptionSelectHandler(blockType); - } -}; - -/** - * Update the save and delete buttons based on the current block type of the - * block the user is currently editing. - * @param {boolean} Whether changes to the block have been saved. - */ -BlockLibraryController.prototype.updateButtons = function(savedChanges) { - var blockType = this.getCurrentBlockType(); - var isInLibrary = this.has(blockType); - this.view.updateButtons(blockType, isInLibrary, savedChanges); -}; diff --git a/trunk/web/blockly/demos/blockfactory/block_library_storage.js b/trunk/web/blockly/demos/blockfactory/block_library_storage.js deleted file mode 100644 index 750717752f0..00000000000 --- a/trunk/web/blockly/demos/blockfactory/block_library_storage.js +++ /dev/null @@ -1,170 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Javascript for Block Library's Storage Class. - * Depends on Block Library for its namespace. - * - * @author quachtina96 (Tina Quach) - */ - -'use strict'; - -goog.provide('BlockLibraryStorage'); - - -/** - * Represents a block library's storage. - * @param {string} blockLibraryName Desired name of Block Library, also used - * to create the key for where it's stored in local storage. - * @param {Object} opt_blocks Object mapping block type to XML. - * @constructor - */ -BlockLibraryStorage = function(blockLibraryName, opt_blocks) { - // Add prefix to this.name to avoid collisions in local storage. - this.name = 'BlockLibraryStorage.' + blockLibraryName; - if (!opt_blocks) { - // Initialize this.blocks by loading from local storage. - this.loadFromLocalStorage(); - if (this.blocks == null) { - this.blocks = Object.create(null); - // The line above is equivalent of {} except that this object is TRULY - // empty. It doesn't have built-in attributes/functions such as length or - // toString. - this.saveToLocalStorage(); - } - } else { - this.blocks = opt_blocks; - this.saveToLocalStorage(); - } -}; - -/** - * Reads the named block library from local storage and saves it in this.blocks. - */ -BlockLibraryStorage.prototype.loadFromLocalStorage = function() { - // goog.global is synonymous to window, and allows for flexibility - // between browsers. - var object = goog.global.localStorage[this.name]; - this.blocks = object ? JSON.parse(object) : null; -}; - -/** - * Writes the current block library (this.blocks) to local storage. - */ -BlockLibraryStorage.prototype.saveToLocalStorage = function() { - goog.global.localStorage[this.name] = JSON.stringify(this.blocks); -}; - -/** - * Clears the current block library. - */ -BlockLibraryStorage.prototype.clear = function() { - this.blocks = Object.create(null); - // The line above is equivalent of {} except that this object is TRULY - // empty. It doesn't have built-in attributes/functions such as length or - // toString. -}; - -/** - * Saves block to block library. - * @param {string} blockType Type of block. - * @param {Element} blockXML The block's XML pulled from workspace. - */ -BlockLibraryStorage.prototype.addBlock = function(blockType, blockXML) { - var prettyXml = Blockly.Xml.domToPrettyText(blockXML); - this.blocks[blockType] = prettyXml; -}; - -/** - * Removes block from current block library (this.blocks). - * @param {string} blockType Type of block. - */ -BlockLibraryStorage.prototype.removeBlock = function(blockType) { - delete this.blocks[blockType]; -}; - -/** - * Returns the XML of given block type stored in current block library - * (this.blocks). - * @param {string} blockType Type of block. - * @return {Element} The XML that represents the block type or null. - */ -BlockLibraryStorage.prototype.getBlockXml = function(blockType) { - var xml = this.blocks[blockType] || null; - if (xml) { - var xml = Blockly.Xml.textToDom(xml); - } - return xml; -}; - - -/** - * Returns map of each block type to its corresponding XML stored in current - * block library (this.blocks). - * @param {!Array.} blockTypes Types of blocks. - * @return {!Object} Map of block type to corresponding XML. - */ -BlockLibraryStorage.prototype.getBlockXmlMap = function(blockTypes) { - var blockXmlMap = {}; - for (var i = 0; i < blockTypes.length; i++) { - var blockType = blockTypes[i]; - var xml = this.getBlockXml(blockType); - blockXmlMap[blockType] = xml; - } - return blockXmlMap; -}; - -/** - * Returns array of all block types stored in current block library. - * @return {!Array.} Array of block types stored in library. - */ -BlockLibraryStorage.prototype.getBlockTypes = function() { - return Object.keys(this.blocks); -}; - -/** - * Checks to see if block library is empty. - * @return {boolean} True if empty, false otherwise. - */ -BlockLibraryStorage.prototype.isEmpty = function() { - for (var blockType in this.blocks) { - return false; - } - return true; -}; - -/** - * Returns array of all block types stored in current block library. - * @return {!Array.} Map of block type to corresponding XML text. - */ -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]; -}; diff --git a/trunk/web/blockly/demos/blockfactory/block_library_view.js b/trunk/web/blockly/demos/blockfactory/block_library_view.js deleted file mode 100644 index 16181f290c6..00000000000 --- a/trunk/web/blockly/demos/blockfactory/block_library_view.js +++ /dev/null @@ -1,201 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Javascript for BlockLibraryView class. It manages the display - * of the Block Library dropdown, save, and delete buttons. - * - * @author quachtina96 (Tina Quach) - */ - -'use strict'; - -goog.provide('BlockLibraryView'); - -goog.require('goog.dom'); -goog.require('goog.dom.classlist'); - - -/** - * BlockLibraryView Class - * @constructor - */ -var BlockLibraryView = function() { - // Div element to contain the block types to choose from. - this.dropdown = document.getElementById('dropdownDiv_blockLib'); - // Map of block type to corresponding 'a' element that is the option in the - // dropdown. Used to quickly and easily get a specific option. - this.optionMap = Object.create(null); - // Save and delete buttons. - this.saveButton = document.getElementById('saveToBlockLibraryButton'); - this.deleteButton = document.getElementById('removeBlockFromLibraryButton'); - // Initially, user should not be able to delete a block. They must save a - // block or select a stored block first. - this.deleteButton.disabled = true; -}; - -/** - * Creates a node of a given element type and appends to the node with given ID. - * @param {string} blockType Type of block. - * @param {boolean} selected Whether or not the option should be selected on - * the dropdown. - */ -BlockLibraryView.prototype.addOption = function(blockType, selected) { - // Create option. - var option = goog.dom.createDom('a', { - 'id': 'dropdown_' + blockType, - 'class': 'blockLibOpt' - }, blockType); - - // Add option to dropdown. - this.dropdown.appendChild(option); - this.optionMap[blockType] = option; - - // Select the block. - if (selected) { - this.setSelectedBlockType(blockType); - } -}; - -/** - * Sets a given block type to selected and all other blocks to deselected. - * If null, deselects all blocks. - * @param {string} blockTypeToSelect Type of block to select or null. - */ -BlockLibraryView.prototype.setSelectedBlockType = function(blockTypeToSelect) { - // Select given block type and deselect all others. Will deselect all blocks - // if null or invalid block type selected. - for (var blockType in this.optionMap) { - var option = this.optionMap[blockType]; - if (blockType == blockTypeToSelect) { - this.selectOption_(option); - } else { - this.deselectOption_(option); - } - } -}; - -/** - * Selects a given option. - * @param {!Element} option HTML 'a' element in the dropdown that represents - * a particular block type. - * @private - */ -BlockLibraryView.prototype.selectOption_ = function(option) { - goog.dom.classlist.add(option, 'dropdown-content-selected'); -}; - -/** - * Deselects a given option. - * @param {!Element} option HTML 'a' element in the dropdown that represents - * a particular block type. - * @private - */ -BlockLibraryView.prototype.deselectOption_ = function(option) { - goog.dom.classlist.remove(option, 'dropdown-content-selected'); -}; - -/** - * Updates the save and delete buttons to represent how the current block will - * be saved by including the block type in the button text as well as indicating - * whether the block is being saved or updated. - * @param {string} blockType The type of block being edited. - * @param {boolean} isInLibrary Whether the block type is in the library. - * @param {boolean} savedChanges Whether changes to block have been saved. - */ -BlockLibraryView.prototype.updateButtons = - function(blockType, isInLibrary, savedChanges) { - if (blockType) { - // User is editing a block. - - if (!isInLibrary) { - // Block type has not been saved to library yet. Disable the delete button - // and allow user to save. - this.saveButton.textContent = 'Save "' + blockType + '"'; - this.saveButton.disabled = false; - this.deleteButton.disabled = true; - } else { - // Block type has already been saved. Disable the save button unless the - // there are unsaved changes (checked below). - this.saveButton.textContent = 'Update "' + blockType + '"'; - this.saveButton.disabled = true; - this.deleteButton.disabled = false; - } - this.deleteButton.textContent = 'Delete "' + blockType + '"'; - - // If changes to block have been made and are not saved, make button - // green to encourage user to save the block. - if (!savedChanges) { - var buttonFormatClass = 'button_warn'; - - // If block type is the default, 'block_type', make button red to alert - // user. - if (blockType == 'block_type') { - buttonFormatClass = 'button_alert'; - } - goog.dom.classlist.add(this.saveButton, buttonFormatClass); - this.saveButton.disabled = false; - - } else { - // No changes to save. - var classesToRemove = ['button_alert', 'button_warn']; - goog.dom.classlist.removeAll(this.saveButton, classesToRemove); - this.saveButton.disabled = true; - } - - } -}; - -/** - * Removes option currently selected in dropdown from dropdown menu. - */ -BlockLibraryView.prototype.removeSelectedOption = function() { - var selectedOption = this.getSelectedOption(); - this.dropdown.removeNode(selectedOption); -}; - -/** - * Returns block type of selected block. - * @return {string} Type of block selected. - */ -BlockLibraryView.prototype.getSelectedBlockType = function() { - var selectedOption = this.getSelectedOption(); - var blockType = selectedOption.textContent; - return blockType; -}; - -/** - * Returns selected option. - * @return {!Element} HTML 'a' element that is the option for a block type. - */ -BlockLibraryView.prototype.getSelectedOption = function() { - return this.dropdown.getElementsByClassName('dropdown-content-selected')[0]; -}; - -/** - * Removes all options from dropdown. - */ -BlockLibraryView.prototype.clearOptions = function() { - var blockOpts = this.dropdown.getElementsByClassName('blockLibOpt'); - var option; - while ((option = blockOpts[0])) { - option.parentNode.removeChild(option); - } -}; diff --git a/trunk/web/blockly/demos/blockfactory/block_option.js b/trunk/web/blockly/demos/blockfactory/block_option.js deleted file mode 100644 index 8bc1a2fd411..00000000000 --- a/trunk/web/blockly/demos/blockfactory/block_option.js +++ /dev/null @@ -1,176 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Javascript for the BlockOption class, used to represent each of - * the various blocks that you may select. Each block option has a checkbox, - * a label, and a preview workspace through which to view the block. - * - * @author quachtina96 (Tina Quach) - */ -'use strict'; - -goog.provide('BlockOption'); -goog.require('goog.dom'); - - - /** - * BlockOption Class - * A block option includes checkbox, label, and div element that shows a preview - * of the block. - * @param {!Element} blockSelector Scrollable div that will contain the - * block options for the selector. - * @param {string} blockType Type of block for which to create an option. - * @param {!Element} previewBlockXml XML element containing the preview block. - * @constructor - */ -var BlockOption = function(blockSelector, blockType, previewBlockXml) { - // The div to contain the block option. - this.blockSelector = blockSelector; - // The type of block represented by the option. - this.blockType = blockType; - // The checkbox for the option. Set in createDom. - this.checkbox = null; - // The dom for the option. Set in createDom. - this.dom = null; - // Xml element containing the preview block. - this.previewBlockXml = previewBlockXml; - // Workspace containing preview of block. Set upon injection of workspace in - // showPreviewBlock. - this.previewWorkspace = null; - // Whether or not block the option is selected. - this.selected = false; - // Using this.selected rather than this.checkbox.checked allows for proper - // handling of click events on the block option; Without this, clicking - // directly on the checkbox does not toggle selection. -}; - -/** - * Creates the dom for a single block option. Includes checkbox, label, and div - * in which to inject the preview block. - * @return {!Element} Root node of the selector dom which consists of a - * checkbox, a label, and a fixed size preview workspace per block. - */ -BlockOption.prototype.createDom = function() { - // Create the div for the block option. - var blockOptContainer = goog.dom.createDom('div', { - 'id': this.blockType, - 'class': 'blockOption' - }, ''); // Empty quotes for empty div. - - // Create and append div in which to inject the workspace for viewing the - // block option. - var blockOptionPreview = goog.dom.createDom('div', { - 'id' : this.blockType + '_workspace', - 'class': 'blockOption_preview' - }, ''); - blockOptContainer.appendChild(blockOptionPreview); - - // Create and append container to hold checkbox and label. - var checkLabelContainer = goog.dom.createDom('div', { - 'class': 'blockOption_checkLabel' - }, ''); - blockOptContainer.appendChild(checkLabelContainer); - - // Create and append container for checkbox. - var checkContainer = goog.dom.createDom('div', { - 'class': 'blockOption_check' - }, ''); - checkLabelContainer.appendChild(checkContainer); - - // Create and append checkbox. - this.checkbox = goog.dom.createDom('input', { - 'type': 'checkbox', - 'id': this.blockType + '_check' - }, ''); - checkContainer.appendChild(this.checkbox); - - // Create and append container for block label. - var labelContainer = goog.dom.createDom('div', { - 'class': 'blockOption_label' - }, ''); - checkLabelContainer.appendChild(labelContainer); - - // Create and append text node for the label. - var labelText = goog.dom.createDom('p', { - 'id': this.blockType + '_text' - }, this.blockType); - labelContainer.appendChild(labelText); - - this.dom = blockOptContainer; - return this.dom; -}; - -/** - * Injects a workspace containing the block into the block option's preview div. - */ -BlockOption.prototype.showPreviewBlock = function() { - // Get ID of preview workspace. - var blockOptPreviewID = this.dom.id + '_workspace'; - - // Inject preview block. - var workspace = Blockly.inject(blockOptPreviewID, {readOnly:true}); - Blockly.Xml.domToWorkspace(this.previewBlockXml, workspace); - this.previewWorkspace = workspace; - - // Center the preview block in the workspace. - this.centerBlock(); -}; - -/** - * Centers the preview block in the workspace. - */ -BlockOption.prototype.centerBlock = function() { - // Get metrics. - var block = this.previewWorkspace.getTopBlocks()[0]; - var blockMetrics = block.getHeightWidth(); - var blockCoordinates = block.getRelativeToSurfaceXY(); - var workspaceMetrics = this.previewWorkspace.getMetrics(); - - // Calculate new coordinates. - var x = workspaceMetrics.viewWidth/2 - blockMetrics['width']/2 - - blockCoordinates.x; - var y = workspaceMetrics.viewHeight/2 - blockMetrics['height']/2 - - blockCoordinates.y; - - // Move block. - block.moveBy(x, y); -}; - -/** - * Selects or deselects the block option. - * @param {!boolean} selected True if selecting option, false if deselecting - * option. - */ -BlockOption.prototype.setSelected = function(selected) { - this.selected = selected; - if (this.checkbox) { - this.checkbox.checked = selected; - } -}; - -/** - * Returns boolean telling whether or not block is selected. - * @return {!boolean} True if selecting option, false if deselecting - * option. - */ -BlockOption.prototype.isSelected = function() { - return this.selected; -}; diff --git a/trunk/web/blockly/demos/blockfactory/blocks.js b/trunk/web/blockly/demos/blockfactory/blocks.js deleted file mode 100644 index 6dcd0061709..00000000000 --- a/trunk/web/blockly/demos/blockfactory/blocks.js +++ /dev/null @@ -1,905 +0,0 @@ -/** - * Blockly Demos: Block Factory Blocks - * - * Copyright 2012 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Blocks for Blockly's Block Factory application. - * @author fraser@google.com (Neil Fraser) - */ -'use strict'; - -Blockly.Blocks['factory_base'] = { - // Base of new block. - init: function() { - this.setColour(120); - this.appendDummyInput() - .appendField('name') - .appendField(new Blockly.FieldTextInput('block_type'), 'NAME'); - this.appendStatementInput('INPUTS') - .setCheck('Input') - .appendField('inputs'); - var dropdown = new Blockly.FieldDropdown([ - ['automatic inputs', 'AUTO'], - ['external inputs', 'EXT'], - ['inline inputs', 'INT']]); - this.appendDummyInput() - .appendField(dropdown, 'INLINE'); - dropdown = new Blockly.FieldDropdown([ - ['no connections', 'NONE'], - ['← left output', 'LEFT'], - ['↕ top+bottom connections', 'BOTH'], - ['↑ top connection', 'TOP'], - ['↓ bottom connection', 'BOTTOM']], - function(option) { - this.sourceBlock_.updateShape_(option); - // Connect a shadow block to this new input. - this.sourceBlock_.spawnOutputShadow_(option); - }); - this.appendDummyInput() - .appendField(dropdown, 'CONNECTIONS'); - this.appendValueInput('TOOLTIP') - .setCheck('String') - .appendField('tooltip'); - this.appendValueInput('HELPURL') - .setCheck('String') - .appendField('help url'); - this.appendValueInput('COLOUR') - .setCheck('Colour') - .appendField('colour'); - this.setTooltip('Build a custom block by plugging\n' + - 'fields, inputs and other blocks here.'); - this.setHelpUrl( - 'https://developers.google.com/blockly/guides/create-custom-blocks/block-factory'); - }, - mutationToDom: function() { - var container = document.createElement('mutation'); - container.setAttribute('connections', this.getFieldValue('CONNECTIONS')); - return container; - }, - domToMutation: function(xmlElement) { - var connections = xmlElement.getAttribute('connections'); - this.updateShape_(connections); - }, - spawnOutputShadow_: function(option) { - // Helper method for deciding which type of outputs this block needs - // to attach shaddow blocks to. - switch (option) { - case 'LEFT': - this.connectOutputShadow_('OUTPUTTYPE'); - break; - case 'TOP': - this.connectOutputShadow_('TOPTYPE'); - break; - case 'BOTTOM': - this.connectOutputShadow_('BOTTOMTYPE'); - break; - case 'BOTH': - this.connectOutputShadow_('TOPTYPE'); - this.connectOutputShadow_('BOTTOMTYPE'); - break; - } - }, - connectOutputShadow_: function(outputType) { - // Helper method to create & connect shadow block. - var type = this.workspace.newBlock('type_null'); - type.setShadow(true); - type.outputConnection.connect(this.getInput(outputType).connection); - type.initSvg(); - type.render(); - }, - updateShape_: function(option) { - var outputExists = this.getInput('OUTPUTTYPE'); - var topExists = this.getInput('TOPTYPE'); - var bottomExists = this.getInput('BOTTOMTYPE'); - if (option == 'LEFT') { - if (!outputExists) { - this.addTypeInput_('OUTPUTTYPE', 'output type'); - } - } else if (outputExists) { - this.removeInput('OUTPUTTYPE'); - } - if (option == 'TOP' || option == 'BOTH') { - if (!topExists) { - this.addTypeInput_('TOPTYPE', 'top type'); - } - } else if (topExists) { - this.removeInput('TOPTYPE'); - } - if (option == 'BOTTOM' || option == 'BOTH') { - if (!bottomExists) { - this.addTypeInput_('BOTTOMTYPE', 'bottom type'); - } - } else if (bottomExists) { - this.removeInput('BOTTOMTYPE'); - } - }, - addTypeInput_: function(name, label) { - this.appendValueInput(name) - .setCheck('Type') - .appendField(label); - this.moveInputBefore(name, 'COLOUR'); - } -}; - -var FIELD_MESSAGE = 'fields %1 %2'; -var FIELD_ARGS = [ - { - "type": "field_dropdown", - "name": "ALIGN", - "options": [['left', 'LEFT'], ['right', 'RIGHT'], ['centre', 'CENTRE']], - }, - { - "type": "input_statement", - "name": "FIELDS", - "check": "Field" - } -]; - -var TYPE_MESSAGE = 'type %1'; -var TYPE_ARGS = [ - { - "type": "input_value", - "name": "TYPE", - "check": "Type", - "align": "RIGHT" - } -]; - -Blockly.Blocks['input_value'] = { - // Value input. - init: function() { - this.jsonInit({ - "message0": "value input %1 %2", - "args0": [ - { - "type": "field_input", - "name": "INPUTNAME", - "text": "NAME" - }, - { - "type": "input_dummy" - } - ], - "message1": FIELD_MESSAGE, - "args1": FIELD_ARGS, - "message2": TYPE_MESSAGE, - "args2": TYPE_ARGS, - "previousStatement": "Input", - "nextStatement": "Input", - "colour": 210, - "tooltip": "A value socket for horizontal connections.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=71" - }); - }, - onchange: function() { - inputNameCheck(this); - } -}; - -Blockly.Blocks['input_statement'] = { - // Statement input. - init: function() { - this.jsonInit({ - "message0": "statement input %1 %2", - "args0": [ - { - "type": "field_input", - "name": "INPUTNAME", - "text": "NAME" - }, - { - "type": "input_dummy" - }, - ], - "message1": FIELD_MESSAGE, - "args1": FIELD_ARGS, - "message2": TYPE_MESSAGE, - "args2": TYPE_ARGS, - "previousStatement": "Input", - "nextStatement": "Input", - "colour": 210, - "tooltip": "A statement socket for enclosed vertical stacks.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=246" - }); - }, - onchange: function() { - inputNameCheck(this); - } -}; - -Blockly.Blocks['input_dummy'] = { - // Dummy input. - init: function() { - this.jsonInit({ - "message0": "dummy input", - "message1": FIELD_MESSAGE, - "args1": FIELD_ARGS, - "previousStatement": "Input", - "nextStatement": "Input", - "colour": 210, - "tooltip": "For adding fields on a separate row with no " + - "connections. Alignment options (left, right, centre) " + - "apply only to multi-line fields.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=293" - }); - } -}; - -Blockly.Blocks['field_static'] = { - // Text value. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('text') - .appendField(new Blockly.FieldTextInput(''), 'TEXT'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Static text that serves as a label.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=88'); - } -}; - -Blockly.Blocks['field_input'] = { - // Text input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('text input') - .appendField(new Blockly.FieldTextInput('default'), 'TEXT') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('An input field for the user to enter text.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=319'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_number'] = { - // Numeric input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('numeric input') - .appendField(new Blockly.FieldNumber(0), 'VALUE') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.appendDummyInput() - .appendField('min') - .appendField(new Blockly.FieldNumber(-Infinity), 'MIN') - .appendField('max') - .appendField(new Blockly.FieldNumber(Infinity), 'MAX') - .appendField('precision') - .appendField(new Blockly.FieldNumber(0, 0), 'PRECISION'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('An input field for the user to enter a number.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=319'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_angle'] = { - // Angle input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('angle input') - .appendField(new Blockly.FieldAngle('90'), 'ANGLE') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('An input field for the user to enter an angle.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=372'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_dropdown'] = { - // Dropdown menu. - init: function() { - this.appendDummyInput() - .appendField('dropdown') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.optionList_ = ['text', 'text', 'text']; - this.updateShape_(); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setMutator(new Blockly.Mutator(['field_dropdown_option_text', - 'field_dropdown_option_image'])); - this.setColour(160); - this.setTooltip('Dropdown menu with a list of options.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386'); - }, - mutationToDom: function(workspace) { - // Create XML to represent menu options. - var container = document.createElement('mutation'); - container.setAttribute('options', JSON.stringify(this.optionList_)); - return container; - }, - domToMutation: function(container) { - // Parse XML to restore the menu options. - var value = JSON.parse(container.getAttribute('options')); - if (typeof value == 'number') { - // Old format from before images were added. November 2016. - this.optionList_ = []; - for (var i = 0; i < value; i++) { - this.optionList_.push('text'); - } - } else { - this.optionList_ = value; - } - this.updateShape_(); - }, - decompose: function(workspace) { - // Populate the mutator's dialog with this block's components. - var containerBlock = workspace.newBlock('field_dropdown_container'); - containerBlock.initSvg(); - var connection = containerBlock.getInput('STACK').connection; - for (var i = 0; i < this.optionList_.length; i++) { - var optionBlock = workspace.newBlock( - 'field_dropdown_option_' + this.optionList_[i]); - optionBlock.initSvg(); - connection.connect(optionBlock.previousConnection); - connection = optionBlock.nextConnection; - } - return containerBlock; - }, - compose: function(containerBlock) { - // Reconfigure this block based on the mutator dialog's components. - var optionBlock = containerBlock.getInputTargetBlock('STACK'); - // Count number of inputs. - this.optionList_.length = 0; - var data = []; - while (optionBlock) { - if (optionBlock.type == 'field_dropdown_option_text') { - this.optionList_.push('text'); - } else if (optionBlock.type == 'field_dropdown_option_image') { - this.optionList_.push('image'); - } - data.push([optionBlock.userData_, optionBlock.cpuData_]); - optionBlock = optionBlock.nextConnection && - optionBlock.nextConnection.targetBlock(); - } - this.updateShape_(); - // Restore any data. - for (var i = 0; i < this.optionList_.length; i++) { - var userData = data[i][0]; - if (userData !== undefined) { - if (typeof userData == 'string') { - this.setFieldValue(userData || 'option', 'USER' + i); - } else { - this.setFieldValue(userData.src, 'SRC' + i); - this.setFieldValue(userData.width, 'WIDTH' + i); - this.setFieldValue(userData.height, 'HEIGHT' + i); - this.setFieldValue(userData.alt, 'ALT' + i); - } - this.setFieldValue(data[i][1] || 'OPTIONNAME', 'CPU' + i); - } - } - }, - saveConnections: function(containerBlock) { - // Store all data for each option. - var optionBlock = containerBlock.getInputTargetBlock('STACK'); - var i = 0; - while (optionBlock) { - optionBlock.userData_ = this.getUserData(i); - optionBlock.cpuData_ = this.getFieldValue('CPU' + i); - i++; - optionBlock = optionBlock.nextConnection && - optionBlock.nextConnection.targetBlock(); - } - }, - updateShape_: function() { - // Delete everything. - var i = 0; - while (this.getInput('OPTION' + i)) { - this.removeInput('OPTION' + i); - this.removeInput('OPTION_IMAGE' + i, true); - i++; - } - // Rebuild block. - var src = 'https://www.gstatic.com/codesite/ph/images/star_on.gif'; - for (var i = 0; i <= this.optionList_.length; i++) { - var type = this.optionList_[i]; - if (type == 'text') { - this.appendDummyInput('OPTION' + i) - .appendField('•') - .appendField(new Blockly.FieldTextInput('option'), 'USER' + i) - .appendField(',') - .appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU' + i); - } else if (type == 'image') { - this.appendDummyInput('OPTION' + i) - .appendField('•') - .appendField('image') - .appendField(new Blockly.FieldTextInput(src), 'SRC' + i); - this.appendDummyInput('OPTION_IMAGE' + i) - .appendField(' ') - .appendField('width') - .appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'WIDTH' + i) - .appendField('height') - .appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'HEIGHT' + i) - .appendField('alt text') - .appendField(new Blockly.FieldTextInput('*'), 'ALT' + i) - .appendField(',') - .appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU' + i); - } - } - }, - onchange: function() { - if (this.workspace && this.optionList_.length < 1) { - this.setWarningText('Drop down menu must\nhave at least one option.'); - } else { - fieldNameCheck(this); - } - }, - getUserData: function(n) { - if (this.optionList_[n] == 'text') { - return this.getFieldValue('USER' + n); - } - if (this.optionList_[n] == 'image') { - return { - src: this.getFieldValue('SRC' + n), - width: Number(this.getFieldValue('WIDTH' + n)), - height: Number(this.getFieldValue('HEIGHT' + n)), - alt: this.getFieldValue('ALT' + n) - }; - } - throw 'Unknown dropdown type'; - } -}; - -Blockly.Blocks['field_dropdown_container'] = { - // Container. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('add options'); - this.appendStatementInput('STACK'); - this.setTooltip('Add, remove, or reorder options\n' + - 'to reconfigure this dropdown menu.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386'); - this.contextMenu = false; - } -}; - -Blockly.Blocks['field_dropdown_option_text'] = { - // Add text option. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('text option'); - this.setPreviousStatement(true); - this.setNextStatement(true); - this.setTooltip('Add a new text option to the dropdown menu.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386'); - this.contextMenu = false; - } -}; - -Blockly.Blocks['field_dropdown_option_image'] = { - // Add image option. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('image option'); - this.setPreviousStatement(true); - this.setNextStatement(true); - this.setTooltip('Add a new image option to the dropdown menu.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386'); - this.contextMenu = false; - } -}; - -Blockly.Blocks['field_checkbox'] = { - // Checkbox. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('checkbox') - .appendField(new Blockly.FieldCheckbox('TRUE'), 'CHECKED') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Checkbox field.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=485'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_colour'] = { - // Colour input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('colour') - .appendField(new Blockly.FieldColour('#ff0000'), 'COLOUR') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Colour input field.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=495'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_date'] = { - // Date input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('date') - .appendField(new Blockly.FieldDate(), 'DATE') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Date input field.'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_variable'] = { - // Dropdown for variables. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('variable') - .appendField(new Blockly.FieldTextInput('item'), 'TEXT') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Dropdown menu for variable names.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=510'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_image'] = { - // Image. - init: function() { - this.setColour(160); - var src = 'https://www.gstatic.com/codesite/ph/images/star_on.gif'; - this.appendDummyInput() - .appendField('image') - .appendField(new Blockly.FieldTextInput(src), 'SRC'); - this.appendDummyInput() - .appendField('width') - .appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'WIDTH') - .appendField('height') - .appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'HEIGHT') - .appendField('alt text') - .appendField(new Blockly.FieldTextInput('*'), 'ALT'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Static image (JPEG, PNG, GIF, SVG, BMP).\n' + - 'Retains aspect ratio regardless of height and width.\n' + - 'Alt text is for when collapsed.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=567'); - } -}; - -Blockly.Blocks['type_group'] = { - // Group of types. - init: function() { - this.typeCount_ = 2; - this.updateShape_(); - this.setOutput(true, 'Type'); - this.setMutator(new Blockly.Mutator(['type_group_item'])); - this.setColour(230); - this.setTooltip('Allows more than one type to be accepted.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677'); - }, - mutationToDom: function(workspace) { - // Create XML to represent a group of types. - var container = document.createElement('mutation'); - container.setAttribute('types', this.typeCount_); - return container; - }, - domToMutation: function(container) { - // Parse XML to restore the group of types. - this.typeCount_ = parseInt(container.getAttribute('types'), 10); - this.updateShape_(); - for (var i = 0; i < this.typeCount_; i++) { - this.removeInput('TYPE' + i); - } - for (var i = 0; i < this.typeCount_; i++) { - var input = this.appendValueInput('TYPE' + i) - .setCheck('Type'); - if (i == 0) { - input.appendField('any of'); - } - } - }, - decompose: function(workspace) { - // Populate the mutator's dialog with this block's components. - var containerBlock = workspace.newBlock('type_group_container'); - containerBlock.initSvg(); - var connection = containerBlock.getInput('STACK').connection; - for (var i = 0; i < this.typeCount_; i++) { - var typeBlock = workspace.newBlock('type_group_item'); - typeBlock.initSvg(); - connection.connect(typeBlock.previousConnection); - connection = typeBlock.nextConnection; - } - return containerBlock; - }, - compose: function(containerBlock) { - // Reconfigure this block based on the mutator dialog's components. - var typeBlock = containerBlock.getInputTargetBlock('STACK'); - // Count number of inputs. - var connections = []; - while (typeBlock) { - connections.push(typeBlock.valueConnection_); - typeBlock = typeBlock.nextConnection && - typeBlock.nextConnection.targetBlock(); - } - // Disconnect any children that don't belong. - for (var i = 0; i < this.typeCount_; i++) { - var connection = this.getInput('TYPE' + i).connection.targetConnection; - if (connection && connections.indexOf(connection) == -1) { - connection.disconnect(); - } - } - this.typeCount_ = connections.length; - this.updateShape_(); - // Reconnect any child blocks. - for (var i = 0; i < this.typeCount_; i++) { - Blockly.Mutator.reconnect(connections[i], this, 'TYPE' + i); - } - }, - saveConnections: function(containerBlock) { - // Store a pointer to any connected child blocks. - var typeBlock = containerBlock.getInputTargetBlock('STACK'); - var i = 0; - while (typeBlock) { - var input = this.getInput('TYPE' + i); - typeBlock.valueConnection_ = input && input.connection.targetConnection; - i++; - typeBlock = typeBlock.nextConnection && - typeBlock.nextConnection.targetBlock(); - } - }, - updateShape_: function() { - // Modify this block to have the correct number of inputs. - // Add new inputs. - for (var i = 0; i < this.typeCount_; i++) { - if (!this.getInput('TYPE' + i)) { - var input = this.appendValueInput('TYPE' + i); - if (i == 0) { - input.appendField('any of'); - } - } - } - // Remove deleted inputs. - while (this.getInput('TYPE' + i)) { - this.removeInput('TYPE' + i); - i++; - } - } -}; - -Blockly.Blocks['type_group_container'] = { - // Container. - init: function() { - this.jsonInit({ - "message0": "add types %1 %2", - "args0": [ - {"type": "input_dummy"}, - {"type": "input_statement", "name": "STACK"} - ], - "colour": 230, - "tooltip": "Add, or remove allowed type.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677" - }); - } -}; - -Blockly.Blocks['type_group_item'] = { - // Add type. - init: function() { - this.jsonInit({ - "message0": "type", - "previousStatement": null, - "nextStatement": null, - "colour": 230, - "tooltip": "Add a new allowed type.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677" - }); - } -}; - -Blockly.Blocks['type_null'] = { - // Null type. - valueType: null, - init: function() { - this.jsonInit({ - "message0": "any", - "output": "Type", - "colour": 230, - "tooltip": "Any type is allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_boolean'] = { - // Boolean type. - valueType: 'Boolean', - init: function() { - this.jsonInit({ - "message0": "Boolean", - "output": "Type", - "colour": 230, - "tooltip": "Booleans (true/false) are allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_number'] = { - // Number type. - valueType: 'Number', - init: function() { - this.jsonInit({ - "message0": "Number", - "output": "Type", - "colour": 230, - "tooltip": "Numbers (int/float) are allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_string'] = { - // String type. - valueType: 'String', - init: function() { - this.jsonInit({ - "message0": "String", - "output": "Type", - "colour": 230, - "tooltip": "Strings (text) are allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_list'] = { - // List type. - valueType: 'Array', - init: function() { - this.jsonInit({ - "message0": "Array", - "output": "Type", - "colour": 230, - "tooltip": "Arrays (lists) are allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_other'] = { - // Other type. - init: function() { - this.jsonInit({ - "message0": "other %1", - "args0": [{"type": "field_input", "name": "TYPE", "text": ""}], - "output": "Type", - "colour": 230, - "tooltip": "Custom type to allow.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=702" - }); - } -}; - -Blockly.Blocks['colour_hue'] = { - // Set the colour of the block. - init: function() { - this.appendDummyInput() - .appendField('hue:') - .appendField(new Blockly.FieldAngle('0', this.validator), 'HUE'); - this.setOutput(true, 'Colour'); - this.setTooltip('Paint the block with this colour.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=55'); - }, - validator: function(text) { - // Update the current block's colour to match. - var hue = parseInt(text, 10); - if (!isNaN(hue)) { - this.sourceBlock_.setColour(hue); - } - }, - mutationToDom: function(workspace) { - var container = document.createElement('mutation'); - container.setAttribute('colour', this.getColour()); - return container; - }, - domToMutation: function(container) { - this.setColour(container.getAttribute('colour')); - } -}; - -/** - * Check to see if more than one field has this name. - * Highly inefficient (On^2), but n is small. - * @param {!Blockly.Block} referenceBlock Block to check. - */ -function fieldNameCheck(referenceBlock) { - if (!referenceBlock.workspace) { - // Block has been deleted. - return; - } - var name = referenceBlock.getFieldValue('FIELDNAME').toLowerCase(); - var count = 0; - var blocks = referenceBlock.workspace.getAllBlocks(); - for (var i = 0, block; block = blocks[i]; i++) { - var otherName = block.getFieldValue('FIELDNAME'); - if (!block.disabled && !block.getInheritedDisabled() && - otherName && otherName.toLowerCase() == name) { - count++; - } - } - var msg = (count > 1) ? - 'There are ' + count + ' field blocks\n with this name.' : null; - referenceBlock.setWarningText(msg); -} - -/** - * Check to see if more than one input has this name. - * Highly inefficient (On^2), but n is small. - * @param {!Blockly.Block} referenceBlock Block to check. - */ -function inputNameCheck(referenceBlock) { - if (!referenceBlock.workspace) { - // Block has been deleted. - return; - } - var name = referenceBlock.getFieldValue('INPUTNAME').toLowerCase(); - var count = 0; - var blocks = referenceBlock.workspace.getAllBlocks(); - for (var i = 0, block; block = blocks[i]; i++) { - var otherName = block.getFieldValue('INPUTNAME'); - if (!block.disabled && !block.getInheritedDisabled() && - otherName && otherName.toLowerCase() == name) { - count++; - } - } - var msg = (count > 1) ? - 'There are ' + count + ' input blocks\n with this name.' : null; - referenceBlock.setWarningText(msg); -} diff --git a/trunk/web/blockly/demos/blockfactory/factory.css b/trunk/web/blockly/demos/blockfactory/factory.css deleted file mode 100644 index 6661c139c87..00000000000 --- a/trunk/web/blockly/demos/blockfactory/factory.css +++ /dev/null @@ -1,609 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -html, body { - height: 100%; - min-height: 375px; -} - -body { - background-color: #fff; - font-family: sans-serif; - margin: 0 5px; - overflow: hidden; -} - -h1 { - font-weight: normal; - font-size: 140%; -} - -h3 { - margin-top: 5px; - margin-bottom: 0; -} - -table { - border: none; - border-collapse: collapse; - height: 100%; - margin: 0; - padding: 0; - width: 100%; -} - -td { - vertical-align: top; - padding: 0; -} - -p { - display: block; - -webkit-margin-before: 0em; - -webkit-margin-after: 0em; - -webkit-margin-start: 0px; - -webkit-margin-end: 0px; - padding: 5px 0px; -} - -#factoryHeader { - display: table; - height: 10%; -} - -#blockly { - position: absolute; -} - -#blocklyMask { - background-color: #000; - cursor: not-allowed; - display: none; - position: fixed; - opacity: 0.2; - z-index: 9; -} - -#preview { - position: absolute; -} - -pre, -#languageTA { - border: #ddd 1px solid; - margin-top: 0; - position: absolute; - overflow: scroll; -} - -#languageTA { - display: none; - font: 10pt monospace; -} - -.downloadButton { - padding: 5px; -} - -.disabled { - color: #888; -} - -button:disabled, .buttonStyle:disabled { - opacity: 0.6; -} - -button>*, .buttonStyle>* { - opacity: 1; - vertical-align: text-bottom; -} - -button, .buttonStyle { - border-radius: 4px; - border: 1px solid #ddd; - background-color: #eee; - color: #000; - padding: 10px; - margin: 10px 5px; - font-size: small; -} - -.buttonStyle:hover:not(:disabled), button:hover:not(:disabled) { - box-shadow: 2px 2px 5px #888; -} - -.buttonStyle:hover:not(:disabled)>*, button:hover:not(:disabled)>* { - opacity: 1; -} - -#linkButton { - display: none; -} - -#helpButton { - float: right; -} - -#blockFactoryContent { - height: 85%; - width: 100%; - overflow: hidden; -} - -#blockFactoryPreview { - height: 100%; - width: 100%; -} - -#blockLibraryContainer { - vertical-align: bottom; -} - -#blockLibraryControls { - text-align: right; - vertical-align: middle; -} - -#previewContainer { - vertical-align: bottom; -} - -#buttonContainer { - text-align: right; - vertical-align: middle; -} - -#files { - position: absolute; - visibility: hidden; -} - -.toolbox { - display: none; -} - -#blocklyWorkspaceContainer { - width: 50%; -} - -#workspaceFactoryContent { - clear: both; - display: none; - height: 90%; - overflow-x: hidden; - overflow-y: scroll; -} - -/* Exporter */ - -#blockLibraryExporter { - clear: both; - display: none; - height: 90%; - overflow-x: hidden; - overflow-y: scroll; -} - -#exportSelector { - display: inline-block; - float: left; - height: 70%; - width: 30%; -} - -#exportSettings { - float: left; - overflow: hidden; - padding-left: 16px; - width: 20%; -} - -#selectedBlocksTextContainer { - max-height: 200px; - overflow-y: scroll; - padding-bottom: 2em; -} - -::-webkit-scrollbar { - -webkit-appearance: none; - width: 7px; -} - -::-webkit-scrollbar-thumb { - border-radius: 4px; - background-color: #ccc; - -webkit-box-shadow: 0 0 1px rgba(255,255,255,.5); -} - -.subsettings { - margin: 0px 25px; -} - -#exporterHiddenWorkspace { - display: none; -} - -#exportPreview { - float: right; - height: 90%; - overflow: hidden; - width: 45%; -} - -.exportPreviewTextArea { - display: block; - float: right; - height: 40%; - width: 100%; -} - -#genStubs_textArea, #blockDefs_textArea { - display: block; - height: 80%; - margin-right: 20px; - max-height: 300px; - overflow: scroll; - position: static; -} - -#blockDefs_label, #genStubs_label { - display: block; -} - -#blockSelector { - background-color: #eee; - border: 1px solid lightgrey; - width: 80%; - height: 90%; - overflow-y: scroll; - position: relative; -} - -/* Exporter Block Option */ - -.blockOption { - background-color: #eee; - padding: 0px 20px; - width: 95%; -} - -.blockOption_check_label { - position: relative; -} - -.blockOption_check { - float: left; - display:inline; - padding: 4px; -} - -.blockOption_label { - display:inline; - max-width: inherit; - word-wrap: break-word; -} - -.blockOption_preview { - height: 100px; - padding-top: 10px; - width: 90%; -} - -/* Block Library */ - -#dropdownDiv_blockLib { - max-height: 65%; - overflow-y: scroll; -} - -#button_blockLib { - border-color: darkgrey; - font-size: large; -} - -.button_alert { - background-color: #fcc; - border-color: #f99; -} - -.button_warn { - background-color: #aea; - border-color: #5d5; -} - -/* Tabs */ - -.tab { - float: left; - padding: 5px 19px; -} - -.tab:hover:not(.tabon){ - background-color: #e8e8e8; -} - -.tab.tabon { - background-color: #ccc; -} - -.tab.taboff { - cursor: pointer; -} - -#tabContainer { - background-color: #f8f8f8; - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - display: table; - width: 100%; -} - -/* Workspace Factory */ - -section { - float: left; -} - -aside { - float: right; -} - -#categoryTable>table { - border: 1px solid #ccc; - border-bottom: none; - width: auto; -} - -td.tabon { - background-color: #ccc; - border-bottom-color: #ccc; - padding: 5px 19px; -} - -td.taboff { - cursor: pointer; - padding: 5px 19px; -} - -td.taboff:hover { - background-color: #eee; -} - -.large { - font-size: large; -} - -.inputfile { - height: 0; - opacity: 0; - overflow: hidden; - position: absolute; - width: 0; - z-index: -1; -} -#wfactoryHeader { - height: 29%; - padding: 0.5%; -} - -#workspaceTabs { - background-color: #f8f8f8; - border: 1px solid #ccc; - display: table; - width: auto; -} - -#toolbox_section { - height: 85%; - width: 60%; -} - -#previewHelp { - padding: 10px; - width: 98%; -} - -#toolbox_blocks { - height: 100%; - width: 100%; -} - -#preview_blocks { - height: 80%; - padding: 10px; - width: 100%; -} - -#createDiv { - height: 79%; - padding: 0.5%; - width: 60%; -} - -#previewDiv { - border: 10px solid #eee; - height: 77%; - margin-right: 0.5%; - padding-bottom: 10px; - width: 35%; -} - -#previewBorder { - border: 5px solid #ddd; - height: 100%; - padding-right: 20px; -} - -.disabled { - background-color: white; - opacity: 0.5; -} - -#toolbox_div { - display: table; - height: auto; - margin-right: 5%; - overflow: hidden; - width: 35%; -} - -#preload_div { - display: table; - height: 75%; - margin-left: 2%; - margin-right: 2%; - max-height: 500px; - overflow: hidden; - overflow-y: scroll; - width: 30%; -} - -#shadowBlockDropdown { - height: 15%; -} - -#preloadHelp { - display: table-row; - height: 30%; -} - -#workspace_options { - display: table-row; - margin-top: 2%; -} - -#disable_div { - background-color: white; - height: 100%; - left: 0; - opacity: .5; - position: absolute; - top: 0; - width: 100%; - z-index: -1; /* Start behind workspace */ -} - -#grid_options, #zoom_options, #maxBlockNumber_option { - padding-left: 15px; -} - -#modalShadow { - display: none; - position: fixed; - top: 0; - right: 0; - bottom: 0; - left: 0; - background: rgba(0, 0, 0, 0.05); - z-index: 100; -} - -/* Rules for Closure popup color picker */ -.goog-palette { - outline: none; - cursor: default; -} - -.goog-palette-cell { - height: 13px; - width: 15px; - margin: 0; - border: 0; - text-align: center; - vertical-align: middle; - border-right: 1px solid #000; - font-size: 1px; -} - -.goog-palette-colorswatch { - border: 1px solid #000; - height: 13px; - position: relative; - width: 15px; -} - -.goog-palette-cell-hover .goog-palette-colorswatch { - border: 1px solid #fff; -} - -.goog-palette-cell-selected .goog-palette-colorswatch { - border: 1px solid #000; - color: #fff; -} - -.goog-palette-table { - border: 1px solid #000; - border-collapse: collapse; -} - -.goog-popupcolorpicker { - position: absolute; - z-index: 101; /* On top of the modal Shadow. */ -} - -/* The container
- needed to position the dropdown content */ -.dropdown { - display: inline-block; -} - -/* Dropdown Content (Hidden by Default) */ -.dropdown-content { - background-color: #fff; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,.2); - display: none; - min-width: 170px; - opacity: 1; - position: absolute; - z-index: 101; /* On top of the modal Shadow. */ -} - -/* Links inside the dropdown */ -.dropdown-content a, .dropdown-content label { - color: black; - display: block; - font-size: small; - padding: 12px 16px; - text-decoration: none; -} - -/* Change color of dropdown links on hover. */ -.dropdown-content a:hover, .dropdown-content label:hover { - background-color: #EEE; -} - -/* Change color of dropdown links on selected. */ -.dropdown-content-selected { - background-color: #DDD; -} - -/* Show the dropdown menu */ -.show { - display: block; -} - -.shadowBlock>.blocklyPath { - fill-opacity: .5; - stroke-opacity: .5; -} - -.shadowBlock>.blocklyPathLight, -.shadowBlock>.blocklyPathDark { - display: none; -} diff --git a/trunk/web/blockly/demos/blockfactory/factory.js b/trunk/web/blockly/demos/blockfactory/factory.js deleted file mode 100644 index 974cd8a7ec5..00000000000 --- a/trunk/web/blockly/demos/blockfactory/factory.js +++ /dev/null @@ -1,276 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview JavaScript for Blockly's Block Factory application through - * which users can build blocks using a visual interface and dynamically - * generate a preview block and starter code for the block (block definition and - * generator stub. Uses the Block Factory namespace. Depends on the FactoryUtils - * for its code generation functions. - * - * @author fraser@google.com (Neil Fraser), quachtina96 (Tina Quach) - */ -'use strict'; - -/** - * Namespace for Block Factory. - */ -goog.provide('BlockFactory'); - -goog.require('FactoryUtils'); -goog.require('StandardCategories'); - - -/** - * Workspace for user to build block. - * @type {Blockly.Workspace} - */ -BlockFactory.mainWorkspace = null; - -/** - * Workspace for preview of block. - * @type {Blockly.Workspace} - */ -BlockFactory.previewWorkspace = null; - -/** - * Name of block if not named. - */ -BlockFactory.UNNAMED = 'unnamed'; - -/** - * Existing direction ('ltr' vs 'rtl') of preview. - */ -BlockFactory.oldDir = null; - -/* - * The starting XML for the Block Factory main workspace. Contains the - * unmovable, undeletable factory_base block. - */ -BlockFactory.STARTER_BLOCK_XML_TEXT = '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '230' + - ''; - -/** - * Change the language code format. - */ -BlockFactory.formatChange = function() { - var mask = document.getElementById('blocklyMask'); - var languagePre = document.getElementById('languagePre'); - var languageTA = document.getElementById('languageTA'); - if (document.getElementById('format').value == 'Manual') { - Blockly.hideChaff(); - mask.style.display = 'block'; - languagePre.style.display = 'none'; - languageTA.style.display = 'block'; - var code = languagePre.textContent.trim(); - languageTA.value = code; - languageTA.focus(); - BlockFactory.updatePreview(); - } else { - mask.style.display = 'none'; - languageTA.style.display = 'none'; - languagePre.style.display = 'block'; - BlockFactory.updateLanguage(); - } - BlockFactory.disableEnableLink(); -}; - -/** - * Update the language code based on constructs made in Blockly. - */ -BlockFactory.updateLanguage = function() { - var rootBlock = FactoryUtils.getRootBlock(BlockFactory.mainWorkspace); - if (!rootBlock) { - return; - } - var blockType = rootBlock.getFieldValue('NAME').trim().toLowerCase(); - if (!blockType) { - blockType = BlockFactory.UNNAMED; - } - var format = document.getElementById('format').value; - var code = FactoryUtils.getBlockDefinition(blockType, rootBlock, format, - BlockFactory.mainWorkspace); - FactoryUtils.injectCode(code, 'languagePre'); - BlockFactory.updatePreview(); -}; - -/** - * Update the generator code. - * @param {!Blockly.Block} block Rendered block in preview workspace. - */ -BlockFactory.updateGenerator = function(block) { - var language = document.getElementById('language').value; - var generatorStub = FactoryUtils.getGeneratorStub(block, language); - FactoryUtils.injectCode(generatorStub, 'generatorPre'); -}; - -/** - * Update the preview display. - */ -BlockFactory.updatePreview = function() { - // Toggle between LTR/RTL if needed (also used in first display). - var newDir = document.getElementById('direction').value; - if (BlockFactory.oldDir != newDir) { - if (BlockFactory.previewWorkspace) { - BlockFactory.previewWorkspace.dispose(); - } - var rtl = newDir == 'rtl'; - BlockFactory.previewWorkspace = Blockly.inject('preview', - {rtl: rtl, - media: '../../media/', - scrollbars: true}); - BlockFactory.oldDir = newDir; - } - BlockFactory.previewWorkspace.clear(); - - // Fetch the code and determine its format (JSON or JavaScript). - var format = document.getElementById('format').value; - if (format == 'Manual') { - var code = document.getElementById('languageTA').value; - // If the code is JSON, it will parse, otherwise treat as JS. - try { - JSON.parse(code); - format = 'JSON'; - } catch (e) { - format = 'JavaScript'; - } - } else { - var code = document.getElementById('languagePre').textContent; - } - if (!code.trim()) { - // Nothing to render. Happens while cloud storage is loading. - return; - } - - // Backup Blockly.Blocks object so that main workspace and preview don't - // collide if user creates a 'factory_base' block, for instance. - var backupBlocks = Blockly.Blocks; - try { - // Make a shallow copy. - Blockly.Blocks = Object.create(null); - for (var prop in backupBlocks) { - Blockly.Blocks[prop] = backupBlocks[prop]; - } - - if (format == 'JSON') { - var json = JSON.parse(code); - Blockly.Blocks[json.type || BlockFactory.UNNAMED] = { - init: function() { - this.jsonInit(json); - } - }; - } else if (format == 'JavaScript') { - eval(code); - } else { - throw 'Unknown format: ' + format; - } - - // Look for a block on Blockly.Blocks that does not match the backup. - var blockType = null; - for (var type in Blockly.Blocks) { - if (typeof Blockly.Blocks[type].init == 'function' && - Blockly.Blocks[type] != backupBlocks[type]) { - blockType = type; - break; - } - } - if (!blockType) { - return; - } - - // Create the preview block. - var previewBlock = BlockFactory.previewWorkspace.newBlock(blockType); - previewBlock.initSvg(); - previewBlock.render(); - previewBlock.setMovable(false); - previewBlock.setDeletable(false); - previewBlock.moveBy(15, 10); - BlockFactory.previewWorkspace.clearUndo(); - BlockFactory.updateGenerator(previewBlock); - - // Warn user only if their block type is already exists in Blockly's - // standard library. - var rootBlock = FactoryUtils.getRootBlock(BlockFactory.mainWorkspace); - if (StandardCategories.coreBlockTypes.indexOf(blockType) != -1) { - rootBlock.setWarningText('A core Blockly block already exists ' + - 'under this name.'); - - } else if (blockType == 'block_type') { - // Warn user to let them know they can't save a block under the default - // name 'block_type' - rootBlock.setWarningText('You cannot save a block with the default ' + - 'name, "block_type"'); - - } else { - rootBlock.setWarningText(null); - } - - } finally { - Blockly.Blocks = backupBlocks; - } -}; - -/** - * Disable link and save buttons if the format is 'Manual', enable otherwise. - */ -BlockFactory.disableEnableLink = function() { - var linkButton = document.getElementById('linkButton'); - var saveBlockButton = document.getElementById('localSaveButton'); - var saveToLibButton = document.getElementById('saveToBlockLibraryButton'); - var disabled = document.getElementById('format').value == 'Manual'; - linkButton.disabled = disabled; - saveBlockButton.disabled = disabled; - saveToLibButton.disabled = disabled; -}; - -/** - * Render starter block (factory_base). - */ -BlockFactory.showStarterBlock = function() { - BlockFactory.mainWorkspace.clear(); - var xml = Blockly.Xml.textToDom(BlockFactory.STARTER_BLOCK_XML_TEXT); - Blockly.Xml.domToWorkspace(xml, BlockFactory.mainWorkspace); -}; - -/** - * Returns whether or not the current block open is the starter block. - */ -BlockFactory.isStarterBlock = function() { - var rootBlock = FactoryUtils.getRootBlock(BlockFactory.mainWorkspace); - // The starter block does not have blocks nested into the factory_base block. - return !(rootBlock.getChildren().length > 0 || - // The starter block's name is the default, 'block_type'. - rootBlock.getFieldValue('NAME').trim().toLowerCase() != 'block_type' || - // The starter block has no connections. - rootBlock.getFieldValue('CONNECTIONS') != 'NONE' || - // The starter block has automatic inputs. - rootBlock.getFieldValue('INLINE') != 'AUTO'); -}; diff --git a/trunk/web/blockly/demos/blockfactory/factory_utils.js b/trunk/web/blockly/demos/blockfactory/factory_utils.js deleted file mode 100644 index 5da02f9c47a..00000000000 --- a/trunk/web/blockly/demos/blockfactory/factory_utils.js +++ /dev/null @@ -1,999 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview FactoryUtils is a namespace that holds block starter code - * generation functions shared by the Block Factory, Workspace Factory, and - * Exporter applications within Blockly Factory. Holds functions to generate - * block definitions and generator stubs and to create and download files. - * - * @author fraser@google.com (Neil Fraser), quachtina96 (Tina Quach) - */ - 'use strict'; - -/** - * Namespace for FactoryUtils. - */ -goog.provide('FactoryUtils'); - - -/** - * Get block definition code for the current block. - * @param {string} blockType Type of block. - * @param {!Blockly.Block} rootBlock RootBlock from main workspace in which - * user uses Block Factory Blocks to create a custom block. - * @param {string} format 'JSON' or 'JavaScript'. - * @param {!Blockly.Workspace} workspace Where the root block lives. - * @return {string} Block definition. - */ -FactoryUtils.getBlockDefinition = function(blockType, rootBlock, format, workspace) { - blockType = FactoryUtils.cleanBlockType(blockType); - switch (format) { - case 'JSON': - var code = FactoryUtils.formatJson_(blockType, rootBlock); - break; - case 'JavaScript': - var code = FactoryUtils.formatJavaScript_(blockType, rootBlock, workspace); - break; - } - return code; -}; - -/** - * Convert invalid block name to a valid one. Replaces whitespace - * and prepend names that start with a digit with an '_'. - * @param {string} blockType Type of block. - * @return {string} Cleaned up block type. - */ -FactoryUtils.cleanBlockType = function(blockType) { - if (!blockType) { - return ''; - } - return blockType.replace(/\W/g, '_').replace(/^(\d)/, '_$1'); -}; - -/** - * Get the generator code for a given block. - * @param {!Blockly.Block} block Rendered block in preview workspace. - * @param {string} generatorLanguage 'JavaScript', 'Python', 'PHP', 'Lua', - * 'Dart'. - * @return {string} Generator code for multiple blocks. - */ -FactoryUtils.getGeneratorStub = function(block, generatorLanguage) { - function makeVar(root, name) { - name = name.toLowerCase().replace(/\W/g, '_'); - return ' var ' + root + '_' + name; - } - // The makevar function lives in the original update generator. - var language = generatorLanguage; - var code = []; - code.push("Blockly." + language + "['" + block.type + - "'] = function(block) {"); - - // Generate getters for any fields or inputs. - for (var i = 0, input; input = block.inputList[i]; i++) { - for (var j = 0, field; field = input.fieldRow[j]; j++) { - var name = field.name; - if (!name) { - continue; - } - if (field instanceof Blockly.FieldVariable) { - // Subclass of Blockly.FieldDropdown, must test first. - code.push(makeVar('variable', name) + - " = Blockly." + language + - ".variableDB_.getName(block.getFieldValue('" + name + - "'), Blockly.Variables.NAME_TYPE);"); - } else if (field instanceof Blockly.FieldAngle) { - // Subclass of Blockly.FieldTextInput, must test first. - code.push(makeVar('angle', name) + - " = block.getFieldValue('" + name + "');"); - } else if (Blockly.FieldDate && field instanceof Blockly.FieldDate) { - // Blockly.FieldDate may not be compiled into Blockly. - code.push(makeVar('date', name) + - " = block.getFieldValue('" + name + "');"); - } else if (field instanceof Blockly.FieldColour) { - code.push(makeVar('colour', name) + - " = block.getFieldValue('" + name + "');"); - } else if (field instanceof Blockly.FieldCheckbox) { - code.push(makeVar('checkbox', name) + - " = block.getFieldValue('" + name + "') == 'TRUE';"); - } else if (field instanceof Blockly.FieldDropdown) { - code.push(makeVar('dropdown', name) + - " = block.getFieldValue('" + name + "');"); - } else if (field instanceof Blockly.FieldNumber) { - code.push(makeVar('number', name) + - " = block.getFieldValue('" + name + "');"); - } else if (field instanceof Blockly.FieldTextInput) { - code.push(makeVar('text', name) + - " = block.getFieldValue('" + name + "');"); - } - } - var name = input.name; - if (name) { - if (input.type == Blockly.INPUT_VALUE) { - code.push(makeVar('value', name) + - " = Blockly." + language + ".valueToCode(block, '" + name + - "', Blockly." + language + ".ORDER_ATOMIC);"); - } else if (input.type == Blockly.NEXT_STATEMENT) { - code.push(makeVar('statements', name) + - " = Blockly." + language + ".statementToCode(block, '" + - name + "');"); - } - } - } - // Most languages end lines with a semicolon. Python does not. - var lineEnd = { - 'JavaScript': ';', - 'Python': '', - 'PHP': ';', - 'Dart': ';' - }; - code.push(" // TODO: Assemble " + language + " into code variable."); - if (block.outputConnection) { - code.push(" var code = '...';"); - code.push(" // TODO: Change ORDER_NONE to the correct strength."); - code.push(" return [code, Blockly." + language + ".ORDER_NONE];"); - } else { - code.push(" var code = '..." + (lineEnd[language] || '') + "\\n';"); - code.push(" return code;"); - } - code.push("};"); - - return code.join('\n'); -}; - -/** - * Update the language code as JSON. - * @param {string} blockType Name of block. - * @param {!Blockly.Block} rootBlock Factory_base block. - * @return {string} Generanted language code. - * @private - */ -FactoryUtils.formatJson_ = function(blockType, rootBlock) { - var JS = {}; - // Type is not used by Blockly, but may be used by a loader. - JS.type = blockType; - // Generate inputs. - var message = []; - var args = []; - var contentsBlock = rootBlock.getInputTargetBlock('INPUTS'); - var lastInput = null; - while (contentsBlock) { - if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) { - var fields = FactoryUtils.getFieldsJson_( - contentsBlock.getInputTargetBlock('FIELDS')); - for (var i = 0; i < fields.length; i++) { - if (typeof fields[i] == 'string') { - message.push(fields[i].replace(/%/g, '%%')); - } else { - args.push(fields[i]); - message.push('%' + args.length); - } - } - - var input = {type: contentsBlock.type}; - // Dummy inputs don't have names. Other inputs do. - if (contentsBlock.type != 'input_dummy') { - input.name = contentsBlock.getFieldValue('INPUTNAME'); - } - var check = JSON.parse( - FactoryUtils.getOptTypesFrom(contentsBlock, 'TYPE') || 'null'); - if (check) { - input.check = check; - } - var align = contentsBlock.getFieldValue('ALIGN'); - if (align != 'LEFT') { - input.align = align; - } - args.push(input); - message.push('%' + args.length); - lastInput = contentsBlock; - } - contentsBlock = contentsBlock.nextConnection && - contentsBlock.nextConnection.targetBlock(); - } - // Remove last input if dummy and not empty. - if (lastInput && lastInput.type == 'input_dummy') { - var fields = lastInput.getInputTargetBlock('FIELDS'); - if (fields && FactoryUtils.getFieldsJson_(fields).join('').trim() != '') { - var align = lastInput.getFieldValue('ALIGN'); - if (align != 'LEFT') { - JS.lastDummyAlign0 = align; - } - args.pop(); - message.pop(); - } - } - JS.message0 = message.join(' '); - if (args.length) { - JS.args0 = args; - } - // Generate inline/external switch. - if (rootBlock.getFieldValue('INLINE') == 'EXT') { - JS.inputsInline = false; - } else if (rootBlock.getFieldValue('INLINE') == 'INT') { - JS.inputsInline = true; - } - // Generate output, or next/previous connections. - switch (rootBlock.getFieldValue('CONNECTIONS')) { - case 'LEFT': - JS.output = - JSON.parse( - FactoryUtils.getOptTypesFrom(rootBlock, 'OUTPUTTYPE') || 'null'); - break; - case 'BOTH': - JS.previousStatement = - JSON.parse( - FactoryUtils.getOptTypesFrom(rootBlock, 'TOPTYPE') || 'null'); - JS.nextStatement = - JSON.parse( - FactoryUtils.getOptTypesFrom(rootBlock, 'BOTTOMTYPE') || 'null'); - break; - case 'TOP': - JS.previousStatement = - JSON.parse( - FactoryUtils.getOptTypesFrom(rootBlock, 'TOPTYPE') || 'null'); - break; - case 'BOTTOM': - JS.nextStatement = - JSON.parse( - FactoryUtils.getOptTypesFrom(rootBlock, 'BOTTOMTYPE') || 'null'); - break; - } - // Generate colour. - var colourBlock = rootBlock.getInputTargetBlock('COLOUR'); - if (colourBlock && !colourBlock.disabled) { - var hue = parseInt(colourBlock.getFieldValue('HUE'), 10); - JS.colour = hue; - } - - JS.tooltip = FactoryUtils.getTooltipFromRootBlock_(rootBlock); - JS.helpUrl = FactoryUtils.getHelpUrlFromRootBlock_(rootBlock); - - return JSON.stringify(JS, null, ' '); -}; - -/** - * Update the language code as JavaScript. - * @param {string} blockType Name of block. - * @param {!Blockly.Block} rootBlock Factory_base block. - * @param {!Blockly.Workspace} workspace Where the root block lives. - * @return {string} Generated language code. - * @private - */ -FactoryUtils.formatJavaScript_ = function(blockType, rootBlock, workspace) { - var code = []; - code.push("Blockly.Blocks['" + blockType + "'] = {"); - code.push(" init: function() {"); - // Generate inputs. - var TYPES = {'input_value': 'appendValueInput', - 'input_statement': 'appendStatementInput', - 'input_dummy': 'appendDummyInput'}; - var contentsBlock = rootBlock.getInputTargetBlock('INPUTS'); - while (contentsBlock) { - if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) { - var name = ''; - // Dummy inputs don't have names. Other inputs do. - if (contentsBlock.type != 'input_dummy') { - name = - JSON.stringify(contentsBlock.getFieldValue('INPUTNAME')); - } - code.push(' this.' + TYPES[contentsBlock.type] + '(' + name + ')'); - var check = FactoryUtils.getOptTypesFrom(contentsBlock, 'TYPE'); - if (check) { - code.push(' .setCheck(' + check + ')'); - } - var align = contentsBlock.getFieldValue('ALIGN'); - if (align != 'LEFT') { - code.push(' .setAlign(Blockly.ALIGN_' + align + ')'); - } - var fields = FactoryUtils.getFieldsJs_( - contentsBlock.getInputTargetBlock('FIELDS')); - for (var i = 0; i < fields.length; i++) { - code.push(' .appendField(' + fields[i] + ')'); - } - // Add semicolon to last line to finish the statement. - code[code.length - 1] += ';'; - } - contentsBlock = contentsBlock.nextConnection && - contentsBlock.nextConnection.targetBlock(); - } - // Generate inline/external switch. - if (rootBlock.getFieldValue('INLINE') == 'EXT') { - code.push(' this.setInputsInline(false);'); - } else if (rootBlock.getFieldValue('INLINE') == 'INT') { - code.push(' this.setInputsInline(true);'); - } - // Generate output, or next/previous connections. - switch (rootBlock.getFieldValue('CONNECTIONS')) { - case 'LEFT': - code.push(FactoryUtils.connectionLineJs_('setOutput', 'OUTPUTTYPE', workspace)); - break; - case 'BOTH': - code.push( - FactoryUtils.connectionLineJs_('setPreviousStatement', 'TOPTYPE', workspace)); - code.push( - FactoryUtils.connectionLineJs_('setNextStatement', 'BOTTOMTYPE', workspace)); - break; - case 'TOP': - code.push( - FactoryUtils.connectionLineJs_('setPreviousStatement', 'TOPTYPE', workspace)); - break; - case 'BOTTOM': - code.push( - FactoryUtils.connectionLineJs_('setNextStatement', 'BOTTOMTYPE', workspace)); - break; - } - // Generate colour. - var colourBlock = rootBlock.getInputTargetBlock('COLOUR'); - if (colourBlock && !colourBlock.disabled) { - var hue = parseInt(colourBlock.getFieldValue('HUE'), 10); - if (!isNaN(hue)) { - code.push(' this.setColour(' + hue + ');'); - } - } - - var tooltip = FactoryUtils.getTooltipFromRootBlock_(rootBlock); - var helpUrl = FactoryUtils.getHelpUrlFromRootBlock_(rootBlock); - code.push(" this.setTooltip('" + tooltip + "');"); - code.push(" this.setHelpUrl('" + helpUrl + "');"); - code.push(' }'); - code.push('};'); - return code.join('\n'); -}; - -/** - * Create JS code required to create a top, bottom, or value connection. - * @param {string} functionName JavaScript function name. - * @param {string} typeName Name of type input. - * @param {!Blockly.Workspace} workspace Where the root block lives. - * @return {string} Line of JavaScript code to create connection. - * @private - */ -FactoryUtils.connectionLineJs_ = function(functionName, typeName, workspace) { - var type = FactoryUtils.getOptTypesFrom( - FactoryUtils.getRootBlock(workspace), typeName); - if (type) { - type = ', ' + type; - } else { - type = ''; - } - return ' this.' + functionName + '(true' + type + ');'; -}; - -/** - * Returns field strings and any config. - * @param {!Blockly.Block} block Input block. - * @return {!Array.} Field strings. - * @private - */ -FactoryUtils.getFieldsJs_ = function(block) { - var fields = []; - while (block) { - if (!block.disabled && !block.getInheritedDisabled()) { - switch (block.type) { - case 'field_static': - // Result: 'hello' - fields.push(JSON.stringify(block.getFieldValue('TEXT'))); - break; - case 'field_input': - // Result: new Blockly.FieldTextInput('Hello'), 'GREET' - fields.push('new Blockly.FieldTextInput(' + - JSON.stringify(block.getFieldValue('TEXT')) + '), ' + - JSON.stringify(block.getFieldValue('FIELDNAME'))); - break; - case 'field_number': - // Result: new Blockly.FieldNumber(10, 0, 100, 1), 'NUMBER' - var args = [ - Number(block.getFieldValue('VALUE')), - Number(block.getFieldValue('MIN')), - Number(block.getFieldValue('MAX')), - Number(block.getFieldValue('PRECISION')) - ]; - // Remove any trailing arguments that aren't needed. - if (args[3] == 0) { - args.pop(); - if (args[2] == Infinity) { - args.pop(); - if (args[1] == -Infinity) { - args.pop(); - } - } - } - fields.push('new Blockly.FieldNumber(' + args.join(', ') + '), ' + - JSON.stringify(block.getFieldValue('FIELDNAME'))); - break; - case 'field_angle': - // Result: new Blockly.FieldAngle(90), 'ANGLE' - fields.push('new Blockly.FieldAngle(' + - parseFloat(block.getFieldValue('ANGLE')) + '), ' + - JSON.stringify(block.getFieldValue('FIELDNAME'))); - break; - case 'field_checkbox': - // Result: new Blockly.FieldCheckbox('TRUE'), 'CHECK' - fields.push('new Blockly.FieldCheckbox(' + - JSON.stringify(block.getFieldValue('CHECKED')) + - '), ' + - JSON.stringify(block.getFieldValue('FIELDNAME'))); - break; - case 'field_colour': - // Result: new Blockly.FieldColour('#ff0000'), 'COLOUR' - fields.push('new Blockly.FieldColour(' + - JSON.stringify(block.getFieldValue('COLOUR')) + - '), ' + - JSON.stringify(block.getFieldValue('FIELDNAME'))); - break; - case 'field_date': - // Result: new Blockly.FieldDate('2015-02-04'), 'DATE' - fields.push('new Blockly.FieldDate(' + - JSON.stringify(block.getFieldValue('DATE')) + '), ' + - JSON.stringify(block.getFieldValue('FIELDNAME'))); - break; - case 'field_variable': - // Result: new Blockly.FieldVariable('item'), 'VAR' - var varname - = JSON.stringify(block.getFieldValue('TEXT') || null); - fields.push('new Blockly.FieldVariable(' + varname + '), ' + - JSON.stringify(block.getFieldValue('FIELDNAME'))); - break; - case 'field_dropdown': - // Result: - // new Blockly.FieldDropdown([['yes', '1'], ['no', '0']]), 'TOGGLE' - var options = []; - for (var i = 0; i < block.optionList_.length; i++) { - options[i] = JSON.stringify([block.getUserData(i), - block.getFieldValue('CPU' + i)]); - } - if (options.length) { - fields.push('new Blockly.FieldDropdown([' + - options.join(', ') + ']), ' + - JSON.stringify(block.getFieldValue('FIELDNAME'))); - } - break; - case 'field_image': - // Result: new Blockly.FieldImage('http://...', 80, 60, '*') - var src = JSON.stringify(block.getFieldValue('SRC')); - var width = Number(block.getFieldValue('WIDTH')); - var height = Number(block.getFieldValue('HEIGHT')); - var alt = JSON.stringify(block.getFieldValue('ALT')); - fields.push('new Blockly.FieldImage(' + - src + ', ' + width + ', ' + height + ', ' + alt + ')'); - break; - } - } - block = block.nextConnection && block.nextConnection.targetBlock(); - } - return fields; -}; - -/** - * Returns field strings and any config. - * @param {!Blockly.Block} block Input block. - * @return {!Array.} Array of static text and field configs. - * @private - */ -FactoryUtils.getFieldsJson_ = function(block) { - var fields = []; - while (block) { - if (!block.disabled && !block.getInheritedDisabled()) { - switch (block.type) { - case 'field_static': - // Result: 'hello' - fields.push(block.getFieldValue('TEXT')); - break; - case 'field_input': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - text: block.getFieldValue('TEXT') - }); - break; - case 'field_number': - var obj = { - type: block.type, - name: block.getFieldValue('FIELDNAME'), - value: parseFloat(block.getFieldValue('VALUE')) - }; - var min = parseFloat(block.getFieldValue('MIN')); - if (min > -Infinity) { - obj.min = min; - } - var max = parseFloat(block.getFieldValue('MAX')); - if (max < Infinity) { - obj.max = max; - } - var precision = parseFloat(block.getFieldValue('PRECISION')); - if (precision) { - obj.precision = precision; - } - fields.push(obj); - break; - case 'field_angle': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - angle: Number(block.getFieldValue('ANGLE')) - }); - break; - case 'field_checkbox': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - checked: block.getFieldValue('CHECKED') == 'TRUE' - }); - break; - case 'field_colour': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - colour: block.getFieldValue('COLOUR') - }); - break; - case 'field_date': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - date: block.getFieldValue('DATE') - }); - break; - case 'field_variable': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - variable: block.getFieldValue('TEXT') || null - }); - break; - case 'field_dropdown': - var options = []; - for (var i = 0; i < block.optionList_.length; i++) { - options[i] = [block.getUserData(i), - block.getFieldValue('CPU' + i)]; - } - if (options.length) { - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - options: options - }); - } - break; - case 'field_image': - fields.push({ - type: block.type, - src: block.getFieldValue('SRC'), - width: Number(block.getFieldValue('WIDTH')), - height: Number(block.getFieldValue('HEIGHT')), - alt: block.getFieldValue('ALT') - }); - break; - } - } - block = block.nextConnection && block.nextConnection.targetBlock(); - } - return fields; -}; - -/** - * Fetch the type(s) defined in the given input. - * Format as a string for appending to the generated code. - * @param {!Blockly.Block} block Block with input. - * @param {string} name Name of the input. - * @return {?string} String defining the types. - */ -FactoryUtils.getOptTypesFrom = function(block, name) { - var types = FactoryUtils.getTypesFrom_(block, name); - if (types.length == 0) { - return undefined; - } else if (types.indexOf('null') != -1) { - return 'null'; - } else if (types.length == 1) { - return types[0]; - } else { - return '[' + types.join(', ') + ']'; - } -}; - - -/** - * Fetch the type(s) defined in the given input. - * @param {!Blockly.Block} block Block with input. - * @param {string} name Name of the input. - * @return {!Array.} List of types. - * @private - */ -FactoryUtils.getTypesFrom_ = function(block, name) { - var typeBlock = block.getInputTargetBlock(name); - var types; - if (!typeBlock || typeBlock.disabled) { - types = []; - } else if (typeBlock.type == 'type_other') { - types = [JSON.stringify(typeBlock.getFieldValue('TYPE'))]; - } else if (typeBlock.type == 'type_group') { - types = []; - for (var n = 0; n < typeBlock.typeCount_; n++) { - types = types.concat(FactoryUtils.getTypesFrom_(typeBlock, 'TYPE' + n)); - } - // Remove duplicates. - var hash = Object.create(null); - for (var n = types.length - 1; n >= 0; n--) { - if (hash[types[n]]) { - types.splice(n, 1); - } - hash[types[n]] = true; - } - } else { - types = [JSON.stringify(typeBlock.valueType)]; - } - return types; -}; - -/** - * Return the uneditable container block that everything else attaches to in - * given workspace. - * @param {!Blockly.Workspace} workspace Where the root block lives. - * @return {Blockly.Block} Root block. - */ -FactoryUtils.getRootBlock = function(workspace) { - var blocks = workspace.getTopBlocks(false); - for (var i = 0, block; block = blocks[i]; i++) { - if (block.type == 'factory_base') { - return block; - } - } - return null; -}; - -// TODO(quachtina96): Move hide, show, makeInvisible, and makeVisible to a new -// AppView namespace. - -/** - * Hides element so that it's invisible and doesn't take up space. - * @param {string} elementID ID of element to hide. - */ -FactoryUtils.hide = function(elementID) { - document.getElementById(elementID).style.display = 'none'; -}; - -/** - * Un-hides an element. - * @param {string} elementID ID of element to hide. - */ -FactoryUtils.show = function(elementID) { - document.getElementById(elementID).style.display = 'block'; -}; - -/** - * Hides element so that it's invisible but still takes up space. - * @param {string} elementID ID of element to hide. - */ -FactoryUtils.makeInvisible = function(elementID) { - document.getElementById(elementID).visibility = 'hidden'; -}; - -/** - * Makes element visible. - * @param {string} elementID ID of element to hide. - */ -FactoryUtils.makeVisible = function(elementID) { - document.getElementById(elementID).visibility = 'visible'; -}; - -/** - * Create a file with the given attributes and download it. - * @param {string} contents The contents of the file. - * @param {string} filename The name of the file to save to. - * @param {string} fileType The type of the file to save. - */ -FactoryUtils.createAndDownloadFile = function(contents, filename, fileType) { - var data = new Blob([contents], {type: 'text/' + fileType}); - var clickEvent = new MouseEvent("click", { - "view": window, - "bubbles": true, - "cancelable": false - }); - - var a = document.createElement('a'); - a.href = window.URL.createObjectURL(data); - a.download = filename; - a.textContent = 'Download file!'; - a.dispatchEvent(clickEvent); -}; - -/** - * Get Blockly Block by rendering pre-defined block in workspace. - * @param {!Element} blockType Type of block that has already been defined. - * @param {!Blockly.Workspace} workspace Workspace on which to render - * the block. - * @return {!Blockly.Block} The Blockly.Block of desired type. - */ -FactoryUtils.getDefinedBlock = function(blockType, workspace) { - workspace.clear(); - return workspace.newBlock(blockType); -}; - -/** - * Parses a block definition get the type of the block it defines. - * @param {string} blockDef A single block definition. - * @return {string} Type of block defined by the given definition. - */ -FactoryUtils.getBlockTypeFromJsDefinition = function(blockDef) { - var indexOfStartBracket = blockDef.indexOf('[\''); - var indexOfEndBracket = blockDef.indexOf('\']'); - if (indexOfStartBracket != -1 && indexOfEndBracket != -1) { - return blockDef.substring(indexOfStartBracket + 2, indexOfEndBracket); - } else { - throw new Error ('Could not parse block type out of JavaScript block ' + - 'definition. Brackets normally enclosing block type not found.'); - } -}; - -/** - * Generates a category containing blocks of the specified block types. - * @param {!Array.} blocks Blocks to include in the category. - * @param {string} categoryName Name to use for the generated category. - * @return {!Element} Category XML containing the given block types. - */ -FactoryUtils.generateCategoryXml = function(blocks, categoryName) { - // Create category DOM element. - var categoryElement = goog.dom.createDom('category'); - categoryElement.setAttribute('name', categoryName); - - // For each block, add block element to category. - for (var i = 0, block; block = blocks[i]; i++) { - - // Get preview block XML. - var blockXml = Blockly.Xml.blockToDom(block); - blockXml.removeAttribute('id'); - - // Add block to category and category to XML. - categoryElement.appendChild(blockXml); - } - return categoryElement; -}; - -/** - * Parses a string containing JavaScript block definition(s) to create an array - * in which each element is a single block definition. - * @param {string} blockDefsString JavaScript block definition(s). - * @return {!Array.} Array of block definitions. - */ -FactoryUtils.parseJsBlockDefinitions = function(blockDefsString) { - var blockDefArray = []; - var defStart = blockDefsString.indexOf('Blockly.Blocks'); - - while (blockDefsString.indexOf('Blockly.Blocks', defStart) != -1) { - var nextStart = blockDefsString.indexOf('Blockly.Blocks', defStart + 1); - if (nextStart == -1) { - // This is the last block definition. - nextStart = blockDefsString.length; - } - var blockDef = blockDefsString.substring(defStart, nextStart); - blockDefArray.push(blockDef); - defStart = nextStart; - } - return blockDefArray; -}; - -/** - * Parses a string containing JSON block definition(s) to create an array - * in which each element is a single block definition. Expected input is - * one or more block definitions in the form of concatenated, stringified - * JSON objects. - * @param {string} blockDefsString String containing JSON block - * definition(s). - * @return {!Array.} Array of block definitions. - */ -FactoryUtils.parseJsonBlockDefinitions = function(blockDefsString) { - var blockDefArray = []; - var unbalancedBracketCount = 0; - var defStart = 0; - // Iterate through the blockDefs string. Keep track of whether brackets - // are balanced. - for (var i = 0; i < blockDefsString.length; i++) { - var currentChar = blockDefsString[i]; - if (currentChar == '{') { - unbalancedBracketCount++; - } - else if (currentChar == '}') { - unbalancedBracketCount--; - if (unbalancedBracketCount == 0 && i > 0) { - // The brackets are balanced. We've got a complete block defintion. - var blockDef = blockDefsString.substring(defStart, i + 1); - blockDefArray.push(blockDef); - defStart = i + 1; - } - } - } - return blockDefArray; -}; - -/** - * Define blocks from imported block definitions. - * @param {string} blockDefsString Block definition(s). - * @param {string} format Block definition format ('JSON' or 'JavaScript'). - * @return {!Array.} Array of block types defined. - */ -FactoryUtils.defineAndGetBlockTypes = function(blockDefsString, format) { - var blockTypes = []; - - // Define blocks and get block types. - if (format == 'JSON') { - var blockDefArray = FactoryUtils.parseJsonBlockDefinitions(blockDefsString); - - // Populate array of blocktypes and define each block. - for (var i = 0, blockDef; blockDef = blockDefArray[i]; i++) { - var json = JSON.parse(blockDef); - blockTypes.push(json.type); - - // Define the block. - Blockly.Blocks[json.type] = { - init: function() { - this.jsonInit(json); - } - }; - } - } else if (format == 'JavaScript') { - var blockDefArray = FactoryUtils.parseJsBlockDefinitions(blockDefsString); - - // Populate array of block types. - for (var i = 0, blockDef; blockDef = blockDefArray[i]; i++) { - var blockType = FactoryUtils.getBlockTypeFromJsDefinition(blockDef); - blockTypes.push(blockType); - } - - // Define all blocks. - eval(blockDefsString); - } - - return blockTypes; -}; - -/** - * Inject code into a pre tag, with syntax highlighting. - * Safe from HTML/script injection. - * @param {string} code Lines of code. - * @param {string} id ID of
 element to inject into.
- */
-FactoryUtils.injectCode = function(code, id) {
-  var pre = document.getElementById(id);
-  pre.textContent = code;
-  code = pre.textContent;
-  code = prettyPrintOne(code, 'js');
-  pre.innerHTML = code;
-};
-
-/**
- * Returns whether or not two blocks are the same based on their XML. Expects
- * XML with a single child node that is a factory_base block, the XML found on
- * Block Factory's main workspace.
- * @param {!Element} blockXml1 An XML element with a single child node that
- *    is a factory_base block.
- * @param {!Element} blockXml2 An XML element with a single child node that
- *    is a factory_base block.
- * @return {boolean} Whether or not two blocks are the same based on their XML.
- */
-FactoryUtils.sameBlockXml = function(blockXml1, blockXml2) {
-  // Each XML element should contain a single child element with a 'block' tag
-  if (blockXml1.tagName.toLowerCase() != 'xml' ||
-      blockXml2.tagName.toLowerCase() != 'xml') {
-    throw new Error('Expected two XML elements, recieved elements with tag ' +
-        'names: ' + blockXml1.tagName + ' and ' + blockXml2.tagName + '.');
-  }
-
-  // Compare the block elements directly. The XML tags may include other meta
-  // information we want to igrore.
-  var blockElement1 = blockXml1.getElementsByTagName('block')[0];
-  var blockElement2 = blockXml2.getElementsByTagName('block')[0];
-
-  if (!(blockElement1 && blockElement2)) {
-    throw new Error('Could not get find block element in XML.');
-  }
-
-  var blockXmlText1 = Blockly.Xml.domToText(blockElement1);
-  var blockXmlText2 = Blockly.Xml.domToText(blockElement2);
-
-  // Strip white space.
-  blockXmlText1 = blockXmlText1.replace(/\s+/g, '');
-  blockXmlText2 = blockXmlText2.replace(/\s+/g, '');
-
-  // Return whether or not changes have been saved.
-  return blockXmlText1 == blockXmlText2;
-};
-
-/*
- * 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.
- */
-FactoryUtils.hasVariableField = function(block) {
-  if (!block) {
-    return false;
-  }
-  return block.getVars().length > 0;
-};
-
-/**
- * Checks if a block is a procedures block. If procedures block names are
- * ever updated or expanded, this function should be updated as well (no
- * other known markers for procedure blocks beyond name).
- * @param {Blockly.Block} block The block to check.
- * @return {boolean} True if the block is a procedure block, false otherwise.
- */
-FactoryUtils.isProcedureBlock = function(block) {
-  return block &&
-      (block.type == 'procedures_defnoreturn' ||
-      block.type == 'procedures_defreturn' ||
-      block.type == 'procedures_callnoreturn' ||
-      block.type == 'procedures_callreturn' ||
-      block.type == 'procedures_ifreturn');
-};
-
-/**
- * Returns whether or not a modified block's changes has been saved to the
- * Block Library.
- * TODO(quachtina96): move into the Block Factory Controller once made.
- * @param {!BlockLibraryController} blockLibraryController Block Library
- *    Controller storing custom blocks.
- * @return {boolean} True if all changes made to the block have been saved to
- *    the given Block Library.
- */
-FactoryUtils.savedBlockChanges = function(blockLibraryController) {
-  if (BlockFactory.isStarterBlock()) {
-    return true;
-  }
-  var blockType = blockLibraryController.getCurrentBlockType();
-  var currentXml = Blockly.Xml.workspaceToDom(BlockFactory.mainWorkspace);
-
-  if (blockLibraryController.has(blockType)) {
-    // Block is saved in block library.
-    var savedXml = blockLibraryController.getBlockXml(blockType);
-    return FactoryUtils.sameBlockXml(savedXml, currentXml);
-  }
-  return false;
-};
-
-/**
- * Given the root block of the factory, return the tooltip specified by the user
- * or the empty string if no tooltip is found.
- * @param {!Blockly.Block} rootBlock Factory_base block.
- * @return {string} The tooltip for the generated block, or the empty string.
- */
-FactoryUtils.getTooltipFromRootBlock_ = function(rootBlock) {
-  var tooltipBlock = rootBlock.getInputTargetBlock('TOOLTIP');
-  if (tooltipBlock && !tooltipBlock.disabled) {
-    return tooltipBlock.getFieldValue('TEXT');
-  }
-  return '';
-};
-
-/**
- * Given the root block of the factory, return the help url specified by the
- * user or the empty string if no tooltip is found.
- * @param {!Blockly.Block} rootBlock Factory_base block.
- * @return {string} The help url for the generated block, or the empty string.
- */
-FactoryUtils.getHelpUrlFromRootBlock_ = function(rootBlock) {
-  var helpUrlBlock = rootBlock.getInputTargetBlock('HELPURL');
-  if (helpUrlBlock && !helpUrlBlock.disabled) {
-    return helpUrlBlock.getFieldValue('TEXT');
-  }
-  return '';
-};
diff --git a/trunk/web/blockly/demos/blockfactory/icon.png b/trunk/web/blockly/demos/blockfactory/icon.png
deleted file mode 100644
index 2fcb25ed7fb..00000000000
Binary files a/trunk/web/blockly/demos/blockfactory/icon.png and /dev/null differ
diff --git a/trunk/web/blockly/demos/blockfactory/index.html b/trunk/web/blockly/demos/blockfactory/index.html
deleted file mode 100644
index 4a4423a82a1..00000000000
--- a/trunk/web/blockly/demos/blockfactory/index.html
+++ /dev/null
@@ -1,746 +0,0 @@
-
-
-
-  
-  
-  Blockly Demo: Blockly Developer Tools
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-
-
-  

Blockly > - Demos > Blockly Developer Tools - -

-
-
Block Factory
-
Block Exporter
-
Workspace Factory
-
- - -
-
-

- First, select blocks from your block library by clicking on them. Then, use the Export Settings form to download starter code for selected blocks. -

-
-
-

Block Selector

- - -
-
- - -
-
-

Export Settings

-
- -
-

Currently Selected:

-

-
-
-
- -
- -
-
- -
-
- -
-
-
-
-
- -
-
-
-

Export Preview

-
-

Block Definitions:

-

-      
-
-

Generator Stubs:

-

-      
-
-
- - - -
-
-

-

- - - - - - -

-
- -
-
-

Edit

-

Drag blocks into the workspace to configure the toolbox in your custom workspace.

-
- - - - - -
ToolboxWorkspace
-
-
-
- - - - - - - -
- - -
- - - - - - - - - - - -
- - - - - -
- - - - - - - -
-
- - - - - -
-

Preview: - -

-
- - - - - -
-
-
-
-
- - - - - - - - - - - - - - - - -
-
-
-

Block Definition: - -

-
-

-              
-            
-

Generator stub: - -

-
-

-            
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 20 - 65 - 120 - 160 - 210 - 230 - 260 - 290 - 330 - - - - - - - - - - - - - - - - - - 10 - - - - - - - - 1 - - - - - 10 - - - - - 1 - - - - - - - - - - - - 1 - - - - - 1 - - - - - - - 9 - - - - - - - 45 - - - - - - - - 0 - - - - - - - 3.1 - - - - - - - - 64 - - - - - 10 - - - - - - - 50 - - - - - 1 - - - - - 100 - - - - - - - 1 - - - - - 100 - - - - - - - - - - - - - - - - - abc - - - - - - - - - - - - - - text - - - - - abc - - - - - - - text - - - - - - - text - - - - - - - abc - - - - - - - abc - - - - - - - abc - - - - - - - abc - - - - - - - - - - - - - 5 - - - - - - - - - list - - - - - - - list - - - - - - - list - - - - - - - list - - - - - - - , - - - - - - - - - - - - 100 - - - - - 50 - - - - - 0 - - - - - - - #ff0000 - - - - - #3333ff - - - - - 0.5 - - - - - - - - - - - - - diff --git a/trunk/web/blockly/demos/blockfactory/link.png b/trunk/web/blockly/demos/blockfactory/link.png deleted file mode 100644 index 11dfd82845e..00000000000 Binary files a/trunk/web/blockly/demos/blockfactory/link.png and /dev/null differ diff --git a/trunk/web/blockly/demos/blockfactory/standard_categories.js b/trunk/web/blockly/demos/blockfactory/standard_categories.js deleted file mode 100644 index 6b4072680c5..00000000000 --- a/trunk/web/blockly/demos/blockfactory/standard_categories.js +++ /dev/null @@ -1,395 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Contains a map of standard Blockly categories used to load - * standard Blockly categories into the user's toolbox. The map is keyed by - * the lower case name of the category, and contains the Category object for - * that particular category. Also has a list of core block types provided - * by Blockly. - * - * @author Emma Dauterman (evd2014) - */ - 'use strict'; - -/** - * Namespace for StandardCategories - */ -goog.provide('StandardCategories'); - - -// Map of standard category information necessary to add a standard category -// to the toolbox. -StandardCategories.categoryMap = Object.create(null); - -StandardCategories.categoryMap['logic'] = - new ListElement(ListElement.TYPE_CATEGORY, 'Logic'); -StandardCategories.categoryMap['logic'].xml = - Blockly.Xml.textToDom( - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - ''); -StandardCategories.categoryMap['logic'].color ='#5C81A6'; - -StandardCategories.categoryMap['loops'] = - new ListElement(ListElement.TYPE_CATEGORY, 'Loops'); -StandardCategories.categoryMap['loops'].xml = - Blockly.Xml.textToDom( - '' + - '' + - '' + - '' + - '10' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '1' + - '' + - '' + - '' + - '' + - '10' + - '' + - '' + - '' + - '' + - '1' + - '' + - '' + - '' + - '' + - '' + - ''); -StandardCategories.categoryMap['loops'].color = '#5CA65C'; - -StandardCategories.categoryMap['math'] = - new ListElement(ListElement.TYPE_CATEGORY, 'Math'); -StandardCategories.categoryMap['math'].xml = - Blockly.Xml.textToDom( - '' + - '' + - '' + - '' + - '' + - '1' + - '' + - '' + - '' + - '' + - '1' + - '' + - '' + - '' + - '' + - '' + - '' + - '9' + - '' + - '' + - '' + - '' + - '' + - '' + - '45' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '0' + - '' + - '' + - '' + - '' + - '' + - '' + - '3.1' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '64' + - '' + - '' + - '' + - '' + - '10'+ - '' + - '' + - '' + - '' + - '' + - '' + - '50' + - '' + - '' + - '' + - '' + - '1' + - '' + - '' + - '' + - '' + - '100' + - '' + - '' + - '' + - '' + - '' + - '' + - '1' + - '' + - '' + - '' + - '' + - '100' + - '' + - '' + - '' + - '' + - ''); -StandardCategories.categoryMap['math'].color = '#5C68A6'; - -StandardCategories.categoryMap['text'] = - new ListElement(ListElement.TYPE_CATEGORY, 'Text'); -StandardCategories.categoryMap['text'].xml = - Blockly.Xml.textToDom( - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - 'abc' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - 'text' + - '' + - '' + - '' + - '' + - 'abc' + - '' + - '' + - '' + - '' + - '' + - '' + - 'text' + - '' + - '' + - '' + - '' + - '' + - '' + - 'text' + - '' + - '' + - '' + - '' + - '' + - '' + - 'abc' + - '' + - '' + - '' + - '' + - '' + - '' + - 'abc' + - '' + - '' + - '' + - '' + - '' + - '' + - 'abc' + - '' + - '' + - '' + - '' + - '' + - '' + - 'abc' + - '' + - '' + - '' + - ''); -StandardCategories.categoryMap['text'].color = '#5CA68D'; - -StandardCategories.categoryMap['lists'] = - new ListElement(ListElement.TYPE_CATEGORY, 'Lists'); -StandardCategories.categoryMap['lists'].xml = - Blockly.Xml.textToDom( - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '5' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - 'list' + - '' + - '' + - '' + - '' + - '' + - '' + - 'list' + - '' + - '' + - '' + - '' + - '' + - '' + - 'list' + - '' + - '' + - '' + - '' + - '' + - '' + - 'list' + - '' + - '' + - '' + - '' + - '' + - '' + - ',' + - '' + - '' + - '' + - '' + - ''); -StandardCategories.categoryMap['lists'].color = '#745CA6'; - -StandardCategories.categoryMap['colour'] = - new ListElement(ListElement.TYPE_CATEGORY, 'Colour'); -StandardCategories.categoryMap['colour'].xml = - Blockly.Xml.textToDom( - '' + - '' + - '' + - '' + - '' + - '' + - '100' + - '' + - '' + - '' + - '' + - '50' + - '' + - '' + - '' + - '' + - '0' + - '' + - '' + - '' + - '' + - '' + - '' + - '#ff0000' + - '' + - '' + - '' + - '' + - '#3333ff' + - '' + - '' + - '' + - '' + - '0.5' + - '' + - '' + - '' + - ''); -StandardCategories.categoryMap['colour'].color = '#A6745C'; - -StandardCategories.categoryMap['functions'] = - new ListElement(ListElement.TYPE_CATEGORY, 'Functions'); -StandardCategories.categoryMap['functions'].color = '#9A5CA6' -StandardCategories.categoryMap['functions'].custom = 'PROCEDURE'; - -StandardCategories.categoryMap['variables'] = - new ListElement(ListElement.TYPE_CATEGORY, 'Variables'); -StandardCategories.categoryMap['variables'].color = '#A65C81'; -StandardCategories.categoryMap['variables'].custom = 'VARIABLE'; - -// All standard block types in provided in Blockly core. -StandardCategories.coreBlockTypes = ["controls_if", "logic_compare", - "logic_operation", "logic_negate", "logic_boolean", "logic_null", - "logic_ternary", "controls_repeat_ext", "controls_whileUntil", - "controls_for", "controls_forEach", "controls_flow_statements", - "math_number", "math_arithmetic", "math_single", "math_trig", - "math_constant", "math_number_property", "math_change", "math_round", - "math_on_list", "math_modulo", "math_constrain", "math_random_int", - "math_random_float", "text", "text_join", "text_append", "text_length", - "text_isEmpty", "text_indexOf", "variables_get", "text_charAt", - "text_getSubstring", "text_changeCase", "text_trim", "text_print", - "text_prompt_ext", "colour_picker", "colour_random", "colour_rgb", - "colour_blend", "lists_create_with", "lists_repeat", "lists_length", - "lists_isEmpty", "lists_indexOf", "lists_getIndex", "lists_setIndex", - "lists_getSublist", "lists_split", "lists_sort", "variables_set", - "procedures_defreturn", "procedures_ifreturn", "procedures_defnoreturn", - "procedures_callreturn"]; diff --git a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_controller.js b/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_controller.js deleted file mode 100644 index 85b14d11bbe..00000000000 --- a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_controller.js +++ /dev/null @@ -1,1330 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Contains the controller code for workspace factory. Depends - * on the model and view objects (created as internal variables) and interacts - * with previewWorkspace and toolboxWorkspace (internal references stored to - * both). Also depends on standard_categories.js for standard Blockly - * categories. Provides the functionality for the actions the user can initiate: - * - adding and removing categories - * - switching between categories - * - printing and downloading configuration xml - * - updating the preview workspace - * - changing a category name - * - moving the position of a category. - * - * @author Emma Dauterman (evd2014) - */ - - goog.require('FactoryUtils'); - goog.require('StandardCategories'); - - -/** - * Class for a WorkspaceFactoryController - * @param {string} toolboxName Name of workspace toolbox XML. - * @param {string} toolboxDiv Name of div to inject toolbox workspace in. - * @param {string} previewDiv Name of div to inject preview workspace in. - * @constructor - */ -WorkspaceFactoryController = function(toolboxName, toolboxDiv, previewDiv) { - // Toolbox XML element for the editing workspace. - this.toolbox = document.getElementById(toolboxName); - - // Workspace for user to drag blocks in for a certain category. - this.toolboxWorkspace = Blockly.inject(toolboxDiv, - {grid: - {spacing: 25, - length: 3, - colour: '#ccc', - snap: true}, - media: '../../media/', - toolbox: this.toolbox - }); - - // Workspace for user to preview their changes. - this.previewWorkspace = Blockly.inject(previewDiv, - {grid: - {spacing: 25, - length: 3, - colour: '#ccc', - snap: true}, - media: '../../media/', - toolbox: '', - zoom: - {controls: true, - wheel: true} - }); - - // Model to keep track of categories and blocks. - this.model = new WorkspaceFactoryModel(); - // Updates the category tabs. - this.view = new WorkspaceFactoryView(); - // Generates XML for categories. - this.generator = new WorkspaceFactoryGenerator(this.model); - // Tracks which editing mode the user is in. Toolbox mode on start. - this.selectedMode = WorkspaceFactoryController.MODE_TOOLBOX; - // True if key events are enabled, false otherwise. - this.keyEventsEnabled = true; - // True if there are unsaved changes in the toolbox, false otherwise. - this.hasUnsavedToolboxChanges = false; - // True if there are unsaved changes in the preloaded blocks, false otherwise. - this.hasUnsavedPreloadChanges = false; -}; - -// Toolbox editing mode. Changes the user makes to the workspace updates the -// toolbox. -WorkspaceFactoryController.MODE_TOOLBOX = 'toolbox'; -// Pre-loaded workspace editing mode. Changes the user makes to the workspace -// udpates the pre-loaded blocks. -WorkspaceFactoryController.MODE_PRELOAD = 'preload'; - -/** - * Currently prompts the user for a name, checking that it's valid (not used - * before), and then creates a tab and switches to it. - */ -WorkspaceFactoryController.prototype.addCategory = function() { - // 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(); - // Get name from user. - var name = this.promptForNewCategoryName('Enter the name of your new category:'); - if (!name) { // Exit if cancelled. - return; - } - // Create category. - this.createCategory(name); - // Switch to category. - this.switchElement(this.model.getCategoryIdByName(name)); - - // Sets the default options for injecting the workspace - // when there are categories if adding the first category. - if (isFirstCategory) { - this.view.setCategoryOptions(this.model.hasElements()); - this.generateNewOptions(); - } - // Update preview. - this.updatePreview(); -}; - -/** - * Helper method for addCategory. Adds a category to the view given a name, ID, - * and a boolean for if it's the first category created. Assumes the category - * has already been created in the model. Does not switch to category. - * @param {string} name Name of category being added. - * @param {string} id The ID of the category being added. - */ -WorkspaceFactoryController.prototype.createCategory = function(name) { - // Create empty category - var category = new ListElement(ListElement.TYPE_CATEGORY, name); - this.model.addElementToList(category); - // Create new category. - var tab = this.view.addCategoryRow(name, category.id); - this.addClickToSwitch(tab, category.id); -}; - -/** - * Given a tab and a ID to be associated to that tab, adds a listener to - * that tab so that when the user clicks on the tab, it switches to the - * element associated with that ID. - * @param {!Element} tab The DOM element to add the listener to. - * @param {string} id The ID of the element to switch to when tab is clicked. - */ -WorkspaceFactoryController.prototype.addClickToSwitch = function(tab, id) { - var self = this; - var clickFunction = function(id) { // Keep this in scope for switchElement. - return function() { - self.switchElement(id); - }; - }; - this.view.bindClick(tab, clickFunction(id)); -}; - -/** - * 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.transferFlyoutBlocksToCategory = - function() { - // 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) { - // 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(); - } -}; - -/** - * Attached to "-" button. Checks if the user wants to delete - * the current element. Removes the element and switches to another element. - * When the last element is removed, it switches to a single flyout mode. - */ -WorkspaceFactoryController.prototype.removeElement = function() { - // Check that there is a currently selected category to remove. - if (!this.model.getSelected()) { - return; - } - - // Check if user wants to remove current category. - var check = confirm('Are you sure you want to delete the currently selected ' - + this.model.getSelected().type + '?'); - if (!check) { // If cancelled, exit. - return; - } - - var selectedId = this.model.getSelectedId(); - var selectedIndex = this.model.getIndexByElementId(selectedId); - // Delete element visually. - this.view.deleteElementRow(selectedId, selectedIndex); - // Delete element in model. - this.model.deleteElementFromList(selectedIndex); - - // Find next logical element to switch to. - var next = this.model.getElementByIndex(selectedIndex); - if (!next && this.model.hasElements()) { - next = this.model.getElementByIndex(selectedIndex - 1); - } - var nextId = next ? next.id : null; - - // Open next element. - this.clearAndLoadElement(nextId); - - // If no element to switch to, display message, clear the workspace, and - // set a default selected element not in toolbox list in the model. - if (!nextId) { - alert('You currently have no categories or separators. All your blocks' + - ' will be displayed in a single flyout.'); - this.toolboxWorkspace.clear(); - this.toolboxWorkspace.clearUndo(); - this.model.createDefaultSelectedIfEmpty(); - } - // Update preview. - this.updatePreview(); -}; - -/** - * Gets a valid name for a new category from the user. - * @param {string} promptString Prompt for the user to enter a name. - * @param {string=} opt_oldName The current name. - * @return {string?} Valid name for a new category, or null if cancelled. - */ -WorkspaceFactoryController.prototype.promptForNewCategoryName = - function(promptString, opt_oldName) { - var defaultName = opt_oldName; - do { - var name = prompt(promptString, defaultName); - if (!name) { // If cancelled. - return null; - } - defaultName = name; - } while (this.model.hasCategoryByName(name)); - return name; -}; - -/** - * Switches to a new tab for the element given by ID. Stores XML and blocks - * to reload later, updates selected accordingly, and clears the workspace - * and clears undo, then loads the new element. - * @param {string} id ID of tab to be opened, must be valid element ID. - */ -WorkspaceFactoryController.prototype.switchElement = function(id) { - // Disables events while switching so that Blockly delete and create events - // don't update the preview repeatedly. - Blockly.Events.disable(); - // Caches information to reload or generate XML if switching to/from element. - // Only saves if a category is selected. - if (this.model.getSelectedId() != null && id != null) { - this.model.getSelected().saveFromWorkspace(this.toolboxWorkspace); - } - // Load element. - this.clearAndLoadElement(id); - // Enable Blockly events again. - Blockly.Events.enable(); -}; - -/** - * Switches to a new tab for the element by ID. Helper for switchElement. - * Updates selected, clears the workspace and clears undo, loads a new element. - * @param {string} id ID of category to load. - */ -WorkspaceFactoryController.prototype.clearAndLoadElement = function(id) { - // Unselect current tab if switching to and from an element. - if (this.model.getSelectedId() != null && id != null) { - this.view.setCategoryTabSelection(this.model.getSelectedId(), false); - } - - // If switching to another category, set category selection in the model and - // view. - if (id != null) { - // Set next category. - this.model.setSelectedById(id); - - // Clears workspace and loads next category. - this.clearAndLoadXml_(this.model.getSelectedXml()); - - // Selects the next tab. - this.view.setCategoryTabSelection(id, true); - - // Order blocks as shown in flyout. - this.toolboxWorkspace.cleanUp(); - - // Update category editing buttons. - this.view.updateState(this.model.getIndexByElementId - (this.model.getSelectedId()), this.model.getSelected()); - } else { - // Update category editing buttons for no categories. - this.view.updateState(-1, null); - } -}; - -/** - * Tied to "Export" button. Gets a file name from the user and downloads - * the corresponding configuration XML to that file. - * @param {string} exportMode The type of file to export - * (WorkspaceFactoryController.MODE_TOOLBOX for the toolbox configuration, - * and WorkspaceFactoryController.MODE_PRELOAD for the pre-loaded workspace - * configuration) - */ -WorkspaceFactoryController.prototype.exportXmlFile = function(exportMode) { - // Get file name. - if (exportMode == WorkspaceFactoryController.MODE_TOOLBOX) { - var fileName = prompt('File Name for toolbox XML:', 'toolbox.xml'); - } else { - var fileName = prompt('File Name for pre-loaded workspace XML:', - 'workspace.xml'); - } - if (!fileName) { // If cancelled. - return; - } - - // Generate XML. - if (exportMode == WorkspaceFactoryController.MODE_TOOLBOX) { - // Export the toolbox XML. - var configXml = Blockly.Xml.domToPrettyText - (this.generator.generateToolboxXml()); - this.hasUnsavedToolboxChanges = false; - } else if (exportMode == WorkspaceFactoryController.MODE_PRELOAD) { - // Export the pre-loaded block XML. - var configXml = Blockly.Xml.domToPrettyText - (this.generator.generateWorkspaceXml()); - this.hasUnsavedPreloadChanges = false; - } else { - // Unknown mode. Throw error. - throw new Error ("Unknown export mode: " + exportMode); - } - - // Download file. - var data = new Blob([configXml], {type: 'text/xml'}); - this.view.createAndDownloadFile(fileName, data); - }; - -/** - * 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.exportInjectFile = function() { - var fileName = prompt('File Name for starter Blockly workspace code:', - 'workspace.js'); - if (!fileName) { // If cancelled. - return; - } - // Generate new options to remove toolbox XML from options object (if - // necessary). - this.generateNewOptions(); - var printableOptions = this.generator.generateInjectString() - var data = new Blob([printableOptions], {type: 'text/javascript'}); - this.view.createAndDownloadFile(fileName, data); -}; - -/** - * Tied to "Print" button. Mainly used for debugging purposes. Prints - * the configuration XML to the console. - */ -WorkspaceFactoryController.prototype.printConfig = function() { - // Capture any changes made by user before generating XML. - this.saveStateFromWorkspace(); - // Print XML. - window.console.log(Blockly.Xml.domToPrettyText - (this.generator.generateToolboxXml())); -}; - -/** - * Updates the preview workspace based on the toolbox workspace. If switching - * from no categories to categories or categories to no categories, reinjects - * Blockly with reinjectPreview, otherwise just updates without reinjecting. - * Called whenever a list element is created, removed, or modified and when - * Blockly move and delete events are fired. Do not call on create events - * or disabling will cause the user to "drop" their current blocks. Make sure - * that no changes have been made to the workspace since updating the model - * (if this might be the case, call saveStateFromWorkspace). - */ -WorkspaceFactoryController.prototype.updatePreview = function() { - // Disable events to stop updatePreview from recursively calling itself - // through event handlers. - Blockly.Events.disable(); - - // Only update the toolbox if not in read only mode. - if (!this.model.options['readOnly']) { - // Get toolbox XML. - var tree = Blockly.Options.parseToolboxTree( - this.generator.generateToolboxXml()); - - // No categories, creates a simple flyout. - if (tree.getElementsByTagName('category').length == 0) { - // No categories, creates a simple flyout. - if (this.previewWorkspace.toolbox_) { - this.reinjectPreview(tree); // Switch to simple flyout, expensive. - } else { - this.previewWorkspace.updateToolbox(tree); - } - } else { - // Uses categories, creates a toolbox. - if (!this.previewWorkspace.toolbox_) { - this.reinjectPreview(tree); // Create a toolbox, expensive. - } else { - // Close the toolbox before updating it so that the user has to reopen - // the flyout and see their updated toolbox (open flyout doesn't update) - this.previewWorkspace.toolbox_.clearSelection(); - this.previewWorkspace.updateToolbox(tree); - } - } - } - - // Update pre-loaded blocks in the preview workspace. - this.previewWorkspace.clear(); - Blockly.Xml.domToWorkspace(this.generator.generateWorkspaceXml(), - this.previewWorkspace); - - // Reenable events. - Blockly.Events.enable(); -}; - -/** - * Saves the state from the workspace depending on the current mode. Should - * be called after making changes to the workspace. - */ -WorkspaceFactoryController.prototype.saveStateFromWorkspace = function() { - if (this.selectedMode == WorkspaceFactoryController.MODE_TOOLBOX) { - // If currently editing the toolbox. - // Update flags if toolbox has been changed. - if (this.model.getSelectedXml() != - Blockly.Xml.workspaceToDom(this.toolboxWorkspace)) { - this.hasUnsavedToolboxChanges = true; - } - - this.model.getSelected().saveFromWorkspace(this.toolboxWorkspace); - - } else if (this.selectedMode == WorkspaceFactoryController.MODE_PRELOAD) { - // If currently editing the pre-loaded workspace. - // Update flags if preloaded blocks have been changed. - if (this.model.getPreloadXml() != - Blockly.Xml.workspaceToDom(this.toolboxWorkspace)) { - this.hasUnsavedPreloadChanges = true; - } - - this.model.savePreloadXml( - Blockly.Xml.workspaceToDom(this.toolboxWorkspace)); - } -}; - -/** - * Used to completely reinject the preview workspace. This should be used only - * when switching from simple flyout to categories, or categories to simple - * flyout. More expensive than simply updating the flyout or toolbox. - * @param {!Element} Tree of XML elements - * @package - */ -WorkspaceFactoryController.prototype.reinjectPreview = function(tree) { - this.previewWorkspace.dispose(); - var injectOptions = this.readOptions_(); - injectOptions['toolbox'] = Blockly.Xml.domToPrettyText(tree); - this.previewWorkspace = Blockly.inject('preview_blocks', injectOptions); - Blockly.Xml.domToWorkspace(this.generator.generateWorkspaceXml(), - this.previewWorkspace); -}; - -/** - * Tied to "change name" button. Changes the name of the selected category. - * Continues prompting the user until they input a category name that is not - * currently in use, exits if user presses cancel. - */ -WorkspaceFactoryController.prototype.changeCategoryName = function() { - var selected = this.model.getSelected(); - // Return if a category is not selected. - if (selected.type != ListElement.TYPE_CATEGORY) { - return; - } - // Get new name from user. - window.foo = selected; - var newName = this.promptForNewCategoryName('What do you want to change this' - + ' category\'s name to?', selected.name); - if (!newName) { // If cancelled. - return; - } - // Change category name. - selected.changeName(newName); - this.view.updateCategoryName(newName, this.model.getSelectedId()); - // Update preview. - this.updatePreview(); -}; - -/** - * Tied to arrow up and arrow down buttons. Swaps with the element above or - * below the currently selected element (offset categories away from the - * current element). Updates state to enable the correct element editing - * buttons. - * @param {number} offset The index offset from the currently selected element - * to swap with. Positive if the element to be swapped with is below, negative - * if the element to be swapped with is above. - */ -WorkspaceFactoryController.prototype.moveElement = function(offset) { - var curr = this.model.getSelected(); - if (!curr) { // Return if no selected element. - return; - } - var currIndex = this.model.getIndexByElementId(curr.id); - var swapIndex = this.model.getIndexByElementId(curr.id) + offset; - var swap = this.model.getElementByIndex(swapIndex); - if (!swap) { // Return if cannot swap in that direction. - return; - } - // Move currently selected element to index of other element. - // Indexes must be valid because confirmed that curr and swap exist. - this.moveElementToIndex(curr, swapIndex, currIndex); - // Update element editing buttons. - this.view.updateState(swapIndex, this.model.getSelected()); - // Update preview. - this.updatePreview(); -}; - -/** - * Moves a element to a specified index and updates the model and view - * accordingly. Helper functions throw an error if indexes are out of bounds. - * @param {!Element} element The element to move. - * @param {number} newIndex The index to insert the element at. - * @param {number} oldIndex The index the element is currently at. - */ -WorkspaceFactoryController.prototype.moveElementToIndex = function(element, - newIndex, oldIndex) { - this.model.moveElementToIndex(element, newIndex, oldIndex); - this.view.moveTabToIndex(element.id, newIndex, oldIndex); -}; - -/** - * Changes the color of the selected category. Return if selected element is - * a separator. - * @param {string} color The color to change the selected category. Must be - * a valid CSS string. - */ -WorkspaceFactoryController.prototype.changeSelectedCategoryColor = - function(color) { - // Return if category is not selected. - if (this.model.getSelected().type != ListElement.TYPE_CATEGORY) { - return; - } - // Change color of selected category. - this.model.getSelected().changeColor(color); - this.view.setBorderColor(this.model.getSelectedId(), color); - this.updatePreview(); -}; - -/** - * Tied to the "Standard Category" dropdown option, this function prompts - * the user for a name of a standard Blockly category (case insensitive) and - * loads it as a new category and switches to it. Leverages StandardCategories. - */ -WorkspaceFactoryController.prototype.loadCategory = function() { - // Prompt user for the name of the standard category to load. - do { - var name = prompt('Enter the name of the category you would like to import ' - + '(Logic, Loops, Math, Text, Lists, Colour, Variables, or Functions)'); - if (!name) { - return; // Exit if cancelled. - } - } while (!this.isStandardCategoryName(name)); - - // Load category. - this.loadCategoryByName(name); -}; - -/** - * Loads a Standard Category by name and switches to it. Leverages - * StandardCategories. Returns if cannot load standard category. - * @param {string} name Name of the standard category to load. - */ -WorkspaceFactoryController.prototype.loadCategoryByName = function(name) { - // Check if the user can load that standard category. - if (!this.isStandardCategoryName(name)) { - return; - } - if (this.model.hasVariables() && name.toLowerCase() == 'variables') { - alert('A Variables category already exists. You cannot create multiple' + - ' variables categories.'); - return; - } - if (this.model.hasProcedures() && name.toLowerCase() == 'functions') { - alert('A Functions category already exists. You cannot create multiple' + - ' functions categories.'); - return; - } - // Check if the user can create a category with that name. - var standardCategory = StandardCategories.categoryMap[name.toLowerCase()] - if (this.model.hasCategoryByName(standardCategory.name)) { - alert('You already have a category with the name ' + standardCategory.name - + '. Rename your category and try again.'); - return; - } - // 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. - var copy = standardCategory.copy(); - - // Add it to the model. - this.model.addElementToList(copy); - - // Update the copy in the view. - var tab = this.view.addCategoryRow(copy.name, copy.id); - this.addClickToSwitch(tab, copy.id); - // Color the category tab in the view. - if (copy.color) { - this.view.setBorderColor(copy.id, copy.color); - } - // Switch to loaded category. - this.switchElement(copy.id); - // Convert actual shadow blocks to user-generated shadow blocks. - this.convertShadowBlocks(); - // Save state from workspace before updating preview. - this.saveStateFromWorkspace(); - if (isFirstCategory) { - // Allow the user to use the default options for injecting the workspace - // when there are categories. - this.view.setCategoryOptions(this.model.hasElements()); - this.generateNewOptions(); - } - // Update preview. - 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). - * @param {string} name The name of the category that should be checked if it's - * in StandardCategories categoryMap - * @return {boolean} True if name is a standard category name, false otherwise. - */ -WorkspaceFactoryController.prototype.isStandardCategoryName = function(name) { - for (var category in StandardCategories.categoryMap) { - if (name.toLowerCase() == category) { - return true; - } - } - return false; -}; - -/** - * Connected to the "add separator" dropdown option. If categories already - * exist, adds a separator to the model and view. Does not switch to select - * the separator, and updates the preview. - */ -WorkspaceFactoryController.prototype.addSeparator = function() { - // 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); - // Create the separator in the view. - var tab = this.view.addSeparatorTab(separator.id); - this.addClickToSwitch(tab, separator.id); - // Switch to the separator and update the preview. - this.switchElement(separator.id); - this.updatePreview(); -}; - -/** - * Connected to the import button. Given the file path inputted by the user - * from file input, if the import mode is for the toolbox, this function loads - * that toolbox XML to the workspace, creating category and separator tabs as - * necessary. If the import mode is for pre-loaded blocks in the workspace, - * this function loads that XML to the workspace to be edited further. This - * function switches mode to whatever the import mode is. Catches errors from - * file reading and prints an error message alerting the user. - * @param {string} file The path for the file to be imported into the workspace. - * Should contain valid toolbox XML. - * @param {string} importMode The mode corresponding to the type of file the - * user is importing (WorkspaceFactoryController.MODE_TOOLBOX or - * WorkspaceFactoryController.MODE_PRELOAD). - */ -WorkspaceFactoryController.prototype.importFile = function(file, importMode) { - // Exit if cancelled. - if (!file) { - return; - } - - Blockly.Events.disable(); - var controller = this; - var reader = new FileReader(); - - // To be executed when the reader has read the file. - reader.onload = function() { - // Try to parse XML from file and load it into toolbox editing area. - // Print error message if fail. - try { - var tree = Blockly.Xml.textToDom(reader.result); - if (importMode == WorkspaceFactoryController.MODE_TOOLBOX) { - // Switch mode. - controller.setMode(WorkspaceFactoryController.MODE_TOOLBOX); - - // Confirm that the user wants to override their current toolbox. - var hasToolboxElements = controller.model.hasElements() || - controller.toolboxWorkspace.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. - 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. - throw new Error("Unknown import mode: " + importMode); - } - } catch(e) { - alert('Cannot load XML from file.'); - console.log(e); - } finally { - Blockly.Events.enable(); - } - } - - // Read the file asynchronously. - reader.readAsText(file); -}; - -/** - * Given a XML DOM tree, loads it into the toolbox editing area so that the - * user can continue editing their work. Assumes that tree is in valid toolbox - * XML format. Assumes that the mode is MODE_TOOLBOX. - * @param {!Element} tree XML tree to be loaded to toolbox editing area. - * @private - */ -WorkspaceFactoryController.prototype.importToolboxFromTree_ = function(tree) { - // Clear current editing area. - this.model.clearToolboxList(); - this.view.clearToolboxTabs(); - - if (tree.getElementsByTagName('category').length == 0) { - // No categories present. - // Load all the blocks into a single category evenly spaced. - Blockly.Xml.domToWorkspace(tree, this.toolboxWorkspace); - this.toolboxWorkspace.cleanUp(); - - // Convert actual shadow blocks to user-generated shadow blocks. - this.convertShadowBlocks(); - - // Add message to denote empty category. - this.view.addEmptyCategoryMessage(); - - } else { - // Categories/separators present. - for (var i = 0, item; item = tree.children[i]; i++) { - - if (item.tagName == 'category') { - // If the element is a category, create a new category and switch to it. - this.createCategory(item.getAttribute('name'), false); - var category = this.model.getElementByIndex(i); - this.switchElement(category.id); - - // Load all blocks in that category to the workspace to be evenly - // spaced and saved to that category. - for (var j = 0, blockXml; blockXml = item.children[j]; j++) { - Blockly.Xml.domToBlock(blockXml, this.toolboxWorkspace); - } - - // Evenly space the blocks. - this.toolboxWorkspace.cleanUp(); - - // Convert actual shadow blocks to user-generated shadow blocks. - this.convertShadowBlocks(); - - // Set category color. - if (item.getAttribute('colour')) { - category.changeColor(item.getAttribute('colour')); - this.view.setBorderColor(category.id, category.color); - } - // Set any custom tags. - if (item.getAttribute('custom')) { - this.model.addCustomTag(category, item.getAttribute('custom')); - } - } else { - // If the element is a separator, add the separator and switch to it. - this.addSeparator(); - this.switchElement(this.model.getElementByIndex(i).id); - } - } - } - this.view.updateState(this.model.getIndexByElementId - (this.model.getSelectedId()), this.model.getSelected()); - - this.saveStateFromWorkspace(); - - // Set default configuration options for a single flyout or multiple - // categories. - this.view.setCategoryOptions(this.model.hasElements()); - this.generateNewOptions(); - - this.updatePreview(); -}; - -/** - * Given a XML DOM tree, loads it into the pre-loaded workspace editing area. - * Assumes that tree is in valid XML format and that the selected mode is - * MODE_PRELOAD. - * @param {!Element} tree XML tree to be loaded to pre-loaded block editing - * area. - */ -WorkspaceFactoryController.prototype.importPreloadFromTree_ = function(tree) { - this.clearAndLoadXml_(tree); - this.model.savePreloadXml(tree); - this.updatePreview(); -}; - -/** - * Given a XML DOM tree, loads it into the pre-loaded workspace editing area. - * Assumes that tree is in valid XML format and that the selected mode is - * MODE_PRELOAD. - * @param {!Element} tree XML tree to be loaded to pre-loaded block editing - * area. - */ -WorkspaceFactoryController.prototype.importPreloadFromTree_ = function(tree) { - this.clearAndLoadXml_(tree); - this.model.savePreloadXml(tree); - this.saveStateFromWorkspace(); - this.updatePreview(); -}; - -/** - * Given a XML DOM tree, loads it into the pre-loaded workspace editing area. - * Assumes that tree is in valid XML format and that the selected mode is - * MODE_PRELOAD. - * @param {!Element} tree XML tree to be loaded to pre-loaded block editing - * area. - */ -WorkspaceFactoryController.prototype.importPreloadFromTree_ = function(tree) { - this.clearAndLoadXml_(tree); - this.model.savePreloadXml(tree); - this.saveStateFromWorkspace(); - this.updatePreview(); -}; - -/** - * Clears the editing area completely, deleting all categories and all - * blocks in the model and view and all pre-loaded blocks. Tied to the - * "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(); - this.model.savePreloadXml(Blockly.Xml.textToDom('')); - this.view.addEmptyCategoryMessage(); - this.view.updateState(-1, null); - this.toolboxWorkspace.clear(); - this.toolboxWorkspace.clearUndo(); - this.saveStateFromWorkspace(); - this.hasUnsavedToolboxChanges = false; - this.hasUnsavedPreloadChanges = false; - this.view.setCategoryOptions(this.model.hasElements()); - this.generateNewOptions(); - this.updatePreview(); -}; - -/* - * Makes the currently selected block a user-generated shadow block. These - * blocks are not made into real shadow blocks, but recorded in the model - * and visually marked as shadow blocks, allowing the user to move and edit - * them (which would be impossible with actual shadow blocks). Updates the - * preview when done. - */ -WorkspaceFactoryController.prototype.addShadow = function() { - // No block selected to make a shadow block. - if (!Blockly.selected) { - return; - } - // 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. - * @param {!Blockly.Block} block The block to be converted to a user-generated - * shadow block. - * @private - */ -WorkspaceFactoryController.prototype.addShadowForBlockAndChildren_ = - function(block) { - // Convert to shadow block. - this.view.markShadowBlock(block); - this.model.addShadowBlock(block.id); - - if (FactoryUtils.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]); - } -}; - -/** - * 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 - * shadow blocks and loading the workspace again. Updates the preview again. - */ -WorkspaceFactoryController.prototype.removeShadow = function() { - // No block selected to modify. - if (!Blockly.selected) { - return; - } - 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(); -}; - -/** - * Given a unique block ID, uses the model to determine if a block is a - * user-generated shadow block. - * @param {string} blockId The unique ID of the block to examine. - * @return {boolean} True if the block is a user-generated shadow block, false - * otherwise. - */ -WorkspaceFactoryController.prototype.isUserGenShadowBlock = function(blockId) { - return this.model.isShadowBlock(blockId); -}; - -/** - * Call when importing XML containing real shadow blocks. This function turns - * all real shadow blocks loaded in the workspace into user-generated shadow - * blocks, meaning they are marked as shadow blocks by the model and appear as - * shadow blocks in the view but are still editable and movable. - */ -WorkspaceFactoryController.prototype.convertShadowBlocks = function() { - var blocks = this.toolboxWorkspace.getAllBlocks(); - for (var i = 0, block; block = blocks[i]; i++) { - if (block.isShadow()) { - block.setShadow(false); - // Delete the shadow DOM attached to the block so that the shadow block - // does not respawn. Dependent on implementation details. - var parentConnection = block.outputConnection ? - block.outputConnection.targetConnection : - block.previousConnection.targetConnection; - if (parentConnection) { - parentConnection.setShadowDom(null); - } - this.model.addShadowBlock(block.id); - this.view.markShadowBlock(block); - } - } -}; - -/** - * Sets the currently selected mode that determines what the toolbox workspace - * is being used to edit. Updates the view and then saves and loads XML - * to and from the toolbox and updates the help text. - * @param {string} tab The type of tab being switched to - * (WorkspaceFactoryController.MODE_TOOLBOX or - * WorkspaceFactoryController.MODE_PRELOAD). - */ -WorkspaceFactoryController.prototype.setMode = function(mode) { - // No work to change mode that's currently set. - if (this.selectedMode == mode) { - return; - } - - // No work to change mode that's currently set. - if (this.selectedMode == mode) { - return; - } - - // Set tab selection and display appropriate tab. - this.view.setModeSelection(mode); - - // Update selected tab. - this.selectedMode = mode; - - // Update help text above workspace. - this.view.updateHelpText(mode); - - if (mode == WorkspaceFactoryController.MODE_TOOLBOX) { - // Open the toolbox editing space. - this.model.savePreloadXml - (Blockly.Xml.workspaceToDom(this.toolboxWorkspace)); - this.clearAndLoadXml_(this.model.getSelectedXml()); - this.view.disableWorkspace(this.view.shouldDisableWorkspace - (this.model.getSelected())); - } else { - // Open the pre-loaded workspace editing space. - if (this.model.getSelected()) { - this.model.getSelected().saveFromWorkspace(this.toolboxWorkspace); - } - this.clearAndLoadXml_(this.model.getPreloadXml()); - this.view.disableWorkspace(false); - } -}; - -/** - * Clears the toolbox workspace and loads XML to it, marking shadow blocks - * as necessary. - * @private - * @param {!Element} xml The XML to be loaded to the workspace. - */ -WorkspaceFactoryController.prototype.clearAndLoadXml_ = function(xml) { - this.toolboxWorkspace.clear(); - this.toolboxWorkspace.clearUndo(); - Blockly.Xml.domToWorkspace(xml, this.toolboxWorkspace); - this.view.markShadowBlocks(this.model.getShadowBlocksInWorkspace - (this.toolboxWorkspace.getAllBlocks())); - this.warnForUndefinedBlocks_(); -}; - -/** - * Sets the standard default options for the options object and updates - * the preview workspace. The default values depends on if categories are - * present. - */ -WorkspaceFactoryController.prototype.setStandardOptionsAndUpdate = function() { - this.view.setBaseOptions(); - this.view.setCategoryOptions(this.model.hasElements()); - this.generateNewOptions(); -}; - -/** - * Generates a new options object for injecting a Blockly workspace based - * on user input. Should be called every time a change has been made to - * an input field. Updates the model and reinjects the preview workspace. - */ -WorkspaceFactoryController.prototype.generateNewOptions = function() { - this.model.setOptions(this.readOptions_()); - - this.reinjectPreview(Blockly.Options.parseToolboxTree - (this.generator.generateToolboxXml())); -}; - -/** - * Generates a new options object for injecting a Blockly workspace based on - * user input. - * @return {!Object} Blockly injection options object. - * @private - */ -WorkspaceFactoryController.prototype.readOptions_ = function() { - var optionsObj = Object.create(null); - - // Add all standard options to the options object. - // Use parse int to get numbers from value inputs. - var readonly = document.getElementById('option_readOnly_checkbox').checked; - if (readonly) { - optionsObj['readOnly'] = true; - } else { - optionsObj['collapse'] = - document.getElementById('option_collapse_checkbox').checked; - optionsObj['comments'] = - document.getElementById('option_comments_checkbox').checked; - optionsObj['disable'] = - document.getElementById('option_disable_checkbox').checked; - if (document.getElementById('option_infiniteBlocks_checkbox').checked) { - optionsObj['maxBlocks'] = Infinity; - } else { - var maxBlocksValue = - document.getElementById('option_maxBlocks_number').value; - optionsObj['maxBlocks'] = typeof maxBlocksValue == 'string' ? - parseInt(maxBlocksValue) : maxBlocksValue; - } - optionsObj['trashcan'] = - document.getElementById('option_trashcan_checkbox').checked; - optionsObj['horizontalLayout'] = - document.getElementById('option_horizontalLayout_checkbox').checked; - optionsObj['toolboxPosition'] = - document.getElementById('option_toolboxPosition_checkbox').checked ? - 'end' : 'start'; - } - - optionsObj['css'] = document.getElementById('option_css_checkbox').checked; - optionsObj['media'] = document.getElementById('option_media_text').value; - optionsObj['rtl'] = document.getElementById('option_rtl_checkbox').checked; - optionsObj['scrollbars'] = - document.getElementById('option_scrollbars_checkbox').checked; - optionsObj['sounds'] = - document.getElementById('option_sounds_checkbox').checked; - optionsObj['oneBasedIndex'] = - document.getElementById('option_oneBasedIndex_checkbox').checked; - - // If using a grid, add all grid options. - if (document.getElementById('option_grid_checkbox').checked) { - var grid = Object.create(null); - var spacingValue = - document.getElementById('gridOption_spacing_number').value; - grid['spacing'] = typeof spacingValue == 'string' ? - parseInt(spacingValue) : spacingValue; - var lengthValue = document.getElementById('gridOption_length_number').value; - grid['length'] = typeof lengthValue == 'string' ? - parseInt(lengthValue) : lengthValue; - grid['colour'] = document.getElementById('gridOption_colour_text').value; - if (!readonly) { - grid['snap'] = - document.getElementById('gridOption_snap_checkbox').checked; - } - optionsObj['grid'] = grid; - } - - // If using zoom, add all zoom options. - if (document.getElementById('option_zoom_checkbox').checked) { - var zoom = Object.create(null); - zoom['controls'] = - document.getElementById('zoomOption_controls_checkbox').checked; - zoom['wheel'] = - document.getElementById('zoomOption_wheel_checkbox').checked; - var startScaleValue = - document.getElementById('zoomOption_startScale_number').value; - zoom['startScale'] = typeof startScaleValue == 'string' ? - parseFloat(startScaleValue) : startScaleValue; - var maxScaleValue = - document.getElementById('zoomOption_maxScale_number').value; - zoom['maxcale'] = typeof maxScaleValue == 'string' ? - parseFloat(maxScaleValue) : maxScaleValue; - var minScaleValue = - document.getElementById('zoomOption_minScale_number').value; - zoom['minScale'] = typeof minScaleValue == 'string' ? - parseFloat(minScaleValue) : minScaleValue; - var scaleSpeedValue = - document.getElementById('zoomOption_scaleSpeed_number').value; - zoom['startScale'] = typeof startScaleValue == 'string' ? - parseFloat(scaleSpeedValue) : scaleSpeedValue; - optionsObj['zoom'] = zoom; - } - - return optionsObj; -}; - -/** - * Imports blocks from a file, generating a category in the toolbox workspace - * to allow the user to use imported blocks in the toolbox and in pre-loaded - * blocks. - * @param {!File} file File object for the blocks to import. - * @param {string} format The format of the file to import, either 'JSON' or - * 'JavaScript'. - */ -WorkspaceFactoryController.prototype.importBlocks = function(file, format) { - // Generate category name from file name. - var categoryName = file.name; - - var controller = this; - var reader = new FileReader(); - - // To be executed when the reader has read the file. - reader.onload = function() { - try { - // Define blocks using block types from file. - var blockTypes = FactoryUtils.defineAndGetBlockTypes(reader.result, - format); - - // 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 - // category a different color. - var randomColor = Math.floor(Math.random() * 360); - categoryXml.setAttribute('colour', randomColor); - controller.toolbox.appendChild(categoryXml); - controller.toolboxWorkspace.updateToolbox(controller.toolbox); - // Update imported block types. - controller.model.addImportedBlockTypes(blockTypes); - // Reload current category to possibly reflect any newly defined blocks. - controller.clearAndLoadXml_ - (Blockly.Xml.workspaceToDom(controller.toolboxWorkspace)); - } catch (e) { - alert('Cannot read blocks from file.'); - window.console.log(e); - } - } - - // Read the file asynchronously. - reader.readAsText(file); -}; - -/* - * Updates the block library category in the toolbox workspace toolbox. - * @param {!Element} categoryXml XML for the block library category. - * @param {!Array.} libBlockTypes Array of block types from the block - * library. - */ -WorkspaceFactoryController.prototype.setBlockLibCategory = - function(categoryXml, libBlockTypes) { - var blockLibCategory = document.getElementById('blockLibCategory'); - - // Set category ID so that it can be easily replaced, and set a standard, - // arbitrary block library color. - categoryXml.setAttribute('id', 'blockLibCategory'); - categoryXml.setAttribute('colour', 260); - - // Update the toolbox and toolboxWorkspace. - this.toolbox.replaceChild(categoryXml, blockLibCategory); - this.toolboxWorkspace.toolbox_.clearSelection(); - this.toolboxWorkspace.updateToolbox(this.toolbox); - - // Update the block library types. - this.model.updateLibBlockTypes(libBlockTypes); - - // Reload XML on page to account for blocks now defined or undefined in block - // library. - this.clearAndLoadXml_(Blockly.Xml.workspaceToDom(this.toolboxWorkspace)); -}; - -/** - * 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(); -}; - -/** - * Determines if a block loaded in the workspace has a definition (if it - * is a standard block, is defined in the block library, or has a definition - * imported). - * @param {!Blockly.Block} block The block to examine. - */ -WorkspaceFactoryController.prototype.isDefinedBlock = function(block) { - return this.model.isDefinedBlockType(block.type); -}; - -/** - * Sets a warning on blocks loaded to the workspace that are not defined. - * @private - */ -WorkspaceFactoryController.prototype.warnForUndefinedBlocks_ = function() { - var blocks = this.toolboxWorkspace.getAllBlocks(); - for (var i = 0, block; block = blocks[i]; i++) { - if (!this.isDefinedBlock(block)) { - block.setWarningText(block.type + ' is not defined (it is not a standard ' - + 'block, \nin your block library, or an imported block)'); - } - } -}; - -/* - * Determines if a standard variable category is in the custom toolbox. - * @return {boolean} True if a variables category is in use, false otherwise. - */ -WorkspaceFactoryController.prototype.hasVariablesCategory = function() { - return this.model.hasVariables(); -}; - -/** - * Determines if a standard procedures category is in the custom toolbox. - * @return {boolean} True if a procedures category is in use, false otherwise. - */ -WorkspaceFactoryController.prototype.hasProceduresCategory = function() { - return this.model.hasProcedures(); -}; - -/** - * Determines if there are any unsaved changes in workspace factory. - * @return {boolean} True if there are unsaved changes, false otherwise. - */ -WorkspaceFactoryController.prototype.hasUnsavedChanges = function() { - return this.hasUnsavedToolboxChanges || this.hasUnsavedPreloadChanges; -}; diff --git a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_generator.js b/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_generator.js deleted file mode 100644 index 3b06ac282e1..00000000000 --- a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_generator.js +++ /dev/null @@ -1,243 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Generates the configuration XML used to update the preview - * workspace or print to the console or download to a file. Leverages - * Blockly.Xml and depends on information in the model (holds a reference). - * Depends on a hidden workspace created in the generator to load saved XML in - * order to generate toolbox XML. - * - * @author Emma Dauterman (evd2014) - */ - -goog.require('FactoryUtils'); - - -/** - * Class for a WorkspaceFactoryGenerator - * @constructor - */ -WorkspaceFactoryGenerator = function(model) { - // Model to share information about categories and shadow blocks. - this.model = model; - // Create hidden workspace to load saved XML to generate toolbox XML. - var hiddenBlocks = document.createElement('div'); - // Generate a globally unique ID for the hidden div element to avoid - // collisions. - var hiddenBlocksId = Blockly.utils.genUid(); - hiddenBlocks.id = hiddenBlocksId; - hiddenBlocks.style.display = 'none'; - document.body.appendChild(hiddenBlocks); - this.hiddenWorkspace = Blockly.inject(hiddenBlocksId); -}; - -/** - * Generates the XML for the toolbox or flyout with information from - * toolboxWorkspace and the model. Uses the hiddenWorkspace to generate XML. - * Save state of workspace in model (saveFromWorkspace) before calling if - * changes might have been made to the selected category. - * @param {!Blockly.workspace} toolboxWorkspace Toolbox editing workspace where - * blocks are added by user to be part of the toolbox. - * @return {!Element} XML element representing toolbox or flyout corresponding - * to toolbox workspace. - */ -WorkspaceFactoryGenerator.prototype.generateToolboxXml = function() { - // Create DOM for XML. - var xmlDom = goog.dom.createDom('xml', - { - 'id' : 'toolbox', - 'style' : 'display:none' - }); - if (!this.model.hasElements()) { - // Toolbox has no categories. Use XML directly from workspace. - this.loadToHiddenWorkspace_(this.model.getSelectedXml()); - this.appendHiddenWorkspaceToDom_(xmlDom); - } else { - // Toolbox has categories. - // Assert that selected != null - if (!this.model.getSelected()) { - throw new Error('Selected is null when the toolbox is empty.'); - } - - var xml = this.model.getSelectedXml(); - var toolboxList = this.model.getToolboxList(); - - // Iterate through each category to generate XML for each using the - // hidden workspace. Load each category to the hidden workspace to make sure - // that all the blocks that are not top blocks are also captured as block - // groups in the flyout. - for (var i = 0; i < toolboxList.length; i++) { - var element = toolboxList[i]; - if (element.type == ListElement.TYPE_SEPARATOR) { - // If the next element is a separator. - var nextElement = goog.dom.createDom('sep'); - } else if (element.type == ListElement.TYPE_CATEGORY) { - // If the next element is a category. - var nextElement = goog.dom.createDom('category'); - nextElement.setAttribute('name', element.name); - // Add a colour attribute if one exists. - if (element.color != null) { - nextElement.setAttribute('colour', element.color); - } - // Add a custom attribute if one exists. - if (element.custom != null) { - nextElement.setAttribute('custom', element.custom); - } - // Load that category to hidden workspace, setting user-generated shadow - // blocks as real shadow blocks. - this.loadToHiddenWorkspace_(element.xml); - this.appendHiddenWorkspaceToDom_(nextElement); - } - xmlDom.appendChild(nextElement); - } - } - return xmlDom; - }; - - - /** - * Generates XML for the workspace (different from generateConfigXml in that - * it includes XY and ID attributes). Uses a workspace and converts user - * generated shadow blocks to actual shadow blocks. - * @return {!Element} XML element representing toolbox or flyout corresponding - * to toolbox workspace. - */ -WorkspaceFactoryGenerator.prototype.generateWorkspaceXml = function() { - // Load workspace XML to hidden workspace with user-generated shadow blocks - // as actual shadow blocks. - this.hiddenWorkspace.clear(); - Blockly.Xml.domToWorkspace(this.model.getPreloadXml(), this.hiddenWorkspace); - this.setShadowBlocksInHiddenWorkspace_(); - - // Generate XML and set attributes. - var generatedXml = Blockly.Xml.workspaceToDom(this.hiddenWorkspace); - generatedXml.setAttribute('id', 'workspaceBlocks'); - generatedXml.setAttribute('style', 'display:none'); - return generatedXml; -}; - -/** - * Generates a string representation of the options object for injecting the - * workspace and starter code. - * @return {string} String representation of starter code for injecting. - */ -WorkspaceFactoryGenerator.prototype.generateInjectString = function() { - var addAttributes = function(obj, tabChar) { - if (!obj) { - return '{}\n'; - } - var str = ''; - for (var key in obj) { - if (key == 'grid' || key == 'zoom') { - var temp = tabChar + key + ' : {\n' + addAttributes(obj[key], - tabChar + '\t') + tabChar + '}, \n'; - } else if (typeof obj[key] == 'string') { - var temp = tabChar + key + ' : \'' + obj[key] + '\', \n'; - } else { - var temp = tabChar + key + ' : ' + obj[key] + ', \n'; - } - str += temp; - } - var lastCommaIndex = str.lastIndexOf(','); - str = str.slice(0, lastCommaIndex) + '\n'; - return str; - }; - - var attributes = addAttributes(this.model.options, '\t'); - if (!this.model.options['readOnly']) { - attributes = '\ttoolbox : toolbox, \n' + - attributes; - } - var finalStr = '/* TODO: Change toolbox XML ID if necessary. Can export ' + - 'toolbox XML from Workspace Factory. */\n' + - 'var toolbox = document.getElementById("toolbox");\n\n'; - 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 all code below if no blocks to load */\n\n' + - '/* TODO: Change workspace blocks XML ID if necessary. Can export' + - ' workspace blocks XML from Workspace Factory. */\n' + - 'var workspaceBlocks = document.getElementById("workspaceBlocks"); \n\n' + - '/* Load blocks to workspace. */\n' + - 'Blockly.Xml.domToWorkspace(workspace, workspaceBlocks);'; - return finalStr; -}; - -/** - * Loads the given XML to the hidden workspace and sets any user-generated - * shadow blocks to be actual shadow blocks. - * @param {!Element} xml The XML to be loaded to the hidden workspace. - * @private - */ -WorkspaceFactoryGenerator.prototype.loadToHiddenWorkspace_ = function(xml) { - this.hiddenWorkspace.clear(); - Blockly.Xml.domToWorkspace(xml, this.hiddenWorkspace); - this.setShadowBlocksInHiddenWorkspace_(); -}; - -/** - * Encodes blocks in the hidden workspace in a XML DOM element. Very - * similar to workspaceToDom, but doesn't capture IDs. Uses the top-level - * blocks loaded in hiddenWorkspace. - * @private - * @param {!Element} xmlDom Tree of XML elements to be appended to. - */ -WorkspaceFactoryGenerator.prototype.appendHiddenWorkspaceToDom_ = - function(xmlDom) { - var blocks = this.hiddenWorkspace.getTopBlocks(); - for (var i = 0, block; block = blocks[i]; i++) { - var blockChild = Blockly.Xml.blockToDom(block, /* opt_noId */ true); - xmlDom.appendChild(blockChild); - } -}; - -/** - * Sets the user-generated shadow blocks loaded into hiddenWorkspace to be - * actual shadow blocks. This is done so that blockToDom records them as - * shadow blocks instead of regular blocks. - * @private - */ -WorkspaceFactoryGenerator.prototype.setShadowBlocksInHiddenWorkspace_ = - function() { - var blocks = this.hiddenWorkspace.getAllBlocks(); - for (var i = 0; i < blocks.length; i++) { - if (this.model.isShadowBlock(blocks[i].id)) { - blocks[i].setShadow(true); - } - } -}; - -/** - * Given a set of block types, gets the Blockly.Block objects for each block - * type. - * @param {!Array.} blockTypes Array of blocks that have been defined. - * @return {!Array.} Array of Blockly.Block objects corresponding - * to the array of blockTypes. - */ -WorkspaceFactoryGenerator.prototype.getDefinedBlocks = function(blockTypes) { - var blocks = []; - for (var i = 0; i < blockTypes.length ; i++) { - blocks.push(FactoryUtils.getDefinedBlock(blockTypes[i], - this.hiddenWorkspace)); - } - return blocks; -}; diff --git a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_init.js b/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_init.js deleted file mode 100644 index 31069b0c50d..00000000000 --- a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_init.js +++ /dev/null @@ -1,604 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Contains the init functions for the workspace factory tab. - * Adds click handlers to buttons and dropdowns, adds event listeners for - * keydown events and Blockly events, and configures the initial setup of - * the page. - * - * @author Emma Dauterman (evd2014) - */ - - goog.require('FactoryUtils'); - -/** - * Namespace for workspace factory initialization methods. - * @namespace - */ -WorkspaceFactoryInit = {}; - -/** - * Initialization for workspace factory tab. - * @param {!FactoryController} controller The controller for the workspace - * factory tab. - */ -WorkspaceFactoryInit.initWorkspaceFactory = function(controller) { - // Disable category editing buttons until categories are created. - document.getElementById('button_remove').disabled = true; - document.getElementById('button_up').disabled = true; - document.getElementById('button_down').disabled = true; - document.getElementById('button_editCategory').disabled = true; - - this.initColorPicker_(controller); - this.addWorkspaceFactoryEventListeners_(controller); - this.assignWorkspaceFactoryClickHandlers_(controller); - this.addWorkspaceFactoryOptionsListeners_(controller); - - // Check standard options and apply the changes to update the view. - controller.setStandardOptionsAndUpdate(); -}; - -/** - * Initialize the color picker in workspace factory. - * @param {!FactoryController} controller The controller for the workspace - * factory tab. - * @private - */ -WorkspaceFactoryInit.initColorPicker_ = function(controller) { - // Array of Blockly category colours, consitent with the 15 degree default - // of the block factory's colour wheel. - var colours = []; - for (var hue = 0; hue < 360; hue += 15) { - colours.push(WorkspaceFactoryInit.hsvToHex_(hue, - Blockly.HSV_SATURATION, Blockly.HSV_VALUE)); - } - - // Create color picker with specific set of Blockly colours. - var colourPicker = new goog.ui.ColorPicker(); - colourPicker.setSize(6); - colourPicker.setColors(colours); - - // Create and render the popup colour picker and attach to button. - var popupPicker = new goog.ui.PopupColorPicker(null, colourPicker); - popupPicker.render(); - popupPicker.attach(document.getElementById('dropdown_color')); - popupPicker.setFocusable(true); - goog.events.listen(popupPicker, 'change', function(e) { - controller.changeSelectedCategoryColor(popupPicker.getSelectedColor()); - blocklyFactory.closeModal(); - }); -}; - -/** - * Converts from h,s,v values to a hex string - * @param {number} h Hue, in [0, 360]. - * @param {number} s Saturation, in [0, 1]. - * @param {number} v Value, in [0, 1]. - * @return {string} hex representation of the color. - * @private - */ -WorkspaceFactoryInit.hsvToHex_ = function(h, s, v) { - var brightness = v * 255; - var red = 0; - var green = 0; - var blue = 0; - if (s == 0) { - red = brightness; - green = brightness; - blue = brightness; - } else { - var sextant = Math.floor(h / 60); - var remainder = (h / 60) - sextant; - var val1 = brightness * (1 - s); - var val2 = brightness * (1 - (s * remainder)); - var val3 = brightness * (1 - (s * (1 - remainder))); - switch (sextant) { - case 1: - red = val2; - green = brightness; - blue = val1; - break; - case 2: - red = val1; - green = brightness; - blue = val3; - break; - case 3: - red = val1; - green = val2; - blue = brightness; - break; - case 4: - red = val3; - green = val1; - blue = brightness; - break; - case 5: - red = brightness; - green = val1; - blue = val2; - break; - case 6: - case 0: - red = brightness; - green = val3; - blue = val1; - break; - } - } - - var hexR = ('0' + Math.floor(red).toString(16)).slice(-2); - var hexG = ('0' + Math.floor(green).toString(16)).slice(-2); - var hexB = ('0' + Math.floor(blue).toString(16)).slice(-2); - return '#' + hexR + hexG + hexB; -}; - -/** - * Assign click handlers for workspace factory. - * @param {!FactoryController} controller The controller for the workspace - * factory tab. - * @private - */ -WorkspaceFactoryInit.assignWorkspaceFactoryClickHandlers_ = - function(controller) { - - // Import Custom Blocks button. - document.getElementById('button_importBlocks').addEventListener - ('click', - function() { - blocklyFactory.openModal('dropdownDiv_importBlocks'); - }); - document.getElementById('input_importBlocksJson').addEventListener - ('change', - function() { - controller.importBlocks(event.target.files[0], 'JSON'); - }); - document.getElementById('input_importBlocksJson').addEventListener - ('click', function() {blocklyFactory.closeModal()}); - document.getElementById('input_importBlocksJs').addEventListener - ('change', - function() { - controller.importBlocks(event.target.files[0], 'JavaScript'); - }); - document.getElementById('input_importBlocksJs').addEventListener - ('click', function() {blocklyFactory.closeModal()}); - - // Load to Edit button. - document.getElementById('button_load').addEventListener - ('click', - function() { - blocklyFactory.openModal('dropdownDiv_load'); - }); - document.getElementById('input_loadToolbox').addEventListener - ('change', - function() { - controller.importFile(event.target.files[0], - WorkspaceFactoryController.MODE_TOOLBOX); - }); - document.getElementById('input_loadToolbox').addEventListener - ('click', function() {blocklyFactory.closeModal()}); - document.getElementById('input_loadPreload').addEventListener - ('change', - function() { - controller.importFile(event.target.files[0], - WorkspaceFactoryController.MODE_PRELOAD); - }); - document.getElementById('input_loadPreload').addEventListener - ('click', function() {blocklyFactory.closeModal()}); - - // Export button. - document.getElementById('dropdown_exportOptions').addEventListener - ('click', - function() { - controller.exportInjectFile(); - blocklyFactory.closeModal(); - }); - document.getElementById('dropdown_exportToolbox').addEventListener - ('click', - function() { - controller.exportXmlFile(WorkspaceFactoryController.MODE_TOOLBOX); - blocklyFactory.closeModal(); - }); - document.getElementById('dropdown_exportPreload').addEventListener - ('click', - function() { - controller.exportXmlFile(WorkspaceFactoryController.MODE_PRELOAD); - blocklyFactory.closeModal(); - }); - document.getElementById('dropdown_exportAll').addEventListener - ('click', - function() { - controller.exportInjectFile(); - controller.exportXmlFile(WorkspaceFactoryController.MODE_TOOLBOX); - controller.exportXmlFile(WorkspaceFactoryController.MODE_PRELOAD); - blocklyFactory.closeModal(); - }); - document.getElementById('button_export').addEventListener - ('click', - function() { - blocklyFactory.openModal('dropdownDiv_export'); - }); - - // Clear button. - document.getElementById('button_clear').addEventListener - ('click', - function() { - controller.clearAll(); - }); - - // Toolbox and Workspace tabs. - document.getElementById('tab_toolbox').addEventListener - ('click', - function() { - controller.setMode(WorkspaceFactoryController.MODE_TOOLBOX); - }); - document.getElementById('tab_preload').addEventListener - ('click', - function() { - controller.setMode(WorkspaceFactoryController.MODE_PRELOAD); - }); - - // '+' button. - document.getElementById('button_add').addEventListener - ('click', - function() { - blocklyFactory.openModal('dropdownDiv_add'); - }); - document.getElementById('dropdown_newCategory').addEventListener - ('click', - function() { - controller.addCategory(); - blocklyFactory.closeModal(); - }); - document.getElementById('dropdown_loadCategory').addEventListener - ('click', - function() { - controller.loadCategory(); - blocklyFactory.closeModal(); - }); - document.getElementById('dropdown_separator').addEventListener - ('click', - function() { - controller.addSeparator(); - blocklyFactory.closeModal(); - }); - document.getElementById('dropdown_loadStandardToolbox').addEventListener - ('click', - function() { - controller.loadStandardToolbox(); - blocklyFactory.closeModal(); - }); - - // '-' button. - document.getElementById('button_remove').addEventListener - ('click', - function() { - controller.removeElement(); - }); - - // Up/Down buttons. - document.getElementById('button_up').addEventListener - ('click', - function() { - controller.moveElement(-1); - }); - document.getElementById('button_down').addEventListener - ('click', - function() { - controller.moveElement(1); - }); - - // Edit Category button. - document.getElementById('button_editCategory').addEventListener - ('click', - function() { - blocklyFactory.openModal('dropdownDiv_editCategory'); - }); - document.getElementById('dropdown_name').addEventListener - ('click', - function() { - controller.changeCategoryName(); - blocklyFactory.closeModal(); - }); - - // Make/Remove Shadow buttons. - document.getElementById('button_addShadow').addEventListener - ('click', - function() { - controller.addShadow(); - WorkspaceFactoryInit.displayAddShadow_(false); - WorkspaceFactoryInit.displayRemoveShadow_(true); - }); - document.getElementById('button_removeShadow').addEventListener - ('click', - function() { - controller.removeShadow(); - WorkspaceFactoryInit.displayAddShadow_(true); - WorkspaceFactoryInit.displayRemoveShadow_(false); - - // Disable shadow editing button if turning invalid shadow block back - // to normal block. - if (!Blockly.selected.getSurroundParent()) { - document.getElementById('button_addShadow').disabled = true; - } - }); - - // Help button on workspace tab. - document.getElementById('button_optionsHelp').addEventListener - ('click', function() { - open('https://developers.google.com/blockly/guides/get-started/web#configuration'); - }); - - // Reset to Default button on workspace tab. - document.getElementById('button_standardOptions').addEventListener - ('click', function() { - controller.setStandardOptionsAndUpdate(); - }); -}; - -/** - * Add event listeners for workspace factory. - * @param {!FactoryController} controller The controller for the workspace - * factory tab. - * @private - */ -WorkspaceFactoryInit.addWorkspaceFactoryEventListeners_ = function(controller) { - // Use up and down arrow keys to move categories. - window.addEventListener('keydown', function(e) { - // Don't let arrow keys have any effect if not in Workspace Factory - // editing the toolbox. - if (!(controller.keyEventsEnabled && controller.selectedMode - == WorkspaceFactoryController.MODE_TOOLBOX)) { - return; - } - - if (e.keyCode == 38) { - // Arrow up. - controller.moveElement(-1); - } else if (e.keyCode == 40) { - // Arrow down. - controller.moveElement(1); - } - }); - - // 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. - // Not listening for Blockly create events because causes the user to drop - // blocks when dragging them into workspace. Could cause problems if ever - // load blocks into workspace directly without calling updatePreview. - if (e.type == Blockly.Events.MOVE || e.type == Blockly.Events.DELETE || - e.type == Blockly.Events.CHANGE) { - controller.saveStateFromWorkspace(); - controller.updatePreview(); - } - - // Listen for Blockly UI events to correctly enable the "Edit Block" button. - // Only enable "Edit Block" when a block is selected and it has a - // surrounding parent, meaning it is nested in another block (blocks that - // are not nested in parents cannot be shadow blocks). - if (e.type == Blockly.Events.MOVE || (e.type == Blockly.Events.UI && - e.element == 'selected')) { - var selected = Blockly.selected; - - // Show shadow button if a block is selected. Show "Add Shadow" if - // a block is not a shadow block, show "Remove Shadow" if it is a - // shadow block. - if (selected) { - var isShadow = controller.isUserGenShadowBlock(selected.id); - WorkspaceFactoryInit.displayAddShadow_(!isShadow); - WorkspaceFactoryInit.displayRemoveShadow_(isShadow); - } else { - WorkspaceFactoryInit.displayAddShadow_(false); - WorkspaceFactoryInit.displayRemoveShadow_(false); - } - - 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. - - // Enable block editing and remove warnings if the block is not a - // variable user-generated shadow block. - document.getElementById('button_addShadow').disabled = false; - document.getElementById('button_removeShadow').disabled = false; - - if (!FactoryUtils.hasVariableField(selected) && - controller.isDefinedBlock(selected)) { - selected.setWarningText(null); - } - } else { - // Selected block cannot be a valid shadow block. - - 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\n' - + 'other shadow blocks.'); - } else if (!FactoryUtils.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_removeShadow').disabled = false; - document.getElementById('button_addShadow').disabled = true; - } 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.isDefinedBlock(selected) && - (!FactoryUtils.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. - document.getElementById('button_addShadow').disabled = true; - document.getElementById('button_removeShadow').disabled = true; - } - } - } - - // Convert actual shadow blocks added from the toolbox to user-generated - // shadow blocks. - if (e.type == Blockly.Events.CREATE) { - controller.convertShadowBlocks(); - - // Let the user create a Variables or Functions category if they use - // blocks from either category. - - // Get all children of a block and add them to childList. - var getAllChildren = function(block, childList) { - childList.push(block); - var children = block.getChildren(); - for (var i = 0, child; child = children[i]; i++) { - getAllChildren(child, childList); - } - }; - - var newBaseBlock = controller.toolboxWorkspace.getBlockById(e.blockId); - var allNewBlocks = []; - getAllChildren(newBaseBlock, allNewBlocks); - var variableCreated = false; - var procedureCreated = false; - - // Check if the newly created block or any of its children are variable - // or procedure blocks. - for (var i = 0, block; block = allNewBlocks[i]; i++) { - if (FactoryUtils.hasVariableField(block)) { - variableCreated = true; - } else if (FactoryUtils.isProcedureBlock(block)) { - procedureCreated = true; - } - } - - // If any of the newly created blocks are variable or procedure blocks, - // prompt the user to create the corresponding standard category. - if (variableCreated && !controller.hasVariablesCategory()) { - if (confirm('Your new block has a variables field. To use this block ' - + 'fully, you will need a Variables category. Do you want to add ' - + 'a Variables category to your custom toolbox?')) { - controller.setMode(WorkspaceFactoryController.MODE_TOOLBOX); - controller.loadCategoryByName('variables'); - } - } - - if (procedureCreated && !controller.hasProceduresCategory()) { - if (confirm('Your new block is a function block. To use this block ' - + 'fully, you will need a Functions category. Do you want to add ' - + 'a Functions category to your custom toolbox?')) { - controller.setMode(WorkspaceFactoryController.MODE_TOOLBOX); - controller.loadCategoryByName('functions'); - } - } - } - }); -}; - -/** - * Display or hide the add shadow button. - * @param {boolean} show True if the add shadow button should be shown, false - * otherwise. - */ -WorkspaceFactoryInit.displayAddShadow_ = function(show) { - document.getElementById('button_addShadow').style.display = - show ? 'inline-block' : 'none'; -}; - -/** - * Display or hide the remove shadow button. - * @param {boolean} show True if the remove shadow button should be shown, false - * otherwise. - */ -WorkspaceFactoryInit.displayRemoveShadow_ = function(show) { - document.getElementById('button_removeShadow').style.display = - show ? 'inline-block' : 'none'; -}; - -/** - * Add listeners for workspace factory options input elements. - * @param {!FactoryController} controller The controller for the workspace - * factory tab. - * @private - */ -WorkspaceFactoryInit.addWorkspaceFactoryOptionsListeners_ = - function(controller) { - // Checking the grid checkbox displays grid options. - document.getElementById('option_grid_checkbox').addEventListener('change', - function(e) { - document.getElementById('grid_options').style.display = - document.getElementById('option_grid_checkbox').checked ? - 'block' : 'none'; - }); - - // Checking the zoom checkbox displays zoom options. - document.getElementById('option_zoom_checkbox').addEventListener('change', - function(e) { - document.getElementById('zoom_options').style.display = - document.getElementById('option_zoom_checkbox').checked ? - 'block' : 'none'; - }); - - // Checking the readonly checkbox enables/disables other options. - document.getElementById('option_readOnly_checkbox').addEventListener('change', - function(e) { - var checkbox = document.getElementById('option_readOnly_checkbox'); - blocklyFactory.ifCheckedEnable(!checkbox.checked, - ['readonly1', 'readonly2']); - }); - - document.getElementById('option_infiniteBlocks_checkbox').addEventListener('change', - function(e) { - document.getElementById('maxBlockNumber_option').style.display = - document.getElementById('option_infiniteBlocks_checkbox').checked ? - 'none' : 'block'; - }); - - // Generate new options every time an options input is updated. - var div = document.getElementById('workspace_options'); - var options = div.getElementsByTagName('input'); - for (var i = 0, option; option = options[i]; i++) { - option.addEventListener('change', function() { - controller.generateNewOptions(); - }); - } -}; diff --git a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_model.js b/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_model.js deleted file mode 100644 index 7b60810d38a..00000000000 --- a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_model.js +++ /dev/null @@ -1,563 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Stores and updates information about state and categories - * in workspace factory. Each list element is either a separator or a category, - * and each category stores its name, XML to load that category, color, - * custom tags, and a unique ID making it possible to change category names and - * move categories easily. Keeps track of the currently selected list - * element. Also keeps track of all the user-created shadow blocks and - * manipulates them as necessary. - * - * @author Emma Dauterman (evd2014) - */ - -/** - * Class for a WorkspaceFactoryModel - * @constructor - */ -WorkspaceFactoryModel = function() { - // Ordered list of ListElement objects. Empty if there is a single flyout. - this.toolboxList = []; - // ListElement for blocks in a single flyout. Null if a toolbox exists. - this.flyout = new ListElement(ListElement.TYPE_FLYOUT); - // Array of block IDs for all user created shadow blocks. - this.shadowBlocks = []; - // Reference to currently selected ListElement. Stored in this.toolboxList if - // there are categories, or in this.flyout if blocks are displayed in a single - // flyout. - this.selected = this.flyout; - // Boolean for if a Variable category has been added. - this.hasVariableCategory = false; - // Boolean for if a Procedure category has been added. - this.hasProcedureCategory = false; - // XML to be pre-loaded to workspace. Empty on default; - this.preloadXml = Blockly.Xml.textToDom(''); - // Options object to be configured for Blockly inject call. - this.options = new Object(null); - // Block Library block types. - this.libBlockTypes = []; - // Imported block types. - this.importedBlockTypes = []; - // -}; - -/** - * Given a name, determines if it is the name of a category already present. - * Used when getting a valid category name from the user. - * @param {string} name String name to be compared against. - * @return {boolean} True if string is a used category name, false otherwise. - */ -WorkspaceFactoryModel.prototype.hasCategoryByName = function(name) { - for (var i = 0; i < this.toolboxList.length; i++) { - if (this.toolboxList[i].type == ListElement.TYPE_CATEGORY && - this.toolboxList[i].name == name) { - return true; - } - } - return false; -}; - -/** - * Determines if a category with the 'VARIABLE' tag exists. - * @return {boolean} True if there exists a category with the Variables tag, - * false otherwise. - */ -WorkspaceFactoryModel.prototype.hasVariables = function() { - return this.hasVariableCategory; -}; - -/** - * Determines if a category with the 'PROCEDURE' tag exists. - * @return {boolean} True if there exists a category with the Procedures tag, - * false otherwise. - */ -WorkspaceFactoryModel.prototype.hasProcedures = function() { - return this.hasProcedureCategory; -}; - -/** - * Determines if the user has any elements in the toolbox. Uses the length of - * toolboxList. - * @return {boolean} True if elements exist, false otherwise. - */ -WorkspaceFactoryModel.prototype.hasElements = function() { - return this.toolboxList.length > 0; -}; - -/** - * Given a ListElement, adds it to the toolbox list. - * @param {!ListElement} element The element to be added to the list. - */ -WorkspaceFactoryModel.prototype.addElementToList = function(element) { - // Update state if the copied category has a custom tag. - this.hasVariableCategory = element.custom == 'VARIABLE' ? true : - this.hasVariableCategory; - this.hasProcedureCategory = element.custom == 'PROCEDURE' ? true : - this.hasProcedureCategory; - // Add element to toolboxList. - this.toolboxList.push(element); - // Empty single flyout. - this.flyout = null; -}; - -/** - * Given an index, deletes a list element and all associated data. - * @param {number} index The index of the list element to delete. - */ -WorkspaceFactoryModel.prototype.deleteElementFromList = function(index) { - // Check if index is out of bounds. - if (index < 0 || index >= this.toolboxList.length) { - return; // No entry to delete. - } - // Check if need to update flags. - this.hasVariableCategory = this.toolboxList[index].custom == 'VARIABLE' ? - false : this.hasVariableCategory; - this.hasProcedureCategory = this.toolboxList[index].custom == 'PROCEDURE' ? - false : this.hasProcedureCategory; - // Remove element. - this.toolboxList.splice(index, 1); -}; - -/** - * Sets selected to be an empty category not in toolbox list if toolbox list - * is empty. Should be called when removing the last element from toolbox list. - * If the toolbox list is empty, selected stores the XML for the single flyout - * of blocks displayed. - */ -WorkspaceFactoryModel.prototype.createDefaultSelectedIfEmpty = function() { - if (this.toolboxList.length == 0) { - this.flyout = new ListElement(ListElement.TYPE_FLYOUT); - this.selected = this.flyout; - } -}; - -/** - * Moves a list element to a certain position in toolboxList by removing it - * and then inserting it at the correct index. Checks that indices are in - * bounds (throws error if not), but assumes that oldIndex is the correct index - * for list element. - * @param {!ListElement} element The element to move in toolboxList. - * @param {number} newIndex The index to insert the element at. - * @param {number} oldIndex The index the element is currently at. - */ -WorkspaceFactoryModel.prototype.moveElementToIndex = function(element, newIndex, - oldIndex) { - // Check that indexes are in bounds. - if (newIndex < 0 || newIndex >= this.toolboxList.length || oldIndex < 0 || - oldIndex >= this.toolboxList.length) { - throw new Error('Index out of bounds when moving element in the model.'); - } - this.deleteElementFromList(oldIndex); - this.toolboxList.splice(newIndex, 0, element); -}; - -/** - * Returns the ID of the currently selected element. Returns null if there are - * no categories (if selected == null). - * @return {string} The ID of the element currently selected. - */ -WorkspaceFactoryModel.prototype.getSelectedId = function() { - return this.selected ? this.selected.id : null; -}; - -/** - * Returns the name of the currently selected category. Returns null if there - * are no categories (if selected == null) or the selected element is not - * a category (in which case its name is null). - * @return {string} The name of the category currently selected. - */ -WorkspaceFactoryModel.prototype.getSelectedName = function() { - return this.selected ? this.selected.name : null; -}; - -/** - * Returns the currently selected list element object. - * @return {ListElement} The currently selected ListElement - */ -WorkspaceFactoryModel.prototype.getSelected = function() { - return this.selected; -}; - -/** - * Sets list element currently selected by id. - * @param {string} id ID of list element that should now be selected. - */ -WorkspaceFactoryModel.prototype.setSelectedById = function(id) { - this.selected = this.getElementById(id); -}; - -/** - * Given an ID of a list element, returns the index of that list element in - * toolboxList. Returns -1 if ID is not present. - * @param {string} id The ID of list element to search for. - * @return {number} The index of the list element in toolboxList, or -1 if it - * doesn't exist. - */ -WorkspaceFactoryModel.prototype.getIndexByElementId = function(id) { - for (var i = 0; i < this.toolboxList.length; i++) { - if (this.toolboxList[i].id == id) { - return i; - } - } - return -1; // ID not present in toolboxList. -}; - -/** - * Given the ID of a list element, returns that ListElement object. - * @param {string} id The ID of element to search for. - * @return {ListElement} Corresponding ListElement object in toolboxList, or - * null if that element does not exist. - */ -WorkspaceFactoryModel.prototype.getElementById = function(id) { - for (var i = 0; i < this.toolboxList.length; i++) { - if (this.toolboxList[i].id == id) { - return this.toolboxList[i]; - } - } - return null; // ID not present in toolboxList. -}; - -/** - * Given the index of a list element in toolboxList, returns that ListElement - * object. - * @param {number} index The index of the element to return. - * @return {ListElement} The corresponding ListElement object in toolboxList. - */ -WorkspaceFactoryModel.prototype.getElementByIndex = function(index) { - if (index < 0 || index >= this.toolboxList.length) { - return null; - } - return this.toolboxList[index]; -}; - -/** - * Returns the XML to load the selected element. - * @return {!Element} The XML of the selected element, or null if there is - * no selected element. - */ -WorkspaceFactoryModel.prototype.getSelectedXml = function() { - return this.selected ? this.selected.xml : null; -}; - -/** - * Return ordered list of ListElement objects. - * @return {!Array.} ordered list of ListElement objects - */ -WorkspaceFactoryModel.prototype.getToolboxList = function() { - return this.toolboxList; -}; - -/** - * Gets the ID of a category given its name. - * @param {string} name Name of category. - * @return {number} ID of category - */ -WorkspaceFactoryModel.prototype.getCategoryIdByName = function(name) { - for (var i = 0; i < this.toolboxList.length; i++) { - if (this.toolboxList[i].name == name) { - return this.toolboxList[i].id; - } - } - return null; // Name not present in toolboxList. -}; - -/** - * Clears the toolbox list, deleting all ListElements. - */ -WorkspaceFactoryModel.prototype.clearToolboxList = function() { - this.toolboxList = []; - this.hasVariableCategory = false; - this.hasProcedureCategory = false; - this.shadowBlocks = []; - this.selected.xml = Blockly.Xml.textToDom(''); -}; - -/** - * Class for a ListElement - * Adds a shadow block to the list of shadow blocks. - * @param {string} blockId The unique ID of block to be added. - */ -WorkspaceFactoryModel.prototype.addShadowBlock = function(blockId) { - this.shadowBlocks.push(blockId); -}; - -/** - * Removes a shadow block ID from the list of shadow block IDs if that ID is - * in the list. - * @param {string} blockId The unique ID of block to be removed. - */ -WorkspaceFactoryModel.prototype.removeShadowBlock = function(blockId) { - for (var i = 0; i < this.shadowBlocks.length; i++) { - if (this.shadowBlocks[i] == blockId) { - this.shadowBlocks.splice(i, 1); - return; - } - } -}; - -/** - * Determines if a block is a shadow block given a unique block ID. - * @param {string} blockId The unique ID of the block to examine. - * @return {boolean} True if the block is a user-generated shadow block, false - * otherwise. - */ -WorkspaceFactoryModel.prototype.isShadowBlock = function(blockId) { - for (var i = 0; i < this.shadowBlocks.length; i++) { - if (this.shadowBlocks[i] == blockId) { - return true; - } - } - return false; -}; - -/** - * Given a set of blocks currently loaded, returns all blocks in the workspace - * that are user generated shadow blocks. - * @param {!} blocks Array of blocks currently loaded. - * @return {!} Array of user-generated shadow blocks currently - * loaded. - */ -WorkspaceFactoryModel.prototype.getShadowBlocksInWorkspace = - function(workspaceBlocks) { - var shadowsInWorkspace = []; - for (var i = 0; i < workspaceBlocks.length; i++) { - if (this.isShadowBlock(workspaceBlocks[i].id)) { - shadowsInWorkspace.push(workspaceBlocks[i]); - } - } - return shadowsInWorkspace; -}; - -/** - * Adds a custom tag to a category, updating state variables accordingly. - * Only accepts 'VARIABLE' and 'PROCEDURE' tags. - * @param {!ListElement} category The category to add the tag to. - * @param {string} tag The custom tag to add to the category. - */ -WorkspaceFactoryModel.prototype.addCustomTag = function(category, tag) { - // Only update list elements that are categories. - if (category.type != ListElement.TYPE_CATEGORY) { - return; - } - // Only update the tag to be 'VARIABLE' or 'PROCEDURE'. - if (tag == 'VARIABLE') { - this.hasVariableCategory = true; - category.custom = 'VARIABLE'; - } else if (tag == 'PROCEDURE') { - this.hasProcedureCategory = true; - category.custom = 'PROCEDURE'; - } -}; - -/** - * Have basic pre-loaded workspace working - * Saves XML as XML to be pre-loaded into the workspace. - * @param {!Element} xml The XML to be saved. - */ -WorkspaceFactoryModel.prototype.savePreloadXml = function(xml) { - this.preloadXml = xml -}; - -/** - * Gets the XML to be pre-loaded into the workspace. - * @return {!Element} The XML for the workspace. - */ -WorkspaceFactoryModel.prototype.getPreloadXml = function() { - return this.preloadXml; -}; - -/** - * Sets a new options object for injecting a Blockly workspace. - * @param {Object} options Options object for injecting a Blockly workspace. - */ -WorkspaceFactoryModel.prototype.setOptions = function(options) { - this.options = options; -}; - -/* - * Returns an array of all the block types currently being used in the toolbox - * and the pre-loaded blocks. No duplicates. - * TODO(evd2014): Move pushBlockTypesToList to FactoryUtils. - * @return {!Array.} Array of block types currently being used. - */ -WorkspaceFactoryModel.prototype.getAllUsedBlockTypes = function() { - var blockTypeList = []; - - // Given XML for the workspace, adds all block types included in the XML - // to the list, not including duplicates. - var pushBlockTypesToList = function(xml, list) { - // Get all block XML nodes. - var blocks = xml.getElementsByTagName('block'); - - // Add block types if not already in list. - for (var i = 0; i < blocks.length; i++) { - var type = blocks[i].getAttribute('type'); - if (list.indexOf(type) == -1) { - list.push(type); - } - } - }; - - if (this.flyout) { - // If has a single flyout, add block types for the single flyout. - 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) { - pushBlockTypesToList(category.xml, blockTypeList); - } - } - } - - // Add the block types from any pre-loaded blocks. - pushBlockTypesToList(this.getPreloadXml(), blockTypeList); - - return blockTypeList; -}; - -/** - * Adds new imported block types to the list of current imported block types. - * @param {!Array.} blockTypes Array of block types imported. - */ -WorkspaceFactoryModel.prototype.addImportedBlockTypes = function(blockTypes) { - this.importedBlockTypes = this.importedBlockTypes.concat(blockTypes); -}; - -/** - * Updates block types in block library. - * @param {!Array.} blockTypes Array of block types in block library. - */ -WorkspaceFactoryModel.prototype.updateLibBlockTypes = function(blockTypes) { - this.libBlockTypes = blockTypes; -}; - -/** - * Determines if a block type is defined as a standard block, in the block - * library, or as an imported block. - * @param {string} blockType Block type to check. - * @return {boolean} True if blockType is defined, false otherwise. - */ -WorkspaceFactoryModel.prototype.isDefinedBlockType = function(blockType) { - var isStandardBlock = StandardCategories.coreBlockTypes.indexOf(blockType) - != -1; - 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; -}; - -/** - * Class for a ListElement. - * @constructor - */ -ListElement = function(type, opt_name) { - this.type = type; - // XML DOM element to load the element. - this.xml = Blockly.Xml.textToDom(''); - // Name of category. Can be changed by user. Null if separator. - this.name = opt_name ? opt_name : null; - // Unique ID of element. Does not change. - this.id = Blockly.utils.genUid(); - // Color of category. Default is no color. Null if separator. - this.color = null; - // Stores a custom tag, if necessary. Null if no custom tag or separator. - this.custom = null; -}; - -// List element types. -ListElement.TYPE_CATEGORY = 'category'; -ListElement.TYPE_SEPARATOR = 'separator'; -ListElement.TYPE_FLYOUT = 'flyout'; - -/** - * Saves a category by updating its XML (does not save XML for - * elements that are not categories). - * @param {!Blockly.workspace} workspace The workspace to save category entry - * from. - */ -ListElement.prototype.saveFromWorkspace = function(workspace) { - // Only save XML for categories and flyouts. - if (this.type == ListElement.TYPE_FLYOUT || - this.type == ListElement.TYPE_CATEGORY) { - this.xml = Blockly.Xml.workspaceToDom(workspace); - } -}; - - -/** - * Changes the name of a category object given a new name. Returns if - * not a category. - * @param {string} name New name of category. - */ -ListElement.prototype.changeName = function (name) { - // Only update list elements that are categories. - if (this.type != ListElement.TYPE_CATEGORY) { - return; - } - this.name = name; -}; - -/** - * Sets the color of a category. If tries to set the color of something other - * than a category, returns. - * @param {string} color The color that should be used for that category. - */ -ListElement.prototype.changeColor = function (color) { - if (this.type != ListElement.TYPE_CATEGORY) { - return; - } - this.color = color; -}; - -/** - * Makes a copy of the original element and returns it. Everything about the - * copy is identical except for its ID. - * @return {!ListElement} The copy of the ListElement. - */ -ListElement.prototype.copy = function() { - copy = new ListElement(this.type); - // Generate a unique ID for the element. - copy.id = Blockly.utils.genUid(); - // Copy all attributes except ID. - copy.name = this.name; - copy.xml = this.xml; - copy.color = this.color; - copy.custom = this.custom; - // Return copy. - return copy; -}; diff --git a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_view.js b/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_view.js deleted file mode 100644 index bf7463eb98f..00000000000 --- a/trunk/web/blockly/demos/blockfactory/workspacefactory/wfactory_view.js +++ /dev/null @@ -1,436 +0,0 @@ -/** - * @license - * Blockly Demos: Block Factory - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Controls the UI elements for workspace factory, mainly the category tabs. - * Also includes downloading files because that interacts directly with the DOM. - * Depends on WorkspaceFactoryController (for adding mouse listeners). Tabs for - * each category are stored in tab map, which associates a unique ID for a - * category with a particular tab. - * - * @author Emma Dauterman (edauterman) - */ - -goog.require('FactoryUtils'); - -/** - * Class for a WorkspaceFactoryView - * @constructor - */ -WorkspaceFactoryView = function() { - // For each tab, maps ID of a ListElement to the td DOM element. - this.tabMap = Object.create(null); -}; - -/** - * Adds a category tab to the UI, and updates tabMap accordingly. - * @param {string} name The name of the category being created - * @param {string} id ID of category being created - * @return {!Element} DOM element created for tab - */ -WorkspaceFactoryView.prototype.addCategoryRow = function(name, id) { - var table = document.getElementById('categoryTable'); - var count = table.rows.length; - - // Delete help label and enable category buttons if it's the first category. - if (count == 0) { - document.getElementById('categoryHeader').textContent = 'Your categories:'; - } - - // Create tab. - var row = table.insertRow(count); - var nextEntry = row.insertCell(0); - // Configure tab. - nextEntry.id = this.createCategoryIdName(name); - nextEntry.textContent = name; - // Store tab. - this.tabMap[id] = table.rows[count].cells[0]; - // Return tab. - return nextEntry; -}; - -/** - * Deletes a category tab from the UI and updates tabMap accordingly. - * @param {string} id ID of category to be deleted. - * @param {string} name The name of the category to be deleted. - */ -WorkspaceFactoryView.prototype.deleteElementRow = function(id, index) { - // Delete tab entry. - delete this.tabMap[id]; - // Delete tab row. - var table = document.getElementById('categoryTable'); - var count = table.rows.length; - table.deleteRow(index); - - // If last category removed, add category help text and disable category - // buttons. - this.addEmptyCategoryMessage(); -}; - -/** - * If there are no toolbox elements created, adds a help message to show - * where categories will appear. Should be called when deleting list elements - * in case the last element is deleted. - */ -WorkspaceFactoryView.prototype.addEmptyCategoryMessage = function() { - var table = document.getElementById('categoryTable'); - if (!table.rows.length) { - document.getElementById('categoryHeader').textContent = - 'You currently have no categories.'; - } -}; - -/** - * Given the index of the currently selected element, updates the state of - * the buttons that allow the user to edit the list elements. Updates the edit - * and arrow buttons. Should be called when adding or removing elements - * or when changing to a new element or when swapping to a different element. - * TODO(evd2014): Switch to using CSS to add/remove styles. - * @param {number} selectedIndex The index of the currently selected category, - * -1 if no categories created. - * @param {ListElement} selected The selected ListElement. - */ -WorkspaceFactoryView.prototype.updateState = function(selectedIndex, selected) { - // Disable/enable editing buttons as necessary. - document.getElementById('button_editCategory').disabled = selectedIndex < 0 || - selected.type != ListElement.TYPE_CATEGORY; - document.getElementById('button_remove').disabled = selectedIndex < 0; - document.getElementById('button_up').disabled = selectedIndex <= 0; - var table = document.getElementById('categoryTable'); - document.getElementById('button_down').disabled = selectedIndex >= - table.rows.length - 1 || selectedIndex < 0; - // Disable/enable the workspace as necessary. - this.disableWorkspace(this.shouldDisableWorkspace(selected)); -}; - -/** - * Determines the DOM ID for a category given its name. - * @param {string} name Name of category - * @return {string} ID of category tab - */ -WorkspaceFactoryView.prototype.createCategoryIdName = function(name) { - return 'tab_' + name; -}; - -/** - * Switches a tab on or off. - * @param {string} id ID of the tab to switch on or off. - * @param {boolean} selected True if tab should be on, false if tab should be - * off. - */ -WorkspaceFactoryView.prototype.setCategoryTabSelection = - function(id, selected) { - if (!this.tabMap[id]) { - return; // Exit if tab does not exist. - } - this.tabMap[id].className = selected ? 'tabon' : 'taboff'; -}; - -/** - * Used to bind a click to a certain DOM element (used for category tabs). - * Taken directly from code.js - * @param {string|!Element} e1 Tab element or corresponding ID string. - * @param {!Function} func Function to be executed on click. - */ -WorkspaceFactoryView.prototype.bindClick = function(el, func) { - if (typeof el == 'string') { - el = document.getElementById(el); - } - el.addEventListener('click', func, true); - el.addEventListener('touchend', func, true); -}; - -/** - * Creates a file and downloads it. In some browsers downloads, and in other - * browsers, opens new tab with contents. - * @param {string} filename Name of file - * @param {!Blob} data Blob containing contents to download - */ -WorkspaceFactoryView.prototype.createAndDownloadFile = - function(filename, data) { - var clickEvent = new MouseEvent('click', { - 'view': window, - 'bubbles': true, - 'cancelable': false - }); - var a = document.createElement('a'); - a.href = window.URL.createObjectURL(data); - a.download = filename; - a.textContent = 'Download file!'; - a.dispatchEvent(clickEvent); -}; - -/** - * Given the ID of a certain category, updates the corresponding tab in - * the DOM to show a new name. - * @param {string} newName Name of string to be displayed on tab - * @param {string} id ID of category to be updated - */ -WorkspaceFactoryView.prototype.updateCategoryName = function(newName, id) { - this.tabMap[id].textContent = newName; - this.tabMap[id].id = this.createCategoryIdName(newName); -}; - -/** - * Moves a tab from one index to another. Adjusts index inserting before - * based on if inserting before or after. Checks that the indexes are in - * bounds, throws error if not. - * @param {string} id The ID of the category to move. - * @param {number} newIndex The index to move the category to. - * @param {number} oldIndex The index the category is currently at. - */ -WorkspaceFactoryView.prototype.moveTabToIndex = - function(id, newIndex, oldIndex) { - var table = document.getElementById('categoryTable'); - // Check that indexes are in bounds. - if (newIndex < 0 || newIndex >= table.rows.length || oldIndex < 0 || - oldIndex >= table.rows.length) { - throw new Error('Index out of bounds when moving tab in the view.'); - } - - if (newIndex < oldIndex) { - // Inserting before. - var row = table.insertRow(newIndex); - row.appendChild(this.tabMap[id]); - table.deleteRow(oldIndex + 1); - } else { - // Inserting after. - var row = table.insertRow(newIndex + 1); - row.appendChild(this.tabMap[id]); - table.deleteRow(oldIndex); - } -}; - -/** - * Given a category ID and color, use that color to color the left border of the - * tab for that category. - * @param {string} id The ID of the category to color. - * @param {string} color The color for to be used for the border of the tab. - * Must be a valid CSS string. - */ -WorkspaceFactoryView.prototype.setBorderColor = function(id, color) { - var tab = this.tabMap[id]; - tab.style.borderLeftWidth = '8px'; - tab.style.borderLeftStyle = 'solid'; - tab.style.borderColor = color; -}; - -/** - * Given a separator ID, creates a corresponding tab in the view, updates - * tab map, and returns the tab. - * @param {string} id The ID of the separator. - * @param {!Element} The td DOM element representing the separator. - */ -WorkspaceFactoryView.prototype.addSeparatorTab = function(id) { - var table = document.getElementById('categoryTable'); - var count = table.rows.length; - - if (count == 0) { - document.getElementById('categoryHeader').textContent = 'Your categories:'; - } - // Create separator. - var row = table.insertRow(count); - var nextEntry = row.insertCell(0); - // Configure separator. - nextEntry.style.height = '10px'; - // Store and return separator. - this.tabMap[id] = table.rows[count].cells[0]; - return nextEntry; -}; - -/** - * Disables or enables the workspace by putting a div over or under the - * toolbox workspace, depending on the value of disable. Used when switching - * to/from separators where the user shouldn't be able to drag blocks into - * the workspace. - * @param {boolean} disable True if the workspace should be disabled, false - * if it should be enabled. - */ -WorkspaceFactoryView.prototype.disableWorkspace = function(disable) { - if (disable) { - document.getElementById('toolbox_section').className = 'disabled'; - document.getElementById('toolbox_blocks').style.pointerEvents = 'none'; - } else { - document.getElementById('toolbox_section').className = ''; - document.getElementById('toolbox_blocks').style.pointerEvents = 'auto'; - } - -}; - -/** - * Determines if the workspace should be disabled. The workspace should be - * disabled if category is a separator or has VARIABLE or PROCEDURE tags. - * @return {boolean} True if the workspace should be disabled, false otherwise. - */ -WorkspaceFactoryView.prototype.shouldDisableWorkspace = function(category) { - return category != null && category.type != ListElement.TYPE_FLYOUT && - (category.type == ListElement.TYPE_SEPARATOR || - category.custom == 'VARIABLE' || category.custom == 'PROCEDURE'); -}; - -/** - * Removes all categories and separators in the view. Clears the tabMap to - * reflect this. - */ -WorkspaceFactoryView.prototype.clearToolboxTabs = function() { - this.tabMap = []; - var oldCategoryTable = document.getElementById('categoryTable'); - var newCategoryTable = document.createElement('table'); - newCategoryTable.id = 'categoryTable'; - newCategoryTable.style.width = 'auto'; - oldCategoryTable.parentElement.replaceChild(newCategoryTable, - oldCategoryTable); -}; - -/** - * Given a set of blocks currently loaded user-generated shadow blocks, visually - * marks them without making them actual shadow blocks (allowing them to still - * be editable and movable). - * @param {!Array.} blocks Array of user-generated shadow blocks - * currently loaded. - */ -WorkspaceFactoryView.prototype.markShadowBlocks = function(blocks) { - for (var i = 0; i < blocks.length; i++) { - this.markShadowBlock(blocks[i]); - } -}; - -/** - * Visually marks a user-generated shadow block as a shadow block in the - * workspace without making the block an actual shadow block (allowing it - * to be moved and edited). - * @param {!Blockly.Block} block The block that should be marked as a shadow - * block (must be rendered). - */ -WorkspaceFactoryView.prototype.markShadowBlock = function(block) { - // Add Blockly CSS for user-generated shadow blocks. - Blockly.utils.addClass(block.svgGroup_, 'shadowBlock'); - // If not a valid shadow block, add a warning message. - if (!block.getSurroundParent()) { - block.setWarningText('Shadow blocks must be nested inside' + - ' other blocks to be displayed.'); - } - if (FactoryUtils.hasVariableField(block)) { - block.setWarningText('Cannot make variable blocks shadow blocks.'); - } -}; - -/** - * Removes visual marking for a shadow block given a rendered block. - * @param {!Blockly.Block} block The block that should be unmarked as a shadow - * block (must be rendered). - */ -WorkspaceFactoryView.prototype.unmarkShadowBlock = function(block) { - // Remove Blockly CSS for user-generated shadow blocks. - Blockly.utils.removeClass(block.svgGroup_, 'shadowBlock'); -}; - -/** - * Sets the tabs for modes according to which mode the user is currenly - * editing in. - * @param {string} mode The mode being switched to - * (WorkspaceFactoryController.MODE_TOOLBOX or WorkspaceFactoryController.MODE_PRELOAD). - */ -WorkspaceFactoryView.prototype.setModeSelection = function(mode) { - document.getElementById('tab_preload').className = mode == - WorkspaceFactoryController.MODE_PRELOAD ? 'tabon' : 'taboff'; - document.getElementById('preload_div').style.display = mode == - WorkspaceFactoryController.MODE_PRELOAD ? 'block' : 'none'; - document.getElementById('tab_toolbox').className = mode == - WorkspaceFactoryController.MODE_TOOLBOX ? 'tabon' : 'taboff'; - document.getElementById('toolbox_div').style.display = mode == - WorkspaceFactoryController.MODE_TOOLBOX ? 'block' : 'none'; -}; - -/** - * Updates the help text above the workspace depending on the selected mode. - * @param {string} mode The selected mode (WorkspaceFactoryController.MODE_TOOLBOX or - * WorkspaceFactoryController.MODE_PRELOAD). - */ -WorkspaceFactoryView.prototype.updateHelpText = function(mode) { - if (mode == WorkspaceFactoryController.MODE_TOOLBOX) { - var helpText = 'Drag blocks into the workspace to configure the toolbox ' + - 'in your custom workspace.'; - } else { - var helpText = 'Drag blocks into the workspace to pre-load them in your ' + - 'custom workspace.' - } - document.getElementById('editHelpText').textContent = helpText; -}; - -/** - * Sets the basic options that are not dependent on if there are categories - * or a single flyout of blocks. Updates checkboxes and text fields. - */ -WorkspaceFactoryView.prototype.setBaseOptions = function() { - // Readonly mode. - document.getElementById('option_readOnly_checkbox').checked = false; - blocklyFactory.ifCheckedEnable(true, ['readonly1', 'readonly2']); - - // Set basic options. - document.getElementById('option_css_checkbox').checked = true; - document.getElementById('option_maxBlocks_number').value = 100; - document.getElementById('option_media_text').value = - 'https://blockly-demo.appspot.com/static/media/'; - document.getElementById('option_rtl_checkbox').checked = false; - document.getElementById('option_sounds_checkbox').checked = true; - document.getElementById('option_oneBasedIndex_checkbox').checked = true; - document.getElementById('option_horizontalLayout_checkbox').checked = false; - document.getElementById('option_toolboxPosition_checkbox').checked = false; - - // Check infinite blocks and hide suboption. - document.getElementById('option_infiniteBlocks_checkbox').checked = true; - document.getElementById('maxBlockNumber_option').style.display = - 'none'; - - // Uncheck grid and zoom options and hide suboptions. - document.getElementById('option_grid_checkbox').checked = false; - document.getElementById('grid_options').style.display = 'none'; - document.getElementById('option_zoom_checkbox').checked = false; - document.getElementById('zoom_options').style.display = 'none'; - - // Set grid options. - document.getElementById('gridOption_spacing_number').value = 20; - document.getElementById('gridOption_length_number').value = 1; - document.getElementById('gridOption_colour_text').value = '#888'; - document.getElementById('gridOption_snap_checkbox').checked = false; - - // Set zoom options. - document.getElementById('zoomOption_controls_checkbox').checked = true; - document.getElementById('zoomOption_wheel_checkbox').checked = true; - document.getElementById('zoomOption_startScale_number').value = 1.0; - document.getElementById('zoomOption_maxScale_number').value = 3; - document.getElementById('zoomOption_minScale_number').value = 0.3; - document.getElementById('zoomOption_scaleSpeed_number').value = 1.2; -}; - -/** - * Updates category specific options depending on if there are categories - * currently present. Updates checkboxes and text fields in the view. - * @param {boolean} hasCategories True if categories are present, false if all - * blocks are displayed in a single flyout. - */ -WorkspaceFactoryView.prototype.setCategoryOptions = function(hasCategories) { - document.getElementById('option_collapse_checkbox').checked = hasCategories; - document.getElementById('option_comments_checkbox').checked = hasCategories; - document.getElementById('option_disable_checkbox').checked = hasCategories; - document.getElementById('option_scrollbars_checkbox').checked = hasCategories; - document.getElementById('option_trashcan_checkbox').checked = hasCategories; -}; diff --git a/trunk/web/blockly/demos/blockfactory_old/blocks.js b/trunk/web/blockly/demos/blockfactory_old/blocks.js deleted file mode 100644 index 856780a526a..00000000000 --- a/trunk/web/blockly/demos/blockfactory_old/blocks.js +++ /dev/null @@ -1,826 +0,0 @@ -/** - * Blockly Demos: Block Factory Blocks - * - * Copyright 2012 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Blocks for Blockly's Block Factory application. - * @author fraser@google.com (Neil Fraser) - */ -'use strict'; - -Blockly.Blocks['factory_base'] = { - // Base of new block. - init: function() { - this.setColour(120); - this.appendDummyInput() - .appendField('name') - .appendField(new Blockly.FieldTextInput('block_type'), 'NAME'); - this.appendStatementInput('INPUTS') - .setCheck('Input') - .appendField('inputs'); - var dropdown = new Blockly.FieldDropdown([ - ['automatic inputs', 'AUTO'], - ['external inputs', 'EXT'], - ['inline inputs', 'INT']]); - this.appendDummyInput() - .appendField(dropdown, 'INLINE'); - dropdown = new Blockly.FieldDropdown([ - ['no connections', 'NONE'], - ['← left output', 'LEFT'], - ['↕ top+bottom connections', 'BOTH'], - ['↑ top connection', 'TOP'], - ['↓ bottom connection', 'BOTTOM']], - function(option) { - this.sourceBlock_.updateShape_(option); - // Connect a shadow block to this new input. - this.sourceBlock_.spawnOutputShadow_(option); - }); - this.appendDummyInput() - .appendField(dropdown, 'CONNECTIONS'); - this.appendValueInput('COLOUR') - .setCheck('Colour') - .appendField('colour'); - this.setTooltip('Build a custom block by plugging\n' + - 'fields, inputs and other blocks here.'); - this.setHelpUrl( - 'https://developers.google.com/blockly/guides/create-custom-blocks/block-factory'); - }, - mutationToDom: function() { - var container = document.createElement('mutation'); - container.setAttribute('connections', this.getFieldValue('CONNECTIONS')); - return container; - }, - domToMutation: function(xmlElement) { - var connections = xmlElement.getAttribute('connections'); - this.updateShape_(connections); - }, - spawnOutputShadow_: function(option) { - // Helper method for deciding which type of outputs this block needs - // to attach shaddow blocks to. - switch (option) { - case 'LEFT': - this.connectOutputShadow_('OUTPUTTYPE'); - break; - case 'TOP': - this.connectOutputShadow_('TOPTYPE'); - break; - case 'BOTTOM': - this.connectOutputShadow_('BOTTOMTYPE'); - break; - case 'BOTH': - this.connectOutputShadow_('TOPTYPE'); - this.connectOutputShadow_('BOTTOMTYPE'); - break; - } - }, - connectOutputShadow_: function(outputType) { - // Helper method to create & connect shadow block. - var type = this.workspace.newBlock('type_null'); - type.setShadow(true); - type.outputConnection.connect(this.getInput(outputType).connection); - type.initSvg(); - type.render(); - }, - updateShape_: function(option) { - var outputExists = this.getInput('OUTPUTTYPE'); - var topExists = this.getInput('TOPTYPE'); - var bottomExists = this.getInput('BOTTOMTYPE'); - if (option == 'LEFT') { - if (!outputExists) { - this.addTypeInput_('OUTPUTTYPE', 'output type'); - } - } else if (outputExists) { - this.removeInput('OUTPUTTYPE'); - } - if (option == 'TOP' || option == 'BOTH') { - if (!topExists) { - this.addTypeInput_('TOPTYPE', 'top type'); - } - } else if (topExists) { - this.removeInput('TOPTYPE'); - } - if (option == 'BOTTOM' || option == 'BOTH') { - if (!bottomExists) { - this.addTypeInput_('BOTTOMTYPE', 'bottom type'); - } - } else if (bottomExists) { - this.removeInput('BOTTOMTYPE'); - } - }, - addTypeInput_: function(name, label) { - this.appendValueInput(name) - .setCheck('Type') - .appendField(label); - this.moveInputBefore(name, 'COLOUR'); - } -}; - -var FIELD_MESSAGE = 'fields %1 %2'; -var FIELD_ARGS = [ - { - "type": "field_dropdown", - "name": "ALIGN", - "options": [['left', 'LEFT'], ['right', 'RIGHT'], ['centre', 'CENTRE']], - }, - { - "type": "input_statement", - "name": "FIELDS", - "check": "Field" - } -]; - -var TYPE_MESSAGE = 'type %1'; -var TYPE_ARGS = [ - { - "type": "input_value", - "name": "TYPE", - "check": "Type", - "align": "RIGHT" - } -]; - -Blockly.Blocks['input_value'] = { - // Value input. - init: function() { - this.jsonInit({ - "message0": "value input %1 %2", - "args0": [ - { - "type": "field_input", - "name": "INPUTNAME", - "text": "NAME" - }, - { - "type": "input_dummy" - } - ], - "message1": FIELD_MESSAGE, - "args1": FIELD_ARGS, - "message2": TYPE_MESSAGE, - "args2": TYPE_ARGS, - "previousStatement": "Input", - "nextStatement": "Input", - "colour": 210, - "tooltip": "A value socket for horizontal connections.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=71" - }); - }, - onchange: function() { - inputNameCheck(this); - } -}; - -Blockly.Blocks['input_statement'] = { - // Statement input. - init: function() { - this.jsonInit({ - "message0": "statement input %1 %2", - "args0": [ - { - "type": "field_input", - "name": "INPUTNAME", - "text": "NAME" - }, - { - "type": "input_dummy" - }, - ], - "message1": FIELD_MESSAGE, - "args1": FIELD_ARGS, - "message2": TYPE_MESSAGE, - "args2": TYPE_ARGS, - "previousStatement": "Input", - "nextStatement": "Input", - "colour": 210, - "tooltip": "A statement socket for enclosed vertical stacks.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=246" - }); - }, - onchange: function() { - inputNameCheck(this); - } -}; - -Blockly.Blocks['input_dummy'] = { - // Dummy input. - init: function() { - this.jsonInit({ - "message0": "dummy input", - "message1": FIELD_MESSAGE, - "args1": FIELD_ARGS, - "previousStatement": "Input", - "nextStatement": "Input", - "colour": 210, - "tooltip": "For adding fields on a separate row with no " + - "connections. Alignment options (left, right, centre) " + - "apply only to multi-line fields.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=293" - }); - } -}; - -Blockly.Blocks['field_static'] = { - // Text value. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('text') - .appendField(new Blockly.FieldTextInput(''), 'TEXT'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Static text that serves as a label.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=88'); - } -}; - -Blockly.Blocks['field_input'] = { - // Text input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('text input') - .appendField(new Blockly.FieldTextInput('default'), 'TEXT') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('An input field for the user to enter text.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=319'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_number'] = { - // Numeric input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('numeric input') - .appendField(new Blockly.FieldNumber(0), 'VALUE') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.appendDummyInput() - .appendField('min') - .appendField(new Blockly.FieldNumber(-Infinity), 'MIN') - .appendField('max') - .appendField(new Blockly.FieldNumber(Infinity), 'MAX') - .appendField('precision') - .appendField(new Blockly.FieldNumber(0, 0), 'PRECISION'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('An input field for the user to enter a number.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=319'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_angle'] = { - // Angle input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('angle input') - .appendField(new Blockly.FieldAngle('90'), 'ANGLE') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('An input field for the user to enter an angle.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=372'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_dropdown'] = { - // Dropdown menu. - init: function() { - this.appendDummyInput() - .appendField('dropdown') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.optionCount_ = 3; - this.updateShape_(); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setMutator(new Blockly.Mutator(['field_dropdown_option'])); - this.setColour(160); - this.setTooltip('Dropdown menu with a list of options.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386'); - }, - mutationToDom: function(workspace) { - // Create XML to represent menu options. - var container = document.createElement('mutation'); - container.setAttribute('options', this.optionCount_); - return container; - }, - domToMutation: function(container) { - // Parse XML to restore the menu options. - this.optionCount_ = parseInt(container.getAttribute('options'), 10); - this.updateShape_(); - }, - decompose: function(workspace) { - // Populate the mutator's dialog with this block's components. - var containerBlock = workspace.newBlock('field_dropdown_container'); - containerBlock.initSvg(); - var connection = containerBlock.getInput('STACK').connection; - for (var i = 0; i < this.optionCount_; i++) { - var optionBlock = workspace.newBlock('field_dropdown_option'); - optionBlock.initSvg(); - connection.connect(optionBlock.previousConnection); - connection = optionBlock.nextConnection; - } - return containerBlock; - }, - compose: function(containerBlock) { - // Reconfigure this block based on the mutator dialog's components. - var optionBlock = containerBlock.getInputTargetBlock('STACK'); - // Count number of inputs. - var data = []; - while (optionBlock) { - data.push([optionBlock.userData_, optionBlock.cpuData_]); - optionBlock = optionBlock.nextConnection && - optionBlock.nextConnection.targetBlock(); - } - this.optionCount_ = data.length; - this.updateShape_(); - // Restore any data. - for (var i = 0; i < this.optionCount_; i++) { - this.setFieldValue(data[i][0] || 'option', 'USER' + i); - this.setFieldValue(data[i][1] || 'OPTIONNAME', 'CPU' + i); - } - }, - saveConnections: function(containerBlock) { - // Store names and values for each option. - var optionBlock = containerBlock.getInputTargetBlock('STACK'); - var i = 0; - while (optionBlock) { - optionBlock.userData_ = this.getFieldValue('USER' + i); - optionBlock.cpuData_ = this.getFieldValue('CPU' + i); - i++; - optionBlock = optionBlock.nextConnection && - optionBlock.nextConnection.targetBlock(); - } - }, - updateShape_: function() { - // Modify this block to have the correct number of options. - // Add new options. - for (var i = 0; i < this.optionCount_; i++) { - if (!this.getInput('OPTION' + i)) { - this.appendDummyInput('OPTION' + i) - .appendField(new Blockly.FieldTextInput('option'), 'USER' + i) - .appendField(',') - .appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU' + i); - } - } - // Remove deleted options. - while (this.getInput('OPTION' + i)) { - this.removeInput('OPTION' + i); - i++; - } - }, - onchange: function() { - if (this.workspace && this.optionCount_ < 1) { - this.setWarningText('Drop down menu must\nhave at least one option.'); - } else { - fieldNameCheck(this); - } - } -}; - -Blockly.Blocks['field_dropdown_container'] = { - // Container. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('add options'); - this.appendStatementInput('STACK'); - this.setTooltip('Add, remove, or reorder options\n' + - 'to reconfigure this dropdown menu.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386'); - this.contextMenu = false; - } -}; - -Blockly.Blocks['field_dropdown_option'] = { - // Add option. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('option'); - this.setPreviousStatement(true); - this.setNextStatement(true); - this.setTooltip('Add a new option to the dropdown menu.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386'); - this.contextMenu = false; - } -}; - -Blockly.Blocks['field_checkbox'] = { - // Checkbox. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('checkbox') - .appendField(new Blockly.FieldCheckbox('TRUE'), 'CHECKED') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Checkbox field.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=485'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_colour'] = { - // Colour input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('colour') - .appendField(new Blockly.FieldColour('#ff0000'), 'COLOUR') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Colour input field.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=495'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_date'] = { - // Date input. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('date') - .appendField(new Blockly.FieldDate(), 'DATE') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Date input field.'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_variable'] = { - // Dropdown for variables. - init: function() { - this.setColour(160); - this.appendDummyInput() - .appendField('variable') - .appendField(new Blockly.FieldTextInput('item'), 'TEXT') - .appendField(',') - .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Dropdown menu for variable names.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=510'); - }, - onchange: function() { - fieldNameCheck(this); - } -}; - -Blockly.Blocks['field_image'] = { - // Image. - init: function() { - this.setColour(160); - var src = 'https://www.gstatic.com/codesite/ph/images/star_on.gif'; - this.appendDummyInput() - .appendField('image') - .appendField(new Blockly.FieldTextInput(src), 'SRC'); - this.appendDummyInput() - .appendField('width') - .appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'WIDTH') - .appendField('height') - .appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'HEIGHT') - .appendField('alt text') - .appendField(new Blockly.FieldTextInput('*'), 'ALT'); - this.setPreviousStatement(true, 'Field'); - this.setNextStatement(true, 'Field'); - this.setTooltip('Static image (JPEG, PNG, GIF, SVG, BMP).\n' + - 'Retains aspect ratio regardless of height and width.\n' + - 'Alt text is for when collapsed.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=567'); - } -}; - -Blockly.Blocks['type_group'] = { - // Group of types. - init: function() { - this.typeCount_ = 2; - this.updateShape_(); - this.setOutput(true, 'Type'); - this.setMutator(new Blockly.Mutator(['type_group_item'])); - this.setColour(230); - this.setTooltip('Allows more than one type to be accepted.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677'); - }, - mutationToDom: function(workspace) { - // Create XML to represent a group of types. - var container = document.createElement('mutation'); - container.setAttribute('types', this.typeCount_); - return container; - }, - domToMutation: function(container) { - // Parse XML to restore the group of types. - this.typeCount_ = parseInt(container.getAttribute('types'), 10); - this.updateShape_(); - for (var i = 0; i < this.typeCount_; i++) { - this.removeInput('TYPE' + i); - } - for (var i = 0; i < this.typeCount_; i++) { - var input = this.appendValueInput('TYPE' + i) - .setCheck('Type'); - if (i == 0) { - input.appendField('any of'); - } - } - }, - decompose: function(workspace) { - // Populate the mutator's dialog with this block's components. - var containerBlock = workspace.newBlock('type_group_container'); - containerBlock.initSvg(); - var connection = containerBlock.getInput('STACK').connection; - for (var i = 0; i < this.typeCount_; i++) { - var typeBlock = workspace.newBlock('type_group_item'); - typeBlock.initSvg(); - connection.connect(typeBlock.previousConnection); - connection = typeBlock.nextConnection; - } - return containerBlock; - }, - compose: function(containerBlock) { - // Reconfigure this block based on the mutator dialog's components. - var typeBlock = containerBlock.getInputTargetBlock('STACK'); - // Count number of inputs. - var connections = []; - while (typeBlock) { - connections.push(typeBlock.valueConnection_); - typeBlock = typeBlock.nextConnection && - typeBlock.nextConnection.targetBlock(); - } - // Disconnect any children that don't belong. - for (var i = 0; i < this.typeCount_; i++) { - var connection = this.getInput('TYPE' + i).connection.targetConnection; - if (connection && connections.indexOf(connection) == -1) { - connection.disconnect(); - } - } - this.typeCount_ = connections.length; - this.updateShape_(); - // Reconnect any child blocks. - for (var i = 0; i < this.typeCount_; i++) { - Blockly.Mutator.reconnect(connections[i], this, 'TYPE' + i); - } - }, - saveConnections: function(containerBlock) { - // Store a pointer to any connected child blocks. - var typeBlock = containerBlock.getInputTargetBlock('STACK'); - var i = 0; - while (typeBlock) { - var input = this.getInput('TYPE' + i); - typeBlock.valueConnection_ = input && input.connection.targetConnection; - i++; - typeBlock = typeBlock.nextConnection && - typeBlock.nextConnection.targetBlock(); - } - }, - updateShape_: function() { - // Modify this block to have the correct number of inputs. - // Add new inputs. - for (var i = 0; i < this.typeCount_; i++) { - if (!this.getInput('TYPE' + i)) { - var input = this.appendValueInput('TYPE' + i); - if (i == 0) { - input.appendField('any of'); - } - } - } - // Remove deleted inputs. - while (this.getInput('TYPE' + i)) { - this.removeInput('TYPE' + i); - i++; - } - } -}; - -Blockly.Blocks['type_group_container'] = { - // Container. - init: function() { - this.jsonInit({ - "message0": "add types %1 %2", - "args0": [ - {"type": "input_dummy"}, - {"type": "input_statement", "name": "STACK"} - ], - "colour": 230, - "tooltip": "Add, or remove allowed type.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677" - }); - } -}; - -Blockly.Blocks['type_group_item'] = { - // Add type. - init: function() { - this.jsonInit({ - "message0": "type", - "previousStatement": null, - "nextStatement": null, - "colour": 230, - "tooltip": "Add a new allowed type.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677" - }); - } -}; - -Blockly.Blocks['type_null'] = { - // Null type. - valueType: null, - init: function() { - this.jsonInit({ - "message0": "any", - "output": "Type", - "colour": 230, - "tooltip": "Any type is allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_boolean'] = { - // Boolean type. - valueType: 'Boolean', - init: function() { - this.jsonInit({ - "message0": "Boolean", - "output": "Type", - "colour": 230, - "tooltip": "Booleans (true/false) are allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_number'] = { - // Number type. - valueType: 'Number', - init: function() { - this.jsonInit({ - "message0": "Number", - "output": "Type", - "colour": 230, - "tooltip": "Numbers (int/float) are allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_string'] = { - // String type. - valueType: 'String', - init: function() { - this.jsonInit({ - "message0": "String", - "output": "Type", - "colour": 230, - "tooltip": "Strings (text) are allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_list'] = { - // List type. - valueType: 'Array', - init: function() { - this.jsonInit({ - "message0": "Array", - "output": "Type", - "colour": 230, - "tooltip": "Arrays (lists) are allowed.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602" - }); - } -}; - -Blockly.Blocks['type_other'] = { - // Other type. - init: function() { - this.jsonInit({ - "message0": "other %1", - "args0": [{"type": "field_input", "name": "TYPE", "text": ""}], - "output": "Type", - "colour": 230, - "tooltip": "Custom type to allow.", - "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=702" - }); - } -}; - -Blockly.Blocks['colour_hue'] = { - // Set the colour of the block. - init: function() { - this.appendDummyInput() - .appendField('hue:') - .appendField(new Blockly.FieldAngle('0', this.validator), 'HUE'); - this.setOutput(true, 'Colour'); - this.setTooltip('Paint the block with this colour.'); - this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=55'); - }, - validator: function(text) { - // Update the current block's colour to match. - var hue = parseInt(text, 10); - if (!isNaN(hue)) { - this.sourceBlock_.setColour(hue); - } - }, - mutationToDom: function(workspace) { - var container = document.createElement('mutation'); - container.setAttribute('colour', this.getColour()); - return container; - }, - domToMutation: function(container) { - this.setColour(container.getAttribute('colour')); - } -}; - -/** - * Check to see if more than one field has this name. - * Highly inefficient (On^2), but n is small. - * @param {!Blockly.Block} referenceBlock Block to check. - */ -function fieldNameCheck(referenceBlock) { - if (!referenceBlock.workspace) { - // Block has been deleted. - return; - } - var name = referenceBlock.getFieldValue('FIELDNAME').toLowerCase(); - var count = 0; - var blocks = referenceBlock.workspace.getAllBlocks(); - for (var i = 0, block; block = blocks[i]; i++) { - var otherName = block.getFieldValue('FIELDNAME'); - if (!block.disabled && !block.getInheritedDisabled() && - otherName && otherName.toLowerCase() == name) { - count++; - } - } - var msg = (count > 1) ? - 'There are ' + count + ' field blocks\n with this name.' : null; - referenceBlock.setWarningText(msg); -} - -/** - * Check to see if more than one input has this name. - * Highly inefficient (On^2), but n is small. - * @param {!Blockly.Block} referenceBlock Block to check. - */ -function inputNameCheck(referenceBlock) { - if (!referenceBlock.workspace) { - // Block has been deleted. - return; - } - var name = referenceBlock.getFieldValue('INPUTNAME').toLowerCase(); - var count = 0; - var blocks = referenceBlock.workspace.getAllBlocks(); - for (var i = 0, block; block = blocks[i]; i++) { - var otherName = block.getFieldValue('INPUTNAME'); - if (!block.disabled && !block.getInheritedDisabled() && - otherName && otherName.toLowerCase() == name) { - count++; - } - } - var msg = (count > 1) ? - 'There are ' + count + ' input blocks\n with this name.' : null; - referenceBlock.setWarningText(msg); -} diff --git a/trunk/web/blockly/demos/blockfactory_old/factory.js b/trunk/web/blockly/demos/blockfactory_old/factory.js deleted file mode 100644 index 79df6f148fd..00000000000 --- a/trunk/web/blockly/demos/blockfactory_old/factory.js +++ /dev/null @@ -1,850 +0,0 @@ -/** - * Blockly Demos: Block Factory - * - * Copyright 2012 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview JavaScript for Blockly's Block Factory application. - * @author fraser@google.com (Neil Fraser) - */ -'use strict'; - -/** - * Workspace for user to build block. - * @type {Blockly.Workspace} - */ -var mainWorkspace = null; - -/** - * Workspace for preview of block. - * @type {Blockly.Workspace} - */ -var previewWorkspace = null; - -/** - * Name of block if not named. - */ -var UNNAMED = 'unnamed'; - -/** - * Change the language code format. - */ -function formatChange() { - var mask = document.getElementById('blocklyMask'); - var languagePre = document.getElementById('languagePre'); - var languageTA = document.getElementById('languageTA'); - if (document.getElementById('format').value == 'Manual') { - Blockly.hideChaff(); - mask.style.display = 'block'; - languagePre.style.display = 'none'; - languageTA.style.display = 'block'; - var code = languagePre.textContent.trim(); - languageTA.value = code; - languageTA.focus(); - updatePreview(); - } else { - mask.style.display = 'none'; - languageTA.style.display = 'none'; - languagePre.style.display = 'block'; - updateLanguage(); - } - disableEnableLink(); -} - -/** - * Update the language code based on constructs made in Blockly. - */ -function updateLanguage() { - var rootBlock = getRootBlock(); - if (!rootBlock) { - return; - } - var blockType = rootBlock.getFieldValue('NAME').trim().toLowerCase(); - if (!blockType) { - blockType = UNNAMED; - } - blockType = blockType.replace(/\W/g, '_').replace(/^(\d)/, '_\\1'); - switch (document.getElementById('format').value) { - case 'JSON': - var code = formatJson_(blockType, rootBlock); - break; - case 'JavaScript': - var code = formatJavaScript_(blockType, rootBlock); - break; - } - injectCode(code, 'languagePre'); - updatePreview(); -} - -/** - * Update the language code as JSON. - * @param {string} blockType Name of block. - * @param {!Blockly.Block} rootBlock Factory_base block. - * @return {string} Generanted language code. - * @private - */ -function formatJson_(blockType, rootBlock) { - var JS = {}; - // Type is not used by Blockly, but may be used by a loader. - JS.type = blockType; - // Generate inputs. - var message = []; - var args = []; - var contentsBlock = rootBlock.getInputTargetBlock('INPUTS'); - var lastInput = null; - while (contentsBlock) { - if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) { - var fields = getFieldsJson_(contentsBlock.getInputTargetBlock('FIELDS')); - for (var i = 0; i < fields.length; i++) { - if (typeof fields[i] == 'string') { - message.push(fields[i].replace(/%/g, '%%')); - } else { - args.push(fields[i]); - message.push('%' + args.length); - } - } - - var input = {type: contentsBlock.type}; - // Dummy inputs don't have names. Other inputs do. - if (contentsBlock.type != 'input_dummy') { - input.name = contentsBlock.getFieldValue('INPUTNAME'); - } - var check = JSON.parse(getOptTypesFrom(contentsBlock, 'TYPE') || 'null'); - if (check) { - input.check = check; - } - var align = contentsBlock.getFieldValue('ALIGN'); - if (align != 'LEFT') { - input.align = align; - } - args.push(input); - message.push('%' + args.length); - lastInput = contentsBlock; - } - contentsBlock = contentsBlock.nextConnection && - contentsBlock.nextConnection.targetBlock(); - } - // Remove last input if dummy and not empty. - if (lastInput && lastInput.type == 'input_dummy') { - var fields = lastInput.getInputTargetBlock('FIELDS'); - if (fields && getFieldsJson_(fields).join('').trim() != '') { - var align = lastInput.getFieldValue('ALIGN'); - if (align != 'LEFT') { - JS.lastDummyAlign0 = align; - } - args.pop(); - message.pop(); - } - } - JS.message0 = message.join(' '); - if (args.length) { - JS.args0 = args; - } - // Generate inline/external switch. - if (rootBlock.getFieldValue('INLINE') == 'EXT') { - JS.inputsInline = false; - } else if (rootBlock.getFieldValue('INLINE') == 'INT') { - JS.inputsInline = true; - } - // Generate output, or next/previous connections. - switch (rootBlock.getFieldValue('CONNECTIONS')) { - case 'LEFT': - JS.output = - JSON.parse(getOptTypesFrom(rootBlock, 'OUTPUTTYPE') || 'null'); - break; - case 'BOTH': - JS.previousStatement = - JSON.parse(getOptTypesFrom(rootBlock, 'TOPTYPE') || 'null'); - JS.nextStatement = - JSON.parse(getOptTypesFrom(rootBlock, 'BOTTOMTYPE') || 'null'); - break; - case 'TOP': - JS.previousStatement = - JSON.parse(getOptTypesFrom(rootBlock, 'TOPTYPE') || 'null'); - break; - case 'BOTTOM': - JS.nextStatement = - JSON.parse(getOptTypesFrom(rootBlock, 'BOTTOMTYPE') || 'null'); - break; - } - // Generate colour. - var colourBlock = rootBlock.getInputTargetBlock('COLOUR'); - if (colourBlock && !colourBlock.disabled) { - var hue = parseInt(colourBlock.getFieldValue('HUE'), 10); - JS.colour = hue; - } - JS.tooltip = ''; - JS.helpUrl = 'http://www.example.com/'; - return JSON.stringify(JS, null, ' '); -} - -/** - * Update the language code as JavaScript. - * @param {string} blockType Name of block. - * @param {!Blockly.Block} rootBlock Factory_base block. - * @return {string} Generanted language code. - * @private - */ -function formatJavaScript_(blockType, rootBlock) { - var code = []; - code.push("Blockly.Blocks['" + blockType + "'] = {"); - code.push(" init: function() {"); - // Generate inputs. - var TYPES = {'input_value': 'appendValueInput', - 'input_statement': 'appendStatementInput', - 'input_dummy': 'appendDummyInput'}; - var contentsBlock = rootBlock.getInputTargetBlock('INPUTS'); - while (contentsBlock) { - if (!contentsBlock.disabled && !contentsBlock.getInheritedDisabled()) { - var name = ''; - // Dummy inputs don't have names. Other inputs do. - if (contentsBlock.type != 'input_dummy') { - name = escapeString(contentsBlock.getFieldValue('INPUTNAME')); - } - code.push(' this.' + TYPES[contentsBlock.type] + '(' + name + ')'); - var check = getOptTypesFrom(contentsBlock, 'TYPE'); - if (check) { - code.push(' .setCheck(' + check + ')'); - } - var align = contentsBlock.getFieldValue('ALIGN'); - if (align != 'LEFT') { - code.push(' .setAlign(Blockly.ALIGN_' + align + ')'); - } - var fields = getFieldsJs_(contentsBlock.getInputTargetBlock('FIELDS')); - for (var i = 0; i < fields.length; i++) { - code.push(' .appendField(' + fields[i] + ')'); - } - // Add semicolon to last line to finish the statement. - code[code.length - 1] += ';'; - } - contentsBlock = contentsBlock.nextConnection && - contentsBlock.nextConnection.targetBlock(); - } - // Generate inline/external switch. - if (rootBlock.getFieldValue('INLINE') == 'EXT') { - code.push(' this.setInputsInline(false);'); - } else if (rootBlock.getFieldValue('INLINE') == 'INT') { - code.push(' this.setInputsInline(true);'); - } - // Generate output, or next/previous connections. - switch (rootBlock.getFieldValue('CONNECTIONS')) { - case 'LEFT': - code.push(connectionLineJs_('setOutput', 'OUTPUTTYPE')); - break; - case 'BOTH': - code.push(connectionLineJs_('setPreviousStatement', 'TOPTYPE')); - code.push(connectionLineJs_('setNextStatement', 'BOTTOMTYPE')); - break; - case 'TOP': - code.push(connectionLineJs_('setPreviousStatement', 'TOPTYPE')); - break; - case 'BOTTOM': - code.push(connectionLineJs_('setNextStatement', 'BOTTOMTYPE')); - break; - } - // Generate colour. - var colourBlock = rootBlock.getInputTargetBlock('COLOUR'); - if (colourBlock && !colourBlock.disabled) { - var hue = parseInt(colourBlock.getFieldValue('HUE'), 10); - if (!isNaN(hue)) { - code.push(' this.setColour(' + hue + ');'); - } - } - code.push(" this.setTooltip('');"); - code.push(" this.setHelpUrl('http://www.example.com/');"); - code.push(' }'); - code.push('};'); - return code.join('\n'); -} - -/** - * Create JS code required to create a top, bottom, or value connection. - * @param {string} functionName JavaScript function name. - * @param {string} typeName Name of type input. - * @return {string} Line of JavaScript code to create connection. - * @private - */ -function connectionLineJs_(functionName, typeName) { - var type = getOptTypesFrom(getRootBlock(), typeName); - if (type) { - type = ', ' + type; - } else { - type = ''; - } - return ' this.' + functionName + '(true' + type + ');'; -} - -/** - * Returns field strings and any config. - * @param {!Blockly.Block} block Input block. - * @return {!Array.} Field strings. - * @private - */ -function getFieldsJs_(block) { - var fields = []; - while (block) { - if (!block.disabled && !block.getInheritedDisabled()) { - switch (block.type) { - case 'field_static': - // Result: 'hello' - fields.push(escapeString(block.getFieldValue('TEXT'))); - break; - case 'field_input': - // Result: new Blockly.FieldTextInput('Hello'), 'GREET' - fields.push('new Blockly.FieldTextInput(' + - escapeString(block.getFieldValue('TEXT')) + '), ' + - escapeString(block.getFieldValue('FIELDNAME'))); - break; - case 'field_number': - // Result: new Blockly.FieldNumber(10, 0, 100, 1), 'NUMBER' - var args = [ - Number(block.getFieldValue('VALUE')), - Number(block.getFieldValue('MIN')), - Number(block.getFieldValue('MAX')), - Number(block.getFieldValue('PRECISION')) - ]; - // Remove any trailing arguments that aren't needed. - if (args[3] == 0) { - args.pop(); - if (args[2] == Infinity) { - args.pop(); - if (args[1] == -Infinity) { - args.pop(); - } - } - } - fields.push('new Blockly.FieldNumber(' + args.join(', ') + '), ' + - escapeString(block.getFieldValue('FIELDNAME'))); - break; - case 'field_angle': - // Result: new Blockly.FieldAngle(90), 'ANGLE' - fields.push('new Blockly.FieldAngle(' + - Number(block.getFieldValue('ANGLE')) + '), ' + - escapeString(block.getFieldValue('FIELDNAME'))); - break; - case 'field_checkbox': - // Result: new Blockly.FieldCheckbox('TRUE'), 'CHECK' - fields.push('new Blockly.FieldCheckbox(' + - escapeString(block.getFieldValue('CHECKED')) + '), ' + - escapeString(block.getFieldValue('FIELDNAME'))); - break; - case 'field_colour': - // Result: new Blockly.FieldColour('#ff0000'), 'COLOUR' - fields.push('new Blockly.FieldColour(' + - escapeString(block.getFieldValue('COLOUR')) + '), ' + - escapeString(block.getFieldValue('FIELDNAME'))); - break; - case 'field_date': - // Result: new Blockly.FieldDate('2015-02-04'), 'DATE' - fields.push('new Blockly.FieldDate(' + - escapeString(block.getFieldValue('DATE')) + '), ' + - escapeString(block.getFieldValue('FIELDNAME'))); - break; - case 'field_variable': - // Result: new Blockly.FieldVariable('item'), 'VAR' - var varname = escapeString(block.getFieldValue('TEXT') || null); - fields.push('new Blockly.FieldVariable(' + varname + '), ' + - escapeString(block.getFieldValue('FIELDNAME'))); - break; - case 'field_dropdown': - // Result: - // new Blockly.FieldDropdown([['yes', '1'], ['no', '0']]), 'TOGGLE' - var options = []; - for (var i = 0; i < block.optionCount_; i++) { - options[i] = '[' + escapeString(block.getFieldValue('USER' + i)) + - ', ' + escapeString(block.getFieldValue('CPU' + i)) + ']'; - } - if (options.length) { - fields.push('new Blockly.FieldDropdown([' + - options.join(', ') + ']), ' + - escapeString(block.getFieldValue('FIELDNAME'))); - } - break; - case 'field_image': - // Result: new Blockly.FieldImage('http://...', 80, 60, '*') - var src = escapeString(block.getFieldValue('SRC')); - var width = Number(block.getFieldValue('WIDTH')); - var height = Number(block.getFieldValue('HEIGHT')); - var alt = escapeString(block.getFieldValue('ALT')); - fields.push('new Blockly.FieldImage(' + - src + ', ' + width + ', ' + height + ', ' + alt + ')'); - break; - } - } - block = block.nextConnection && block.nextConnection.targetBlock(); - } - return fields; -} - -/** - * Returns field strings and any config. - * @param {!Blockly.Block} block Input block. - * @return {!Array.} Array of static text and field configs. - * @private - */ -function getFieldsJson_(block) { - var fields = []; - while (block) { - if (!block.disabled && !block.getInheritedDisabled()) { - switch (block.type) { - case 'field_static': - // Result: 'hello' - fields.push(block.getFieldValue('TEXT')); - break; - case 'field_input': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - text: block.getFieldValue('TEXT') - }); - break; - case 'field_number': - var obj = { - type: block.type, - name: block.getFieldValue('FIELDNAME'), - value: parseFloat(block.getFieldValue('VALUE')) - }; - var min = parseFloat(block.getFieldValue('MIN')); - if (min > -Infinity) { - obj.min = min; - } - var max = parseFloat(block.getFieldValue('MAX')); - if (max < Infinity) { - obj.max = max; - } - var precision = parseFloat(block.getFieldValue('PRECISION')); - if (precision) { - obj.precision = precision; - } - fields.push(obj); - break; - case 'field_angle': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - angle: Number(block.getFieldValue('ANGLE')) - }); - break; - case 'field_checkbox': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - checked: block.getFieldValue('CHECKED') == 'TRUE' - }); - break; - case 'field_colour': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - colour: block.getFieldValue('COLOUR') - }); - break; - case 'field_date': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - date: block.getFieldValue('DATE') - }); - break; - case 'field_variable': - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - variable: block.getFieldValue('TEXT') || null - }); - break; - case 'field_dropdown': - var options = []; - for (var i = 0; i < block.optionCount_; i++) { - options[i] = [block.getFieldValue('USER' + i), - block.getFieldValue('CPU' + i)]; - } - if (options.length) { - fields.push({ - type: block.type, - name: block.getFieldValue('FIELDNAME'), - options: options - }); - } - break; - case 'field_image': - fields.push({ - type: block.type, - src: block.getFieldValue('SRC'), - width: Number(block.getFieldValue('WIDTH')), - height: Number(block.getFieldValue('HEIGHT')), - alt: block.getFieldValue('ALT') - }); - break; - } - } - block = block.nextConnection && block.nextConnection.targetBlock(); - } - return fields; -} - -/** - * Escape a string. - * @param {string} string String to escape. - * @return {string} Escaped string surrouned by quotes. - */ -function escapeString(string) { - return JSON.stringify(string); -} - -/** - * Fetch the type(s) defined in the given input. - * Format as a string for appending to the generated code. - * @param {!Blockly.Block} block Block with input. - * @param {string} name Name of the input. - * @return {?string} String defining the types. - */ -function getOptTypesFrom(block, name) { - var types = getTypesFrom_(block, name); - if (types.length == 0) { - return undefined; - } else if (types.indexOf('null') != -1) { - return 'null'; - } else if (types.length == 1) { - return types[0]; - } else { - return '[' + types.join(', ') + ']'; - } -} - -/** - * Fetch the type(s) defined in the given input. - * @param {!Blockly.Block} block Block with input. - * @param {string} name Name of the input. - * @return {!Array.} List of types. - * @private - */ -function getTypesFrom_(block, name) { - var typeBlock = block.getInputTargetBlock(name); - var types; - if (!typeBlock || typeBlock.disabled) { - types = []; - } else if (typeBlock.type == 'type_other') { - types = [escapeString(typeBlock.getFieldValue('TYPE'))]; - } else if (typeBlock.type == 'type_group') { - types = []; - for (var i = 0; i < typeBlock.typeCount_; i++) { - types = types.concat(getTypesFrom_(typeBlock, 'TYPE' + i)); - } - // Remove duplicates. - var hash = Object.create(null); - for (var n = types.length - 1; n >= 0; n--) { - if (hash[types[n]]) { - types.splice(n, 1); - } - hash[types[n]] = true; - } - } else { - types = [escapeString(typeBlock.valueType)]; - } - return types; -} - -/** - * Update the generator code. - * @param {!Blockly.Block} block Rendered block in preview workspace. - */ -function updateGenerator(block) { - function makeVar(root, name) { - name = name.toLowerCase().replace(/\W/g, '_'); - return ' var ' + root + '_' + name; - } - var language = document.getElementById('language').value; - var code = []; - code.push("Blockly." + language + "['" + block.type + - "'] = function(block) {"); - - // Generate getters for any fields or inputs. - for (var i = 0, input; input = block.inputList[i]; i++) { - for (var j = 0, field; field = input.fieldRow[j]; j++) { - var name = field.name; - if (!name) { - continue; - } - if (field instanceof Blockly.FieldVariable) { - // Subclass of Blockly.FieldDropdown, must test first. - code.push(makeVar('variable', name) + - " = Blockly." + language + - ".variableDB_.getName(block.getFieldValue('" + name + - "'), Blockly.Variables.NAME_TYPE);"); - } else if (field instanceof Blockly.FieldAngle) { - // Subclass of Blockly.FieldTextInput, must test first. - code.push(makeVar('angle', name) + - " = block.getFieldValue('" + name + "');"); - } else if (Blockly.FieldDate && field instanceof Blockly.FieldDate) { - // Blockly.FieldDate may not be compiled into Blockly. - code.push(makeVar('date', name) + - " = block.getFieldValue('" + name + "');"); - } else if (field instanceof Blockly.FieldColour) { - code.push(makeVar('colour', name) + - " = block.getFieldValue('" + name + "');"); - } else if (field instanceof Blockly.FieldCheckbox) { - code.push(makeVar('checkbox', name) + - " = block.getFieldValue('" + name + "') == 'TRUE';"); - } else if (field instanceof Blockly.FieldDropdown) { - code.push(makeVar('dropdown', name) + - " = block.getFieldValue('" + name + "');"); - } else if (field instanceof Blockly.FieldNumber) { - code.push(makeVar('number', name) + - " = block.getFieldValue('" + name + "');"); - } else if (field instanceof Blockly.FieldTextInput) { - code.push(makeVar('text', name) + - " = block.getFieldValue('" + name + "');"); - } - } - var name = input.name; - if (name) { - if (input.type == Blockly.INPUT_VALUE) { - code.push(makeVar('value', name) + - " = Blockly." + language + ".valueToCode(block, '" + name + - "', Blockly." + language + ".ORDER_ATOMIC);"); - } else if (input.type == Blockly.NEXT_STATEMENT) { - code.push(makeVar('statements', name) + - " = Blockly." + language + ".statementToCode(block, '" + - name + "');"); - } - } - } - // Most languages end lines with a semicolon. Python does not. - var lineEnd = { - 'JavaScript': ';', - 'Python': '', - 'PHP': ';', - 'Dart': ';' - }; - code.push(" // TODO: Assemble " + language + " into code variable."); - if (block.outputConnection) { - code.push(" var code = '...';"); - code.push(" // TODO: Change ORDER_NONE to the correct strength."); - code.push(" return [code, Blockly." + language + ".ORDER_NONE];"); - } else { - code.push(" var code = '..." + (lineEnd[language] || '') + "\\n';"); - code.push(" return code;"); - } - code.push("};"); - - injectCode(code.join('\n'), 'generatorPre'); -} - -/** - * Existing direction ('ltr' vs 'rtl') of preview. - */ -var oldDir = null; - -/** - * Update the preview display. - */ -function updatePreview() { - // Toggle between LTR/RTL if needed (also used in first display). - var newDir = document.getElementById('direction').value; - if (oldDir != newDir) { - if (previewWorkspace) { - previewWorkspace.dispose(); - } - var rtl = newDir == 'rtl'; - previewWorkspace = Blockly.inject('preview', - {rtl: rtl, - media: '../../media/', - scrollbars: true}); - oldDir = newDir; - } - previewWorkspace.clear(); - - // Fetch the code and determine its format (JSON or JavaScript). - var format = document.getElementById('format').value; - if (format == 'Manual') { - var code = document.getElementById('languageTA').value; - // If the code is JSON, it will parse, otherwise treat as JS. - try { - JSON.parse(code); - format = 'JSON'; - } catch (e) { - format = 'JavaScript'; - } - } else { - var code = document.getElementById('languagePre').textContent; - } - if (!code.trim()) { - // Nothing to render. Happens while cloud storage is loading. - return; - } - - // Backup Blockly.Blocks object so that main workspace and preview don't - // collide if user creates a 'factory_base' block, for instance. - var backupBlocks = Blockly.Blocks; - try { - // Make a shallow copy. - Blockly.Blocks = {}; - for (var prop in backupBlocks) { - Blockly.Blocks[prop] = backupBlocks[prop]; - } - - if (format == 'JSON') { - var json = JSON.parse(code); - Blockly.Blocks[json.type || UNNAMED] = { - init: function() { - this.jsonInit(json); - } - }; - } else if (format == 'JavaScript') { - eval(code); - } else { - throw 'Unknown format: ' + format; - } - - // Look for a block on Blockly.Blocks that does not match the backup. - var blockType = null; - for (var type in Blockly.Blocks) { - if (typeof Blockly.Blocks[type].init == 'function' && - Blockly.Blocks[type] != backupBlocks[type]) { - blockType = type; - break; - } - } - if (!blockType) { - return; - } - - // Create the preview block. - var previewBlock = previewWorkspace.newBlock(blockType); - previewBlock.initSvg(); - previewBlock.render(); - previewBlock.setMovable(false); - previewBlock.setDeletable(false); - previewBlock.moveBy(15, 10); - previewWorkspace.clearUndo(); - - updateGenerator(previewBlock); - } finally { - Blockly.Blocks = backupBlocks; - } -} - -/** - * Inject code into a pre tag, with syntax highlighting. - * Safe from HTML/script injection. - * @param {string} code Lines of code. - * @param {string} id ID of
 element to inject into.
- */
-function injectCode(code, id) {
-  var pre = document.getElementById(id);
-  pre.textContent = code;
-  code = pre.textContent;
-  code = prettyPrintOne(code, 'js');
-  pre.innerHTML = code;
-}
-
-/**
- * Return the uneditable container block that everything else attaches to.
- * @return {Blockly.Block}
- */
-function getRootBlock() {
-  var blocks = mainWorkspace.getTopBlocks(false);
-  for (var i = 0, block; block = blocks[i]; i++) {
-    if (block.type == 'factory_base') {
-      return block;
-    }
-  }
-  return null;
-}
-
-/**
- * Disable the link button if the format is 'Manual', enable otherwise.
- */
-function disableEnableLink() {
-  var linkButton = document.getElementById('linkButton');
-  linkButton.disabled = document.getElementById('format').value == 'Manual';
-}
-
-/**
- * Initialize Blockly and layout.  Called on page load.
- */
-function init() {
-  if ('BlocklyStorage' in window) {
-    BlocklyStorage.HTTPREQUEST_ERROR =
-        'There was a problem with the request.\n';
-    BlocklyStorage.LINK_ALERT =
-        'Share your blocks with this link:\n\n%1';
-    BlocklyStorage.HASH_ERROR =
-        'Sorry, "%1" doesn\'t correspond with any saved Blockly file.';
-    BlocklyStorage.XML_ERROR = 'Could not load your saved file.\n'+
-        'Perhaps it was created with a different version of Blockly?';
-    var linkButton = document.getElementById('linkButton');
-    linkButton.style.display = 'inline-block';
-    linkButton.addEventListener('click',
-        function() {BlocklyStorage.link(mainWorkspace);});
-    disableEnableLink();
-  }
-
-  document.getElementById('helpButton').addEventListener('click',
-    function() {
-      open('https://developers.google.com/blockly/guides/create-custom-blocks/block-factory',
-           'BlockFactoryHelp');
-    });
-
-  var expandList = [
-    document.getElementById('blockly'),
-    document.getElementById('blocklyMask'),
-    document.getElementById('preview'),
-    document.getElementById('languagePre'),
-    document.getElementById('languageTA'),
-    document.getElementById('generatorPre')
-  ];
-  var onresize = function(e) {
-    for (var i = 0, expand; expand = expandList[i]; i++) {
-      expand.style.width = (expand.parentNode.offsetWidth - 2) + 'px';
-      expand.style.height = (expand.parentNode.offsetHeight - 2) + 'px';
-    }
-  };
-  onresize();
-  window.addEventListener('resize', onresize);
-
-  var toolbox = document.getElementById('toolbox');
-  mainWorkspace = Blockly.inject('blockly',
-      {collapse: false,
-       toolbox: toolbox,
-       media: '../../media/'});
-
-  // Create the root block.
-  if ('BlocklyStorage' in window && window.location.hash.length > 1) {
-    BlocklyStorage.retrieveXml(window.location.hash.substring(1),
-                               mainWorkspace);
-  } else {
-    var xml = '';
-    Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), mainWorkspace);
-  }
-  mainWorkspace.clearUndo();
-
-  mainWorkspace.addChangeListener(Blockly.Events.disableOrphans);
-  mainWorkspace.addChangeListener(updateLanguage);
-  document.getElementById('direction')
-      .addEventListener('change', updatePreview);
-  document.getElementById('languageTA')
-      .addEventListener('change', updatePreview);
-  document.getElementById('languageTA')
-      .addEventListener('keyup', updatePreview);
-  document.getElementById('format')
-      .addEventListener('change', formatChange);
-  document.getElementById('language')
-      .addEventListener('change', updatePreview);
-}
-window.addEventListener('load', init);
diff --git a/trunk/web/blockly/demos/blockfactory_old/icon.png b/trunk/web/blockly/demos/blockfactory_old/icon.png
deleted file mode 100644
index d4d19b45768..00000000000
Binary files a/trunk/web/blockly/demos/blockfactory_old/icon.png and /dev/null differ
diff --git a/trunk/web/blockly/demos/blockfactory_old/index.html b/trunk/web/blockly/demos/blockfactory_old/index.html
deleted file mode 100644
index 449b9a5e889..00000000000
--- a/trunk/web/blockly/demos/blockfactory_old/index.html
+++ /dev/null
@@ -1,230 +0,0 @@
-
-
-
-  
-  
-  Blockly Demo: Block Factory
-  
-  
-  
-  
-  
-  
-  
-  
-
-
-  
-    
-      
-      
-    
-    
-      
-      
-    
-  
-

Blockly > - Demos > Block Factory

-
- - - - - -
-

Preview: - -

-
- - - -
-
-
-
-
- - - - - - - - - - - - - - - - -
-
-
-

Language code: - -

-
-

-              
-            
-

Generator stub: - -

-
-

-            
-
- - - diff --git a/trunk/web/blockly/demos/blockfactory_old/link.png b/trunk/web/blockly/demos/blockfactory_old/link.png deleted file mode 100644 index 11dfd82845e..00000000000 Binary files a/trunk/web/blockly/demos/blockfactory_old/link.png and /dev/null differ diff --git a/trunk/web/blockly/demos/code/index.html b/trunk/web/blockly/demos/code/index.html index 89571d2692f..e465efd3536 100644 --- a/trunk/web/blockly/demos/code/index.html +++ b/trunk/web/blockly/demos/code/index.html @@ -5,7 +5,7 @@ Blockly Demo: - + diff --git a/trunk/web/blockly/demos/custom-dialogs/custom-dialog.js b/trunk/web/blockly/demos/custom-dialogs/custom-dialog.js deleted file mode 100644 index 1892303a401..00000000000 --- a/trunk/web/blockly/demos/custom-dialogs/custom-dialog.js +++ /dev/null @@ -1,173 +0,0 @@ -/** - * Blockly Demos: Custom Dialogs - * - * Copyright 2016 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * An example implementation of how one might replace Blockly's browser - * dialogs. This is just an example, and applications are not encouraged to use - * it verbatim. - * - * @namespace - */ -CustomDialog = {}; - -/** Override Blockly.alert() with custom implementation. */ -Blockly.alert = function(message, callback) { - console.log('Alert: ' + message); - CustomDialog.show('Alert', message, { - onCancel: callback - }); -}; - -/** Override Blockly.confirm() with custom implementation. */ -Blockly.confirm = function(message, callback) { - console.log('Confirm: ' + message); - CustomDialog.show('Confirm', message, { - showOkay: true, - onOkay: function() { - callback(true) - }, - showCancel: true, - onCancel: function() { - callback(false) - } - }); -}; - -/** Override Blockly.prompt() with custom implementation. */ -Blockly.prompt = function(message, defaultValue, callback) { - console.log('Prompt: ' + message); - CustomDialog.show('Prompt', message, { - showInput: true, - showOkay: true, - onOkay: function() { - callback(CustomDialog.inputField.value) - }, - showCancel: true, - onCancel: function() { - callback(null) - } - }); - CustomDialog.inputField.value = defaultValue; -}; - -/** Hides any currently visible dialog. */ -CustomDialog.hide = function() { - if (CustomDialog.backdropDiv_) { - CustomDialog.backdropDiv_.style.display = 'none' - CustomDialog.dialogDiv_.style.display = 'none' - } -}; - -/** - * Shows the dialog. - * Allowed options: - * - showOkay: Whether to show the OK button. - * - showCancel: Whether to show the Cancel button. - * - showInput: Whether to show the text input field. - * - onOkay: Callback to handle the okay button. - * - onCancel: Callback to handle the cancel button and backdrop clicks. - */ -CustomDialog.show = function(title, message, options) { - var backdropDiv = CustomDialog.backdropDiv_; - var dialogDiv = CustomDialog.dialogDiv_; - if (!dialogDiv) { - // Generate HTML - backdropDiv = document.createElement('div'); - backdropDiv.id = 'customDialogBackdrop'; - backdropDiv.style.cssText = - 'position: absolute;' + - 'top: 0; left: 0; right: 0; bottom: 0;' + - 'background-color: rgba(0, 0, 0, .7);'; - document.body.appendChild(backdropDiv); - - dialogDiv = document.createElement('div'); - dialogDiv.id = 'customDialog'; - dialogDiv.style.cssText = - 'background-color: #fff;' + - 'width: 400px;' + - 'margin: 20px auto 0;' + - 'padding: 10px;'; - backdropDiv.appendChild(dialogDiv); - - dialogDiv.onclick = function(event) { - event.stopPropagation(); - }; - - CustomDialog.backdropDiv_ = backdropDiv; - CustomDialog.dialogDiv_ = dialogDiv; - } - backdropDiv.style.display = 'block'; - dialogDiv.style.display = 'block'; - - dialogDiv.innerHTML = - '
' + - '

' + - (options.showInput ? '
' : '') + - '
' + - (options.showCancel ? '': '') + - (options.showOkay ? '': '') + - '
'; - dialogDiv.getElementsByClassName('customDialogTitle')[0] - .appendChild(document.createTextNode(title)); - dialogDiv.getElementsByClassName('customDialogMessage')[0] - .appendChild(document.createTextNode(message)); - - var onOkay = function(event) { - CustomDialog.hide(); - options.onOkay && options.onOkay(); - event && event.stopPropagation(); - }; - var onCancel = function(event) { - CustomDialog.hide(); - options.onCancel && options.onCancel(); - event && event.stopPropagation(); - }; - - var dialogInput = document.getElementById('customDialogInput'); - CustomDialog.inputField = dialogInput; - if (dialogInput) { - dialogInput.focus(); - - dialogInput.onkeyup = function(event) { - if (event.keyCode == 13) { - // Process as OK when user hits enter. - onOkay(); - return false; - } else if (event.keyCode == 27) { - // Process as cancel when user hits esc. - onCancel(); - return false; - } - }; - } else { - var okay = document.getElementById('customDialogOkay'); - okay && okay.focus(); - } - - if (options.showOkay) { - document.getElementById('customDialogOkay') - .addEventListener('click', onOkay); - } - if (options.showCancel) { - document.getElementById('customDialogCancel') - .addEventListener('click', onCancel); - } - - backdropDiv.onclick = onCancel; -}; diff --git a/trunk/web/blockly/demos/custom-dialogs/index.html b/trunk/web/blockly/demos/custom-dialogs/index.html deleted file mode 100644 index 42cba547758..00000000000 --- a/trunk/web/blockly/demos/custom-dialogs/index.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - Blockly Demo: Custom Dialog - - - - - - -

Blockly > - Demos > Custom Dialog

- -

This is a simple demo of replacing modal browser dialogs with HTML.

- -

Try creating new variables, creating variables with names already in - use, or deleting multiple blocks on the workspace. -

- -
- - - - - - - - diff --git a/trunk/web/blockly/demos/fixed/icon.png b/trunk/web/blockly/demos/fixed/icon.png deleted file mode 100644 index 1158acf0176..00000000000 Binary files a/trunk/web/blockly/demos/fixed/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/fixed/index.html b/trunk/web/blockly/demos/fixed/index.html deleted file mode 100644 index 680fa7691cf..00000000000 --- a/trunk/web/blockly/demos/fixed/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - Blockly Demo: Fixed Blockly - - - - - - -

Blockly > - Demos > Fixed Blockly

- -

This is a simple demo of injecting Blockly into a fixed-sized 'div' element.

- -

→ More info on injecting fixed-sized Blockly

- -
- - - - - - - diff --git a/trunk/web/blockly/demos/generator/icon.png b/trunk/web/blockly/demos/generator/icon.png deleted file mode 100644 index 132016e3f23..00000000000 Binary files a/trunk/web/blockly/demos/generator/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/generator/index.html b/trunk/web/blockly/demos/generator/index.html deleted file mode 100644 index 7bc48385524..00000000000 --- a/trunk/web/blockly/demos/generator/index.html +++ /dev/null @@ -1,145 +0,0 @@ - - - - - Blockly Demo: Generating JavaScript - - - - - - - -

Blockly > - Demos > Generating JavaScript

- -

This is a simple demo of generating code from blocks.

- -

→ More info on Code Generators

- -

- - -

- -
- - - - - - - - - diff --git a/trunk/web/blockly/demos/graph/icon.png b/trunk/web/blockly/demos/graph/icon.png deleted file mode 100644 index ad8b582f69d..00000000000 Binary files a/trunk/web/blockly/demos/graph/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/graph/index.html b/trunk/web/blockly/demos/graph/index.html deleted file mode 100644 index 4732070d977..00000000000 --- a/trunk/web/blockly/demos/graph/index.html +++ /dev/null @@ -1,358 +0,0 @@ - - - - - Blockly Demo: Graph - - - - - - - - -

Blockly > - Demos > Graph

- -

This is a demo of giving instant feedback as blocks are changed.

- -

→ More info on Realtime generation

- - - - - - -
-
-
-
-
- -
- - ... -
- - - - - - - - - diff --git a/trunk/web/blockly/demos/headless/icon.png b/trunk/web/blockly/demos/headless/icon.png deleted file mode 100644 index af9ebe71422..00000000000 Binary files a/trunk/web/blockly/demos/headless/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/headless/index.html b/trunk/web/blockly/demos/headless/index.html deleted file mode 100644 index 62d49fdfac1..00000000000 --- a/trunk/web/blockly/demos/headless/index.html +++ /dev/null @@ -1,120 +0,0 @@ - - - - - Blockly Demo: Headless - - - - - - - -

Blockly > - Demos > Headless

- -

This is a simple demo of generating Python code from XML with no graphics. - This might be useful for server-side code generation.

- - - - - - - -
- - - - -
- -
- -
- - - - - diff --git a/trunk/web/blockly/demos/interpreter/acorn_interpreter.js b/trunk/web/blockly/demos/interpreter/acorn_interpreter.js deleted file mode 100644 index 05fd7397c1b..00000000000 --- a/trunk/web/blockly/demos/interpreter/acorn_interpreter.js +++ /dev/null @@ -1,169 +0,0 @@ -// Acorn: Copyright 2012 Marijn Haverbeke, MIT License -var mod$$inline_58=function(a){function b(a){n=a||{};for(var b in Ua)Object.prototype.hasOwnProperty.call(n,b)||(n[b]=Ua[b]);wa=n.sourceFile||null}function c(a,b){var c=Ab(k,a);b+=" ("+c.line+":"+c.column+")";var d=new SyntaxError(b);d.pos=a;d.loc=c;d.raisedAt=f;throw d;}function d(a){function b(a){if(1==a.length)return c+="return str === "+JSON.stringify(a[0])+";";c+="switch(str){";for(var va=0;vaa)++f;else if(47===a)if(a=k.charCodeAt(f+1),42===a){var a=n.onComment&&n.locations&&new e,b=f,d=k.indexOf("*/",f+=2);-1===d&&c(f-2,"Unterminated comment"); -f=d+2;if(n.locations){Y.lastIndex=b;for(var g=void 0;(g=Y.exec(k))&&g.index=a?a=P(!0):(++f,a=g(xa)),a;case 40:return++f,g(I);case 41:return++f,g(E);case 59:return++f,g(J);case 44:return++f,g(L);case 91:return++f,g(ja); -case 93:return++f,g(ka);case 123:return++f,g(Z);case 125:return++f,g(T);case 58:return++f,g(aa);case 63:return++f,g(ya);case 48:if(a=k.charCodeAt(f+1),120===a||88===a)return f+=2,a=B(16),null==a&&c(x+2,"Expected hexadecimal number"),la(k.charCodeAt(f))&&c(f,"Identifier directly after number"),a=g(ba,a);case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return P(!1);case 34:case 39:a:{f++;for(var b="";;){f>=S&&c(x,"Unterminated string constant");var d=k.charCodeAt(f);if(d===a){++f; -a=g(da,b);break a}if(92===d){var d=k.charCodeAt(++f),e=/^[0-7]+/.exec(k.slice(f,f+3));for(e&&(e=e[0]);e&&255=S)return g(pa);var b=k.charCodeAt(f);if(la(b)||92===b)return Ya();a=m(b);if(!1===a){b=String.fromCharCode(b);if("\\"===b||Za.test(b))return Ya();c(f,"Unexpected character '"+b+"'")}return a}function t(a,b){var c=k.slice(f,f+b);f+=b;g(a,c)}function K(){for(var a,b,d=f;;){f>=S&&c(d, -"Unterminated regular expression");var e=k.charAt(f);na.test(e)&&c(d,"Unterminated regular expression");if(a)a=!1;else{if("["===e)b=!0;else if("]"===e&&b)b=!1;else if("/"===e&&!b)break;a="\\"===e}++f}a=k.slice(d,f);++f;(b=$a())&&!/^[gmsiy]*$/.test(b)&&c(d,"Invalid regexp flag");return g(Ba,new RegExp(a,b))}function B(a,b){for(var c=f,d=0,e=0,g=null==b?Infinity:b;e=h?h-48:Infinity;if(h>=a)break;++f;d=d*a+h}return f===c||null!=b&& -f-c!==b?null:d}function P(a){var b=f,d=!1,e=48===k.charCodeAt(f);a||null!==B(10)||c(b,"Invalid number");46===k.charCodeAt(f)&&(++f,B(10),d=!0);a=k.charCodeAt(f);if(69===a||101===a)a=k.charCodeAt(++f),43!==a&&45!==a||++f,null===B(10)&&c(b,"Invalid number"),d=!0;la(k.charCodeAt(f))&&c(f,"Identifier directly after number");a=k.slice(b,f);var h;d?h=parseFloat(a):e&&1!==a.length?/[89]/.test(a)||C?c(b,"Invalid number"):h=parseInt(a,8):h=parseInt(a,10);return g(ba,h)}function ma(a){a=B(16,a);null===a&&c(x, -"Bad character escape sequence");return a}function $a(){ca=!1;for(var a,b=!0,d=f;;){var e=k.charCodeAt(f);if(ab(e))ca&&(a+=k.charAt(f)),++f;else if(92===e){ca||(a=k.slice(d,f));ca=!0;117!=k.charCodeAt(++f)&&c(f,"Expecting Unicode escape sequence \\uXXXX");++f;var e=ma(4),g=String.fromCharCode(e);g||c(f-1,"Invalid Unicode escape");(b?la(e):ab(e))||c(f-4,"Invalid Unicode escape");a+=g}else break;b=!1}return ca?a:k.slice(d,f)}function Ya(){var a=$a(),b=V;ca||(Lb(a)?b=Ca[a]:(n.forbidReserved&&(3===n.ecmaVersion? -Mb:Nb)(a)||C&&bb(a))&&c(x,"The keyword '"+a+"' is reserved"));return g(b,a)}function r(){Da=x;M=X;Ea=ia;z()}function Fa(a){C=a;f=M;if(n.locations)for(;fb){var e=Q(a);e.left=a;e.operator=H;a=p;r();e.right=Ra(Sa(),d,c);d=q(e,a===Va||a===Wa?"LogicalExpression":"BinaryExpression");return Ra(d,b,c)}return a}function Sa(){if(p.prefix){var a=y(),b=p.isUpdate;a.operator=H;R=a.prefix=!0;r();a.argument= -Sa();b?ra(a.argument):C&&"delete"===a.operator&&"Identifier"===a.argument.type&&c(a.start,"Deleting local variable in strict mode");return q(a,b?"UpdateExpression":"UnaryExpression")}for(b=ha(ua());p.postfix&&!qa();)a=Q(b),a.operator=H,a.prefix=!1,a.argument=b,ra(b),r(),b=q(a,"UpdateExpression");return b}function ha(a,b){if(u(xa)){var c=Q(a);c.object=a;c.property=O(!0);c.computed=!1;return ha(q(c,"MemberExpression"),b)}return u(ja)?(c=Q(a),c.object=a,c.property=A(),c.computed=!0,v(ka),ha(q(c,"MemberExpression"), -b)):!b&&u(I)?(c=Q(a),c.callee=a,c.arguments=Ta(E,!1),ha(q(c,"CallExpression"),b)):a}function ua(){switch(p){case ub:var a=y();r();return q(a,"ThisExpression");case V:return O();case ba:case da:case Ba:return a=y(),a.value=H,a.raw=k.slice(x,X),r(),q(a,"Literal");case vb:case wb:case xb:return a=y(),a.value=p.atomValue,a.raw=p.keyword,r(),q(a,"Literal");case I:var a=oa,b=x;r();var d=A();d.start=b;d.end=X;n.locations&&(d.loc.start=a,d.loc.end=ia);n.ranges&&(d.range=[b,X]);v(E);return d;case ja:return a= -y(),r(),a.elements=Ta(ka,!0,!0),q(a,"ArrayExpression");case Z:a=y();b=!0;d=!1;a.properties=[];for(r();!u(T);){if(b)b=!1;else if(v(L),n.allowTrailingCommas&&u(T))break;var e={key:p===ba||p===da?ua():O(!0)},g=!1,h;u(aa)?(e.value=A(!0),h=e.kind="init"):5<=n.ecmaVersion&&"Identifier"===e.key.type&&("get"===e.key.name||"set"===e.key.name)?(g=d=!0,h=e.kind=e.key.name,e.key=p===ba||p===da?ua():O(!0),p!==I&&N(),e.value=Na(y(),!1)):N();if("Identifier"===e.key.type&&(C||d))for(var f=0;fd?a.id:a.params[d],(bb(e.name)||sa(e.name))&&c(e.start,"Defining '"+e.name+"' in strict mode"),0<=d)for(var g=0;ga?36===a:91>a?!0:97>a?95===a:123>a?!0:170<=a&&Za.test(String.fromCharCode(a))},ab=a.isIdentifierChar=function(a){return 48>a?36===a:58>a?!0:65>a?!1:91>a?!0:97>a?95===a:123>a?!0:170<=a&&Pb.test(String.fromCharCode(a))},ca,Ia={kind:"loop"},Ob={kind:"switch"}}; -"object"==typeof exports&&"object"==typeof module?mod$$inline_58(exports):"function"==typeof define&&define.amd?define(["exports"],mod$$inline_58):mod$$inline_58(this.acorn||(this.acorn={})); -// JS-Interpreter: Copyright 2013 Google Inc, Apache 2.0 -var Interpreter=function(a,b){"string"==typeof a&&(a=acorn.parse(a,Interpreter.PARSE_OPTIONS));this.ast=a;this.initFunc_=b;this.paused_=!1;this.polyfills_=[];this.UNDEFINED=new Interpreter.Primitive(void 0,this);this.NULL=new Interpreter.Primitive(null,this);this.NAN=new Interpreter.Primitive(NaN,this);this.TRUE=new Interpreter.Primitive(!0,this);this.FALSE=new Interpreter.Primitive(!1,this);this.NUMBER_ZERO=new Interpreter.Primitive(0,this);this.NUMBER_ONE=new Interpreter.Primitive(1,this);this.STRING_EMPTY= -new Interpreter.Primitive("",this);b=this.createScope(this.ast,null);this.NAN.parent=this.NUMBER;this.TRUE.parent=this.BOOLEAN;this.FALSE.parent=this.BOOLEAN;this.NUMBER_ZERO.parent=this.NUMBER;this.NUMBER_ONE.parent=this.NUMBER;this.STRING_EMPTY.parent=this.STRING;this.ast=acorn.parse(this.polyfills_.join("\n"),Interpreter.PARSE_OPTIONS);this.polyfills_=void 0;this.stripLocations_(this.ast);this.stateStack=[{node:this.ast,scope:b,thisExpression:b,done:!1}];this.run();this.value=this.UNDEFINED;this.ast= -a;this.stateStack=[{node:this.ast,scope:b,thisExpression:b,done:!1}]};Interpreter.PARSE_OPTIONS={ecmaVersion:5};Interpreter.READONLY_DESCRIPTOR={configurable:!0,enumerable:!0,writable:!1};Interpreter.NONENUMERABLE_DESCRIPTOR={configurable:!0,enumerable:!1,writable:!0};Interpreter.READONLY_NONENUMERABLE_DESCRIPTOR={configurable:!0,enumerable:!1,writable:!1}; -Interpreter.prototype.appendCode=function(a){var b=this.stateStack[this.stateStack.length-1];if(!b||"Program"!=b.node.type)throw Error("Expecting original AST to start with a Program node.");"string"==typeof a&&(a=acorn.parse(a,Interpreter.PARSE_OPTIONS));if(!a||"Program"!=a.type)throw Error("Expecting new AST to start with a Program node.");this.populateScope_(a,b.scope);for(var c=0,d;d=a.body[c];c++)b.node.body.push(d);b.done=!1}; -Interpreter.prototype.step=function(){var a=this.stateStack[0];if(!a||"Program"==a.node.type&&a.done)return!1;if(this.paused_)return!0;this["step"+a.node.type]();return a.node.end?!0:this.step()};Interpreter.prototype.run=function(){for(;!this.paused_&&this.step(););return this.paused_}; -Interpreter.prototype.initGlobalScope=function(a){this.setProperty(a,"Infinity",this.createPrimitive(Infinity),Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"NaN",this.NAN,Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"undefined",this.UNDEFINED,Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"window",a,Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"self",a);this.initFunction(a);this.initObject(a);a.parent=this.OBJECT;this.initArray(a);this.initNumber(a);this.initString(a);this.initBoolean(a); -this.initDate(a);this.initMath(a);this.initRegExp(a);this.initJSON(a);this.initError(a);var b=this,c;c=function(a){a=a||b.UNDEFINED;return b.createPrimitive(isNaN(a.toNumber()))};this.setProperty(a,"isNaN",this.createNativeFunction(c));c=function(a){a=a||b.UNDEFINED;return b.createPrimitive(isFinite(a.toNumber()))};this.setProperty(a,"isFinite",this.createNativeFunction(c));this.setProperty(a,"parseFloat",this.getProperty(this.NUMBER,"parseFloat"));this.setProperty(a,"parseInt",this.getProperty(this.NUMBER, -"parseInt"));c=this.createObject(this.FUNCTION);c.eval=!0;this.setProperty(c,"length",this.NUMBER_ONE,Interpreter.READONLY_DESCRIPTOR);this.setProperty(a,"eval",c);for(var d=[[escape,"escape"],[unescape,"unescape"],[decodeURI,"decodeURI"],[decodeURIComponent,"decodeURIComponent"],[encodeURI,"encodeURI"],[encodeURIComponent,"encodeURIComponent"]],h=0;ha?Math.max(this.length+a,0):Math.min(a,this.length);d=c(d,Infinity);d=Math.min(d,this.length-a);for(var g=b.createObject(b.ARRAY),h=a;h=a;h--)this.properties[h+arguments.length-2]=this.properties[h];this.length+=arguments.length-2;for(h=2;hh&&(h=this.length+h);h=Math.max(0,Math.min(h,this.length)); -d=c(d,this.length);0>d&&(d=this.length+d);d=Math.max(0,Math.min(d,this.length));for(a=0;hd&&(d=this.length+d);for(d=Math.max(0,d);dd&&(d=this.length+d);for(d=Math.min(d,this.length-1);0<=d;d--){var h=b.getProperty(this,d);if(h.isPrimitive&&a.isPrimitive?h.data===a.data:h===a)return b.createPrimitive(d)}return b.createPrimitive(-1)};this.setNativeFunctionPrototype(this.ARRAY,"lastIndexOf",d);this.polyfills_.push("Object.defineProperty(Array.prototype, 'every', {configurable: true, value:","function(callbackfn, thisArg) {", -"if (this == null || typeof callbackfn !== 'function') throw new TypeError;","var T, k;","var O = Object(this);","var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","k = 0;","while (k < len) {","if (k in O && !callbackfn.call(T, O[k], k, O)) return false;","k++;","}","return true;","}","});","Object.defineProperty(Array.prototype, 'filter', {configurable: true, value:","function(fun/*, thisArg*/) {","if (this === void 0 || this === null || typeof fun !== 'function') throw new TypeError;", -"var t = Object(this);","var len = t.length >>> 0;","var res = [];","var thisArg = arguments.length >= 2 ? arguments[1] : void 0;","for (var i = 0; i < len; i++) {","if (i in t) {","var val = t[i];","if (fun.call(thisArg, val, i, t)) res.push(val);","}","}","return res;","}","});","Object.defineProperty(Array.prototype, 'forEach', {configurable: true, value:","function(callback, thisArg) {","if (this == null || typeof callback !== 'function') throw new TypeError;","var T, k;","var O = Object(this);", -"var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","k = 0;","while (k < len) {","if (k in O) callback.call(T, O[k], k, O);","k++;","}","}","});","Object.defineProperty(Array.prototype, 'map', {configurable: true, value:","function(callback, thisArg) {","if (this == null || typeof callback !== 'function') new TypeError;","var T, A, k;","var O = Object(this);","var len = O.length >>> 0;","if (arguments.length > 1) T = thisArg;","A = new Array(len);","k = 0;","while (k < len) {","if (k in O) A[k] = callback.call(T, O[k], k, O);", -"k++;","}","return A;","}","});","Object.defineProperty(Array.prototype, 'reduce', {configurable: true, value:","function(callback /*, initialValue*/) {","if (this == null || typeof callback !== 'function') throw new TypeError;","var t = Object(this), len = t.length >>> 0, k = 0, value;","if (arguments.length == 2) {","value = arguments[1];","} else {","while (k < len && !(k in t)) k++;","if (k >= len) {","throw new TypeError('Reduce of empty array with no initial value');","}","value = t[k++];", -"}","for (; k < len; k++) {","if (k in t) value = callback(value, t[k], k, t);","}","return value;","}","});","Object.defineProperty(Array.prototype, 'reduceRight', {configurable: true, value:","function(callback /*, initialValue*/) {","if (null === this || 'undefined' === typeof this || 'function' !== typeof callback) throw new TypeError;","var t = Object(this), len = t.length >>> 0, k = len - 1, value;","if (arguments.length >= 2) {","value = arguments[1];","} else {","while (k >= 0 && !(k in t)) k--;", -"if (k < 0) {","throw new TypeError('Reduce of empty array with no initial value');","}","value = t[k--];","}","for (; k >= 0; k--) {","if (k in t) value = callback(value, t[k], k, t);","}","return value;","}","});","Object.defineProperty(Array.prototype, 'some', {configurable: true, value:","function(fun/*, thisArg*/) {","if (this == null || typeof fun !== 'function') throw new TypeError;","var t = Object(this);","var len = t.length >>> 0;","var thisArg = arguments.length >= 2 ? arguments[1] : void 0;", -"for (var i = 0; i < len; i++) {","if (i in t && fun.call(thisArg, t[i], i, t)) {","return true;","}","}","return false;","}","});","Object.defineProperty(Array.prototype, 'sort', {configurable: true, value:","function(opt_comp) {","for (var i = 0; i < this.length; i++) {","var changes = 0;","for (var j = 0; j < this.length - i - 1; j++) {","if (opt_comp ?opt_comp(this[j], this[j + 1]) > 0 : this[j] > this[j + 1]) {","var swap = this[j];","this[j] = this[j + 1];","this[j + 1] = swap;","changes++;", -"}","}","if (changes <= 1) break;","}","return this;","}","});","Object.defineProperty(Array.prototype, 'toLocaleString', {configurable: true, value:","function() {","var out = [];","for (var i = 0; i < this.length; i++) {","out[i] = (this[i] === null || this[i] === undefined) ? '' : this[i].toLocaleString();","}","return out.join(',');","}","});","")}; -Interpreter.prototype.initNumber=function(a){var b=this,c;c=function(a){a=a?a.toNumber():0;if(this.parent!=b.NUMBER)return b.createPrimitive(a);this.data=a;return this};this.NUMBER=this.createNativeFunction(c);this.setProperty(a,"Number",this.NUMBER);a=["MAX_VALUE","MIN_VALUE","NaN","NEGATIVE_INFINITY","POSITIVE_INFINITY"];for(c=0;cb?1:0};Interpreter.prototype.arrayIndex=function(a){a=Number(a);return!isFinite(a)||a!=Math.floor(a)||0>a?NaN:a}; -Interpreter.Primitive=function(a,b){var c=typeof a;this.data=a;this.type=c;"number"==c?this.parent=b.NUMBER:"string"==c?this.parent=b.STRING:"boolean"==c&&(this.parent=b.BOOLEAN)};Interpreter.Primitive.prototype.data=void 0;Interpreter.Primitive.prototype.type="undefined";Interpreter.Primitive.prototype.parent=null;Interpreter.Primitive.prototype.isPrimitive=!0;Interpreter.Primitive.prototype.toBoolean=function(){return!!this.data};Interpreter.Primitive.prototype.toNumber=function(){return Number(this.data)}; -Interpreter.Primitive.prototype.toString=function(){return String(this.data)};Interpreter.Primitive.prototype.valueOf=function(){return this.data};Interpreter.prototype.createPrimitive=function(a){return void 0===a?this.UNDEFINED:null===a?this.NULL:!0===a?this.TRUE:!1===a?this.FALSE:0===a?this.NUMBER_ZERO:1===a?this.NUMBER_ONE:""===a?this.STRING_EMPTY:a instanceof RegExp?this.populateRegExp_(this.createObject(this.REGEXP),a):new Interpreter.Primitive(a,this)}; -Interpreter.Object=function(a){this.notConfigurable=Object.create(null);this.notEnumerable=Object.create(null);this.notWritable=Object.create(null);this.getter=Object.create(null);this.setter=Object.create(null);this.properties=Object.create(null);this.parent=a};Interpreter.Object.prototype.type="object";Interpreter.Object.prototype.parent=null;Interpreter.Object.prototype.isPrimitive=!1;Interpreter.Object.prototype.data=void 0;Interpreter.Object.prototype.toBoolean=function(){return!0}; -Interpreter.Object.prototype.toNumber=function(){return Number(void 0===this.data?this.toString():this.data)};Interpreter.Object.prototype.toString=function(){return void 0===this.data?"["+this.type+"]":String(this.data)};Interpreter.Object.prototype.valueOf=function(){return void 0===this.data?this:this.data}; -Interpreter.prototype.createObject=function(a){a=new Interpreter.Object(a);this.isa(a,this.FUNCTION)&&(a.type="function",this.setProperty(a,"prototype",this.createObject(this.OBJECT||null)));this.isa(a,this.ARRAY)&&(a.length=0,a.toString=function(){for(var a=[],c=0;c>="==b.operator)b=d>>h;else if(">>>="==b.operator)b=d>>>h;else if("&="==b.operator)b=d&h;else if("^="==b.operator)b=d^h;else if("|="==b.operator)b=d|h;else throw SyntaxError("Unknown assignment expression: "+b.operator);b=this.createPrimitive(b)}(c=this.setValue(a.leftSide,b))?(a.doneSetter_=b,this.stateStack.unshift({node:{type:"CallExpression"},doneCallee_:!0,funcThis_:a.leftSide[0],func_:c,doneArgs_:!0,arguments:[b]})): -(this.stateStack.shift(),this.stateStack[0].value=b)}else{a.leftSide||(a.leftSide=a.value);a.doneGetter_&&(a.leftValue=a.value);if(!a.doneGetter_&&"="!=b.operator&&(a.leftValue=this.getValue(a.leftSide),a.leftValue.isGetter)){a.leftValue.isGetter=!1;a.doneGetter_=!0;this.stateStack.unshift({node:{type:"CallExpression"},doneCallee_:!0,funcThis_:a.leftSide[0],func_:a.leftValue,doneArgs_:!0,arguments:[]});return}a.doneRight=!0;this.stateStack.unshift({node:b.right})}else a.doneLeft=!0,this.stateStack.unshift({node:b.left, -components:!0})}; -Interpreter.prototype.stepBinaryExpression=function(){var a=this.stateStack[0],b=a.node;if(a.doneLeft)if(a.doneRight){this.stateStack.shift();var c=a.leftValue,a=a.value,d=this.comp(c,a);if("=="==b.operator||"!="==b.operator)c=c.isPrimitive&&a.isPrimitive?c.data==a.data:0===d,"!="==b.operator&&(c=!c);else if("==="==b.operator||"!=="==b.operator)c=c.isPrimitive&&a.isPrimitive?c.data===a.data:c===a,"!=="==b.operator&&(c=!c);else if(">"==b.operator)c=1==d;else if(">="==b.operator)c=1==d||0===d;else if("<"== -b.operator)c=-1==d;else if("<="==b.operator)c=-1==d||0===d;else if("+"==b.operator)c=c.isPrimitive?c.data:c.toString(),a=a.isPrimitive?a.data:a.toString(),c+=a;else if("in"==b.operator)c=this.hasProperty(a,c);else if("instanceof"==b.operator)this.isa(a,this.FUNCTION)||this.throwException(this.TYPE_ERROR,"Expecting a function in instanceof check"),c=this.isa(c,a);else if(c=c.toNumber(),a=a.toNumber(),"-"==b.operator)c-=a;else if("*"==b.operator)c*=a;else if("/"==b.operator)c/=a;else if("%"==b.operator)c%= -a;else if("&"==b.operator)c&=a;else if("|"==b.operator)c|=a;else if("^"==b.operator)c^=a;else if("<<"==b.operator)c<<=a;else if(">>"==b.operator)c>>=a;else if(">>>"==b.operator)c>>>=a;else throw SyntaxError("Unknown binary operator: "+b.operator);this.stateStack[0].value=this.createPrimitive(c)}else a.doneRight=!0,a.leftValue=a.value,this.stateStack.unshift({node:b.right});else a.doneLeft=!0,this.stateStack.unshift({node:b.left})}; -Interpreter.prototype.stepBlockStatement=function(){var a=this.stateStack[0],b=a.node,c=a.n_||0;b.body[c]?(a.done=!1,a.n_=c+1,this.stateStack.unshift({node:b.body[c]})):(a.done=!0,"Program"!=a.node.type&&this.stateStack.shift())}; -Interpreter.prototype.stepBreakStatement=function(){var a=this.stateStack.shift(),a=a.node,b=null;a.label&&(b=a.label.name);for(a=this.stateStack.shift();a&&"CallExpression"!=a.node.type&&"NewExpression"!=a.node.type;){if(b?b==a.label:a.isLoop||a.isSwitch)return;a=this.stateStack.shift()}throw SyntaxError("Illegal break statement");}; -Interpreter.prototype.stepCallExpression=function(){var a=this.stateStack[0],b=a.node;if(a.doneCallee_){if(!a.func_){if("function"==a.value.type)a.func_=a.value;else{a.value.length&&(a.member_=a.value[0]);a.func_=this.getValue(a.value);if(!a.func_)return;if("function"!=a.func_.type){this.throwException(this.TYPE_ERROR,(a.value&&a.value.type)+" is not a function");return}}"NewExpression"==a.node.type?(a.funcThis_=this.createObject(a.func_),a.isConstructor_=!0):a.funcThis_=a.func_.boundThis_?a.func_.boundThis_: -a.value.length?a.value[0]:this.stateStack[this.stateStack.length-1].thisExpression;a.arguments=a.func_.boundArgs_?a.func_.boundArgs_.concat():[];a.n_=0}if(!a.doneArgs_){0!=a.n_&&a.arguments.push(a.value);if(b.arguments[a.n_]){this.stateStack.unshift({node:b.arguments[a.n_]});a.n_++;return}a.doneArgs_=!0}if(a.doneExec_)this.stateStack.shift(),this.stateStack[0].value=a.isConstructor_&&"object"!==a.value.type?a.funcThis_:a.value;else if(a.doneExec_=!0,a.func_.node){for(var b=this.createScope(a.func_.node.body, -a.func_.parentScope),c=0;cc?a.arguments[c]:this.UNDEFINED;this.setProperty(b,d,h)}d=this.createObject(this.ARRAY);for(c=0;c - - - - Blockly Demo: JS Interpreter - - - - - - - - -

Blockly > - Demos > JS Interpreter

- -

This is a simple demo of executing code with a sandboxed JavaScript interpreter.

- -

→ More info on JS Interpreter

- -

- - -

- -
- - - - - - - - - diff --git a/trunk/web/blockly/demos/maxBlocks/icon.png b/trunk/web/blockly/demos/maxBlocks/icon.png deleted file mode 100644 index 13bf65a9c8f..00000000000 Binary files a/trunk/web/blockly/demos/maxBlocks/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/maxBlocks/index.html b/trunk/web/blockly/demos/maxBlocks/index.html deleted file mode 100644 index 17a967339cd..00000000000 --- a/trunk/web/blockly/demos/maxBlocks/index.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - Blockly Demo: Maximum Block Limit - - - - - - -

Blockly > - Demos > Maximum Block Limit

- -

This is a demo of Blockly which has been restricted to a maximum of - five blocks.

- -

You have block(s) left.

- -
- - - - - - - diff --git a/trunk/web/blockly/demos/mirror/icon.png b/trunk/web/blockly/demos/mirror/icon.png deleted file mode 100644 index 45e2a9a290c..00000000000 Binary files a/trunk/web/blockly/demos/mirror/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/mirror/index.html b/trunk/web/blockly/demos/mirror/index.html deleted file mode 100644 index ea029e38d63..00000000000 --- a/trunk/web/blockly/demos/mirror/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - - Blockly Demo: Mirrored Blockly - - - - - - -

Blockly > - Demos > Mirrored Blockly

- -

This is a simple demo of a master Blockly that controls a slave Blockly. - Open the JavaScript console to see the event passing.

- -

→ More info on events

- - - - - - -
-
-
-
-
- - - - - - - diff --git a/trunk/web/blockly/demos/plane/README.txt b/trunk/web/blockly/demos/plane/README.txt deleted file mode 100644 index 6da3fa65d6a..00000000000 --- a/trunk/web/blockly/demos/plane/README.txt +++ /dev/null @@ -1,26 +0,0 @@ -This Blockly demo uses Closure Templates to create a multilingual application. -Any changes to the template.soy file require a recompile. Here is the command -to generate a quick English version for debugging: - -java -jar soy/SoyToJsSrcCompiler.jar --outputPathFormat generated/en.js --srcs template.soy - -To generate a full set of language translations, first extract all the strings -from template.soy using this command: - -java -jar soy/SoyMsgExtractor.jar --outputFile xlf/extracted_msgs.xlf template.soy - -This generates xlf/extracted_msgs.xlf, which may then be used by any -XLIFF-compatible translation console to generate a set of files with the -translated strings. These should be placed in the xlf directory. - -Finally, generate all the language versions wih this command: - -java -jar soy/SoyToJsSrcCompiler.jar --locales ar,be-tarask,br,ca,da,de,el,en,es,fa,fr,he,hrx,hu,ia,is,it,ja,ko,ms,nb,nl,pl,pms,pt-br,ro,ru,sc,sv,th,tr,uk,vi,zh-hans,zh-hant --messageFilePathFormat xlf/translated_msgs_{LOCALE}.xlf --outputPathFormat "generated/{LOCALE}.js" template.soy - -This is the process that Google uses for maintaining Blockly Games in 40+ -languages. The XLIFF fromat is simple enough that it is trival to write a -Python script to reformat it into some other format (such as JSON) for -compatability with other translation consoles. - -For more information, see message translation for Closure Templates: -https://developers.google.com/closure/templates/docs/translation diff --git a/trunk/web/blockly/demos/plane/blocks.js b/trunk/web/blockly/demos/plane/blocks.js deleted file mode 100644 index 18be29c5dd8..00000000000 --- a/trunk/web/blockly/demos/plane/blocks.js +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Blockly Demos: Plane Seat Calculator Blocks - * - * Copyright 2013 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Blocks for Blockly's Plane Seat Calculator application. - * @author fraser@google.com (Neil Fraser) - */ -'use strict'; - -Blockly.Blocks['plane_set_seats'] = { - // Block seat variable setter. - init: function() { - this.setHelpUrl(Blockly.Msg.VARIABLES_SET_HELPURL); - this.setColour(330); - this.appendValueInput('VALUE') - .appendField(Plane.getMsg('Plane_setSeats')); - this.setTooltip(Blockly.Msg.VARIABLES_SET_TOOLTIP); - this.setDeletable(false); - } -}; - -Blockly.JavaScript['plane_set_seats'] = function(block) { - // Generate JavaScript for seat variable setter. - var argument0 = Blockly.JavaScript.valueToCode(block, 'VALUE', - Blockly.JavaScript.ORDER_ASSIGNMENT) || 'NaN'; - return argument0 + ';'; -}; - -Blockly.Blocks['plane_get_rows'] = { - // Block for row variable getter. - init: function() { - this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL); - this.setColour(330); - this.appendDummyInput() - .appendField(Plane.getMsg('Plane_getRows'), 'title'); - this.setOutput(true, 'Number'); - }, - customUpdate: function() { - this.setFieldValue( - Plane.getMsg('Plane_getRows').replace('%1', Plane.rows1st), 'title'); - } -}; - -Blockly.JavaScript['plane_get_rows'] = function(block) { - // Generate JavaScript for row variable getter. - return ['Plane.rows1st', Blockly.JavaScript.ORDER_MEMBER]; -}; - -Blockly.Blocks['plane_get_rows1st'] = { - // Block for first class row variable getter. - init: function() { - this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL); - this.setColour(330); - this.appendDummyInput() - .appendField(Plane.getMsg('Plane_getRows1'), 'title'); - this.setOutput(true, 'Number'); - }, - customUpdate: function() { - this.setFieldValue( - Plane.getMsg('Plane_getRows1').replace('%1', Plane.rows1st), 'title'); - } -}; - -Blockly.JavaScript['plane_get_rows1st'] = function(block) { - // Generate JavaScript for first class row variable getter. - return ['Plane.rows1st', Blockly.JavaScript.ORDER_MEMBER]; -}; - -Blockly.Blocks['plane_get_rows2nd'] = { - // Block for second class row variable getter. - init: function() { - this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL); - this.setColour(330); - this.appendDummyInput() - .appendField(Plane.getMsg('Plane_getRows2'), 'title'); - this.setOutput(true, 'Number'); - }, - customUpdate: function() { - this.setFieldValue( - Plane.getMsg('Plane_getRows2').replace('%1', Plane.rows2nd), 'title'); - } -}; - -Blockly.JavaScript['plane_get_rows2nd'] = function(block) { - // Generate JavaScript for second class row variable getter. - return ['Plane.rows2nd', Blockly.JavaScript.ORDER_MEMBER]; -}; diff --git a/trunk/web/blockly/demos/plane/generated/ar.js b/trunk/web/blockly/demos/plane/generated/ar.js deleted file mode 100644 index 13109490495..00000000000 --- a/trunk/web/blockly/demos/plane/generated/ar.js +++ /dev/null @@ -1,37 +0,0 @@ -// This file was automatically generated from template.soy. -// Please don't edit this file by hand. - -if (typeof planepage == 'undefined') { var planepage = {}; } - - -planepage.messages = function(opt_data, opt_ignored, opt_ijData) { - return '
الصفوف: %1الصفوف (%1)صفوف الطبقة الأولى: %1صفوف الطبقة الأولى (%1)صفوف الفئة الثانية: %1صفوف الفئة الثانية: (%1)المقاعد: %1؟المقاعد =
'; -}; - - -planepage.start = function(opt_data, opt_ignored, opt_ijData) { - var output = planepage.messages(null, null, opt_ijData) + '

Blockly‏ > Demos‏ > آلة حاسبة لمقعد الطائرة   '; - var iLimit37 = opt_ijData.maxLevel + 1; - for (var i37 = 1; i37 < iLimit37; i37++) { - output += ' ' + ((i37 == opt_ijData.level) ? '' + soy.$$escapeHtml(i37) + '' : (i37 < opt_ijData.level) ? '' : '' + soy.$$escapeHtml(i37) + ''); - } - output += '

- - - - - - diff --git a/trunk/web/blockly/demos/plane/plane.js b/trunk/web/blockly/demos/plane/plane.js deleted file mode 100644 index 99e5c175c33..00000000000 --- a/trunk/web/blockly/demos/plane/plane.js +++ /dev/null @@ -1,445 +0,0 @@ -/** - * Blockly Demos: Plane Seat Calculator - * - * Copyright 2012 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview JavaScript for Blockly's Plane Seat Calculator demo. - * @author fraser@google.com (Neil Fraser) - */ -'use strict'; - -/** - * Create a namespace for the application. - */ -var Plane = {}; - -/** - * Lookup for names of supported languages. Keys should be in ISO 639 format. - */ -Plane.LANGUAGE_NAME = { - 'ar': 'العربية', - 'be-tarask': 'Taraškievica', - 'br': 'Brezhoneg', - 'ca': 'Català', - 'da': 'Dansk', - 'de': 'Deutsch', - 'el': 'Ελληνικά', - 'en': 'English', - 'es': 'Español', - 'fa': 'فارسی', - 'fr': 'Français', - 'he': 'עברית', - 'hrx': 'Hunsrik', - 'hu': 'Magyar', - 'ia': 'Interlingua', - 'is': 'Íslenska', - 'it': 'Italiano', - 'ja': '日本語', - 'ko': '한국어', - 'ms': 'Bahasa Melayu', - 'nb': 'Norsk Bokmål', - 'nl': 'Nederlands, Vlaams', - 'pl': 'Polski', - 'pms': 'Piemontèis', - 'pt-br': 'Português Brasileiro', - 'ro': 'Română', - 'ru': 'Русский', - 'sc': 'Sardu', - 'sv': 'Svenska', - 'th': 'ภาษาไทย', - 'tr': 'Türkçe', - 'uk': 'Українська', - 'vi': 'Tiếng Việt', - 'zh-hans': '简体中文', - 'zh-hant': '正體中文' -}; - -/** - * List of RTL languages. - */ -Plane.LANGUAGE_RTL = ['ar', 'fa', 'he']; - -/** - * Main Blockly workspace. - * @type {Blockly.WorkspaceSvg} - */ -Plane.workspace = null; - -/** - * Extracts a parameter from the URL. - * If the parameter is absent default_value is returned. - * @param {string} name The name of the parameter. - * @param {string} defaultValue Value to return if paramater not found. - * @return {string} The parameter value or the default value if not found. - */ -Plane.getStringParamFromUrl = function(name, defaultValue) { - var val = location.search.match(new RegExp('[?&]' + name + '=([^&]+)')); - return val ? decodeURIComponent(val[1].replace(/\+/g, '%20')) : defaultValue; -}; - -/** - * Extracts a numeric parameter from the URL. - * If the parameter is absent or less than min_value, min_value is - * returned. If it is greater than max_value, max_value is returned. - * @param {string} name The name of the parameter. - * @param {number} minValue The minimum legal value. - * @param {number} maxValue The maximum legal value. - * @return {number} A number in the range [min_value, max_value]. - */ -Plane.getNumberParamFromUrl = function(name, minValue, maxValue) { - var val = Number(Plane.getStringParamFromUrl(name, 'NaN')); - return isNaN(val) ? minValue : Math.min(Math.max(minValue, val), maxValue); -}; - -/** - * Get the language of this user from the URL. - * @return {string} User's language. - */ -Plane.getLang = function() { - var lang = Plane.getStringParamFromUrl('lang', ''); - if (Plane.LANGUAGE_NAME[lang] === undefined) { - // Default to English. - lang = 'en'; - } - return lang; -}; - -/** - * Is the current language (Plane.LANG) an RTL language? - * @return {boolean} True if RTL, false if LTR. - */ -Plane.isRtl = function() { - return Plane.LANGUAGE_RTL.indexOf(Plane.LANG) != -1; -}; - -/** - * Load blocks saved in session/local storage. - * @param {string} defaultXml Text representation of default blocks. - */ -Plane.loadBlocks = function(defaultXml) { - try { - var loadOnce = window.sessionStorage.loadOnceBlocks; - } catch(e) { - // Firefox sometimes throws a SecurityError when accessing sessionStorage. - // Restarting Firefox fixes this, so it looks like a bug. - var loadOnce = null; - } - if (loadOnce) { - // Language switching stores the blocks during the reload. - delete window.sessionStorage.loadOnceBlocks; - var xml = Blockly.Xml.textToDom(loadOnce); - Blockly.Xml.domToWorkspace(xml, Plane.workspace); - } else if (defaultXml) { - // Load the editor with default starting blocks. - var xml = Blockly.Xml.textToDom(defaultXml); - Blockly.Xml.domToWorkspace(xml, Plane.workspace); - } - Plane.workspace.clearUndo(); -}; - -/** - * Save the blocks and reload with a different language. - */ -Plane.changeLanguage = function() { - // Store the blocks for the duration of the reload. - // This should be skipped for the index page, which has no blocks and does - // not load Blockly. - // MSIE 11 does not support sessionStorage on file:// URLs. - if (typeof Blockly != 'undefined' && window.sessionStorage) { - var xml = Blockly.Xml.workspaceToDom(Plane.workspace); - var text = Blockly.Xml.domToText(xml); - window.sessionStorage.loadOnceBlocks = text; - } - - var languageMenu = document.getElementById('languageMenu'); - var newLang = encodeURIComponent( - languageMenu.options[languageMenu.selectedIndex].value); - var search = window.location.search; - if (search.length <= 1) { - search = '?lang=' + newLang; - } else if (search.match(/[?&]lang=[^&]*/)) { - search = search.replace(/([?&]lang=)[^&]*/, '$1' + newLang); - } else { - search = search.replace(/\?/, '?lang=' + newLang + '&'); - } - - window.location = window.location.protocol + '//' + - window.location.host + window.location.pathname + search; -}; - -/** - * Gets the message with the given key from the document. - * @param {string} key The key of the document element. - * @return {string} The textContent of the specified element, - * or an error message if the element was not found. - */ -Plane.getMsg = function(key) { - var element = document.getElementById(key); - if (element) { - var text = element.textContent; - // Convert newline sequences. - text = text.replace(/\\n/g, '\n'); - return text; - } else { - return '[Unknown message: ' + key + ']'; - } -}; - -/** - * User's language (e.g. "en"). - * @type {string} - */ -Plane.LANG = Plane.getLang(); - -Plane.MAX_LEVEL = 3; -Plane.LEVEL = Plane.getNumberParamFromUrl('level', 1, Plane.MAX_LEVEL); - -Plane.rows1st = 0; -Plane.rows2nd = 0; - -/** - * Redraw the rows when the slider has moved. - * @param {number} value New slider position. - */ -Plane.sliderChange = function(value) { - var newRows = Math.round(value * 410 / 20); - Plane.redraw(newRows); -}; - -/** - * Change the text of a label. - * @param {string} id ID of element to change. - * @param {string} text New text. - */ -Plane.setText = function(id, text) { - var el = document.getElementById(id); - while (el.firstChild) { - el.removeChild(el.firstChild); - } - el.appendChild(document.createTextNode(text)); -}; - -/** - * Display a checkmark or cross next to the answer. - * @param {?boolean} ok True for checkmark, false for cross, null for nothing. - */ -Plane.setCorrect = function(ok) { - var yes = document.getElementById('seatYes'); - var no = document.getElementById('seatNo'); - yes.style.display = 'none'; - no.style.display = 'none'; - if (ok === true) { - yes.style.display = 'block'; - } else if (ok === false) { - no.style.display = 'block'; - } -}; - -/** - * Initialize Blockly and the SVG plane. - */ -Plane.init = function() { - Plane.initLanguage(); - - // Fixes viewport for small screens. - var viewport = document.querySelector('meta[name="viewport"]'); - if (viewport && screen.availWidth < 725) { - viewport.setAttribute('content', - 'width=725, initial-scale=.35, user-scalable=no'); - } - - Plane.workspace = Blockly.inject('blockly', - {media: '../../media/', - rtl: Plane.isRtl(), - toolbox: document.getElementById('toolbox')}); - - var defaultXml = - '' + - ' ' + - ' ' + - ''; - Plane.loadBlocks(defaultXml); - - Plane.workspace.addChangeListener(Plane.recalculate); - Plane.workspace.addChangeListener(Blockly.Events.disableOrphans); - - // Initialize the slider. - var svg = document.getElementById('plane'); - Plane.rowSlider = new Slider(60, 330, 425, svg, Plane.sliderChange); - Plane.rowSlider.setValue(0.225); - - // Draw five 1st class rows. - Plane.redraw(5); -}; - -/** - * Initialize the page language. - */ -Plane.initLanguage = function() { - // Set the page title with the content of the H1 title. - document.title += ' ' + document.getElementById('title').textContent; - - // Set the HTML's language and direction. - // document.dir fails in Mozilla, use document.body.parentNode.dir instead. - // https://bugzilla.mozilla.org/show_bug.cgi?id=151407 - var rtl = Plane.isRtl(); - document.head.parentElement.setAttribute('dir', rtl ? 'rtl' : 'ltr'); - document.head.parentElement.setAttribute('lang', Plane.LANG); - - // Sort languages alphabetically. - var languages = []; - for (var lang in Plane.LANGUAGE_NAME) { - languages.push([Plane.LANGUAGE_NAME[lang], lang]); - } - var comp = function(a, b) { - // Sort based on first argument ('English', 'Русский', '简体字', etc). - if (a[0] > b[0]) return 1; - if (a[0] < b[0]) return -1; - return 0; - }; - languages.sort(comp); - // Populate the language selection menu. - var languageMenu = document.getElementById('languageMenu'); - languageMenu.options.length = 0; - for (var i = 0; i < languages.length; i++) { - var tuple = languages[i]; - var lang = tuple[tuple.length - 1]; - var option = new Option(tuple[0], lang); - if (lang == Plane.LANG) { - option.selected = true; - } - languageMenu.options.add(option); - } - languageMenu.addEventListener('change', Plane.changeLanguage, true); -}; - -/** - * Use the blocks to calculate the number of seats. - * Display the calculated number. - */ -Plane.recalculate = function() { - // Find the 'set' block and use it as the formula root. - var rootBlock = null; - var blocks = Plane.workspace.getTopBlocks(false); - for (var i = 0, block; block = blocks[i]; i++) { - if (block.type == 'plane_set_seats') { - rootBlock = block; - } - } - var seats = NaN; - Blockly.JavaScript.init(Plane.workspace); - var code = Blockly.JavaScript.blockToCode(rootBlock); - try { - seats = eval(code); - } catch (e) { - // Allow seats to remain NaN. - } - Plane.setText('seatText', - Plane.getMsg('Plane_seats').replace( - '%1', isNaN(seats) ? '?' : seats)); - Plane.setCorrect(isNaN(seats) ? null : (Plane.answer() == seats)); - - // Update blocks to show values. - function updateBlocks(blocks) { - for (var i = 0, block; block = blocks[i]; i++) { - block.customUpdate && block.customUpdate(); - } - } - updateBlocks(Plane.workspace.getAllBlocks()); - updateBlocks(Plane.workspace.flyout_.workspace_.getAllBlocks()); -}; - -/** - * Calculate the correct answer. - * @return {number} Number of seats. - */ -Plane.answer = function() { - if (Plane.LEVEL == 1) { - return Plane.rows1st * 4; - } else if (Plane.LEVEL == 2) { - return 2 + (Plane.rows1st * 4); - } else if (Plane.LEVEL == 3) { - return 2 + (Plane.rows1st * 4) + (Plane.rows2nd * 5); - } - throw 'Unknown level.'; -}; - -/** - * Redraw the SVG to show a new number of rows. - * @param {number} newRows - */ -Plane.redraw = function(newRows) { - var rows1st = Plane.rows1st; - var rows2nd = Plane.rows2nd; - var svg = document.getElementById('plane'); - if (newRows != rows1st) { - while (newRows < rows1st) { - var row = document.getElementById('row1st' + rows1st); - row.parentNode.removeChild(row); - rows1st--; - } - while (newRows > rows1st) { - rows1st++; - var row = document.createElementNS('http://www.w3.org/2000/svg', 'use'); - row.setAttribute('id', 'row1st' + rows1st); - // Row of 4 seats. - row.setAttribute('x', (rows1st - 1) * 20); - row.setAttributeNS('http://www.w3.org/1999/xlink', - 'xlink:href', '#row1st'); - svg.appendChild(row); - } - - if (Plane.LEVEL == 3) { - newRows = Math.floor((21 - newRows) * 1.11); - while (newRows < rows2nd) { - var row = document.getElementById('row2nd' + rows2nd); - row.parentNode.removeChild(row); - rows2nd--; - } - while (newRows > rows2nd) { - rows2nd++; - var row = document.createElementNS('http://www.w3.org/2000/svg', - 'use'); - row.setAttribute('id', 'row2nd' + rows2nd); - row.setAttribute('x', 400 - (rows2nd - 1) * 18); - row.setAttributeNS('http://www.w3.org/1999/xlink', - 'xlink:href', '#row2nd'); - svg.appendChild(row); - } - } - - if (Plane.LEVEL < 3) { - Plane.setText('row1stText', - Plane.getMsg('Plane_rows').replace('%1', rows1st)); - } else { - Plane.setText('row1stText', - Plane.getMsg('Plane_rows1').replace('%1', rows1st)); - Plane.setText('row2ndText', - Plane.getMsg('Plane_rows2').replace('%1', rows2nd)); - } - - Plane.rows1st = rows1st; - Plane.rows2nd = rows2nd; - Plane.recalculate(); - } -}; - -window.addEventListener('load', Plane.init); - -// Load the user's language pack. -document.write('\n'); diff --git a/trunk/web/blockly/demos/plane/slider.js b/trunk/web/blockly/demos/plane/slider.js deleted file mode 100644 index 2df67b83447..00000000000 --- a/trunk/web/blockly/demos/plane/slider.js +++ /dev/null @@ -1,287 +0,0 @@ -/** - * Blockly Demos: SVG Slider - * - * Copyright 2012 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview A slider control in SVG. - * @author fraser@google.com (Neil Fraser) - */ -'use strict'; - - -/** - * Object representing a horizontal slider widget. - * @param {number} x The horizontal offset of the slider. - * @param {number} y The vertical offset of the slider. - * @param {number} width The total width of the slider. - * @param {!Element} svgParent The SVG element to append the slider to. - * @param {Function=} opt_changeFunc Optional callback function that will be - * called when the slider is moved. The current value is passed. - * @constructor - */ -var Slider = function(x, y, width, svgParent, opt_changeFunc) { - this.KNOB_Y_ = y - 12; - this.KNOB_MIN_X_ = x + 8; - this.KNOB_MAX_X_ = x + width - 8; - this.TARGET_OVERHANG_ = 20; - this.value_ = 0.5; - this.changeFunc_ = opt_changeFunc; - this.animationTasks_ = []; - - // Draw the slider. - /* - - - - - */ - var track = document.createElementNS(Slider.SVG_NS_, 'line'); - track.setAttribute('class', 'sliderTrack'); - track.setAttribute('x1', x); - track.setAttribute('y1', y); - track.setAttribute('x2', x + width); - track.setAttribute('y2', y); - svgParent.appendChild(track); - this.track_ = track; - var rect = document.createElementNS(Slider.SVG_NS_, 'rect'); - rect.setAttribute('style', 'opacity: 0'); - rect.setAttribute('x', x - this.TARGET_OVERHANG_); - rect.setAttribute('y', y - this.TARGET_OVERHANG_); - rect.setAttribute('width', width + 2 * this.TARGET_OVERHANG_); - rect.setAttribute('height', 2 * this.TARGET_OVERHANG_); - rect.setAttribute('rx', this.TARGET_OVERHANG_); - rect.setAttribute('ry', this.TARGET_OVERHANG_); - svgParent.appendChild(rect); - this.trackTarget_ = rect; - var knob = document.createElementNS(Slider.SVG_NS_, 'path'); - knob.setAttribute('class', 'sliderKnob'); - knob.setAttribute('d', 'm 0,0 l -8,8 v 12 h 16 v -12 z'); - svgParent.appendChild(knob); - this.knob_ = knob; - var circle = document.createElementNS(Slider.SVG_NS_, 'circle'); - circle.setAttribute('style', 'opacity: 0'); - circle.setAttribute('r', this.TARGET_OVERHANG_); - circle.setAttribute('cy', y); - svgParent.appendChild(circle); - this.knobTarget_ = circle; - this.setValue(0.5); - - // Find the root SVG object. - while (svgParent && svgParent.nodeName.toLowerCase() != 'svg') { - svgParent = svgParent.parentNode; - } - this.SVG_ = svgParent; - - // Bind the events to this slider. - Slider.bindEvent_(this.knobTarget_, 'mousedown', this, this.knobMouseDown_); - Slider.bindEvent_(this.knobTarget_, 'touchstart', this, this.knobMouseDown_); - Slider.bindEvent_(this.trackTarget_, 'mousedown', this, this.rectMouseDown_); - Slider.bindEvent_(this.SVG_, 'mouseup', null, Slider.knobMouseUp_); - Slider.bindEvent_(this.SVG_, 'touchend', null, Slider.knobMouseUp_); - Slider.bindEvent_(this.SVG_, 'mousemove', null, Slider.knobMouseMove_); - Slider.bindEvent_(this.SVG_, 'touchmove', null, Slider.knobMouseMove_); - Slider.bindEvent_(document, 'mouseover', null, Slider.mouseOver_); -}; - - -Slider.SVG_NS_ = 'http://www.w3.org/2000/svg'; - -Slider.activeSlider_ = null; -Slider.startMouseX_ = 0; -Slider.startKnobX_ = 0; - -/** - * Start a drag when clicking down on the knob. - * @param {!Event} e Mouse-down event. - * @private - */ -Slider.prototype.knobMouseDown_ = function(e) { - if (e.type == 'touchstart') { - if (e.changedTouches.length != 1) { - return; - } - Slider.touchToMouse_(e) - } - Slider.activeSlider_ = this; - Slider.startMouseX_ = this.mouseToSvg_(e).x; - Slider.startKnobX_ = 0; - var transform = this.knob_.getAttribute('transform'); - if (transform) { - var r = transform.match(/translate\(\s*([-\d.]+)/); - if (r) { - Slider.startKnobX_ = Number(r[1]); - } - } - // Stop browser from attempting to drag the knob or - // from scrolling/zooming the page. - e.preventDefault(); -}; - -/** - * Stop a drag when clicking up anywhere. - * @param {Event} e Mouse-up event. - * @private - */ -Slider.knobMouseUp_ = function(e) { - Slider.activeSlider_ = null; -}; - -/** - * Stop a drag when the mouse enters a node not part of the SVG. - * @param {Event} e Mouse-up event. - * @private - */ -Slider.mouseOver_ = function(e) { - if (!Slider.activeSlider_) { - return; - } - var node = e.target; - // Find the root SVG object. - do { - if (node == Slider.activeSlider_.SVG_) { - return; - } - } while (node = node.parentNode); - Slider.knobMouseUp_(e); -}; - -/** - * Drag the knob to follow the mouse. - * @param {!Event} e Mouse-move event. - * @private - */ -Slider.knobMouseMove_ = function(e) { - var thisSlider = Slider.activeSlider_; - if (!thisSlider) { - return; - } - if (e.type == 'touchmove') { - if (e.changedTouches.length != 1) { - return; - } - Slider.touchToMouse_(e) - } - var x = thisSlider.mouseToSvg_(e).x - Slider.startMouseX_ + - Slider.startKnobX_; - thisSlider.setValue((x - thisSlider.KNOB_MIN_X_) / - (thisSlider.KNOB_MAX_X_ - thisSlider.KNOB_MIN_X_)); -}; - -/** - * Jump to a new value when the track is clicked. - * @param {!Event} e Mouse-down event. - * @private - */ -Slider.prototype.rectMouseDown_ = function(e) { - if (e.type == 'touchstart') { - if (e.changedTouches.length != 1) { - return; - } - Slider.touchToMouse_(e) - } - var x = this.mouseToSvg_(e).x; - this.animateValue((x - this.KNOB_MIN_X_) / - (this.KNOB_MAX_X_ - this.KNOB_MIN_X_)); -}; - -/** - * Returns the slider's value (0.0 - 1.0). - * @return {number} Current value. - */ -Slider.prototype.getValue = function() { - return this.value_; -}; - -/** - * Animates the slider's value (0.0 - 1.0). - * @param {number} value New value. - */ -Slider.prototype.animateValue = function(value) { - // Clear any ongoing animations. - while (this.animationTasks_.length) { - clearTimeout(this.animationTasks_.pop()); - } - var duration = 200; // Milliseconds to animate for. - var steps = 10; // Number of steps to animate. - var oldValue = this.getValue(); - var thisSlider = this; - var stepFunc = function(i) { - return function() { - var newVal = i * (value - oldValue) / (steps - 1) + oldValue; - thisSlider.setValue(newVal); - }; - } - for (var i = 0; i < steps; i++) { - this.animationTasks_.push(setTimeout(stepFunc(i), i * duration / steps)); - } -}; - -/** - * Sets the slider's value (0.0 - 1.0). - * @param {number} value New value. - */ -Slider.prototype.setValue = function(value) { - this.value_ = Math.min(Math.max(value, 0), 1); - var x = this.KNOB_MIN_X_ + - (this.KNOB_MAX_X_ - this.KNOB_MIN_X_) * this.value_; - this.knob_.setAttribute('transform', - 'translate(' + x + ',' + this.KNOB_Y_ + ')'); - this.knobTarget_.setAttribute('cx', x); - this.changeFunc_ && this.changeFunc_(this.value_); -}; - -/** - * Convert the mouse coordinates into SVG coordinates. - * @param {!Object} e Object with x and y mouse coordinates. - * @return {!Object} Object with x and y properties in SVG coordinates. - * @private - */ -Slider.prototype.mouseToSvg_ = function(e) { - var svgPoint = this.SVG_.createSVGPoint(); - svgPoint.x = e.clientX; - svgPoint.y = e.clientY; - var matrix = this.SVG_.getScreenCTM().inverse(); - return svgPoint.matrixTransform(matrix); -}; - -/** - * Bind an event to a function call. - * @param {!Node} node Node upon which to listen. - * @param {string} name Event name to listen to (e.g. 'mousedown'). - * @param {Object} thisObject The value of 'this' in the function. - * @param {!Function} func Function to call when event is triggered. - * @private - */ -Slider.bindEvent_ = function(node, name, thisObject, func) { - var wrapFunc = function(e) { - func.apply(thisObject, arguments); - }; - node.addEventListener(name, wrapFunc, false); -}; - -/** - * Map the touch event's properties to be compatible with a mouse event. - * @param {TouchEvent} e Event to modify. - */ -Slider.touchToMouse_ = function(e) { - var touchPoint = e.changedTouches[0]; - e.clientX = touchPoint.clientX; - e.clientY = touchPoint.clientY; -}; diff --git a/trunk/web/blockly/demos/plane/style.css b/trunk/web/blockly/demos/plane/style.css deleted file mode 100644 index 16e2c6f412a..00000000000 --- a/trunk/web/blockly/demos/plane/style.css +++ /dev/null @@ -1,97 +0,0 @@ -body { - background-color: #fff; - font-family: sans-serif; - margin-top: 0; -} -h1 { - font-weight: normal; - font-size: 140%; -} -.farSide { - text-align: right; -} -html[dir="RTL"] .farSide { - text-align: left; -} -.tab { - padding: 6px 12px; - text-decoration: none; - color: #000; -} -#selected { - font-weight: bold; - background-color: #ddd; - border-radius: 20px; -} - -/* Pulse the language menu once to draw attention to it. */ -#languageBorder { - border-radius: 4px; - animation: pulse 2s ease-in-out forwards; - animation-delay: 2s; -} -@keyframes pulse { - 0% { background-color: #fff } - 50% { background-color: #f00 } - 100% { background-color: #fff } -} - -#blockly { - height: 300px; - width: 100%; - border-style: solid; - border-color: #ddd; - border-width: 0 1px 1px 0; -} - -/* SVG Plane. */ -#plane { - overflow: hidden; -} -#fuselage { - fill: #fff; - stroke: #000; -} -#wing, #tail { - fill: #ddd; - stroke: #444; -} -.crew { - fill: #f44; - stroke: #000; -} -.seat1st { - fill: #88f; - stroke: #000; -} -.seat2nd { - fill: #8b8; - stroke: #000; -} -#seatYes, #seatNo { - font-size: 40pt; -} -text { - font-family: sans-serif; - font-size: 20pt; - fill: #444; -} -html[dir="RTL"] #plane text { - text-anchor: end; -} - -/* Slider. */ -.sliderTrack { - stroke: #aaa; - stroke-width: 6px; - stroke-linecap: round; -} -.sliderKnob { - fill: #ddd; - stroke: #bbc; - stroke-width: 1px; - stroke-linejoin: round; -} -.sliderKnob:hover { - fill: #eee; -} diff --git a/trunk/web/blockly/demos/plane/template.soy b/trunk/web/blockly/demos/plane/template.soy deleted file mode 100644 index 5b19e99bec7..00000000000 --- a/trunk/web/blockly/demos/plane/template.soy +++ /dev/null @@ -1,225 +0,0 @@ -{namespace planepage} - -/** - * This is a Closure Template. - * - * See the README.txt for details. - */ - -/** - * Translated messages for use in JavaScript. - */ -{template .messages} -
- {msg meaning="Plane.rows" desc="page text - Total number of rows of seats on an airplane.\n\nParameters:\n* %1 - number of rows of seats on an airplane. It is always an integer greater than or equal to zero."}Rows: %1{/msg} - {msg meaning="Plane.getRows" desc="block text - The number of rows on the airplane, to be used in a mathematical equation, such as: 'seats = 4 x '''rows (5)''''.\n\nParameters:\n* %1 - number of rows of seats on an airplane. It is always an integer greater than or equal to zero."}rows (%1){/msg} - {msg meaning="Plane.rows1" desc="page text - The number of rows of first-class seats on the airplane. You can see the block at [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=3].\n\nParameters:\n* %1 - number of rows of first-class seats on an airplane. It is always an integer greater than or equal to zero."}1st class rows: %1{/msg} - {msg meaning="Plane.getRows1" desc="block text - The number of rows of first-class seats on the, to be used in a mathematical equation. See [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=3].\n\nParameters:\n* %1 - number of rows of first-class seats on an airplane. It is always an integer greater than or equal to zero."}1st class rows (%1){/msg} - {msg meaning="Plane.rows2" desc="page text - The number of rows of second-class seats on the airplane. %1 is an integer greater or equal to zero. See [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=3].\n\nParameters:\n* %1 - number of rows of second-class seats on an airplane. It is always an integer greater than or equal to zero."}2nd class rows: %1{/msg} - {msg meaning="Plane.getRows2" desc="block text - The number of rows of second-class (also called 'economy class') seats on the airplane, to be used in a mathematical expression.\n\nParameters:\n* %1 - number of rows of second-class seats on an airplane. It is always an integer greater than or equal to zero."}2nd class rows (%1){/msg} - {msg meaning="Plane.seats" desc="page text - The total number of seats on the airplane.\n\nParameters:\n* %1 - number of seats on an airplane. It is always either the next message or an integer greater than or equal to zero."}Seats: %1{/msg} - {msg meaning="Plane.placeholder" desc="page text - A word or symbol indicating that this numeric value has not yet been determined."}?{/msg} - {msg meaning="Plane.setSeats" desc="block text - The first half of a mathematical equation determining the number of seats in an airplane, such as: ''''seats =''' 4 x rows'."}seats ={/msg} -
-{/template} - -/** - * Web page structure. - */ -{template .start} - {call .messages /} - - - - - -
-

Blockly‏ >{sp} - Demos‏ >{sp} - - {msg meaning="Plane.plane" desc="title - Specifies that this is Blockly's '''Plane''' (airplane) tutorial. The word 'plane' was chosen over 'airplane' in English because it is shorter and less formal."} - Plane Seat Calculator - {/msg} - - {sp} {sp} - {for $i in range(1, $ij.maxLevel + 1)} - {sp} - {if $i == $ij.level} - {$i} - {else} - {if $i < $ij.level} - - {else} - {$i} - {/if} - {/if} - {/for} -

-
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {if $ij.level > 1} - - - {/if} - - -

- {switch $ij.level} - {case 1} - {msg meaning="Plane.description1" desc="instructions - Note that in [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=1 this level], there is only one type of seat on the plane."}An airplane has a number of rows of passenger seats. Each row contains four seats.{/msg} - {case 2} - {msg meaning="Plane.description2" desc="instructions - Note that in [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=2 this level], there are two types of seats on this plane."}An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats.{/msg} - {case 3} - {msg meaning="Plane.description3" desc="instructions - Note that in [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=3 this level], there are three types of seats on this plane. Be sure to use the same terms for '1st class' and '2nd class' as you did for the earlier messages."}An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats.{/msg} - {/switch} -

-

- {msg meaning="Plane.instructions" desc="page text - This text appears below the airplane graphic and above the space for the user to create the formula. The number of rows an the graphic may be changed by the user with a slider. See [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=1] for a picture."}Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above).{/msg} -

- - - - - - - {call .toolbox /} -
-{/template} - -/** - * Toolboxes for each level. - */ -{template .toolbox} - -{/template} diff --git a/trunk/web/blockly/demos/plane/xlf/extracted_msgs.xlf b/trunk/web/blockly/demos/plane/xlf/extracted_msgs.xlf deleted file mode 100644 index 6a4fd44ff4f..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/extracted_msgs.xlf +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - Rows: %1 - page text - Total number of rows of seats on an airplane.\n\nParameters:\n* %1 - number of rows of seats on an airplane. It is always an integer greater than or equal to zero. - Plane.rows - - - seats = - block text - The first half of a mathematical equation determining the number of seats in an airplane, such as: ''''seats =''' 4 x rows'. - Plane.setSeats - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - instructions - Note that in [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=3 this level], there are three types of seats on this plane. Be sure to use the same terms for '1st class' and '2nd class' as you did for the earlier messages. - Plane.description3 - - - ? - page text - A word or symbol indicating that this numeric value has not yet been determined. - Plane.placeholder - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - page text - This text appears below the airplane graphic and above the space for the user to create the formula. The number of rows an the graphic may be changed by the user with a slider. See [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=1] for a picture. - Plane.instructions - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - instructions - Note that in [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=2 this level], there are two types of seats on this plane. - Plane.description2 - - - 1st class rows (%1) - block text - The number of rows of first-class seats on the, to be used in a mathematical equation. See [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=3].\n\nParameters:\n* %1 - number of rows of first-class seats on an airplane. It is always an integer greater than or equal to zero. - Plane.getRows1 - - - 2nd class rows: %1 - page text - The number of rows of second-class seats on the airplane. %1 is an integer greater or equal to zero. See [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=3].\n\nParameters:\n* %1 - number of rows of second-class seats on an airplane. It is always an integer greater than or equal to zero. - Plane.rows2 - - - Seats: %1 - page text - The total number of seats on the airplane.\n\nParameters:\n* %1 - number of seats on an airplane. It is always either the next message or an integer greater than or equal to zero. - Plane.seats - - - Plane Seat Calculator - title - Specifies that this is Blockly's '''Plane''' (airplane) tutorial. The word 'plane' was chosen over 'airplane' in English because it is shorter and less formal. - Plane.plane - - - rows (%1) - block text - The number of rows on the airplane, to be used in a mathematical equation, such as: 'seats = 4 x '''rows (5)''''.\n\nParameters:\n* %1 - number of rows of seats on an airplane. It is always an integer greater than or equal to zero. - Plane.getRows - - - 1st class rows: %1 - page text - The number of rows of first-class seats on the airplane. You can see the block at [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=3].\n\nParameters:\n* %1 - number of rows of first-class seats on an airplane. It is always an integer greater than or equal to zero. - Plane.rows1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - instructions - Note that in [http://blockly-share.appspot.com/static/apps/plane/plane.html?lang=en&level=1 this level], there is only one type of seat on the plane. - Plane.description1 - - - 2nd class rows (%1) - block text - The number of rows of second-class (also called 'economy class') seats on the airplane, to be used in a mathematical expression.\n\nParameters:\n* %1 - number of rows of second-class seats on an airplane. It is always an integer greater than or equal to zero. - Plane.getRows2 - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ar.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_ar.xlf deleted file mode 100644 index c9b8e1689ac..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ar.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - الصفوف: %1 - - - seats = - المقاعد = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - طائرة بمقعدين في مقطورة الطيّار (للطيار ومساعده) وعدد من المقاعد في صفوف الدرجة الأولى والثانية. كل صف من صفوف الدرجة الأولى يحتوي على أربعة مقاعد. ويحتوي كل صف في الدرجة الثانية على خمسة مقاعد. - - - ? - ؟ - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - لبناء صيغة (أدناه) تقوم بحساب إجمالي عدد المقاعد في الطائرة عند تغيير الصفوف (أعلاه). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - طائرة بمقعدين في مقطورة الطيّار (للطيار ومساعده) وعدد من الصفوف يحتوي كل صف على أربعة مقاعد. - - - 1st class rows (%1) - صفوف الطبقة الأولى (%1) - - - 2nd class rows: %1 - صفوف الفئة الثانية: %1 - - - Seats: %1 - المقاعد: %1 - - - Plane Seat Calculator - آلة حاسبة لمقعد الطائرة - - - rows (%1) - الصفوف (%1) - - - 1st class rows: %1 - صفوف الطبقة الأولى: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - هنالك طائرة تحتوي على عدد من صفوف مقاعد الركاب. كل صف يحتوي على أربعة مقاعد. - - - 2nd class rows (%1) - صفوف الفئة الثانية: (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_be-tarask.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_be-tarask.xlf deleted file mode 100644 index 4580b5f1d6e..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_be-tarask.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Радкоў: %1 - - - seats = - месцаў = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Самалёт мае два месцы ў кабіне экіпажа (пілот і другі пілот), і некалькі пасажырскіх шэрагаў месцаў 1-га кляса і 2-га кляса. Кожны шэраг 1-га кляса утрымлівае чатыры месцы. Кожны шэраг 2-га кляса ўтрымлівае пяць месцаў. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Пабудаваць формулу (ніжэй), якая падлічвае агульную колькасьць месцаў у самалёце пры зьмене радоў (гл. вышэй). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Самалёт мае два месцы ў кабіне экіпажа (пілот і другі пілот), і некалькі шэрагаў пасажырскіх сядзеньняў. Кожны шэраг утрымлівае чатыры месцы. - - - 1st class rows (%1) - радкі першага клясу (%1) - - - 2nd class rows: %1 - Радкі другога клясу: %1 - - - Seats: %1 - Месцаў: %1 - - - Plane Seat Calculator - Калькулятар месцаў у самалёце - - - rows (%1) - радкоў (%1) - - - 1st class rows: %1 - Радкі першага клясу: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Самалёт мае некалькі шэрагаў пасажырскіх сядзеньняў. Кожная шэраг утрымлівае чатыры месцы. - - - 2nd class rows (%1) - радкі другога клясу (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_br.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_br.xlf deleted file mode 100644 index 4a7fc0c26c2..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_br.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Renkennadoù : %1 - - - seats = - azezennoù = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - En un nijerez ez eus div azezenn el logell leviañ(evit al loman hag an eil loman), hag un toullad renkennadoù azezennoù tremenidi kentañ hag eil klas. Peder azezenn zo e pep renkennad kentañ klas. Pemp azezenn zo e pemp renkennad eil klas. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Sevel ur formulenn (amañ dindan) evit jediñ an niver a azezennoù en holl en nijerez pa vez kemmet an niver a renkennadoù (amañ a-us). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - En un nijerez ez eus div azezenn el logell leviañ(evit al loman hag an eil loman), hag ur toullad renkennadoù azezennoù evit an dremenidi. Peder azezenn zo e pep renkennad. - - - 1st class rows (%1) - Renkennadoù kentañ klas (%1) - - - 2nd class rows: %1 - Renkennadoù eil klas : %1 - - - Seats: %1 - Azezennoù : %1 - - - Plane Seat Calculator - Jederez azezenn nijerez - - - rows (%1) - renkennadoù (%1) - - - 1st class rows: %1 - Renkennadoù kentañ klas : %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Un nijerez he deus un toullad renkennadoù azezennoù evit ar veajourien. Peder azezenn a zo e pep renkennad. - - - 2nd class rows (%1) - Renkennadoù eil klas (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ca.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_ca.xlf deleted file mode 100644 index 17dfe65e09e..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ca.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Files: %1 - - - seats = - seients = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Un avió té dos seients en la cabina de vol (pel pilot i copilot) i un nombre de files per seients de passatgers de primera classe i de segona classe. Cada fila de primera classe conté quatre seients. Cada fila de segona classe conté cinc seients. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Construïu una fórmula (a sota) que calculi el nombre total de seients de l'avió a mida que canviïn les files (a dalt). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Un avió té dos seients en la cabina de vol (pel pilot i pel copilot) i un nombre de files de seients de passatgers. Cada fila conté quatre seients. - - - 1st class rows (%1) - files de primera classe (%1) - - - 2nd class rows: %1 - files de segona classe: %1 - - - Seats: %1 - Seients: %1 - - - Plane Seat Calculator - Calculadora de seients d'avió - - - rows (%1) - files (%1) - - - 1st class rows: %1 - files de primera classe: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Un avió té un nombre de files de seients de passatgers. Cada fila conté quatre seients. - - - 2nd class rows (%1) - files de segona classe (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_da.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_da.xlf deleted file mode 100644 index 752fe24f5b8..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_da.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Rækker: %1 - - - seats = - sæder = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Et fly har to pladser i cockpittet (til pilot og med-pilot), og et antal rækker af 1. klasses og 2. klasses passagersæder. Hver 1. klasses række indeholder fire sæder. Hver 2. klasses række indeholder fem sæder. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Opbyg en formel (nedenfor), der beregner det samlede antal pladser på flyet, hvis antal rækker ændres (ovenfor). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Et fly har to pladser i cockpittet (til pilot og med-pilot), og et antal rækker af passagersæder. Hver række indeholder fire sæder. - - - 1st class rows (%1) - 1. klasse rækker (%1) - - - 2nd class rows: %1 - 2. klasse rækker: %1 - - - Seats: %1 - Sæder: %1 - - - Plane Seat Calculator - Flysædelommeregner - - - rows (%1) - rækker (%1) - - - 1st class rows: %1 - 1. klasse rækker: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Et fly har et antal rækker af passagersæder. Hver række indeholder fire sæder. - - - 2nd class rows (%1) - 2. klasse rækker (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_de.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_de.xlf deleted file mode 100644 index f06bc77253e..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_de.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Reihen: %1 - - - seats = - Sitze = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Ein Flugzeug hat zwei Sitze im Pilotenstand (für den Piloten und Co-Piloten) und eine Anzahl an Reihen mit Passagiersitzen der 1. und 2. Klasse. Jede 1.-Klasse-Reihe enthält vier Sitze. Jede 2.-Klasse-Reihe enthält fünf Sitze. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Erstelle eine Formel (unten), die die gesamte Anzahl an Sitzen im Flugzeug berechnet, wenn die Reihen (oben) geändert werden. - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Ein Flugzeug hat zwei Sitze im Pilotenstand (für den Piloten und Co-Piloten) und eine Anzahl an Reihen mit Passagiersitzen. Jede Reihe enthält vier Sitze. - - - 1st class rows (%1) - Reihen der 1. Klasse (%1) - - - 2nd class rows: %1 - Reihen der 2. Klasse: %1 - - - Seats: %1 - Sitze: %1 - - - Plane Seat Calculator - Flugzeugsitzrechner - - - rows (%1) - Reihen (%1) - - - 1st class rows: %1 - Reihen der 1. Klasse: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Ein Flugzeug hat eine Anzahl an Reihen mit Passagiersitzen. Jede Reihe enthält vier Sitze. - - - 2nd class rows (%1) - Reihen der 2. Klasse (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_el.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_el.xlf deleted file mode 100644 index 5acb291d2c3..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_el.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Σειρές: %1 - - - seats = - καθίσματα = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Ένα αεροπλάνο έχει δύο καθίσματα στον θάλαμο διακυβέρνησης (για τον κυβερνήτη και τον συγκυβερνήτη), καθώς και έναν αριθμό σειρών καθισμάτων για την 1η και 2η θέση. Κάθε σειρά της 1ης θέσης έχει τέσσερα καθίσματα και κάθε σειρά της 2ης θέσης έχει πέντε καθίσματα. - - - ? - ; - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Φτιάξε έναν τύπο (κάτω) που θα υπολογίζει τον συνολικό αριθμό καθισμάτων του αεροπλάνου καθώς αλλάζουν οι σειρές (πάνω). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Ένα αεροπλάνο έχει δύο καθίσματα στον θάλαμο διακυβέρνησης (για τον κυβερνήτη και τον συγκυβερνήτη), καθώς και έναν αριθμό από σειρές καθισμάτων επιβατών. Κάθε σειρά έχει τέσσερα καθίσματα. - - - 1st class rows (%1) - Σειρές 1ης θέσης (%1) - - - 2nd class rows: %1 - Σειρές 2ης θέσης: %1 - - - Seats: %1 - Καθίσματα: %1 - - - Plane Seat Calculator - Υπολογισμός Θέσεων Σε Αεροπλάνο - - - rows (%1) - σειρές (%1) - - - 1st class rows: %1 - Σειρές 1ης θέσης: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Ένα αεροπλάνο έχει έναν συγκεκριμένο αριθμό σειρών καθισμάτων επιβατών. Κάθε σειρά έχει τέσσερα καθίσματα. - - - 2nd class rows (%1) - Σειρές 2ης θέσης (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_en.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_en.xlf deleted file mode 100644 index e471a00085b..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_en.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Rows: %1 - - - seats = - seats = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - - - 1st class rows (%1) - 1st class rows (%1) - - - 2nd class rows: %1 - 2nd class rows: %1 - - - Seats: %1 - Seats: %1 - - - Plane Seat Calculator - Plane Seat Calculator - - - rows (%1) - rows (%1) - - - 1st class rows: %1 - 1st class rows: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - An airplane has a number of rows of passenger seats. Each row contains four seats. - - - 2nd class rows (%1) - 2nd class rows (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_es.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_es.xlf deleted file mode 100644 index e2022b5f123..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_es.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Filas: %1 - - - seats = - asientos = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Un avión tiene dos asientos en la cabina de vuelo (para el piloto y co-piloto), y un número de filas de asientos para pasajeros de primera y segunda clase. Cada fila de la primera clase contiene cuatro asientos. Cada fila de la segunda clase contiene cinco asientos. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Construir una fórmula (abajo) que calcule el número total de asientos en el avión cuando las filas sean cambiadas (arriba). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Un avión tiene dos asientos en la cabina de vuelo (para el piloto y co-piloto), y un número de filas de asientos de pasajeros. Cada fila contiene cuatro asientos. - - - 1st class rows (%1) - Filas de primera clase: (%1) - - - 2nd class rows: %1 - Filas de segunda clase: %1 - - - Seats: %1 - Asientos: %1 - - - Plane Seat Calculator - Calculadora de asientos de avión - - - rows (%1) - filas (%1) - - - 1st class rows: %1 - Filas de primera clase: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Un avión  tiene un número de filas de asientos de pasajeros. Cada fila contiene cuatro asientos. - - - 2nd class rows (%1) - Filas de segunda clase: (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_et.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_et.xlf deleted file mode 100644 index d88be0a9f73..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_et.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Ridu: %1 - - - seats = - istmete arv = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Lennuki kokpitis on kaks istet (üks kummalegi piloodile), mingi arv ridu 1. klassi reisijatele ja mingi arv ridu 2. klassi reisijatele. Igas 1. klassi reas on neli istet, igas 2. klassi reas viis istet. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Ehita plokkidest valem, mis arvutab istmete arvu lennukis õigesti sõltumata ridade arvust (seda saad muuta lennuki juures oleva liuguriga). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Lennuki kokpitis on kaks istet (üks kummalegi piloodile) ja mingi arv istemridu reisijatele. Igas reas on neli istet. - - - 1st class rows (%1) - 1. klassi ridu (%1) - - - 2nd class rows: %1 - 2. klassi ridu: %1 - - - Seats: %1 - Istmeid: %1 - - - Plane Seat Calculator - Lennukiistmete kalkulaator - - - rows (%1) - rows (%1) - - - 1st class rows: %1 - 1. klassi ridu: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Lennukis on reisijate istmed mitmes reas. Igas reas on neli istet. - - - 2nd class rows (%1) - 2. klassi ridu (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_fa.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_fa.xlf deleted file mode 100644 index 264ec310444..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_fa.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - ردیف: %1 - - - seats = - صندلی‌ها = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - یک هواپیما دو صندلی در کابین خلبان دارد (برای خلبان و کمک خلبان) و تهداد از صندلی‌ها مسافرین درجه یک و درجه دو. هر ردیف درجه یک شامل چهار صندلی است. هر ردیف درجه دو شامل پنج صندلی است. - - - ? - ؟ - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - یک فرمول بسازید (پایین) که تعداد کل صندلی‌های هواپیما با تغییر ردیف را حساب کند (بالا). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - یک هواپیما دو صندلی در عرشهٔ پرواز دارد (برای خلبان و کمک خلبان) و تعدادی صندلی مسافرین. هر ردیف شامل چهار صندلی است. - - - 1st class rows (%1) - اولین کلاس ردیف‌ها (%1) - - - 2nd class rows: %1 - دومین کلاس ردیف: %1 - - - Seats: %1 - صندلی‌ها: %1 - - - Plane Seat Calculator - محاسبه‌گر صندلی‌های هواپیما - - - rows (%1) - ردیف‌ها (%1) - - - 1st class rows: %1 - اولین ردیف کلاس: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - یک هواپیما تعداد از صندلی‌های مسافرین را دارد. هر ردیف شمال چهار صندلی است. - - - 2nd class rows (%1) - دومین کلاس ردیف‌ها (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_fr.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_fr.xlf deleted file mode 100644 index 9485da29bd3..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_fr.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Rangées : %1 - - - seats = - sièges = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Un avion a deux sièges dans la cabine de pilotage (pour le pilote et le copilote), et un certain nombre de rangées de sièges passager de première et seconde classes. Chaque rangée de première classe contient quatre sièges. Chaque rangée de seconde classe contient cinq sièges. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Construire une formule (ci-dessous) qui calcule le nombre total de sièges dans l’avion quand le nombre de rangées est modifié (ci-dessus). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Un avion a deux sièges dans le poste de pilotage (pour le pilote et le copilote), et un certain nombre de rangées de sièges passager. Chaque rangée contient quatre sièges. - - - 1st class rows (%1) - rangées de première classe (%1) - - - 2nd class rows: %1 - rangées de seconde classe : %1 - - - Seats: %1 - Sièges : %1 - - - Plane Seat Calculator - Calculateur de sièges d’avion - - - rows (%1) - rangées (%1) - - - 1st class rows: %1 - rangées de première classe : %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Un avion a un nombre de rangées de sièges passager. Chaque rangée contient quatre sièges. - - - 2nd class rows (%1) - rangées de seconde classe (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_he.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_he.xlf deleted file mode 100644 index 55ac148c5ae..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_he.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - שורות: %1 - - - seats = - מושבים = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - במטוס יש שני מושבים עבור הצוות (בשביל הטייס וטייס המשנה), ומספר שורות מושבים במחלקת הנוסעים הראשונה ובמחלקת הנוסעים השנייה. כל שורה במחלקה הראשונה מכילה ארבעה מושבים. כל שורה במחלקה השנייה מכילה חמישה מושבים. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - בנה נוסחה (למטה) אשר תחשב את סך כל המושבים במטוס בהתאם לשינוי מספר השורות (למעלה). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - במטוס יש שני מושבים עבור הצוות (בשביל הטייס וטייס המשנה), ומספר שורות עם מושבי נוסעים. בכל שורה יש ארבעה מושבים. - - - 1st class rows (%1) - שורות במחלקה ראשונה (%1) - - - 2nd class rows: %1 - שורות במחלקה שנייה: %1 - - - Seats: %1 - מושבים: %1 - - - Plane Seat Calculator - מחשבון מושב במטוס - - - rows (%1) - שורות (%1) - - - 1st class rows: %1 - שורות במחלקה ראשונה: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - במטוס יש מספר שורות עם מושבי נוסעים. בכל שורה יש ארבעה מושבים. - - - 2nd class rows (%1) - שורות במחלקה שנייה: (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_hrx.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_hrx.xlf deleted file mode 100644 index 263d3050749..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_hrx.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Reihe: %1 - - - seats = - Sitze = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - En Fluchzeich hot zwooi Sitze im Pilotstand (für den Pilot und Co-Pilot) und en Oonzohl an Reihe mit Passagiersitze der 1. und 2. Klasse. Jede 1.-Klasse-Reih enthält vier Sitze. Jede 2.-Klasse-Reih enthält fünf Sitze. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Erstell en Formel (unne), die die gesamte Oonzohl an Sitze im Fluchzeich berechnet, wenn die Reihe (uwe) geännert sin. - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - En Fluchzeich hot zwooi Sitze im Pilotestand (für den Pilot und Co-Pilot) und en Oonzohl an Reihe mit Passagiersitze. Jede Reih enthält vier Sitze. - - - 1st class rows (%1) - Reihe von der 1. Klasse (%1) - - - 2nd class rows: %1 - Reihe von der 2. Klasse: %1 - - - Seats: %1 - Sitz: %1 - - - Plane Seat Calculator - Fluchzeichsitzrechner - - - rows (%1) - Reihe (%1) - - - 1st class rows: %1 - Reihe von der 1. Klasse: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - En Fluchzeich hot en Oonzohl an Reihe mit Passagiersitze. Jede Reih enthält vier Sitze. - - - 2nd class rows (%1) - Reihe von der 2. Klasse (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_hu.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_hu.xlf deleted file mode 100644 index c44d1aa9d4a..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_hu.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Sorok száma: %1 - - - seats = - Ülések száma = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Egy repülőgépnek 2 ülése van a pilótafülkében (a pilótának és a másodpilótának), az utasok 1. és 2. osztályon utazhatnak. Az 1. osztályon négy szék van egy sorban. A 2. osztályon öt szék van egy sorban. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Készítsd el a képletet (lent) amivel kiszámolható, hogy hány ülés van összesen a repülőgépen annak függvényében, ahogy (fent) állítod a sorok számát. - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Egy repülőgépnek 2 ülése van a pilótafülkében (a pilótának és a másodpilótának), az utasok több sorban ülnek az utastérben. Az utastér minden sorában négy szék van. - - - 1st class rows (%1) - 1. osztály sorai (%1) - - - 2nd class rows: %1 - 2. osztály: %1 sor - - - Seats: %1 - Ülések száma összesen: %1 - - - Plane Seat Calculator - Repülőgép alkalmazás - - - rows (%1) - Sorok száma (%1) - - - 1st class rows: %1 - 1. osztály: %1 sor - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Egy repülőgépen az utasok több sorban ülnek az utastérben. Az utastér minden sorában négy szék van. - - - 2nd class rows (%1) - 2. osztály sorai (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ia.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_ia.xlf deleted file mode 100644 index 83ae2c6d2f8..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ia.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Filas: %1 - - - seats = - sedes = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Un avion ha duo sedes in le cabina (pro le pilota e le copilota) e un numero de filas de sedes pro passageros del prime classe e del secunde classes. Cata fila del prime classe contine quatro sedes. Cata fila del secunde classe contine cinque sedes. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Construe un formula (ci infra) que calcula le numero total de sedes in le avion quando le numero de filas es cambiate (ci supra). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Un avion ha duo sedes in le cabina (pro le pilota e le copilota) e un numero de filas de sedes pro passageros. Cata fila contine quatro sedes. - - - 1st class rows (%1) - filas de prime classe (%1) - - - 2nd class rows: %1 - Filas de secunde classe: %1 - - - Seats: %1 - Sedes: %1 - - - Plane Seat Calculator - Calculator de sedias de avion - - - rows (%1) - filas (%1) - - - 1st class rows: %1 - Filas de prime classe: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Un avion ha un numero de filas de sedes pro passageros. Cata fila contine quatro sedes. - - - 2nd class rows (%1) - filas de secunde classe (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_is.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_is.xlf deleted file mode 100644 index 3810f4b34c8..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_is.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Raðir: %1 - - - seats = - sæti = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Flugvél er með tvö sæti í stjórnklefa (fyrir flugmanninn og aðstoðarflugmanninn) og einhvern fjölda sætaraða fyrir farþega á 1. og 2. farrými. Hver sætaröð á 1. farrými hefur fjögur sæti. Hver sætaröð á 2. farrými hefur fimm sæti. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Búðu til formúlu (hér fyrir neðan) sem reiknar heildarfjölda sæta í flugvélinni eftir því sem röðunum er breytt (hér fyrir ofan). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Flugvél er með tvö sæti í stjórnklefa (fyrir flugmanninn og aðstoðarflugmanninn) og einhvern fjölda sætaraða fyrir farþega. Hver sætaröð hefur fjögur sæti. - - - 1st class rows (%1) - raðir 1. farrými (%1) - - - 2nd class rows: %1 - Raðir 2. farrými: %1 - - - Seats: %1 - Sæti: %1 - - - Plane Seat Calculator - Flugsætareiknir - - - rows (%1) - raðir (%1) - - - 1st class rows: %1 - Raðir 1. farrými: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Flugvél er með einhvern fjölda sætaraða fyrir farþega. Í hverri röð eru fjögur sæti. - - - 2nd class rows (%1) - raðir 2. farrými (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_it.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_it.xlf deleted file mode 100644 index 27bad0dcffd..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_it.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - File: %1 - - - seats = - sedili = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Un aereo ha due posti nella cabina di pilotaggio (per il pilota e il co-pilota), e un numero di file in prima e seconda classe, con i posti a sedere dei passeggeri. Ogni fila della prima classe contiene quattro posti. Quelle invece della seconda classe, ne contengono cinque. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Costruisci una formula (sotto) che calcola il numero totale di posti a sedere su un aeroplano, così come cambiano le file di posti (sopra). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Un aeroplano ha due posti a sedere nella cabina di pilotaggio (per il pilota e co-pilota), e un numero di file con i posti a sedere dei passeggeri. Ogni fila contiene quattro posti. - - - 1st class rows (%1) - file 1ª classe (%1) - - - 2nd class rows: %1 - File 2ª classe: %1 - - - Seats: %1 - Sedili: %1 - - - Plane Seat Calculator - Calcolo posti aereo - - - rows (%1) - file (%1) - - - 1st class rows: %1 - File 1ª classe: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Un aeroplano ha un numero di file contenenti i posti a sedere dei passeggeri. Ogni fila, contiene quattro posti a sedere. - - - 2nd class rows (%1) - File 2ª classe (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ja.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_ja.xlf deleted file mode 100644 index b04624a2719..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ja.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - 列の数: %1 - - - seats = - 座席の数 = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - 飛行機には、操縦室の 2 つの座席 (操縦士と副操縦士) と、ファーストクラスとセカンドクラスの乗客の座席の列があります。それぞれの列に、ファーストクラスでは 4 つの座席、セカンドクラスでは 5 つの座席があります。 - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - 飛行機の座席の数を計算する式を、上で列の数を変更しても正しくなるように、下に入力してください。 - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - 飛行機には、操縦室の 2 つの座席 (操縦士と副操縦士) と、乗客の座席の列があります。それぞれの列に 4 つの座席があります。 - - - 1st class rows (%1) - ファーストクラスの列数 (%1) - - - 2nd class rows: %1 - セカンドクラスの列数: %1 - - - Seats: %1 - 座席の数: %1 - - - Plane Seat Calculator - 飛行機座席計算機 - - - rows (%1) - 列の数 (%1) - - - 1st class rows: %1 - ファーストクラスの列数: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - 飛行機に乗客の座席の列があります。それぞれの列に 4 つの座席があります。 - - - 2nd class rows (%1) - セカンドクラスの列数 (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ko.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_ko.xlf deleted file mode 100644 index 07e23288e66..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ko.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - 행 수: %1 - - - seats = - 좌석수 = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - 비행기는 비행 갑판(조종사와 부조종사용)에서 좌석 두 개가 있고, 1등석과 2등석 승객 좌석의 행 수가 있습니다. 각 1등석 행에는 시트 네 개가 포함되어 있습니다. 각 2등석 행에는 시트 다섯 개가 포함되어 있습니다. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - 행이 바뀐(위) 비행기에 좌석의 총 수를 계산하는 공식(아래)을 구축하세요. - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - 비행기는 비행 갑판(조종사와 부조종사용)에서 좌석 두 개가 있고, 승객 좌석의 행 수가 있습니다. 각 행에는 시트 네 개가 포함되어 있습니다. - - - 1st class rows (%1) - 1등석 행 수 (%1) - - - 2nd class rows: %1 - 2등석 행 수: %1 - - - Seats: %1 - 좌석 수: %1 - - - Plane Seat Calculator - 비행기 좌석 계산기 - - - rows (%1) - 행 수 (%1) - - - 1st class rows: %1 - 1등석 행 수: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - 비행기는 승객 좌석의 행 수가 있습니다. 각 행에는 시트 네 개가 포함되어 있습니다. - - - 2nd class rows (%1) - 2등석 행 수 (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ms.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_ms.xlf deleted file mode 100644 index c34f084a3d4..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ms.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Baris: %1 - - - seats = - tempat duduk = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Sebuah kapal terbang mempunyai tempat duduk di kokpit (untuk juruterbang dan pembantunya) dan sebilangan baris tempat duduk penumpang kelas pertama dan kelas kedua. Setiap baris kelas pertama mengandungi empat tempat duduk. Setiap baris kelas pertama mengandungi lima tempat duduk. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Wujudkan formula (di bawah) yang mengira jumlah tempat duduk di dalam kapal terbang sedangkan baris-barisnya diubah (di atas). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Sebuah kapal terbang mempunyai tempat duduk di kokpit (untuk juruterbang dan pembantunya) dan sebilangan baris tempat duduk penumpang. Setiap baris mengandungi empat tempat duduk. - - - 1st class rows (%1) - baris kelas pertama (%1) - - - 2nd class rows: %1 - Baris kelas kedua: %1 - - - Seats: %1 - Tempat duduk: %1 - - - Plane Seat Calculator - Pengira Tempat Duduk Kapal Terbang - - - rows (%1) - baris (%1) - - - 1st class rows: %1 - Baris kelas pertama: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Sebuah kapal terbang mempunyai sebilangan baris tempat duduk penumpang. Setiap baris mengandungi empat tempat duduk. - - - 2nd class rows (%1) - baris kelas kedua (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_nb.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_nb.xlf deleted file mode 100644 index 99c9c6a9971..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_nb.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Rader: %1 - - - seats = - seter = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Et fly har to seter i cockpit (for piloten og andrepiloten), og et antall rader med passasjerseter på første og andre klasse. Hver av radene på første klasse har fire seter. Hver av radene på andre klasse har fem seter. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Bygg en formel (under) som beregner det totale antall seter på flyet etter hvert som radene endres (over). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Et fly har to seter i cockpit (for piloten og andrepiloten), og et antall rader med passasjerseter. Hver rad inneholder fire seter. - - - 1st class rows (%1) - Rader i første klasse (%1) - - - 2nd class rows: %1 - Rader i andre klasse: %1 - - - Seats: %1 - Seter: %1 - - - Plane Seat Calculator - Flysetekalkulator - - - rows (%1) - rader (%1) - - - 1st class rows: %1 - Rader i første klasse: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Et fly har et antall rader med passasjerseter. Hver rad inneholder fire seter. - - - 2nd class rows (%1) - Rader i andre klasse (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_nl.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_nl.xlf deleted file mode 100644 index 6f36fa026c7..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_nl.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Rijen: %1 - - - seats = - stoelen= - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Een vliegtuig heeft twee stoelen in de cockpit (voor de piloot en de copiloot) en een aantal rijen voor 1e klasse en 2e klasse passagiers. Iedere rij in de 1e klasse heeft vier stoelen. Iedere rij in de 2e klasse heeft vijf stoelen. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Maak hieronder een formule die het totale aantal stoelen in het vliegtuig berekent als het aantal rijen hierboven wordt aangepast. - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Een vliegtuig heeft twee stoelen in de cockpit (voor de piloot en de copiloot) en een aantal rijen met stoelen voor passagiers. Iedere rij bevat vier stoelen. - - - 1st class rows (%1) - Rijen 1e klas (%1) - - - 2nd class rows: %1 - Rijen 2e klas: %1 - - - Seats: %1 - Zitplaatsen: %1 - - - Plane Seat Calculator - Vliegtuigstoelencalculator - - - rows (%1) - rijen (%1) - - - 1st class rows: %1 - Rijen 1e klas: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Een vliegtuig heeft een aantal rijen met stoelen. Iedere rij heeft vier stoelen. - - - 2nd class rows (%1) - Rijen 2e klas (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_pl.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_pl.xlf deleted file mode 100644 index 4c8b044e2c8..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_pl.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Rzędów: %1 - - - seats = - siedzeń = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Samolot ma dwa miejsca w kabinie pilotów (dla pierwszego i drugiego pilota) oraz rzędy siedzeń dla pasażerów pierwszej i drugiej klasy. Każdy rząd pierwszej klasy składa się z czterech siedzeń. Każdy rząd drugiej klasy składa się z pięciu siedzeń. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Zbuduj wzór (poniżej), który pozwala obliczyć łączną liczbę siedzeń w samolocie w funkcji zmieniającej się liczby rzędów (powyżej). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Samolot ma dwa miejsca w kabinie pilotów (dla pierwszego i drugiego pilota) oraz rzędy siedzeń dla pasażerów. Każdy taki rząd składa się z czterech siedzeń. - - - 1st class rows (%1) - Rzędów w pierwszej klasie (%1) - - - 2nd class rows: %1 - Rzędów w drugiej klasie: %1 - - - Seats: %1 - Siedzeń: %1 - - - Plane Seat Calculator - Kalkulator miejsc w samolocie. - - - rows (%1) - rzędów (%1) - - - 1st class rows: %1 - Rzędów w pierwszej klasie: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Samolot ma kilka rzędów siedzeń pasażerów. Każdy rząd zawiera cztery miejsca. - - - 2nd class rows (%1) - Rzędów w drugiej klasie (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_pms.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_pms.xlf deleted file mode 100644 index 0fef9121763..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_pms.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Linie: %1 - - - seats = - sedij = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - N'avion a l'ha doi sedij ant la cabin-a ëd pilotage (për ël pilòta e ël cò-pilòta) e un chèich nùmer ëd file ëd sedij pr'ij passagé ëd prima e sconda classa. Minca fila ëd prima classa a conten quatr sedij. Minca fila ëd seconda classa a conten sinch sedij. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Fabriché na fórmola (sì-sota) ch'a fa 'l cont dël nùmer total ëd sedij ant l'avion cand che ël nùmer dle file a cangia (sì-dzora). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - N'avion a l'ha doi sedij ant la cabin-a ëd pilotage (për ël pilòta e ël cò-pilòta), e un chèich nùmer ëd file ëd sedij pr'ij passagé. Minca fila a conten quatr sedij. - - - 1st class rows (%1) - linie ëd prima classa (%1) - - - 2nd class rows: %1 - linie ëd seconda classa: %1 - - - Seats: %1 - Sedij: %1 - - - Plane Seat Calculator - Calcolator ëd sedij d'avion - - - rows (%1) - linie (%1) - - - 1st class rows: %1 - linie ëd prima classa: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - N'avion a l'ha un nùmer ëd file ëd sedij da passëgé. Minca fila a l'ha quatr sedij. - - - 2nd class rows (%1) - linie ëd seconda classa (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_pt-br.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_pt-br.xlf deleted file mode 100644 index 7bdd9ccff99..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_pt-br.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Filas: %1 - - - seats = - assentos = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Um avião tem dois assentos na cabine de comando (para o piloto e o copiloto) e um número de filas de assentos na primeira e na segunda classe. Cada fila da primeira classe contém quatro assentos. Cada fila da segunda classe contém cinco assentos. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Elabore uma fórmula (abaixo) que calcule o número total de assentos no avião a medida que as filas são alteradas (acima). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Um avião tem dois assentos na cabine de comando (para o piloto e o copiloto) e um número de filas de assentos para os passageiros. Cada fila contém quatro assentos. - - - 1st class rows (%1) - filas na primeira classe (%1) - - - 2nd class rows: %1 - filas na segunda classe: %1 - - - Seats: %1 - Assentos: %1 - - - Plane Seat Calculator - Calculadora de Assentos em Avião - - - rows (%1) - filas (%1) - - - 1st class rows: %1 - filas na primeira classe: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Um avião tem um número de filas de assentos para os passageiros. Cada fila contém quatro assentos. - - - 2nd class rows (%1) - filas na segunda classe (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ro.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_ro.xlf deleted file mode 100644 index 614a3bda28b..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ro.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Rânduri: %1 - - - seats = - scaune = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Un avion are două scaune în carlingă (pentru pilot și copilot) și un număr de rânduri cu scaune de clasa I și clasa a II-a pentru pasageri. Fiecare rând de clasa I conține patru scaune. Fiecare rând de clasa a II-a conține cinci scaune. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Construiește o formulă (mai jos) care calculează numărul total de locuri dintr-un avion în timp ce rândurile se schimbă (mai sus). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Un avion are două scaune în carlingă (pentru pilot și copilot) și un număr de rânduri cu scaune pentru pasageri. Fiecare rând conține patru scaune. - - - 1st class rows (%1) - rânduri de clasa I (%1) - - - 2nd class rows: %1 - rânduri de clasa a II-a: %1 - - - Seats: %1 - Scaune: %1 - - - Plane Seat Calculator - Calculator pentru locurile dintr-un avion - - - rows (%1) - rânduri (%1) - - - 1st class rows: %1 - rânduri de clasa I: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Un avion are un număr de rânduri cu scaune pentru pasageri. Fiecare rând conține patru scaune. - - - 2nd class rows (%1) - rânduri de clasa a II-a (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ru.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_ru.xlf deleted file mode 100644 index d25b25458d7..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_ru.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Рядов: %1 - - - seats = - места = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - В самолёте 2 места для пилота и его помощника, несколько рядов с пассажирскими местами первого класса, а также несколько рядов с пассажирскими местами второго класса. В каждом ряду первого класса 4 места. В каждом ряду второго класса 5 мест. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Постройте формулу в области ниже, которая поможет рассчитать общее количество мест в самолёте (как на рисунке выше). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - В самолёте 2 места для пилота и его помощника, а также несколько рядов с пассажирскими местами. В каждом ряду 4 места. - - - 1st class rows (%1) - ряды 1-го класса (%1) - - - 2nd class rows: %1 - Рядов 2-го класса: %1 - - - Seats: %1 - Мест: %1 - - - Plane Seat Calculator - Калькулятор посадочных мест в самолёте - - - rows (%1) - ряды (%1) - - - 1st class rows: %1 - Рядов 1-го класса: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - В самолёте несколько рядов с пассажирскими местами. В каждом ряду 4 места. - - - 2nd class rows (%1) - ряды 2-го класса (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_sc.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_sc.xlf deleted file mode 100644 index 63281235617..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_sc.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Fileras: %1 - - - seats = - cadironis = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Unu aparèchiu tenit duus cadironis in sa cabina de cumandu (po su pilota e su co-pilota), e unas cantu fileras de cadironis po passigeris de prima classi e de segunda classi. Dònnia filera de prima classi tenit cuatru cadironis. Dònnia filera de segunda classi tenit cincu cadironis. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Cuncorda una formula (innoi asuta) chi cumpudit su numeru totali de postus a setzi in s'aparechiu, a segunda de comenti mudant is fileras de postus (innoi in susu) - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Unu aparèchiu tenit duus cadironis in sa cabina de cumandu (po su pilota e su co-pilota), e unas cantu fileras de cadironis po passigeris. Dònnia filera tenit cuatru cadironis. - - - 1st class rows (%1) - fileras de primu classi (%1) - - - 2nd class rows: %1 - fileras de segunda classi: %1 - - - Seats: %1 - Cadironis: %1 - - - Plane Seat Calculator - Fai su contu de is cadironis de unu aparèchiu - - - rows (%1) - fileras (%1) - - - 1st class rows: %1 - fileras de primu classi: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Unu aparèchiu tenit unas cantu fileras de cadironis po passigeris. Dònnia filera tenit cuatru cadironis. - - - 2nd class rows (%1) - fileras de segunda classi (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_sv.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_sv.xlf deleted file mode 100644 index f3d836fba33..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_sv.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Rader: %1 - - - seats = - säten = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Ett flygplan har två säten i cockpiten (ett för piloten och ett för andrepiloten) och ett antal rader med passagerarsäten i första och andra klass. Varje rad i första klass innehåller fyra säten. Varje rad i andra klass innehåller fem säten. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Bygg en formel (nedan) som beräknar det totala antalet säten på flygplanet när raderna ändras (ovan). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Ett flygplan har två säten i cockpiten (ett för piloten och ett för andrepiloten) och ett antal rader med passagerarsäten. Varje rad innehåller fyra säten. - - - 1st class rows (%1) - Rader i första klass (%1) - - - 2nd class rows: %1 - Rader i andra klass: %1 - - - Seats: %1 - Säten: %1 - - - Plane Seat Calculator - Plansäteskalkylator - - - rows (%1) - rader (%1) - - - 1st class rows: %1 - Rader i första klass: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Ett flygplan har ett antal rader med passagerarsäten. Varje rad innehåller fyra säten. - - - 2nd class rows (%1) - Rader i andra klass (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_th.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_th.xlf deleted file mode 100644 index 0967d4d199f..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_th.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - %1 แถว - - - seats = - จำนวนที่นั่ง = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - ภายในเครื่องบินจะมีที่นั่งนักบินอยู่ 2 ที่ (สำหรับนักบิน และผู้ช่วยนักบิน) และจะมีแถวที่นั่งสำหรับผู้โดยสาร "ชั้นเฟิร์สคลาส" และ "ชั้นธุรกิจ" อยู่จำนวนหนึ่ง โดยในชั้นเฟิร์สคลาสจะมีแถวละ 4 ที่นั่ง ส่วนในชั้นธุรกิจจะมีแถวละ 5 ที่นั่ง - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - สร้างสูตรคำนวณ (ด้านล่าง) เพื่อคำนวณหาจำนวนที่นั่งทั้งหมดบนเครื่องบิน ตามจำนวนแถวที่เปลี่ยนไป (ด้านบน) - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - ภายในเครื่องบินจะมีที่นั่งนักบินอยู่ 2 ที่ (สำหรับนักบิน และผู้ช่วยนักบิน) และมีแถวที่นั่งผู้โดยสารอยู่จำนวนหนึ่ง ในแต่ละแถวจะมี 4 ที่นั่ง - - - 1st class rows (%1) - จำนวนแถวชั้นเฟิร์สคลาส (%1) - - - 2nd class rows: %1 - ชั้นธุรกิจ %1 แถว - - - Seats: %1 - คำนวณได้ทั้งหมด %1 ที่นั่ง - - - Plane Seat Calculator - ระบบคำนวณที่นั่งบนเครื่องบิน - - - rows (%1) - จำนวนแถว (%1) - - - 1st class rows: %1 - ชั้นเฟิร์สคลาส %1 แถว - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - ภายในเครื่องบินประกอบไปด้วยแถวของที่นั่งผู้โดยสาร ในแต่ละแถวจะมี 4 ที่นั่ง - - - 2nd class rows (%1) - จำนวนแถวชั้นธุรกิจ (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_tr.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_tr.xlf deleted file mode 100644 index 678541a32d9..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_tr.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Sıralar: %1 - - - seats = - koltuklar = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Bir uçağın uçuş güvertesinde iki koltuğu (pilot ve yardımcı pilot için), ve belirli sayıda birinci sınıf ve ikinci sınıf yolcu koltuğu sırası vardır. Her birinci sınıf sıra dört koltuk içerir. Her ikinci sınıf sıra beş koltuk içerir. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Sıralar(üstte) değiştikçe uçaktaki toplam koltuk sayısını hesaplayan bir formül(altta) oluşturun. - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Bir uçağın uçuş güvertesinde iki koltuğu (pilot ve yardımcı pilot için), ve belirli sayıda koltuk sırası vardır. Her sıra dört koltuk içerir. - - - 1st class rows (%1) - Birinci sınıf sıralar (%1) - - - 2nd class rows: %1 - İkinci sınıf sıralar: %1 - - - Seats: %1 - Koltuklar: %1 - - - Plane Seat Calculator - Uçak Koltuğu Hesaplayıcı - - - rows (%1) - sıralar (%1) - - - 1st class rows: %1 - Birinci sınıf sıralar: (%1) - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Bir uçağın belirli sayıda koltuk sırası vardır. Her sıra dört koltuk içerir. - - - 2nd class rows (%1) - İkinci sınıf sıralar (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_uk.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_uk.xlf deleted file mode 100644 index d5e7682a58b..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_uk.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Рядки: %1 - - - seats = - місць= - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Літак має два місця в кабіні екіпажу (пілот і другий пілот), і кілька рядів 1-го класу 2-го класу пасажирських місць. Кожний ряд 1-го класу містить чотири місця. Кожен ряд 2-го класу містить п'ять місць. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Побудувати формулу (нижче), яка обчислює кількість місць на літаку при зміні рядків (див. вище). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Літак має два місця в кабіні екіпажу (пілот і другий пілот), і кілька рядів пасажирських сидінь. Кожен рядок містить чотири місця. - - - 1st class rows (%1) - рядів 1-го класу (%1) - - - 2nd class rows: %1 - рядів 2-го класу: %1 - - - Seats: %1 - Місць: %1 - - - Plane Seat Calculator - Калькулятор місць у літаку - - - rows (%1) - рядки (%1) - - - 1st class rows: %1 - рядів 1-го класу: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Літак має кілька рядів пасажирських сидінь. Кожен ряд містить чотири місця. - - - 2nd class rows (%1) - рядів 2-го класу (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_vi.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_vi.xlf deleted file mode 100644 index 1f4ef6fcf07..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_vi.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - Số hàng ghế: %1 - - - seats = - Tính số chỗ ngồi = - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - Một chiếc máy bay này có hai chỗ ngồi ở sàn (cho phi công trưởng và phi công phó), và một số hàng ghế hạng 1 và hạng 2. Mỗi hàng hạng 1 có bốn chỗ ngồi. Mỗi hàng hạng 2 có năm chỗ ngồi. - - - ? - ? - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - Dưới đây hãy tạo công thức tính số chỗ ngồi trên máy bay để nó thay đổi tùy theo số lượng hàng ghế (hình trên). - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - Một máy bay có hai ghế trong buồng lái (dành cho phi công trưởng và phi công phụ), và một loạt hàng ghế cho hành khách. Mỗi hàng có bốn ghế (bốn chỗ ngồi). - - - 1st class rows (%1) - số hàng hạng nhất (%1) - - - 2nd class rows: %1 - Hàng hạng hai: %1 - - - Seats: %1 - Số chỗ ngồi: %1 - - - Plane Seat Calculator - Máy bay ghế máy tính - - - rows (%1) - đếm số hàng ghế (%1) - - - 1st class rows: %1 - Hàng hạng nhất: %1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - Máy bay có một số hàng ghế hành khách. Mỗi hàng có bốn chỗ ngồi. - - - 2nd class rows (%1) - số hàng hạng hai (%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_zh-hans.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_zh-hans.xlf deleted file mode 100644 index 2cbb7e858f5..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_zh-hans.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - 行:%1 - - - seats = - 座位= - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - 一架飞机除了有两个座位供正副驾驶员,还有一定量行数的头等及经济乘客座位。头等每行共四座,经济每行共五座。 - - - ? - - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - 于下方写出一条公式以计算飞机上的座位总数。 - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - 一架飞机除了有两个座位供正副驾驶员,还有一定量行数的乘客座位。每行共四座。 - - - 1st class rows (%1) - 头等行(%1) - - - 2nd class rows: %1 - 经济等行:%1 - - - Seats: %1 - 座位:%1 - - - Plane Seat Calculator - 飞机座位计算器 - - - rows (%1) - 行 (%1) - - - 1st class rows: %1 - 头等行:%1 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - 一架飞机有一定量行数的乘客座位,每行共四座。 - - - 2nd class rows (%1) - 经济等行(%1) - - - - diff --git a/trunk/web/blockly/demos/plane/xlf/translated_msgs_zh-hant.xlf b/trunk/web/blockly/demos/plane/xlf/translated_msgs_zh-hant.xlf deleted file mode 100644 index 2dadf6d4e7c..00000000000 --- a/trunk/web/blockly/demos/plane/xlf/translated_msgs_zh-hant.xlf +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - Rows: %1 - 排:%1 - - - seats = - 座位= - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of 1st class and 2nd class passenger seats. Each 1st class row contains four seats. Each 2nd class row contains five seats. - 一架飛機除了有兩個座位供正副機師,還有一定量行數的頭等及經濟乘客座位。頭等艙每排都包含四個席位,經濟艙每排都包含五個席位。。 - - - ? - - - - Build a formula (below) that calculates the total number of seats on the airplane as the rows are changed (above). - 於下方寫出一條公式以計算飛機上的座位總數。 - - - An airplane has two seats in the flight deck (for the pilot and co-pilot), and a number of rows of passenger seats. Each row contains four seats. - 一架飛機除了有兩個座位供正副機師,還有一定量行數的乘客座位。每排都包含四個席位。 - - - 1st class rows (%1) - 頭等艙(%1) - - - 2nd class rows: %1 - 經濟艙:%1 排 - - - Seats: %1 - 座位:%1 - - - Plane Seat Calculator - 飛機座位計算器 - - - rows (%1) - 排(%1) - - - 1st class rows: %1 - 頭等艙:%1 排 - - - An airplane has a number of rows of passenger seats. Each row contains four seats. - 一架飛機有一定量行數的乘客座位,每排都包含四個席位。 - - - 2nd class rows (%1) - 經濟艙(%1) - - - - diff --git a/trunk/web/blockly/demos/resizable/icon.png b/trunk/web/blockly/demos/resizable/icon.png deleted file mode 100644 index 4355275854b..00000000000 Binary files a/trunk/web/blockly/demos/resizable/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/resizable/index.html b/trunk/web/blockly/demos/resizable/index.html deleted file mode 100644 index e2ee1e06d76..00000000000 --- a/trunk/web/blockly/demos/resizable/index.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - Blockly Demo: Resizable Blockly (Part 1) - - - - - - - - - - -
-

Blockly > - Demos > Resizable Blockly (Part 1)

- -

The first step in creating a resizable Blockly workspace is to use - CSS or tables to create an area for it. - Next, inject Blockly over that area.

- -

→ More info on injecting resizable Blockly

-
- Blockly will be positioned here. -
- - diff --git a/trunk/web/blockly/demos/resizable/overlay.html b/trunk/web/blockly/demos/resizable/overlay.html deleted file mode 100644 index 2d9f41f9bb7..00000000000 --- a/trunk/web/blockly/demos/resizable/overlay.html +++ /dev/null @@ -1,93 +0,0 @@ - - - - - Blockly Demo: Resizable Blockly (Part 2) - - - - - - - - - - - - - -
-

Blockly > - Demos > Resizable Blockly (Part 2)

- -

- Once an area is defined, Blockly can be - injected and positioned over the area. - A resize handler keeps it in position as the page changes. -

- -

→ More info on injecting resizable Blockly

-
-
- -
- - - - - - diff --git a/trunk/web/blockly/demos/rtl/icon.png b/trunk/web/blockly/demos/rtl/icon.png deleted file mode 100644 index e177e32a307..00000000000 Binary files a/trunk/web/blockly/demos/rtl/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/rtl/index.html b/trunk/web/blockly/demos/rtl/index.html deleted file mode 100644 index fd84febd281..00000000000 --- a/trunk/web/blockly/demos/rtl/index.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - Blockly Demo: RTL - - - - - - - -

Blockly > - Demos > Right-to-Left

- -
- - - - - - diff --git a/trunk/web/blockly/demos/storage/icon.png b/trunk/web/blockly/demos/storage/icon.png deleted file mode 100644 index b8c50b245ac..00000000000 Binary files a/trunk/web/blockly/demos/storage/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/storage/index.html b/trunk/web/blockly/demos/storage/index.html deleted file mode 100644 index 57cad33042f..00000000000 --- a/trunk/web/blockly/demos/storage/index.html +++ /dev/null @@ -1,94 +0,0 @@ - - - - - Blockly Demo: Cloud Storage - - - - - - - -

Blockly > - Demos > Cloud Storage

- -

This is a simple demo of cloud storage using App Engine.

- - - -

→ More info on Cloud Storage

- -

- -

- -
- - - - - - - diff --git a/trunk/web/blockly/demos/toolbox/icon.png b/trunk/web/blockly/demos/toolbox/icon.png deleted file mode 100644 index 336f390289d..00000000000 Binary files a/trunk/web/blockly/demos/toolbox/icon.png and /dev/null differ diff --git a/trunk/web/blockly/demos/toolbox/index.html b/trunk/web/blockly/demos/toolbox/index.html deleted file mode 100644 index 4e81c02ebe2..00000000000 --- a/trunk/web/blockly/demos/toolbox/index.html +++ /dev/null @@ -1,343 +0,0 @@ - - - - - Blockly Demo: Toolbox - - - - - - -

Blockly > - Demos > Toolbox

- -

This is a demo of a complex category structure for the toolbox.

- -

→ More info on the Toolbox

- -
- - - - - - -