├── .gitignore ├── COPYING ├── README.md ├── appengine ├── README.txt ├── app.yaml ├── closure-library-read-only ├── favicon.ico ├── index.yaml ├── index_redirect.py ├── redirect.html ├── report.py ├── robots.txt ├── storage.js └── storage.py ├── apps ├── code │ ├── block.js │ ├── blocks-bit.js │ ├── blocks-colours.js │ ├── blocks-disk.js │ ├── blocks-fs.js │ ├── blocks-help.js │ ├── blocks-keys.js │ ├── blocks-old.js │ ├── blocks-os.js │ ├── blocks-paintutils.js │ ├── blocks-peripheral.js │ ├── blocks-rednet.js │ ├── blocks-redstone.js │ ├── blocks-shell.js │ ├── blocks-table.js │ ├── blocks-term.js │ ├── blocks-test.js │ ├── blocks-textutils.js │ ├── blocks-turtle.js │ ├── blocks-vector.js │ ├── code.js │ ├── dependent_input_block.js │ ├── icons.png │ ├── index.html │ ├── side_input_block.js │ ├── style.css │ ├── value_block.js │ └── var_args_block.js ├── common.css ├── common.js ├── lang-lua.js ├── prettify.css └── prettify.js ├── blockly_compressed.js ├── blockly_uncompressed.js ├── blocks ├── colour.js ├── lists.js ├── logic.js ├── loops.js ├── math.js ├── procedures.js ├── text.js └── variables.js ├── blocks_compressed.js ├── build.py ├── core ├── block.js ├── block_svg.js ├── blockly.js ├── blocks.js ├── bubble.js ├── comment.js ├── connection.js ├── contextmenu.js ├── css.js ├── field.js ├── field_angle.js ├── field_checkbox.js ├── field_colour.js ├── field_dropdown.js ├── field_image.js ├── field_label.js ├── field_textinput.js ├── field_variable.js ├── flyout.js ├── generator.js ├── icon.js ├── inject.js ├── input.js ├── msg.js ├── mutator.js ├── names.js ├── procedures.js ├── scrollbar.js ├── toolbox.js ├── tooltip.js ├── trashcan.js ├── utils.js ├── variables.js ├── warning.js ├── widgetdiv.js ├── workspace.js └── xml.js ├── generators ├── lua.js └── lua │ ├── colour.js │ ├── lists.js │ ├── logic.js │ ├── loops.js │ ├── math.js │ ├── procedures.js │ ├── text.js │ └── variables.js ├── lua_compressed.js ├── media ├── 1x1.gif ├── click.mp3 ├── click.ogg ├── click.wav ├── delete.mp3 ├── delete.ogg ├── delete.wav ├── handclosed.cur ├── handopen.cur ├── quote0.png ├── quote1.png ├── trashbody.png ├── trashlid.png └── tree.png ├── msg ├── js │ ├── de.js │ ├── en.js │ ├── en_us.js │ ├── pt_br.js │ ├── vi.js │ └── zh_tw.js ├── json │ ├── de.json │ ├── en.json │ ├── keys.json │ ├── pt_br.json │ ├── qqq.json │ ├── synonyms.json │ ├── vi.json │ └── zh_tw.json └── messages.js └── tests ├── blockly_test.html ├── blockly_test.js ├── generator_test.js ├── generators ├── colour.xml ├── index.html ├── lists.xml ├── logic.xml ├── loops1.xml ├── loops2.xml ├── math.xml ├── procedures.xml ├── text.xml ├── unittest.js ├── unittest_lua.js └── variables.xml ├── names_test.js └── playground.html /.gitignore: -------------------------------------------------------------------------------- 1 | appengine/static/** 2 | key.js 3 | **~ 4 | **#* 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Blockly Lua allows you to program ComputerCraft turtles in Blockly for use within Minecraft. 2 | 3 | For more information, see the wiki. 4 | 5 | Blockly Lua is no longer active. 6 | -------------------------------------------------------------------------------- /appengine/README.txt: -------------------------------------------------------------------------------- 1 | 2 | Running an App Engine server 3 | 4 | This directory contains the files needed to setup the optional Blockly server. 5 | Although Blockly itself is 100% client-side, the server enables cloud storage 6 | and sharing. Store your programs in Datastore and get a unique URL that allows 7 | you to load the program on any computer. 8 | 9 | To run your own App Engine instance you'll need to create this directory 10 | structure: 11 | 12 | blockly/ 13 | |- app.yaml 14 | |- index.yaml 15 | |- index_redirect.py 16 | |- README.txt 17 | |- storage.js 18 | |- storage.py 19 | |- closure-library-read-only/ 20 | `- static/ 21 | |- apps/ 22 | |- core/ 23 | |- demos/ 24 | |- generators/ 25 | |- language/ 26 | |- media/ 27 | |- tests/ 28 | `- blockly_compressed.js 29 | 30 | Instructions for fetching Closure may be found here: 31 | http://code.google.com/p/blockly/wiki/Closure 32 | 33 | Finally, upload this directory structure to your App Engine account, 34 | wait a minute, then go to http://YOURNAME.appspot.com/ 35 | -------------------------------------------------------------------------------- /appengine/app.yaml: -------------------------------------------------------------------------------- 1 | application: blockly-lua 2 | version: 1 3 | runtime: python27 4 | api_version: 1 5 | threadsafe: no 6 | 7 | handlers: 8 | # Storage API. 9 | - url: /storage 10 | script: storage.py 11 | - url: /storage\.js 12 | static_files: storage.js 13 | upload: storage\.js 14 | 15 | # Blockly files. 16 | - url: /static 17 | static_dir: static 18 | 19 | # Closure library for uncompiled Blockly. 20 | - url: /closure-library-read-only 21 | static_dir: closure-library-read-only 22 | 23 | # Redirect for root directory. 24 | - url: / 25 | script: index_redirect.py 26 | 27 | # Favicon. 28 | - url: /favicon\.ico 29 | static_files: favicon.ico 30 | upload: favicon\.ico 31 | 32 | # robot.txt 33 | - url: /robots\.txt 34 | static_files: robots.txt 35 | upload: robots\.txt 36 | 37 | -------------------------------------------------------------------------------- /appengine/closure-library-read-only: -------------------------------------------------------------------------------- 1 | /home/spertus/src/closure-library-read-only/ -------------------------------------------------------------------------------- /appengine/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/appengine/favicon.ico -------------------------------------------------------------------------------- /appengine/index.yaml: -------------------------------------------------------------------------------- 1 | indexes: 2 | 3 | # AUTOGENERATED 4 | 5 | # This index.yaml is automatically updated whenever the dev_appserver 6 | # detects that a new type of query is run. If you want to manage the 7 | # index.yaml file manually, remove the above marker line (the line 8 | # saying "# AUTOGENERATED"). If you want to manage some indexes 9 | # manually, move them above the marker line. The index.yaml file is 10 | # automatically uploaded to the admin console when you next deploy 11 | # your application using appcfg.py. 12 | -------------------------------------------------------------------------------- /appengine/index_redirect.py: -------------------------------------------------------------------------------- 1 | print("Status: 302") 2 | print("Location: /static/apps/code/index.html") 3 | -------------------------------------------------------------------------------- /appengine/redirect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /appengine/report.py: -------------------------------------------------------------------------------- 1 | """Blockly Demo: Report 2 | 3 | Copyright 2012 Google Inc. 4 | http://blockly.googlecode.com/ 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | """ 18 | 19 | """Store reports about code written by users. 20 | """ 21 | 22 | __author__ = "ellen.spertus@gmail.com (Ellen Spertus)" 23 | 24 | import cgi 25 | import logging 26 | 27 | from google.appengine.ext import db 28 | 29 | print "Content-type: text/plain\n" 30 | 31 | class Report(db.Model): 32 | identifier = db.FloatProperty() 33 | application = db.StringProperty() 34 | date = db.DateTimeProperty(auto_now_add=True) 35 | level = db.IntegerProperty() 36 | result = db.IntegerProperty() 37 | # StringProperty is limited to 500 characters, so use TextProperty. 38 | program = db.TextProperty() 39 | 40 | # Catch errors extracting form fields or converting to numeric types. 41 | # Let any other errors propagate up. 42 | try: 43 | forms = cgi.FieldStorage() 44 | identifier = float(forms["id"].value) 45 | application = forms["app"].value 46 | level = int(forms["level"].value) 47 | result = int(forms["result"].value) 48 | program = forms["program"].value 49 | row = Report(identifier = identifier, application = application, 50 | level = level, result = result, program = program) 51 | row.put() 52 | except ValueError, KeyError: 53 | logging.error("Unable to extract all form fields.") 54 | -------------------------------------------------------------------------------- /appengine/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /storage 3 | -------------------------------------------------------------------------------- /appengine/storage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Demo: Storage 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Loading and saving blocks with localStorage and cloud storage. 22 | * @author q.neutron@gmail.com (Quynh Neutron) 23 | */ 24 | 'use strict'; 25 | 26 | // Create a namespace. 27 | var BlocklyStorage = {}; 28 | 29 | /** 30 | * Backup code blocks to localStorage. 31 | * @private 32 | */ 33 | BlocklyStorage.backupBlocks_ = function() { 34 | if ('localStorage' in window) { 35 | var xml = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()); 36 | // Gets the current URL, not including the hash. 37 | var url = window.location.href.split('#')[0]; 38 | window.localStorage.setItem(url, Blockly.Xml.domToText(xml)); 39 | } 40 | }; 41 | 42 | /** 43 | * Bind the localStorage backup function to the unload event. 44 | */ 45 | BlocklyStorage.backupOnUnload = function() { 46 | window.addEventListener('unload', BlocklyStorage.backupBlocks_, false); 47 | }; 48 | 49 | /** 50 | * Restore code blocks from localStorage. 51 | */ 52 | BlocklyStorage.restoreBlocks = function() { 53 | var url = window.location.href.split('#')[0]; 54 | if ('localStorage' in window && window.localStorage[url]) { 55 | var xml = Blockly.Xml.textToDom(window.localStorage[url]); 56 | Blockly.Xml.domToWorkspace(Blockly.getMainWorkspace(), xml); 57 | } 58 | }; 59 | 60 | /** 61 | * Save blocks to database and return a link containing key to XML. 62 | */ 63 | BlocklyStorage.link = function() { 64 | var xml = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()); 65 | var data = Blockly.Xml.domToText(xml); 66 | BlocklyStorage.makeRequest_('/storage', 'xml', data); 67 | }; 68 | 69 | /** 70 | * Retrieve XML text from database using given key. 71 | * @param {string} key Key to XML, obtained from href. 72 | */ 73 | BlocklyStorage.retrieveXml = function(key) { 74 | var xml = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()); 75 | BlocklyStorage.makeRequest_('/storage', 'key', key); 76 | }; 77 | 78 | /** 79 | * Global reference to current AJAX request. 80 | * @type XMLHttpRequest 81 | * @private 82 | */ 83 | BlocklyStorage.httpRequest_ = null; 84 | 85 | /** 86 | * Fire a new AJAX request. 87 | * @param {string} url URL to fetch. 88 | * @param {string} name Name of parameter. 89 | * @param {string} content Content of parameter. 90 | * @private 91 | */ 92 | BlocklyStorage.makeRequest_ = function(url, name, content) { 93 | if (BlocklyStorage.httpRequest_) { 94 | // AJAX call is in-flight. 95 | BlocklyStorage.httpRequest_.abort(); 96 | } 97 | BlocklyStorage.httpRequest_ = new XMLHttpRequest(); 98 | BlocklyStorage.httpRequest_.name = name; 99 | BlocklyStorage.httpRequest_.onreadystatechange = 100 | BlocklyStorage.handleRequest_; 101 | BlocklyStorage.httpRequest_.open('POST', url); 102 | BlocklyStorage.httpRequest_.setRequestHeader('Content-Type', 103 | 'application/x-www-form-urlencoded'); 104 | BlocklyStorage.httpRequest_.send(name + '=' + encodeURIComponent(content)); 105 | }; 106 | 107 | /** 108 | * Callback function for AJAX call. 109 | * @private 110 | */ 111 | BlocklyStorage.handleRequest_ = function() { 112 | if (BlocklyStorage.httpRequest_.readyState == 4) { 113 | if (BlocklyStorage.httpRequest_.status != 200) { 114 | BlocklyStorage.alert(BlocklyStorage.HTTPREQUEST_ERROR + '\n' + 115 | 'httpRequest_.status: ' + BlocklyStorage.httpRequest_.status); 116 | } else { 117 | var data = BlocklyStorage.httpRequest_.responseText.trim(); 118 | if (BlocklyStorage.httpRequest_.name == 'xml') { 119 | window.location.hash = data; 120 | BlocklyStorage.alert(BlocklyStorage.LINK_ALERT.replace('%1', 121 | window.location.href)); 122 | } else if (BlocklyStorage.httpRequest_.name == 'key') { 123 | if (!data.length) { 124 | BlocklyStorage.alert(BlocklyStorage.HASH_ERROR.replace('%1', 125 | window.location.hash)); 126 | } else { 127 | BlocklyStorage.loadXml_(data); 128 | } 129 | } 130 | BlocklyStorage.monitorChanges_(); 131 | } 132 | BlocklyStorage.httpRequest_ = null; 133 | } 134 | }; 135 | 136 | /** 137 | * Start monitoring the workspace. If a change is made that changes the XML, 138 | * clear the key from the URL. Stop monitoring the workspace once such a 139 | * change is detected. 140 | * @private 141 | */ 142 | BlocklyStorage.monitorChanges_ = function() { 143 | var startXmlDom = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()); 144 | var startXmlText = Blockly.Xml.domToText(startXmlDom); 145 | function change() { 146 | var xmlDom = Blockly.Xml.workspaceToDom(Blockly.getMainWorkspace()); 147 | var xmlText = Blockly.Xml.domToText(xmlDom); 148 | if (startXmlText != xmlText) { 149 | window.location.hash = ''; 150 | Blockly.removeChangeListener(bindData); 151 | } 152 | } 153 | var bindData = Blockly.addChangeListener(change); 154 | }; 155 | 156 | /** 157 | * Load blocks from XML. 158 | * @param {string} xml Text representation of XML. 159 | * @private 160 | */ 161 | BlocklyStorage.loadXml_ = function(xml) { 162 | try { 163 | xml = Blockly.Xml.textToDom(xml); 164 | } catch (e) { 165 | BlocklyStorage.alert(BlocklyStorage.XML_ERROR + '\nXML: ' + xml); 166 | return; 167 | } 168 | // Clear the workspace to avoid merge. 169 | Blockly.getMainWorkspace().clear(); 170 | Blockly.Xml.domToWorkspace(Blockly.getMainWorkspace(), xml); 171 | }; 172 | 173 | /** 174 | * Present a text message to the user. 175 | * Designed to be overridden if an app has custom dialogs, or a butter bar. 176 | * @param {string} message Text to alert. 177 | */ 178 | BlocklyStorage.alert = function(message) { 179 | window.alert(message); 180 | }; 181 | -------------------------------------------------------------------------------- /appengine/storage.py: -------------------------------------------------------------------------------- 1 | """Blockly Demo: Storage 2 | 3 | Copyright 2012 Google Inc. 4 | http://blockly.googlecode.com/ 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | """ 18 | 19 | """Store and retrieve XML with App Engine. 20 | """ 21 | 22 | __author__ = "q.neutron@gmail.com (Quynh Neutron)" 23 | 24 | import cgi 25 | from random import randint 26 | from google.appengine.ext import db 27 | from google.appengine.api import memcache 28 | import logging 29 | 30 | print "Content-Type: text/plain\n" 31 | 32 | def keyGen(): 33 | # Generate a random string of length KEY_LEN. 34 | KEY_LEN = 6 35 | CHARS = "abcdefghijkmnopqrstuvwxyz23456789" # Exclude l, 0, 1. 36 | max_index = len(CHARS) - 1 37 | return "".join([CHARS[randint(0, max_index)] for x in range(KEY_LEN)]) 38 | 39 | class Xml(db.Model): 40 | # A row in the database. 41 | xml_hash = db.IntegerProperty() 42 | xml_content = db.TextProperty() 43 | 44 | forms = cgi.FieldStorage() 45 | if "xml" in forms: 46 | # Store XML and return a generated key. 47 | xml_content = forms["xml"].value 48 | xml_hash = hash(xml_content) 49 | lookup_query = db.Query(Xml) 50 | lookup_query.filter("xml_hash =", xml_hash) 51 | lookup_result = lookup_query.get() 52 | if lookup_result: 53 | xml_key = lookup_result.key().name() 54 | else: 55 | trials = 0 56 | result = True 57 | while result: 58 | trials += 1 59 | if trials == 100: 60 | raise Exception("Sorry, the generator failed to get a key for you.") 61 | xml_key = keyGen() 62 | result = db.get(db.Key.from_path("Xml", xml_key)) 63 | xml = db.Text(xml_content, encoding="utf_8") 64 | row = Xml(key_name = xml_key, xml_hash = xml_hash, xml_content = xml) 65 | row.put() 66 | print xml_key 67 | 68 | if "key" in forms: 69 | # Retrieve stored XML based on the provided key. 70 | key_provided = forms["key"].value 71 | # Normalize the string. 72 | key_provided = key_provided.lower().strip() 73 | # Check memcache for a quick match. 74 | xml = memcache.get("XML_" + key_provided) 75 | if xml is None: 76 | # Check datastore for a definitive match. 77 | result = db.get(db.Key.from_path("Xml", key_provided)) 78 | if not result: 79 | xml = "" 80 | else: 81 | xml = result.xml_content 82 | # Save to memcache for next hit. 83 | if not memcache.add("XML_" + key_provided, xml, 3600): 84 | logging.error("Memcache set failed.") 85 | print xml.encode("utf-8") 86 | -------------------------------------------------------------------------------- /apps/code/blocks-bit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Bit API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Bit API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.ValueBlock'); 26 | 27 | Blockly.ComputerCraft.BIT_BLOCK_COLOUR_ = 290; 28 | 29 | Blockly.ComputerCraft.BIT_FUNCS_ = [ 30 | {blockName: 'shift', 31 | text: 'shift %1 %2 %3 bits', 32 | args: [['N', 'Number'], 33 | ['OPTION', new Blockly.FieldDropdown( 34 | [['left', 'blshift'], 35 | ['right arithmetically', 'brshift'], 36 | ['right logically', 'blogic_rshift']])], 37 | ['BITS', 'Number']], 38 | output: 'Number', 39 | ddFuncName: 'OPTION', 40 | tooltip: 41 | 'Shift the number by the specified number of bits.\n' + 42 | 'This inputs are treated as 32-bit unsigned integers.\n' + 43 | 'An error is raises if either input is greater than 2^32 - 1.', 44 | helpUrlType: Blockly.ComputerCraft.HelpUrlType.PREFIX_DD 45 | }, 46 | {blockName: 'bitwise', 47 | text: '%1 %2 %3', 48 | args: [['X', 'Number'], 49 | ['FUNCTION', new Blockly.FieldDropdown( 50 | [['XOR', 'bxor'], 51 | ['OR', 'bor'], 52 | ['AND', 'band']])], 53 | ['Y', 'Number']], 54 | output: 'Number', 55 | ddFuncName: 'FUNCTION', 56 | tooltip: function(block) { 57 | var HELP = {'bxor': {name: 'exclusive OR', description: 'exactly one'}, 58 | 'bor': {name: 'inclusive OR', description: 'at least one'}, 59 | 'band': {name: 'AND', description: 'both'}}; 60 | var help = HELP[block.getTitleValue('FUNCTION')]; 61 | return 'Compute the bitwise ' + help.name.toUpperCase() 62 | + ' of the two numeric inputs.\n' + 63 | 'For each of the 32 bit positions, the value is 1 if and only if\n' + 64 | help.description.toUpperCase() 65 | + ' of the corresponding bits in the inputs are 1.'; 66 | } 67 | }, 68 | {funcName: 'bnot', 69 | text: 'bitwise not %1', 70 | args: [['X', 'Number']], 71 | output: 'Number', 72 | tooltip: 73 | 'Compute the bitwise inverse of a number, taken in\n' + 74 | 'the domain and range of 32-bit unsigned integers.'} 75 | ]; 76 | 77 | Blockly.ComputerCraft.BIT_FUNCS_.forEach(function(info) { 78 | Blockly.ComputerCraft.buildValueBlock( 79 | 'bit', Blockly.ComputerCraft.BIT_BLOCK_COLOUR_, info)}); 80 | -------------------------------------------------------------------------------- /apps/code/blocks-colours.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Colours API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Colours blocks for ComputerCraft. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.ValueBlock'); 26 | goog.require('ComputerCraft.VarArgsBlock'); 27 | 28 | Blockly.ComputerCraft.COLOURS_BLOCK_COLOUR_ = 80; 29 | 30 | /** 31 | * An array of colours for the palette. The rgb attributes may be tweaked, 32 | * but the value attributes must not, since they correspond to ones on 33 | * "http://computercraft.info/wiki/Colors_%28API%29". 34 | */ 35 | var COLOURS_ = { 36 | white: {rgb: '#f0f0f0', value: 1 << 0 }, 37 | orange: {rgb: '#f2b233', value: 1 << 1 }, 38 | magenta: {rgb: '#e57fd8', value: 1 << 2 }, 39 | lightBlue: {rgb: '#99b2f2', value: 1 << 3 }, 40 | yellow: {rgb: '#dede6c', value: 1 << 4 }, 41 | lime: {rgb: '#7fcc19', value: 1 << 5 }, 42 | pink: {rgb: '#f2b2cc', value: 1 << 6 }, 43 | grey: {rgb: '#4c4c4c', value: 1 << 7 }, 44 | lightGrey: {rgb: '#999999', value: 1 << 8 }, 45 | cyan: {rgb: '#4c99b2', value: 1 << 9 }, 46 | purple: {rgb: '#b266e5', value: 1 << 10 }, 47 | blue: {rgb: '#253192', value: 1 << 11 }, 48 | brown: {rgb: '#7f664c', value: 1 << 12 }, 49 | green: {rgb: '#57a64e', value: 1 << 13 }, 50 | red: {rgb: '#cc4c4c', value: 1 << 14 }, 51 | black: {rgb: '#191919', value: 1 << 15 } 52 | }; 53 | 54 | /** 55 | * The order in which colours should appear on the palette. 56 | * Array.prototype.map is supported by IE 9+ and all other major browsers. 57 | * This overrides a value defined in core/field_colour.js 58 | * (via blockly_[un]compressed.js). 59 | */ 60 | Blockly.FieldColour.COLOURS = Object.keys(COLOURS_).map( 61 | function(name) { 62 | return COLOURS_[name].rgb; 63 | }); 64 | 65 | /** 66 | * Number of columns in the palette. 67 | * This overrides a value defined in core/field_colour.js 68 | * (via blockly_[un]compressed.js). 69 | */ 70 | Blockly.FieldColour.COLUMNS = 4; 71 | 72 | Blockly.Blocks['colours_picker'] = { 73 | // Colour picker. 74 | init: function() { 75 | this.setHelpUrl('http://computercraft.info/wiki/Colors_%28API%29'); 76 | this.setColour(Blockly.ComputerCraft.COLOURS_BLOCK_COLOUR_); 77 | this.appendDummyInput() 78 | .appendTitle(new Blockly.FieldColour('#cc4c4c'), 'COLOUR'); 79 | this.setOutput(true, 'Number'); 80 | this.setTooltip( 81 | 'Choose among colours (from left to right, top to bottom):\n' + 82 | 'white, orange, magenta, light blue,\n' + 83 | 'yellow, lime, pink, grey,\n' + 84 | 'light gray, cyan purple, blue,\n' + 85 | 'brown, green, red, black.'); 86 | } 87 | }; 88 | 89 | // TODO: Change block colour to match chosen colour, if not too hard. Neil? 90 | Blockly.ComputerCraft.buildValueBlock( 91 | 'colours', 92 | Blockly.ComputerCraft.COLOURS_BLOCK_COLOUR_, 93 | {blockName: 'list', 94 | text: '%1', 95 | args: [['COLOUR', 96 | new Blockly.FieldDropdown(Object.keys(COLOURS_).map( 97 | function(name) { 98 | return [Blockly.ComputerCraft.convertFromCamelCase(name). 99 | replace('_', ' '), 100 | name]; 101 | }))]], 102 | output: 'Number', 103 | tooltip: 'Choose among colours by name.'}); 104 | 105 | Blockly.Lua['colours_list'] = function(block) { 106 | var code = 'colours.' + block.getTitleValue('COLOUR'); 107 | return [code, Blockly.Lua.ORDER_HIGH]; 108 | }; 109 | 110 | Blockly.Lua['colours_picker'] = function(block) { 111 | // Generate Lua code for the selected ComputerCraft colour. 112 | var colour = block.inputList[0].titleRow[0].colour_; 113 | var keys = Object.keys(COLOURS_); 114 | for (var x = 0; x < keys.length; x++) { 115 | var key = keys[x]; 116 | var entry = COLOURS_[key]; 117 | if (entry.rgb == colour) { 118 | return ['colours.' + key, Blockly.Lua.ORDER_HIGH]; 119 | } 120 | } 121 | goog.asserts.fail('Error in colour_picker'); 122 | }; 123 | 124 | Blockly.ComputerCraft.buildVarArgsBlock( 125 | 'colours', 126 | Blockly.ComputerCraft.COLOURS_BLOCK_COLOUR_, 127 | {funcName: 'combine', 128 | text: 'combine colours %v into set', 129 | varArgName: 'colour', 130 | varArgType: 'Number', 131 | varArgTooltip: 'A colour to add to the set.', 132 | varArgCount: 2, 133 | varContainerName: 'colours', 134 | varContainerTooltip: 'Add or remove colours.', 135 | output: 'Number', 136 | tooltip: 137 | 'Combine one or more colours (or sets of colours) into a set.\n' + 138 | 'To change the number of colours, click on the star.'}); 139 | 140 | Blockly.ComputerCraft.buildVarArgsBlock( 141 | 'colours', 142 | Blockly.ComputerCraft.COLOURS_BLOCK_COLOUR_, 143 | {funcName: 'subtract', 144 | text: 'subtract colours %v from set %1', 145 | args: [['Set', 'Number']], 146 | varArgName: 'colour', 147 | varArgType: 'Number', 148 | varArgTooltip: 'A colour to subtract.', 149 | varArgCount: 1, 150 | varContainerName: 'colours to remove', 151 | varContainerTooltip: 'Add or remove colours.', 152 | output: 'Number', 153 | tooltip: 154 | 'Remove one or more colours from the specified set of colours.\n' + 155 | 'To change the number of colours to remove, click on the star.\n' + 156 | 'A set can be built with the "combine" block.'}); 157 | 158 | Blockly.ComputerCraft.buildValueBlock( 159 | 'colours', 160 | Blockly.ComputerCraft.COLOURS_BLOCK_COLOUR_, 161 | {funcName: 'test', 162 | text: 'is colour %2 in set %1?', 163 | args: [['Set', 'Number'], 164 | ['Colour', 'Number']], 165 | output: 'Boolean', 166 | tooltip: 167 | 'Test whether the given colour is in the set.\n' + 168 | 'A set can be built with the "combine" block.'}); 169 | -------------------------------------------------------------------------------- /apps/code/blocks-disk.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Disk API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Disk API. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.SideInputBlock'); 26 | 27 | Blockly.ComputerCraft.DISK_BLOCK_COLOUR_ = 290; 28 | 29 | Blockly.ComputerCraft.DISK_FUNCS_ = [ 30 | {funcName: 'isPresent', 31 | output: 'Boolean', 32 | text: 'an item is in disk drive', 33 | tooltip: 34 | 'Check whether any item (such as a music disk or floppy disk)\n'+ 35 | 'is present in the adjacent disk drive.'}, 36 | {funcName: 'hasData', 37 | output: 'Boolean', 38 | text: 'a floppy disk is in drive', 39 | tooltip: 40 | 'Check whether a floppy disk (as opposed to a music disk) is in the drive.' 41 | }, 42 | {funcName: 'getMountPath', 43 | output: 'String', 44 | text: 'get mount path for floppy disk in drive', 45 | tooltip: 46 | 'Get the directory name where the contents\n' + 47 | 'of the floppy disk can be accessed.'}, 48 | {funcName: 'getLabel', 49 | text: 'read label on floppy disk in drive', 50 | output: 'String', 51 | tooltip: 'Read the label of the floppy disk in the drive.'}, 52 | {funcName: 'getID', 53 | text: 'get ID of floppy disk in drive', 54 | output: 'Number', 55 | tooltip: 'Get the floppy disk\'s unique numeric identifier.'}, 56 | {funcName: 'hasAudio', 57 | text: 'music disk is in drive', 58 | output: 'Boolean', 59 | tooltip: 'Check if a music disk is in the drive.'}, 60 | {funcName: 'getAudioTitle', 61 | text: 'get title of music disk in drive', 62 | output: 'String', 63 | tooltip: 'Get the title of the music disk in the drive.'}, 64 | {funcName: 'playAudio', 65 | text: 'play music disk in drive', 66 | tooltip: 'Starts playing the music disk in the drive.'}, 67 | {funcName: 'stopAudio', 68 | text: 'stop music disk in drive', 69 | tooltip: 'Stop playing the music disk in the drive.'}, 70 | {funcName: 'eject', 71 | text: 'eject from drive', 72 | tooltip: 73 | 'Eject any item currently in the drive,\n' + 74 | 'spilling it into the world as a loose item.'}, 75 | {funcName: 'setLabel', 76 | // The label input is added below. 77 | text: 'Set the label on the disk in drive to %1', 78 | args: [['LABEL', 'String']], 79 | tooltip: 'Write to the label to the floppy disk in the attached drive.'}]; 80 | 81 | Blockly.ComputerCraft.DISK_FUNCS_.forEach(function(info) { 82 | Blockly.ComputerCraft.buildSideInputBlock( 83 | 'disk', Blockly.ComputerCraft.DISK_BLOCK_COLOUR_, info);}); 84 | -------------------------------------------------------------------------------- /apps/code/blocks-fs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft File System API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft File System (FS) API. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.ValueBlock'); 26 | 27 | Blockly.ComputerCraft.FS_BLOCK_COLOUR_ = 410; 28 | 29 | Blockly.ComputerCraft.FS_FUNCS_ = [ 30 | {funcName: 'list', 31 | output: 'Table', 32 | text: 'list files in %1', 33 | args: [['DIR', 'String']], 34 | tooltip: 35 | 'Returns a list of all the files\n' + 36 | '(including subdirectories but not their contents)\n' + 37 | 'contained in a directory, as a numerically indexed table.'}, 38 | {funcName: 'exists', 39 | output: 'Boolean', 40 | text: 'path %1 exists?', 41 | args: [['PATH', 'String']], 42 | tooltip: 43 | 'Checks if its input refers to an existing file or directory,\n' + 44 | 'returning true if it does, false otherwise'}, 45 | {funcName: 'isReadOnly', 46 | output: 'Boolean', 47 | text: 'is path %1 read-only?', 48 | args: [['PATH', 'String']], 49 | tooltip: 50 | 'Checks if a file or directory is read-only (cannot be modified),\n' + 51 | 'returning true if it is, false otherwise'}, 52 | {funcName: 'getName', 53 | output: 'String', 54 | text: 'get file name from path %1', 55 | args: [['PATH', 'String']], 56 | tooltip: 57 | 'Gets the final part (file name) from a path'}, 58 | {funcName: 'getDrive', 59 | output: 'String', 60 | text: 'get drive type for path %1', 61 | args: [['PATH', 'String']], 62 | tooltip: 63 | 'Returns the type of the storage medium holding a path,\n' + 64 | 'or nil if the path does not exist. This is one of\n' + 65 | '“hdd” if the path is stored on the computer’s local hard drive,\n' + 66 | '“rom” if the path is in ROM, or the side on which a disk drive\n' + 67 | 'is attached if the path is on a floppy disk.'}, 68 | {funcName: 'getSize', 69 | output: 'Number', 70 | text: 'get size of file %1', 71 | args: [['PATH', 'String']], 72 | tooltip: 'Gets the amount of space taken up by the file, in bytes.\n'}, 73 | {funcName: 'getFreeSpace', 74 | output: 'Number', 75 | text: 'get amount of free space in %1', 76 | args: [['DIR', 'String']], 77 | tooltip: 'Gets the amount of free space in the given directory, in bytes.'}, 78 | {funcName: 'makeDir', 79 | stmtConns: Blockly.ComputerCraft.StmtConns.BOTH, 80 | text: 'create directory %1', 81 | args: [['DIR', 'String']], 82 | tooltip: 83 | 'Creates a directory with the given path,\n' + 84 | 'creating any missing parent components.\n' + 85 | 'If the location is already a directory, nothing changes.\n' + 86 | 'If the location is already a file, an error occurs.'}, 87 | {funcName: 'move', 88 | stmtConns: Blockly.ComputerCraft.StmtConns.BOTH, 89 | text: 'move file/directory from %1 to %2', 90 | args: [['PATH1', 'String'], ['PATH2', 'String']], 91 | tooltip: 'Moves a file or directory to a new location.\n' + 92 | 'The parent of the new location must be an existing writeable directory.\n' + 93 | 'The second input must include a file name and that file must not yet exist.' 94 | }, 95 | {funcName: 'copy', 96 | stmtConns: Blockly.ComputerCraft.StmtConns.BOTH, 97 | text: 'copy file/directory from %1 to %2', 98 | args: [['PATH1', 'String'], ['PATH2', 'String']], 99 | tooltip: 'Copies a file or directory to a new location.\n' + 100 | 'The parent of the new location must be an existing writeable directory.\n' + 101 | 'The second input must include a file name and that file must not yet exist.' 102 | }, 103 | {funcName: 'delete', 104 | stmtConns: Blockly.ComputerCraft.StmtConns.BOTH, 105 | text: 'delete file/directory %1', 106 | args: [['PATH', 'String']], 107 | tooltip: 'Deletes a file or directory and its contents.\n' + 108 | 'Nothing happens if the file/directory does not exist.'}, 109 | {funcName: 'combine', 110 | output: 'String', 111 | text: 'combine file paths %1 and %2', 112 | args: [['PATH1', 'String'], ['PATH2', 'String']], 113 | tooltip: 'Combines two path components, returning a path\n' + 114 | 'consisting of the second path nexted in the first path.\n' + 115 | 'Neither path needs to exist; this function only manipulates strings.'} 116 | ]; 117 | 118 | Blockly.ComputerCraft.FS_FUNCS_.forEach(function(info) { 119 | Blockly.ComputerCraft.buildValueBlock( 120 | 'fs', Blockly.ComputerCraft.FS_BLOCK_COLOUR_, info);}); 121 | -------------------------------------------------------------------------------- /apps/code/blocks-help.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Help API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Help API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.ValueBlock'); 26 | 27 | Blockly.ComputerCraft.HELP_BLOCK_COLOUR_ = 290; 28 | 29 | Blockly.ComputerCraft.HELP_FUNCS_ = [ 30 | {funcName: 'path', 31 | text: 'get help path', 32 | output: 'String', 33 | tooltip: 34 | 'Get the list of locations that will be searched for help files,\n' + 35 | 'as a string containing multiple search paths separated by colons.'}, 36 | {funcName: 'setPath', 37 | text: 'set help path to %1', 38 | args: [['PATH', 'String']], 39 | tooltip: 40 | 'Set the list of locations to be searched for help files.\n' + 41 | 'The input should be a string containing search paths separated by colons.'}, 42 | {funcName: 'lookup', 43 | text: 'get help path for %1', 44 | args: [['TOPIC', 'String']], 45 | tooltip: 46 | 'Get the path to the file containing the help page for the given topic.\n' + 47 | 'If it cannot be found, the result will be null.'}, 48 | {funcName: 'topics', 49 | text: 'get list of help topics', 50 | tooltip: 'Get a list of all available help topics.', 51 | output: 'List'}]; 52 | 53 | Blockly.ComputerCraft.HELP_FUNCS_.forEach(function(info) { 54 | Blockly.ComputerCraft.buildValueBlock( 55 | 'help', Blockly.ComputerCraft.HELP_BLOCK_COLOUR_, info);}); 56 | -------------------------------------------------------------------------------- /apps/code/blocks-keys.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Keys API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Keys API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.ValueBlock'); 26 | 27 | Blockly.ComputerCraft.KEYS_BLOCK_COLOUR_ = 290; 28 | 29 | Blockly.ComputerCraft.buildValueBlock( 30 | 'keys', 31 | Blockly.ComputerCraft.KEYS_BLOCK_COLOUR_, 32 | {funcName: 'getName', 33 | text: 'get key name from code %1', 34 | args: [['CODE', 'Number']], 35 | output: 'String', 36 | tooltip: 'Get the name of a keyboard key from its numeric scan code.' 37 | } 38 | ); 39 | -------------------------------------------------------------------------------- /apps/code/blocks-old.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Deprecated blocks for ComputerCraft turtles. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | 26 | Blockly.ComputerCraft.deprecatedOnChange = function(newBlock) { 27 | return function() { 28 | if (!this.workspace) { 29 | // Block has been deleted. 30 | return; 31 | } 32 | this.setWarningText('This block has been deprecated. Please replace it with the "' + newBlock + '" block.'); 33 | }; 34 | }; 35 | 36 | 37 | Blockly.Blocks['turtle_get_item_count'] = { 38 | // Block for returning the number of items in the supplied slot. 39 | init: function() { 40 | this.setColour(Blockly.ComputerCraft.TURTLE_BLOCK_COLOUR_); 41 | this.appendValueInput('VALUE') 42 | .setCheck('Number') 43 | .appendTitle('get item count in slot'); 44 | this.setOutput(true, 'Number'); 45 | this.setTooltip('Get the count of items in the supplied slot number.'); 46 | }, 47 | onchange: Blockly.ComputerCraft.deprecatedOnChange('get [item count/free space] in slot') 48 | }; 49 | 50 | Blockly.Lua['turtle_get_item_count'] = function(block) { 51 | // Generate Lua for getting the number of items in the supplied slot number 52 | var argument0 = Blockly.Lua.valueToCode( 53 | block, 'VALUE', Blockly.Lua.ORDER_NONE) || ''; 54 | var code = 'turtle.getItemCount(' + argument0 + ')'; 55 | return [code, Blockly.Lua.ORDER_NONE]; 56 | } 57 | 58 | Blockly.Blocks['turtle_get_item_space'] = { 59 | // Block for getting the number of items that can be put in the numbered 60 | // slot. 61 | init: function() { 62 | this.setColour(Blockly.ComputerCraft.TURTLE_BLOCK_COLOUR_); 63 | this.appendValueInput('VALUE') 64 | .setCheck('Number') 65 | .appendTitle('get free space in slot'); 66 | this.setOutput(true, 'Number'); 67 | this.setTooltip('Get the number of items that can be placed in the numbered slot.'); 68 | }, 69 | onchange: Blockly.ComputerCraft.deprecatedOnChange('get [item count/free space] in slot') 70 | }; 71 | 72 | Blockly.Lua['turtle_get_item_space'] = function(block) { 73 | // Generate Lua for getting the number of items that can be put in the 74 | // numbered slot. 75 | var argument0 = Blockly.Lua.valueToCode( 76 | block, 'VALUE', Blockly.Lua.ORDER_NONE) || ''; 77 | var code = 'turtle.getItemSpace(' + argument0 + ')'; 78 | return [code, Blockly.Lua.ORDER_NONE]; 79 | } 80 | -------------------------------------------------------------------------------- /apps/code/blocks-os.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Operating System (OS) API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Operating System (OS) API. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.DependentInputBlock'); 26 | goog.require('ComputerCraft.ValueBlock'); 27 | goog.require('ComputerCraft.VarArgsBlock'); 28 | 29 | Blockly.ComputerCraft.OS_BLOCK_COLOUR_ = 30; 30 | 31 | Blockly.ComputerCraft.OS_FUNCS_ = [ 32 | {funcName: 'terminate', 33 | // This has a previous, but not a following, statement, which is rare. 34 | stmtConns: Blockly.ComputerCraft.StmtConns.PREVIOUS, 35 | text: 'terminate with error %1', 36 | args: [['MSG', null]], 37 | tooltip: 38 | 'End the program with the provided error message. ' + 39 | 'This should not be used for normal termination.' 40 | }, 41 | {funcName: 'sleep', 42 | text: 'sleep %1 seconds', 43 | args: [['VALUE', 'Number']], 44 | tooltip: 'Sleep for the specified number of seconds.' 45 | }, 46 | {funcName: 'version', 47 | text: 'get OS version', 48 | output: 'String', 49 | tooltip: 'Get the name of the version of CraftOS being used.'}, 50 | {funcName: 'getComputerID', 51 | text: 'get computer ID', 52 | output: 'Number', 53 | tooltip: 'Get the unique numeric ID of this computer.'}, 54 | {funcName: 'getComputerLabel', 55 | text: 'get computer label', 56 | output: 'String', 57 | tooltip: 58 | 'Get the label of this computer.\n' + 59 | 'The label can be set with "set computer label".'}, 60 | {funcName: 'setComputerLabel', 61 | text: 'set computer label to %1', 62 | args: [['LABEL', 'String']], 63 | tooltip: 64 | 'Set the label of this computer.\n' + 65 | 'The label can be read with "get computer label".'}, 66 | {blockName: 'api', 67 | text: '%1 API %2', 68 | args: [['OPTION', 69 | new Blockly.FieldDropdown([['load', 'loadAPI'], 70 | ['unload', 'unloadAPI']])], 71 | ['NAME', 'String']], 72 | ddFuncName: 'OPTION', 73 | tooltip: 'Load or unload a Lua script as an API in its own namespace.'}, 74 | {funcName: 'clock', 75 | text: 'get running time', 76 | output: 'Number', 77 | tooltip: 'Get the amount of time this computer has been running, in seconds.'}, 78 | {funcName: 'setAlarm', 79 | text: 'set alarm for %1 s', 80 | args: [['TIME', 'Number']], 81 | output: 'Table', 82 | tooltip: 83 | 'Queue an alarm event to occur after the specified number of seconds.\n' + 84 | 'The ID of the alarm, which is a table, is returned.'}, 85 | {funcName: 'time_day', 86 | ddFuncName: 'OPTION', 87 | text: 'get in-game %1', 88 | args: [['OPTION', 89 | new Blockly.FieldDropdown( 90 | [['time', 'time'], ['day', 'day']])]], 91 | output: 'Number', 92 | tooltip: 93 | 'Get the current in-game time or day.\n' + 94 | 'Time can be converted into a string with\n' + 95 | 'the "format time" block in Text Utilities.\n' + 96 | 'Day is the number of days since the world creation.'}, 97 | {funcName: 'shutdown', 98 | text: 'shut down computer', 99 | tooltip: 'Turn off this computer.'}, 100 | {funcName: 'reboot', 101 | text: 'reboot computer', 102 | tooltip: 'Reboot this computer.'}, 103 | {funcName: 'startTimer', 104 | text: 'start timer for %1 s', 105 | args: [['TIME', 'Number']], 106 | output: 'Number', 107 | expStmt: true, 108 | tooltip: 109 | 'Queue a timer event to occur after\n' + 110 | 'the specified number of seconds.\n' + 111 | 'The ID of the timer is returned.'} 112 | ]; 113 | 114 | Blockly.ComputerCraft.OS_FUNCS_.forEach(function(info) { 115 | Blockly.ComputerCraft.buildValueBlock( 116 | 'os', Blockly.ComputerCraft.OS_BLOCK_COLOUR_, info);}); 117 | 118 | 119 | // Added in order to continue to support programs with the old block name. 120 | Blockly.Blocks['terminate'] = Blockly.Blocks['os_terminate']; 121 | Blockly.Lua['terminate'] = Blockly.Lua['os_terminate']; 122 | 123 | Blockly.ComputerCraft.buildVarArgsBlock( 124 | 'os', 125 | Blockly.ComputerCraft.OS_BLOCK_COLOUR_, 126 | {funcName: 'queueEvent', 127 | text: 'queue event %1 %v', 128 | args: [['EVENT', 'String']], 129 | varArgName: 'name', 130 | varArgType: true, 131 | varArgTooltip: 'A parameter to pass to the event.', 132 | varArgTitle: 'with parameters', 133 | varArgCount: 1, 134 | varContainerName: 'parameters', 135 | varContainerTitle: 'Add, remove, or reorder parameters to pass to the event.', 136 | tooltip: 137 | 'Add an event to the event queue with the given name and parameters.'}); 138 | 139 | Blockly.ComputerCraft.buildDependentInputBlock( 140 | 'os', 141 | Blockly.ComputerCraft.OS_BLOCK_COLOUR_, 142 | {funcName: 'pullEvent', 143 | text: 'pull %1 %2', 144 | output: ['String', 'Number', 'Colour', 'Table', 'Vector', 'Function'], 145 | multipleOutputs: Infinity, // Not really infinite, but unbounded. 146 | args: [['OPTION*', 147 | [['any event', 'any'], 148 | ['named event', 'named*'], 149 | ['raw event', 'raw']]], 150 | ['EVENT^', 'String']], 151 | // pullEvent is used if OPTION is 'any' or 'named'; 152 | // pullEventRaw is used if OPTION is 'raw'. 153 | suppressLua: true, 154 | tooltip: 155 | 'Block until the computer receives an event,\n' + 156 | 'outputting the name of the event and its parameters.\n' + 157 | 'The "terminate" event is only caught in raw mode.'}); 158 | 159 | Blockly.Lua['os_pull_event'] = function(block) { 160 | var code = block.generateLua(); 161 | if (block.getTitleValue('OPTION') == 'raw') { 162 | code[0] = code[0].replace('pullEvent', 'pullEventRaw'); 163 | } 164 | return code; 165 | }; 166 | 167 | Blockly.ComputerCraft.buildVarArgsBlock( 168 | 'os', 169 | Blockly.ComputerCraft.OS_BLOCK_COLOUR_, 170 | {funcName: 'run', 171 | text: 'run program %2 with environment %1 %v', 172 | args: [['ENV', 'Table'], 173 | ['PATH', 'String']], 174 | varArgName: 'parameter', 175 | varArgType: true, 176 | varArgTooltip: 'A parameter to pass to the program.', 177 | varArgTitle: 'and parameters', 178 | varArgCount: 1, 179 | varContainerName: 'parameters', 180 | varContainerTooltip: 'Add, remove, or reorder parameters.', 181 | tooltip: 182 | 'Run the program at the specified path with the given\n' + 183 | 'environment table. Providing parameters is optional.\n' + 184 | 'Parameters can be added or removed by clicking on the star.'}); 185 | -------------------------------------------------------------------------------- /apps/code/blocks-paintutils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Paintutils API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Paintutils API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.ValueBlock'); 26 | 27 | Blockly.ComputerCraft.PAINTUTILS_BLOCK_COLOUR_ = 310; 28 | 29 | Blockly.ComputerCraft.PAINTUTILS_FUNCS_ = [ 30 | {funcName: 'loadImage', 31 | text: 'load image from path %1', 32 | args: [['PATH', 'String']], 33 | output: 'Image', 34 | tooltip: 35 | 'Load an image object from the specified path.'}, 36 | {funcName: 'drawImage', 37 | text: 'draw image %1 at (%2, %3)', 38 | args: [['IMAGE', 'Image'], 39 | ['X', 'Number'], 40 | ['Y', 'Number']], 41 | tooltip: 42 | 'Draw an image at the specified (x, y) coordinates.\n' + 43 | 'An image can be obtained with the "load image" block.'}, 44 | {funcName: 'drawPixel', 45 | text: 'draw %3 pixel at (%1, %2)', 46 | args: [['X', 'Number'], 47 | ['Y', 'Number'], 48 | ['COLOUR', 'Colour']], 49 | tooltip: 50 | 'Draw a pixel (dot) at the specified (x, y) coordinates\n' + 51 | 'in the specified colour.'}, 52 | {funcName: 'drawLine', 53 | text: 'draw %5 line from (%1, %2) to (%3, %4)', 54 | args: [['X1', 'Number'], 55 | ['Y1', 'Number'], 56 | ['X2', 'Number'], 57 | ['Y2', 'Number'], 58 | ['COLOUR', 'Colour']], 59 | tooltip: 60 | 'Draw a line in the specified colour from the first pair\n' + 61 | 'of (x, y) coordinates to the second pair of (x, y) coordinates.'}]; 62 | 63 | Blockly.ComputerCraft.PAINTUTILS_FUNCS_.forEach(function(info) { 64 | Blockly.ComputerCraft.buildValueBlock( 65 | 'paintutils', Blockly.ComputerCraft.PAINTUTILS_BLOCK_COLOUR_, info);}); 66 | -------------------------------------------------------------------------------- /apps/code/blocks-rednet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Rednet API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Rednet API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.DependentInputBlock'); 26 | goog.require('ComputerCraft.ValueBlock'); 27 | 28 | Blockly.ComputerCraft.REDNET_BLOCK_COLOUR_ = 290; 29 | 30 | Blockly.ComputerCraft.REDNET_FUNCS_ = [ 31 | {funcName: 'open', 32 | text: 'open rednet on %1', 33 | args: [['SIDE', new Blockly.FieldDropdown(Blockly.ComputerCraft.ValueBlock.SIDES)]], 34 | tooltip: 35 | 'Tell the computer that the side can be used for networking.'}, 36 | {funcName: 'close', 37 | text: 'close rednet on %1', 38 | args: [['SIDE', new Blockly.FieldDropdown(Blockly.ComputerCraft.ValueBlock.SIDES)]], 39 | tooltip: 40 | 'Tell the computer that the side can no longer be used for networking.'}, 41 | {funcName: 'isOpen', 42 | text: 'is rednet open on %1?', 43 | args: [['SIDE', new Blockly.FieldDropdown(Blockly.ComputerCraft.ValueBlock.SIDES)]], 44 | output: 'Boolean', 45 | tooltip: 46 | 'Check if rednet is open on the specified side.'}, 47 | {funcName: 'run', 48 | text: 'run rednet', 49 | tooltip: 'Run rednet.'}]; 50 | 51 | Blockly.ComputerCraft.REDNET_FUNCS_.forEach(function(info) { 52 | Blockly.ComputerCraft.buildValueBlock( 53 | 'rednet', Blockly.ComputerCraft.REDNET_BLOCK_COLOUR_, info);}); 54 | 55 | Blockly.ComputerCraft.buildDependentInputBlock( 56 | 'rednet', 57 | Blockly.ComputerCraft.REDNET_BLOCK_COLOUR_, 58 | {blockName: 'broadcast', 59 | text:'broadcast %1 %2 on rednet', 60 | args: [['OPTION*', 61 | [['empty message', 'announce'], 62 | ['message', 'broadcast*']]], 63 | ['MESSAGE^', 'String']], 64 | ddFuncName: 'OPTION'}); 65 | 66 | Blockly.ComputerCraft.buildDependentInputBlock( 67 | 'rednet', 68 | Blockly.ComputerCraft.REDNET_BLOCK_COLOUR_, 69 | {funcName: 'receive', 70 | text:'wait %1 %2 for rednet message', 71 | args: [['SECONDS^', 'Number'], 72 | ['OPTION*', 73 | [['forever', 'forever'], 74 | ['seconds', 'seconds*']]]], 75 | multipleOutputs: 3}); 76 | -------------------------------------------------------------------------------- /apps/code/blocks-redstone.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Redstone API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Redstone API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.ValueBlock'); 26 | 27 | Blockly.ComputerCraft.REDSTONE_BLOCK_COLOUR_ = 290; 28 | 29 | Blockly.ComputerCraft.REDSTONE_FUNCS_ = [ 30 | {funcName: 'getSides', 31 | text: 'get sides', 32 | output: 'Table', 33 | tooltip: 34 | 'Get a table whose values are the names of the sides\n' + 35 | '(top, bottom, left, right, front, and back) through\n' + 36 | 'which RedPower cables and redstone could be connected.'}, 37 | {blockName: 'get_input', 38 | text: 'get %1 redstone signal through %2', 39 | args: [['OPTION', 40 | new Blockly.FieldDropdown( 41 | [['digital', 'getInput'], 42 | ['analog', 'getAnalogInput']], 43 | function(value) { 44 | this.sourceBlock_.changeOutput( 45 | value == 'getInput' ? 'Boolean' : 'Number'); 46 | })], 47 | ['SIDE', new Blockly.FieldDropdown(Blockly.ComputerCraft.ValueBlock.SIDES)]], 48 | ddFuncName: 'OPTION', 49 | output: 'Boolean', 50 | tooltip: 51 | 'Get the redstone signal from the cable on the specified side.\n' + 52 | 'Digital signals are either of the boolean values "true" or "false".\n' + 53 | 'Analog signals are in the numeric range 0-15.'}, 54 | {blockName: 'set_output', 55 | text: 'output %1 signal %3 through %2', 56 | args: [['OPTION', 57 | new Blockly.FieldDropdown( 58 | [['digital', 'setOutput'], 59 | ['analog', 'setAnalogOutput']], 60 | function(value) { 61 | this.sourceBlock_.getInput('SIGNAL').setCheck( 62 | value == 'setOutput' ? 'Boolean' : 'Number'); 63 | })], 64 | ['SIDE', new Blockly.FieldDropdown(Blockly.ComputerCraft.ValueBlock.SIDES)], 65 | ['SIGNAL', 'Boolean']], 66 | ddFuncName: 'OPTION', 67 | tooltip: 68 | 'Output the specified signal through an attached redstone cable.\n' + 69 | 'Digital signals are either of the boolean values "true" or "false".\n' + 70 | 'Analog signals are numbers in the range 0-15.'}, 71 | {blockName: 'get_bundled_input', 72 | text: 'get %1 colours on bundled cable on %2', 73 | args: [['OPTION', 74 | new Blockly.FieldDropdown([['all', 'getBundledInput'], 75 | ['activated', 'getBundledOutput']])], 76 | ['SIDE', new Blockly.FieldDropdown(Blockly.ComputerCraft.ValueBlock.SIDES)]], 77 | ddFuncName: 'OPTION', 78 | output: 'Number', 79 | tooltip: 80 | 'Get the set of colours either present (all) or activated\n' + 81 | 'on a RedPower bundled cable connected on the specified side.'}, 82 | {funcName: 'setBundledOutput', 83 | text: 'activate colours %2 on bundled cable on %1', 84 | args: [['SIDE', new Blockly.FieldDropdown(Blockly.ComputerCraft.ValueBlock.SIDES)], 85 | ['COLOURS', 'Number']], 86 | tooltip: 87 | 'Activate the specified coloured wires in the attached bundled cable.\n' + 88 | 'The colour input may be an individual colour, the sum of colours, or\n' + 89 | 'a set of colours, created with the "combine" block in the "Colours" drawer.'}, 90 | {funcName: 'testBundledInput', 91 | text: 'is colour %2 active on bundled cable on %1?', 92 | args: [['SIDE', new Blockly.FieldDropdown(Blockly.ComputerCraft.ValueBlock.SIDES)], 93 | ['COLOURS', 'Number']], 94 | output: 'Boolean', 95 | tooltip: 96 | 'Has the value "true" if the specified colour is\n' + 97 | 'active in the attached bundled cable; otherwise, false.'}]; 98 | 99 | Blockly.ComputerCraft.REDSTONE_FUNCS_.forEach(function(info) { 100 | Blockly.ComputerCraft.buildValueBlock( 101 | 'redstone', Blockly.ComputerCraft.REDSTONE_BLOCK_COLOUR_, info);}); 102 | -------------------------------------------------------------------------------- /apps/code/blocks-shell.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Shell API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Shell API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.DependentInputBlock'); 26 | goog.require('ComputerCraft.ValueBlock'); 27 | goog.require('ComputerCraft.VarArgsBlock'); 28 | 29 | Blockly.ComputerCraft.SHELL_BLOCK_COLOUR_ = 290; 30 | 31 | Blockly.ComputerCraft.SHELL_FUNCS_ = [ 32 | {funcName: 'exit', 33 | text: 'exit program', 34 | tooltip: 35 | 'Exit the current program, or the shell if no programs are running.'}, 36 | {blockName: 'dir', 37 | text: 'get directory', 38 | output: 'String', 39 | tooltip: 'Get the path to the current directory.'}, 40 | {funcName: 'setDir', 41 | text: 'set directory to %1', 42 | args: [['PATH', 'String']], 43 | tooltip: 'Set the working directory.'}, 44 | {funcName: 'path', 45 | text: 'get path', 46 | output: 'String', 47 | tooltip: 'Get a colon-separated string of the directories in the path.'}, 48 | {funcName: 'setPath', 49 | text: 'set path to %1', 50 | args: [['PATH', 'String']], 51 | tooltip: 'Set the path to the colon-separated string.'}, 52 | {funcName: 'resolve', 53 | text: 'resolve %1 %2', 54 | args: [['CHOICE', 55 | new Blockly.FieldDropdown( 56 | [['path', 'resolve'], 57 | ['program', 'resolveProgram']])], 58 | ['PATH', 'String']], 59 | ddFuncName: 'CHOICE', 60 | tooltip: 'Resolve the given local path or program to an absolute path.'}, 61 | {funcName: 'aliases', 62 | output: 'Table', 63 | text: 'get aliases', 64 | tooltip: 65 | 'Get a table containing the default aliases\n' + 66 | 'and any user-specified aliases. The key of\n' + 67 | 'each entry is the alias name, and the value\n' + 68 | 'the name of the associated program.'}, 69 | {funcName: 'programs', 70 | text: 'get %1 files', 71 | output: 'Table', 72 | args: [['FILES', 73 | new Blockly.FieldDropdown( 74 | [['regular', 'false'], 75 | ['all', 'true']])]], 76 | quoteDropdownValues: false, 77 | tooltip: 78 | 'Get a table of files in the current directory and in rom/programs.\n' + 79 | 'Files whose names start with a period will be shown if "all" is selected.'}, 80 | {funcName: 'getRunningProgram', 81 | text: 'get running program', 82 | tooltip: 'Get the path of the currently running shell or program.', 83 | output: 'String'}]; 84 | 85 | Blockly.ComputerCraft.SHELL_FUNCS_.forEach(function(info) { 86 | Blockly.ComputerCraft.buildValueBlock( 87 | 'shell', Blockly.ComputerCraft.SHELL_BLOCK_COLOUR_, info);}); 88 | 89 | Blockly.ComputerCraft.buildDependentInputBlock( 90 | 'shell', 91 | Blockly.ComputerCraft.SHELL_BLOCK_COLOUR_, 92 | {blockName: 'change_alias', 93 | text:'%1 %2 %3', 94 | args: [['OPTION*', 95 | [['set alias', 'setAlias*'], 96 | ['clear alias', 'clearAlias']]], 97 | ['ALIAS', 'String'], 98 | ['VALUE^', 'String']], 99 | depTitle: 'to', 100 | ddFuncName: 'OPTION'}); 101 | 102 | Blockly.ComputerCraft.buildVarArgsBlock( 103 | 'shell', 104 | Blockly.ComputerCraft.SHELL_BLOCK_COLOUR_, 105 | {funcName: 'run', 106 | text: 'run program %1 %v', 107 | args: [['PATH', 'String']], 108 | varArgName: 'argument', 109 | varArgType: 'String', 110 | varArgTitle: 'with arguments', 111 | varArgTooltip: 'Argument to the program.', 112 | varArgCount: 1, 113 | varContainerName: 'arguments', 114 | varContainerTooltip: 'Add, delete, or reorder arguments to the program.', 115 | tooltip: 116 | 'Run the specified program with the provided arguments.\n' + 117 | 'Increase or decrease the number of arguments by clicking the star.'}); 118 | -------------------------------------------------------------------------------- /apps/code/blocks-table.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Table blocks for Blockly Lua. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | 26 | Blockly.ComputerCraft.TABLE_BLOCK_COLOUR_ = 230; 27 | 28 | Blockly.Blocks['tables_create_empty'] = { 29 | // Create an empty table. 30 | init: function() { 31 | this.setHelpUrl(Blockly.Msg.LISTS_CREATE_EMPTY_HELPURL); 32 | this.setColour(260); 33 | this.setOutput(true, 'Array'); 34 | this.appendDummyInput() 35 | .appendTitle(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE); 36 | this.setTooltip(Blockly.Msg.LISTS_CREATE_EMPTY_TOOLTIP); 37 | } 38 | }; 39 | 40 | Blockly.Blocks['lists_create_with'] = { 41 | // Create a list with any number of elements of any type. 42 | init: function() { 43 | this.setColour(260); 44 | this.appendValueInput('ADD0') 45 | .appendTitle(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH); 46 | this.appendValueInput('ADD1'); 47 | this.appendValueInput('ADD2'); 48 | this.setOutput(true, 'Array'); 49 | this.setMutator(new Blockly.Mutator(['lists_create_with_item'])); 50 | this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP); 51 | this.itemCount_ = 3; 52 | }, 53 | mutationToDom: function(workspace) { 54 | var container = document.createElement('mutation'); 55 | container.setAttribute('items', this.itemCount_); 56 | return container; 57 | }, 58 | domToMutation: function(container) { 59 | for (var x = 0; x < this.itemCount_; x++) { 60 | this.removeInput('ADD' + x); 61 | } 62 | -------------------------------------------------------------------------------- /apps/code/blocks-term.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Terminal (term) API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Terminal (term) API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.ValueBlock'); 26 | 27 | Blockly.ComputerCraft.TERM_BLOCK_COLOUR_ = 160; 28 | 29 | Blockly.ComputerCraft.TERM_FUNCS_ = [ 30 | {funcName: 'write', 31 | text: 'write %1 to screen', 32 | args: [['Text', 'String']], 33 | tooltip: 34 | 'Write the given string to the screen (terminal or monitor).' 35 | }, 36 | {funcName: 'clear', 37 | text: 'clear screen', 38 | tooltip: 'Clear the entire screen (terminal or monitor).' 39 | }, 40 | {funcName: 'clearLine', 41 | text: 'clear line on screen', 42 | tooltip: 'Clear the line the cursor is on.' 43 | }, 44 | {funcName: 'getCursorPos', 45 | text: 'get cursor position', 46 | output: 'Number', // first output 47 | tooltip: 'Get the x and y coodinates of the cursor.', 48 | multipleOutputs: 2 49 | }, 50 | {funcName: 'setCursorPos', 51 | text: 'set cursor position to (%1, %2)', 52 | args: [['X', 'Number'], ['Y', 'Number']], 53 | tooltip: 'Set the x and y coodinates, respecitvely, of the cursor.' 54 | }, 55 | {funcName: 'isColor', 56 | text: 'computer supports colour?', 57 | output: 'Boolean', 58 | tooltip: 59 | 'Return true if the computer supports colour, false otherwise.\n' + 60 | 'This indicates whether an Advanced Computer is being used.' 61 | }, 62 | {funcName: 'getSize', 63 | text: 'get width and height of screen', 64 | output: 'Number', // first output 65 | multipleOutputs: 2, 66 | tooltip: 67 | 'Get the maximum x-coordinate (width) and y-coordinate (height)\n' + 68 | 'of the screen (terminal or monitor)' 69 | }, 70 | {funcName: 'scroll', 71 | text: 'scroll the screen %1 line(s)', 72 | args: [['NUM', 'Number']], 73 | tooltip: 74 | 'Scroll the screen (terminal or monitor)\n' + 75 | 'the specified number of lines.' 76 | }, 77 | {funcName: 'redirect', 78 | text: 'redirect display to %1', 79 | args: [['TERM', 'Peripheral']], 80 | tooltip: 81 | 'Redirect terminal output to a monitor or other redirect target.\n' + 82 | 'The input is usually the output of "wrap peripheral"\n' + 83 | 'Display can be restored to the original with the "restore display" block.' 84 | }, 85 | {funcName: 'restore', 86 | text: 'restore display', 87 | tooltip: 88 | 'Restore the display to the previous target, \n' + 89 | 'after changing it with the "redirect display" block.' 90 | }, 91 | {funcName: 'setTextColor', 92 | text: 'set text colour to %1', 93 | args: [['COLOUR', ['Colour', 'Number']]], 94 | tooltip: 95 | 'Set the text colour of the terminal.\n' + 96 | 'This is only available for Advanced Computers\n' + 97 | 'and Advanced Monitors.' 98 | }, 99 | {funcName: 'setBackgroundColor', 100 | text: 'set background colour to %1', 101 | args: [['COLOUR', ['Colour', 'Number']]], 102 | tooltip: 103 | 'Set the background colour of the screen.\n' + 104 | 'This is only available for Advanced Computers\n' + 105 | 'and Advanced Monitors.' 106 | }, 107 | {funcName: 'setTextScale', 108 | text: 'scale text by %1', 109 | args: [['SCALE', 'Number']], 110 | tooltip: 111 | 'Set the size of all text on the connected monitor.\n' + 112 | 'The input must be a multiple of .5 between .5 and 5 (inclusive).\n' + 113 | 'This is only available on monitors, not terminals.' 114 | } 115 | ]; 116 | 117 | Blockly.ComputerCraft.TERM_FUNCS_.forEach(function(info) { 118 | Blockly.ComputerCraft.buildValueBlock( 119 | 'term', Blockly.ComputerCraft.TERM_BLOCK_COLOUR_, info);}); 120 | 121 | // Make sure that a numeric literal argument is in the range [.5, 5], 122 | // and divisible by .5. 123 | Blockly.Blocks['term_set_text_scale'].onchange = function() { 124 | if (!this.workspace) { 125 | // Block has been deleted. 126 | return; 127 | } 128 | // If there's no child block, no warning. 129 | if (!this.childBlocks_) { 130 | this.setWarningText(null); 131 | return; 132 | } 133 | // Don't display (or remove) a warning if the child 134 | // block is selected, since editing might be in progress. 135 | // Flaw: No warning is displayed if after typing (but not entering) 136 | // a bad value, user clicks on 'Lua'. 137 | if (Blockly.selected == this.childBlocks_[0]) { 138 | return; 139 | } 140 | // If the input is a constant, make sure it is divisible by .5 141 | // and in the range [.5, 5]. 142 | var code = Blockly.Lua.valueToCode(this, 'SCALE', Blockly.Lua.ORDER_NONE); 143 | if (code) { 144 | var num = Number(code); 145 | if (num != NaN) { 146 | if (num * 2 != Math.floor(num * 2) || num < .5 || num > 5) { 147 | this.setWarningText( 148 | 'The scale value must be a multiple of .5 in the range .5 to 5.'); 149 | return; 150 | } 151 | } 152 | } 153 | this.setWarningText(null); 154 | }; 155 | 156 | // TODO: Convert to ValueBlock. 157 | Blockly.Blocks['term_set_cursor_blink'] = new Blockly.ComputerCraft.Block( 158 | 'term', Blockly.ComputerCraft.TERM_BLOCK_COLOUR_, { 159 | funcName: 'setCursorBlink', 160 | helpUrlType: Blockly.ComputerCraft.HelpUrlType.PREFIX_NAME, 161 | tooltip: 162 | 'Enable or disable blinking of the\n' + 163 | 'cursor on a screen (terminal or monitor).'}); 164 | 165 | Blockly.Blocks['term_set_cursor_blink'].init = function() { 166 | Blockly.ComputerCraft.Block.prototype.init.call(this); 167 | this.appendDummyInput() 168 | .appendTitle( 169 | new Blockly.FieldDropdown( 170 | [['turn on cursor blinking', 'true'], 171 | ['turn off cursor blinking', 'false']]), 172 | 'STATUS') 173 | }; 174 | 175 | Blockly.Lua['term_set_cursor_blink'] = Blockly.ComputerCraft.generateLuaInner_; 176 | -------------------------------------------------------------------------------- /apps/code/blocks-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft tests 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Test blocks for ComputerCraft. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | 26 | Blockly.ComputerCraft.buildDependentInputBlock( 27 | 'test', 28 | 200, { 29 | funcName: 'vote', 30 | text: 'Vote for %1: %2 %3', 31 | args: [['OFFICE', [['President', 'president'], 32 | ['Vice President', 'vp']]], 33 | ['CANDIDATE*', [['George Washington', 'washington*'], 34 | ['Abraham Lincoln', 'lincoln'], 35 | ['write-in candidate', 'writein']]], 36 | ['WRITE_IN^', 'String']] 37 | }); 38 | 39 | Blockly.ComputerCraft.buildDependentInputBlock( 40 | 'test', 41 | 200, { 42 | funcName: 'count', 43 | text: '%1 %2', 44 | args: [['ENABLE*', [['Disable dependent input', 'disable'], 45 | ['Enable dependent input', 'enable*']]], 46 | ['AMOUNT^', 'Number']], 47 | addChild: Blockly.ComputerCraft.InputAddType.FIRST}); 48 | 49 | Blockly.ComputerCraft.buildVarArgsBlock( 50 | 'test', 51 | 200, 52 | {blockName: 'varargs', 53 | funcName: 'giveMeMore', 54 | text: 'give me more %v', 55 | varArgName: 'argument', 56 | varArgType: 'String', 57 | varContainerName: 'arguments'}); 58 | -------------------------------------------------------------------------------- /apps/code/blocks-textutils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Textutils API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Textutils API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | goog.require('ComputerCraft.DependentInputBlock'); 26 | goog.require('ComputerCraft.ValueBlock'); 27 | goog.require('ComputerCraft.VarArgsBlock'); 28 | 29 | Blockly.ComputerCraft.TEXTUTILS_BLOCK_COLOUR_ = 190; 30 | 31 | Blockly.ComputerCraft.TEXTUTILS_FUNCS_ = [ 32 | {blockName: 'write', 33 | text: 'write string %1 %2 to screen at rate %3', 34 | args: [['TEXT', 'String'], 35 | ['MODE', 36 | new Blockly.FieldDropdown([['without newline', 'slowWrite'], 37 | ['with newline', 'slowPrint']])], 38 | ['RATE', 'Number']], 39 | ddFuncName: 'MODE', 40 | tooltip: 41 | 'Write the given string to the screen (terminal or monitor)\n'+ 42 | 'at the current cursor position character-by-character.\n' + 43 | 'The higher the rate, the faster the string is output.\n' + 44 | 'A value of 1 outputs one character per second.\n' + 45 | 'If a newline is used, the next output will be to a new line.' 46 | }, 47 | {funcName: 'slowPrint', 48 | text: 'write line %1 to screen at rate %2', 49 | args: [['TEXT', 'String'], ['RATE', 'Number']], 50 | tooltip: 51 | 'Write the given string to the screen (terminal or monitor)\n'+ 52 | 'at the current cursor position character-by-character.\n' + 53 | 'The higher the rate, the faster the string is output.\n' + 54 | 'A value of 1 outputs one character per second.' + 55 | 'Unlike with the "write string" block, a newline is printed at the end.\n' 56 | }, 57 | {funcName: 'pagedPrint', 58 | text: 'write string %1 paginated', 59 | args: [['TEXT', 'String']], 60 | tooltip: 61 | 'Print the string to the screen (terminal or monitor),\n' + 62 | 'waiting for confirmation before scrolling down.'}, 63 | {funcName: 'serialize', 64 | text: 'convert table %1 to string', 65 | args: [['TABLE', 'Table']], 66 | output: 'String', 67 | tooltip: 68 | 'Serialize the table into a string for\n' + 69 | 'display, storage, or transmission.\n' + 70 | 'The table can be recovered with the\n' + 71 | '"convert string to table" block.' 72 | }, 73 | {funcName: 'unserialize', 74 | text: 'convert string %1 to table', 75 | args: [['TEXT', 'String']], 76 | output: 'Table', 77 | tooltip: 78 | 'Unserialize a string representation of a table\n' + 79 | 'created with the "convert table to string" block.' 80 | }, 81 | {funcName: 'urlEncode', 82 | text: 'encode %1 for URL', 83 | args: [['TEXT', 'String']], 84 | tooltip: 85 | 'Encode a string for transmission within a URL.\n' + 86 | 'Spaces are replaced with "+s". Unsafe characters,\n' + 87 | 'such as quotation marks, are replaced by their ASCII\n' + 88 | 'values and preceded with a percent sign (%).' 89 | } 90 | ]; 91 | 92 | Blockly.ComputerCraft.TEXTUTILS_FUNCS_.forEach(function(info) { 93 | Blockly.ComputerCraft.buildValueBlock( 94 | 'textutils', Blockly.ComputerCraft.TEXTUTILS_BLOCK_COLOUR_, info);}); 95 | 96 | Blockly.ComputerCraft.buildDependentInputBlock( 97 | 'textutils', 98 | Blockly.ComputerCraft.TEXTUTILS_BLOCK_COLOUR_, 99 | {funcName: 'formatTime', 100 | text: 'format %1 %2', 101 | args: [['CHOICE*', 102 | [['current time', 'current'], 103 | ['time...', 'time*']]], 104 | ['TIME^', 'Number']], 105 | addChild: Blockly.ComputerCraft.InputAddType.NEVER, 106 | tooltip: 'Format the current or given time as a printable string.'}); 107 | 108 | Blockly.ComputerCraft.buildVarArgsBlock( 109 | 'textutils', 110 | Blockly.ComputerCraft.TEXTUTILS_BLOCK_COLOUR_, 111 | {blockName: 'tabulate', 112 | text: 'display tables %v %1', 113 | args: [['MODE', new Blockly.FieldDropdown( 114 | [['with pagination', 'pagedTabulate'], 115 | ['without pagination', 'tabulate']])]], 116 | ddFuncName: 'MODE', 117 | varArgName: 'table', 118 | varArgType: ['Table', 'List'], 119 | varArgTooltip: 'A table to display.', 120 | varArgCount: 1, 121 | varContainerName: 'tables', 122 | varContainerTooltip: 'Add, remove, or reorder the tables to display.', 123 | tooltip: 124 | 'Print tables to the screen in an ordered form.\n' + 125 | 'If pagination is used, this pauses for confirmation before scrolling.\n' + 126 | 'Click on the star to add (or remove) tables.'}); 127 | -------------------------------------------------------------------------------- /apps/code/blocks-vector.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft Vector API 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Blocks for ComputerCraft Vector API 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | 26 | Blockly.ComputerCraft.VECTOR_BLOCK_COLOUR_ = 290; 27 | 28 | Blockly.ComputerCraft.VECTOR_FUNCS_ = [ 29 | {funcName: 'new', 30 | text: 'create vector (%1, %2, %3)', 31 | args: [['X', 'Number'], ['Y', 'Number'], ['Z', 'Number']], 32 | output: 'Vector', 33 | tooltip: 34 | 'Create a vector with the given x, y, and z co-ordinates.'}, 35 | {blockName: 'add_sub', 36 | text: 'vector %1 %2 vector %3', 37 | args: [['X', 'Vector'], 38 | ['OP', new Blockly.FieldDropdown( 39 | [['+', 'add'], 40 | ['-', 'sub']])], 41 | ['Y', 'Vector']], 42 | ddFuncName: 'OP', 43 | output: 'Vector', 44 | tooltip: 45 | 'Compute the sum or difference of two vectors.\n' + 46 | 'This does not modify either of the input vectors.'}, 47 | {funcName: 'mul', 48 | text: 'vector %1 x scalar %2', 49 | args: [['V', 'Vector'], 50 | ['N', 'Number']], 51 | output: 'Vector', 52 | tooltip: 53 | 'Create a vector that scales the input vector by the input number.\n' + 54 | 'This does not modify the input vector.'}, 55 | {funcName: 'dot', 56 | text: 'vector %1 · vector %2', 57 | args: [['X', 'Vector'], 58 | ['Y', 'Vector']], 59 | output: 'Vector', 60 | tooltip: 61 | 'Compute the dot product of the two inputs vectors.\n' + 62 | 'This does not modify either of the input vectors.\n'}, 63 | {funcName: 'cross', 64 | text: 'vector %1 x vector %2', 65 | args: [['X', 'Vector'], 66 | ['Y', 'Vector']], 67 | output: 'Vector', 68 | tooltip: 69 | 'Create a vector that is the cross product of the two inputs vectors.\n' + 70 | 'This does not modify either of the input vectors.\n'}, 71 | {funcName: 'length', 72 | text: 'length of vector %1', 73 | args: [['X', 'Vector']], 74 | output: 'Number', 75 | tooltip: 76 | 'Calculate the length of the input vector.\n' + 77 | 'This is defined as the distance from the origin.\n'}, 78 | {funcName: 'normalize', 79 | text: 'normalize vector %1', 80 | args: [['X', 'Vector']], 81 | output: 'Number', 82 | tooltip: 83 | 'Create a vector that is a normalized version of the input vector.\n' + 84 | 'In other words, each of the values will be scaled proportionately\n' + 85 | 'such that the length of the new vector is 1. The input vector is unchanged.'}, 86 | {funcName: 'tostring', 87 | text: 'create string for vector %1', 88 | args: [['X', 'Vector']], 89 | output: 'String', 90 | tooltip: 'Create a string representation of the input vector.'}, 91 | // A custom code generator for the block is defined below. 92 | {blockName: 'get_coord', 93 | text: 'get the %1 co-ordinate of vector %2', 94 | args: [['COORD', 95 | new Blockly.FieldDropdown([['x', 'x'], ['y', 'y'], ['z', 'z']])], 96 | ['X', 'Vector']], 97 | output: 'Number', 98 | suppressLua: true, 99 | tooltip: 100 | 'Get the specified co-ordinate from the vector.'}]; 101 | 102 | Blockly.ComputerCraft.VECTOR_FUNCS_.forEach(function(info) { 103 | Blockly.ComputerCraft.buildValueBlock( 104 | 'vector', Blockly.ComputerCraft.VECTOR_BLOCK_COLOUR_, info);}); 105 | 106 | Blockly.Lua['vector_get_coord'] = function(block) { 107 | var code = Blockly.Lua.valueToCode(block, 'X', Blockly.Lua.ORDER_NONE) + 108 | '["' + block.getTitleValue('COORD') + '"]'; 109 | return [code, Blockly.Lua.ORDER_HIGH]; 110 | }; 111 | -------------------------------------------------------------------------------- /apps/code/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/apps/code/icons.png -------------------------------------------------------------------------------- /apps/code/side_input_block.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Lua: ComputerCraft SideInputBlock class 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Class for ComputerCraft blocks having an input that can 22 | * specify either a side or a named cable. 23 | * @author ellen.spertus@gmail.com (Ellen Spertus) 24 | */ 25 | 'use strict'; 26 | goog.provide('ComputerCraft.SideInputBlock'); 27 | 28 | goog.require('ComputerCraft.DependentInputBlock'); 29 | 30 | /** 31 | * Class for ComputerCraft blocks with a 'side' input (one of 'front', 'back', 32 | * 'left', 'right', 'top', 'bottom', or an arbitrary string identifying a 33 | * cable). The block may also have both earlier inputs, provided through 34 | * info.text and info.args, and later inputs. If an input is added after 35 | * the block is constructed, the method inputAdded() must be called. 36 | * 37 | * The side input and the dependent string input will be added on to the 38 | * end of the provided inputs, mutating the text and args arguments. They 39 | * are named SIDE and CABLE, respectively. 40 | * 41 | * A question mark will be automatically added to the end of the block name if 42 | * the output (as specified in the 'info' parameter) is Boolean. 43 | * 44 | * @param {string} prefix A ComputerCraft API name, such as 'turtle'. 45 | * @param {number} colour The block colour, an HSV hue value. 46 | * @param {Object} info Information about the block being defined. 47 | * The same fields are used as in the constructor of the parent class, 48 | * Blockly.ComputerCraft.DependentInputBlock. Notes: 49 | * @return {Blockly.ComputerCraft.SideInputBlock} The new block. 50 | */ 51 | Blockly.ComputerCraft.SideInputBlock = function(prefix, colour, info) { 52 | info.codeGenType = 53 | Blockly.ComputerCraft.ControllingInputCodeGenType.ONLY_IF_DEP_HIDDEN; 54 | Blockly.ComputerCraft.SideInputBlock.superClass_.constructor.call( 55 | this, prefix, colour, info); 56 | }; 57 | goog.inherits(Blockly.ComputerCraft.SideInputBlock, 58 | Blockly.ComputerCraft.DependentInputBlock); 59 | 60 | Blockly.ComputerCraft.SideInputBlock.SIDES_ = 61 | [['in front', 'front'], 62 | ['in back', 'back'], 63 | ['to the left', 'left'], 64 | ['to the right', 'right'], 65 | ['above', 'top'], 66 | ['below', 'bottom'], 67 | ['through cable...', 'cable']]; 68 | 69 | /** 70 | * Create a block that has a side input. 71 | * 72 | * @param {string} prefix A ComputerCraft API name, such as 'turtle'. 73 | * @param {number} colour The block colour, an HSV hue value. 74 | * @param {Object} info Information about the block being defined. 75 | * In addition to the fields used by the Blockly.ComputerCraft.SideInputBlock 76 | * constructor, this has: 77 | * 80 | * @return {Blockly.ComputerCraft.SideInputBlock} The new block. 81 | */ 82 | Blockly.ComputerCraft.buildSideInputBlock = function(prefix, colour, info) { 83 | if (!info.helpUrlType) { 84 | info.helpUrlType = Blockly.ComputerCraft.HelpUrlType.PREFIX_NAME; 85 | } 86 | if (!info.args) { 87 | info.args = []; 88 | } 89 | // Add SIDE and CABLE inputs to info.text. 90 | // A dummy input will be inserted in DependentInputBlock.init(). 91 | info.text += ' %' + (info.args.length + 1) + ' %' + (info.args.length + 2); 92 | // Add SIDE and CABLE inputs to info.args. 93 | info.args.push(['SIDE', Blockly.ComputerCraft.SideInputBlock.SIDES_]); 94 | info.args.push(['CABLE', 'String']); 95 | 96 | // Explicitly set the dependent block attributes; otherwise, info.args will be 97 | // mutated in setDependenceInfo_(). 98 | info.ddName = 'SIDE'; // This is the controlling dropdown menu. 99 | info.ddValue = 'cable'; // This is the value for showing the dependent input. 100 | info.depName = 'CABLE'; // This is the dependent input. 101 | info.depType = 'String'; 102 | 103 | // Add question mark at end of text if the block is a predicate. 104 | if (info.output == 'Boolean') { 105 | info.text += '?'; 106 | }; 107 | 108 | // Build block. 109 | var newBlock = new Blockly.ComputerCraft.SideInputBlock(prefix, colour, info); 110 | Blockly.Blocks[newBlock.blockName] = newBlock; 111 | if (!info.suppressLua) { 112 | Blockly.Lua[newBlock.blockName] = 113 | Blockly.ComputerCraft.Block.prototype.generateLua; 114 | } 115 | return newBlock; 116 | }; 117 | -------------------------------------------------------------------------------- /apps/code/style.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | height: 100%; 3 | } 4 | body { 5 | margin: 0; 6 | overflow: hidden; 7 | } 8 | h1 { 9 | margin-left: 5px; 10 | margin-right: 5px; 11 | } 12 | 13 | /* Tabs */ 14 | #tabRow>td { 15 | border: 1px solid #ccc; 16 | } 17 | td.tabon { 18 | border-bottom-color: #ddd !important; 19 | background-color: #ddd; 20 | padding: 5px 19px; 21 | } 22 | td.taboff { 23 | cursor: pointer; 24 | padding: 5px 19px; 25 | } 26 | td.taboff:hover { 27 | background-color: #eee; 28 | } 29 | td.tabmin { 30 | border-top-style: none !important; 31 | border-left-style: none !important; 32 | border-right-style: none !important; 33 | } 34 | td.tabmax { 35 | border-top-style: none !important; 36 | border-left-style: none !important; 37 | border-right-style: none !important; 38 | width: 99%; 39 | padding-left: 10px; 40 | padding-right: 10px; 41 | text-align: right; 42 | } 43 | html[dir=rtl] td.tabmax { 44 | text-align: left; 45 | } 46 | 47 | table { 48 | border-collapse: collapse; 49 | margin: 0; 50 | padding: 0; 51 | border: none; 52 | } 53 | td { 54 | padding: 0; 55 | vertical-align: top; 56 | } 57 | .content { 58 | visibility: hidden; 59 | margin: 0; 60 | padding: 1ex; 61 | position: absolute; 62 | } 63 | pre.content { 64 | overflow: scroll; 65 | } 66 | #content_blocks { 67 | padding: 0; 68 | } 69 | .blocklySvg { 70 | border-top: none !important; 71 | } 72 | #content_xml { 73 | resize: none; 74 | outline: none; 75 | border: none; 76 | font-family: monospace; 77 | overflow: scroll; 78 | } 79 | #languageMenu { 80 | vertical-align: top; 81 | margin-top: 15px; 82 | margin-right: 15px; 83 | } 84 | 85 | /* Buttons */ 86 | button { 87 | padding: 1px 10px; 88 | margin: 1px 5px; 89 | } 90 | #pastebinButton { 91 | position:relative; 92 | height: 28px; 93 | top:-3px; 94 | //background-color:darkblue; 95 | //color:white; 96 | } 97 | .hiddenIframe { 98 | display: none; 99 | } 100 | .visibleIframe { 101 | height: 35px; 102 | width: 100%; 103 | display: block; 104 | border: 0; 105 | } 106 | .hiddenButton { 107 | display: none; 108 | } 109 | /* Sprited icons. */ 110 | .icon21 { 111 | height: 21px; 112 | width: 21px; 113 | background-image: url(icons.png); 114 | } 115 | .trash { 116 | background-position: 0px 0px; 117 | } 118 | .link { 119 | background-position: -21px 0px; 120 | } 121 | .run { 122 | background-position: -42px 0px; 123 | } 124 | -------------------------------------------------------------------------------- /apps/common.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | font-family: sans-serif; 4 | margin-top: 0; 5 | } 6 | h1 { 7 | font-weight: normal; 8 | font-size: 140%; 9 | } 10 | a:hover { 11 | color: #f00; 12 | } 13 | .farSide { 14 | text-align: right; 15 | } 16 | html[dir="RTL"] .farSide { 17 | text-align: left; 18 | } 19 | 20 | /* Buttons */ 21 | button { 22 | margin: 5px; 23 | padding: 10px; 24 | border-radius: 4px; 25 | border: 1px solid #ddd; 26 | font-size: large; 27 | background-color: #eee; 28 | color: #000; 29 | } 30 | button.primary { 31 | border: 1px solid #dd4b39; 32 | background-color: #dd4b39; 33 | color: #fff; 34 | } 35 | button.secondary { 36 | border: 1px solid #4d90fe; 37 | background-color: #4d90fe; 38 | color: #fff; 39 | } 40 | button.primary>img, 41 | button.secondary>img { 42 | opacity: 1; 43 | } 44 | button>img { 45 | opacity: 0.6; 46 | vertical-align: text-bottom; 47 | } 48 | button:hover>img { 49 | opacity: 1; 50 | } 51 | button:active { 52 | border: 1px solid #888 !important; 53 | } 54 | button:hover { 55 | box-shadow: 2px 2px 5px #888; 56 | } 57 | button.disabled:hover>img { 58 | opacity: 0.6; 59 | } 60 | button.disabled { 61 | display: none; 62 | } 63 | button.notext { 64 | font-size: 10%; 65 | } 66 | 67 | /* Dialogs */ 68 | #dialog { 69 | visibility: hidden; 70 | background-color: #fff; 71 | color: #000; 72 | border: 1px solid #ccc; 73 | position: absolute; 74 | border-radius: 8px; 75 | box-shadow: 5px 5px 5px #888; 76 | padding: 10px; 77 | } 78 | #dialogBorder { 79 | visibility: hidden; 80 | position: absolute; 81 | background-color: #fff; 82 | color: #000; 83 | border: 1px solid #000; 84 | border-radius: 6px; 85 | box-shadow: 5px 5px 5px #888; 86 | } 87 | #dialogShadow { 88 | visibility: hidden; 89 | position: fixed; 90 | top: 0; 91 | left: 0; 92 | height: 100%; 93 | width: 100%; 94 | background-color: #000; 95 | opacity: 0.3 96 | } 97 | .dialogAnimate { 98 | transition-property: width height left top opacity; 99 | transition-duration: 0.2s; 100 | transition-timing-function: linear; 101 | } 102 | .dialogHiddenContent { 103 | visibility: hidden; 104 | position: absolute; 105 | top: 0; 106 | left: 0; 107 | z-index: -1; 108 | } 109 | #dialogHeader { 110 | height: 25px; 111 | margin: -10px -10px 15px; 112 | border-top-left-radius: 8px; 113 | border-top-right-radius: 8px; 114 | background-color: #ddd; 115 | cursor: move; 116 | } 117 | #dialog button { 118 | min-width: 4em; 119 | } 120 | -------------------------------------------------------------------------------- /apps/lang-lua.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2008 Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | 17 | /** 18 | * @fileoverview 19 | * Registers a language handler for Lua. 20 | * 21 | * 22 | * To use, include prettify.js and this file in your HTML page. 23 | * Then put your code in an HTML tag like 24 | *
(my Lua code)
25 | * 26 | * 27 | * I used http://www.lua.org/manual/5.1/manual.html#2.1 28 | * Because of the long-bracket concept used in strings and comments, Lua does 29 | * not have a regular lexical grammar, but luckily it fits within the space 30 | * of irregular grammars supported by javascript regular expressions. 31 | * 32 | * @author mikesamuel@gmail.com 33 | */ 34 | 35 | PR['registerLangHandler']( 36 | PR['createSimpleLexer']( 37 | [ 38 | // Whitespace 39 | [PR['PR_PLAIN'], /^[\t\n\r \xA0]+/, null, '\t\n\r \xA0'], 40 | // A double or single quoted, possibly multi-line, string. 41 | [PR['PR_STRING'], /^(?:\"(?:[^\"\\]|\\[\s\S])*(?:\"|$)|\'(?:[^\'\\]|\\[\s\S])*(?:\'|$))/, null, '"\''] 42 | ], 43 | [ 44 | // A comment is either a line comment that starts with two dashes, or 45 | // two dashes preceding a long bracketed block. 46 | [PR['PR_COMMENT'], /^--(?:\[(=*)\[[\s\S]*?(?:\]\1\]|$)|[^\r\n]*)/], 47 | // A long bracketed block not preceded by -- is a string. 48 | [PR['PR_STRING'], /^\[(=*)\[[\s\S]*?(?:\]\1\]|$)/], 49 | [PR['PR_KEYWORD'], /^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/, null], 50 | // A number is a hex integer literal, a decimal real literal, or in 51 | // scientific notation. 52 | [PR['PR_LITERAL'], 53 | /^[+-]?(?:0x[\da-f]+|(?:(?:\.\d+|\d+(?:\.\d*)?)(?:e[+\-]?\d+)?))/i], 54 | // An identifier 55 | [PR['PR_PLAIN'], /^[a-z_]\w*/i], 56 | // A run of punctuation 57 | [PR['PR_PUNCTUATION'], /^[^\w\t\n\r \xA0][^\w\t\n\r \xA0\"\'\-\+=]*/] 58 | ]), 59 | ['lua']); 60 | -------------------------------------------------------------------------------- /apps/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /blocks/colour.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Colour blocks for Blockly. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Blocks.colour'); 27 | 28 | goog.require('Blockly.Blocks'); 29 | 30 | 31 | Blockly.Blocks['colour_picker'] = { 32 | // Colour picker. 33 | init: function() { 34 | this.setHelpUrl(Blockly.Msg.COLOUR_PICKER_HELPURL); 35 | this.setColour(20); 36 | this.appendDummyInput() 37 | .appendTitle(new Blockly.FieldColour('#ff0000'), 'COLOUR'); 38 | this.setOutput(true, 'Colour'); 39 | this.setTooltip(Blockly.Msg.COLOUR_PICKER_TOOLTIP); 40 | } 41 | }; 42 | 43 | Blockly.Blocks['colour_random'] = { 44 | // Random colour. 45 | init: function() { 46 | this.setHelpUrl(Blockly.Msg.COLOUR_RANDOM_HELPURL); 47 | this.setColour(20); 48 | this.appendDummyInput() 49 | .appendTitle(Blockly.Msg.COLOUR_RANDOM_TITLE); 50 | this.setOutput(true, 'Colour'); 51 | this.setTooltip(Blockly.Msg.COLOUR_RANDOM_TOOLTIP); 52 | } 53 | }; 54 | 55 | Blockly.Blocks['colour_rgb'] = { 56 | // Compose a colour from RGB components. 57 | init: function() { 58 | this.setHelpUrl(Blockly.Msg.COLOUR_RGB_HELPURL); 59 | this.setColour(20); 60 | this.appendValueInput('RED') 61 | .setCheck('Number') 62 | .setAlign(Blockly.ALIGN_RIGHT) 63 | .appendTitle(Blockly.Msg.COLOUR_RGB_TITLE) 64 | .appendTitle(Blockly.Msg.COLOUR_RGB_RED); 65 | this.appendValueInput('GREEN') 66 | .setCheck('Number') 67 | .setAlign(Blockly.ALIGN_RIGHT) 68 | .appendTitle(Blockly.Msg.COLOUR_RGB_GREEN); 69 | this.appendValueInput('BLUE') 70 | .setCheck('Number') 71 | .setAlign(Blockly.ALIGN_RIGHT) 72 | .appendTitle(Blockly.Msg.COLOUR_RGB_BLUE); 73 | this.setOutput(true, 'Colour'); 74 | this.setTooltip(Blockly.Msg.COLOUR_RGB_TOOLTIP); 75 | } 76 | }; 77 | 78 | Blockly.Blocks['colour_blend'] = { 79 | // Blend two colours together. 80 | init: function() { 81 | this.setHelpUrl(Blockly.Msg.COLOUR_BLEND_HELPURL); 82 | this.setColour(20); 83 | this.appendValueInput('COLOUR1') 84 | .setCheck('Colour') 85 | .setAlign(Blockly.ALIGN_RIGHT) 86 | .appendTitle(Blockly.Msg.COLOUR_BLEND_TITLE) 87 | .appendTitle(Blockly.Msg.COLOUR_BLEND_COLOUR1); 88 | this.appendValueInput('COLOUR2') 89 | .setCheck('Colour') 90 | .setAlign(Blockly.ALIGN_RIGHT) 91 | .appendTitle(Blockly.Msg.COLOUR_BLEND_COLOUR2); 92 | this.appendValueInput('RATIO') 93 | .setCheck('Number') 94 | .setAlign(Blockly.ALIGN_RIGHT) 95 | .appendTitle(Blockly.Msg.COLOUR_BLEND_RATIO); 96 | this.setOutput(true, 'Colour'); 97 | this.setTooltip(Blockly.Msg.COLOUR_BLEND_TOOLTIP); 98 | } 99 | }; 100 | -------------------------------------------------------------------------------- /blocks/variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Variable blocks for Blockly. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Blocks.variables'); 27 | 28 | goog.require('Blockly.Blocks'); 29 | 30 | 31 | Blockly.Blocks['variables_get'] = { 32 | // Variable getter. 33 | init: function() { 34 | this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL); 35 | this.setColour(330); 36 | this.appendDummyInput() 37 | .appendTitle(Blockly.Msg.VARIABLES_GET_TITLE) 38 | .appendTitle(new Blockly.FieldVariable( 39 | Blockly.Msg.VARIABLES_GET_ITEM), 'VAR') 40 | .appendTitle(Blockly.Msg.VARIABLES_GET_TAIL); 41 | this.setOutput(true); 42 | this.setTooltip(Blockly.Msg.VARIABLES_GET_TOOLTIP); 43 | this.contextMenuMsg_ = Blockly.Msg.VARIABLES_GET_CREATE_SET; 44 | this.contextMenuType_ = 'variables_set'; 45 | }, 46 | getVars: function() { 47 | return [this.getTitleValue('VAR')]; 48 | }, 49 | renameVar: function(oldName, newName) { 50 | if (Blockly.Names.equals(oldName, this.getTitleValue('VAR'))) { 51 | this.setTitleValue(newName, 'VAR'); 52 | } 53 | }, 54 | customContextMenu: function(options) { 55 | var option = {enabled: true}; 56 | var name = this.getTitleValue('VAR'); 57 | option.text = this.contextMenuMsg_.replace('%1', name); 58 | var xmlTitle = goog.dom.createDom('title', null, name); 59 | xmlTitle.setAttribute('name', 'VAR'); 60 | var xmlBlock = goog.dom.createDom('block', null, xmlTitle); 61 | xmlBlock.setAttribute('type', this.contextMenuType_); 62 | option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); 63 | options.push(option); 64 | } 65 | }; 66 | 67 | Blockly.Blocks['variables_set'] = { 68 | // Variable setter. 69 | init: function() { 70 | this.setHelpUrl(Blockly.Msg.VARIABLES_SET_HELPURL); 71 | this.setColour(330); 72 | this.appendValueInput('VALUE') 73 | .appendTitle(Blockly.Msg.VARIABLES_SET_TITLE) 74 | .appendTitle(new Blockly.FieldVariable( 75 | Blockly.Msg.VARIABLES_SET_ITEM), 'VAR') 76 | .appendTitle(Blockly.Msg.VARIABLES_SET_TAIL); 77 | this.setPreviousStatement(true); 78 | this.setNextStatement(true); 79 | this.setTooltip(Blockly.Msg.VARIABLES_SET_TOOLTIP); 80 | this.contextMenuMsg_ = Blockly.Msg.VARIABLES_SET_CREATE_GET; 81 | this.contextMenuType_ = 'variables_get'; 82 | }, 83 | getVars: function() { 84 | return [this.getTitleValue('VAR')]; 85 | }, 86 | renameVar: function(oldName, newName) { 87 | if (Blockly.Names.equals(oldName, this.getTitleValue('VAR'))) { 88 | this.setTitleValue(newName, 'VAR'); 89 | } 90 | }, 91 | customContextMenu: Blockly.Blocks['variables_get'].customContextMenu 92 | }; 93 | 94 | Blockly.Blocks['variables_set_two'] = { 95 | // Set two variables to the return values of a procedure call. 96 | init: function() { 97 | this.setColour(330); 98 | this.appendDummyInput() 99 | .appendTitle('set variables'); 100 | this.appendDummyInput() 101 | .appendTitle(new Blockly.FieldVariable('x'), 'VAR1'); 102 | this.appendDummyInput() 103 | .appendTitle(new Blockly.FieldVariable('y'), 'VAR2'); 104 | this.appendValueInput('VALUE'); 105 | this.setPreviousStatement(true); 106 | this.setNextStatement(true); 107 | this.setInputsInline(true); 108 | this.setTooltip('Set variables to the two values returned by a procedure.'); 109 | }, 110 | renameVar: function(oldName, newName) { 111 | var var1 = this.getTitleValue('VAR1'); 112 | var var2 = this.getTitleValue('VAR2'); 113 | if ((var1 == oldName || var1 == newName) && 114 | (var2 == oldName || var2 == newName)) { 115 | window.alert('Two variables in a set block may not have the same name.'); 116 | return; 117 | } 118 | if (Blockly.Names.equals(oldName, var1)) { 119 | this.setTitleValue(newName, 'VAR1'); 120 | } 121 | if (Blockly.Names.equals(oldName, var2)) { 122 | this.setTitleValue(newName, 'VAR2'); 123 | } 124 | }, 125 | onchange: function() { 126 | if (!this.workspace) { 127 | // Block has been deleted. 128 | return; 129 | } 130 | // If the value input socket is populated, make sure that block produces 131 | // at least two values. 132 | var source = this.getInputTargetBlock('VALUE'); 133 | if (source && !source.multipleOutputs) { 134 | this.setWarningText('The attached block only produces one value, ' + 135 | 'but this block requires two.'); 136 | } else { 137 | this.setWarningText(null); 138 | } 139 | } 140 | }; 141 | 142 | Blockly.Blocks['variables_set_three'] = { 143 | // Set three variables to the return values of a procedure call. 144 | init: function() { 145 | this.setColour(330); 146 | this.appendDummyInput() 147 | .appendTitle('set variables'); 148 | this.appendDummyInput() 149 | .appendTitle(new Blockly.FieldVariable('x'), 'VAR1'); 150 | this.appendDummyInput() 151 | .appendTitle(new Blockly.FieldVariable('y'), 'VAR2'); 152 | this.appendDummyInput() 153 | .appendTitle(new Blockly.FieldVariable('z'), 'VAR3'); 154 | this.appendValueInput('VALUE'); 155 | this.setPreviousStatement(true); 156 | this.setNextStatement(true); 157 | this.setInputsInline(true); 158 | this.setTooltip( 159 | 'Set variables to the three values returned by a procedure.'); 160 | }, 161 | renameVar: function(oldName, newName) { 162 | var var1 = this.getTitleValue('VAR1'); 163 | var var2 = this.getTitleValue('VAR2'); 164 | var var3 = this.getTitleValue('VAR3'); 165 | var matches = 0; 166 | if (var1 == oldName || var1 == newName) { 167 | matches++; 168 | } 169 | if (var2 == oldName || var2 == newName) { 170 | matches++; 171 | } 172 | if (var3 == oldName || var3 == newName) { 173 | matches++; 174 | } 175 | if (matches > 1) { 176 | window.alert( 177 | 'Multiple variables in a set block may not have the same name.'); 178 | return; 179 | } 180 | if (Blockly.Names.equals(oldName, var1)) { 181 | this.setTitleValue(newName, 'VAR1'); 182 | } 183 | if (Blockly.Names.equals(oldName, var2)) { 184 | this.setTitleValue(newName, 'VAR2'); 185 | } 186 | }, 187 | onchange: function() { 188 | if (!this.workspace) { 189 | // Block has been deleted. 190 | return; 191 | } 192 | // If the value input socket is populated, make sure that block produces 193 | // at least three values. 194 | var source = this.getInputTargetBlock('VALUE'); 195 | if (source && (!source.multipleOutputs || source.multipleOutputs < 3)) { 196 | this.setWarningText('The attached block only produces one value, ' + 197 | 'but this block requires three.'); 198 | } else { 199 | this.setWarningText(null); 200 | } 201 | } 202 | }; 203 | -------------------------------------------------------------------------------- /core/blocks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Core JavaScript library for Blockly. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | /** 27 | * Name space for the Blocks singleton. 28 | * Blocks gets populated in the blocks files. 29 | */ 30 | goog.provide('Blockly.Blocks'); 31 | -------------------------------------------------------------------------------- /core/field_checkbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Checkbox field. Checked or not checked. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.FieldCheckbox'); 27 | 28 | goog.require('Blockly.Field'); 29 | 30 | 31 | /** 32 | * Class for a checkbox field. 33 | * @param {string} state The initial state of the field ('TRUE' or 'FALSE'). 34 | * @param {Function} opt_changeHandler A function that is executed when a new 35 | * option is selected. 36 | * @extends {Blockly.Field} 37 | * @constructor 38 | */ 39 | Blockly.FieldCheckbox = function(state, opt_changeHandler) { 40 | Blockly.FieldCheckbox.superClass_.constructor.call(this, ''); 41 | 42 | this.changeHandler_ = opt_changeHandler; 43 | // The checkbox doesn't use the inherited text element. 44 | // Instead it uses a custom checkmark element that is either visible or not. 45 | this.checkElement_ = Blockly.createSvgElement('text', 46 | {'class': 'blocklyText', 'x': -3}, this.fieldGroup_); 47 | var textNode = document.createTextNode('\u2713'); 48 | this.checkElement_.appendChild(textNode); 49 | // Set the initial state. 50 | this.setValue(state); 51 | }; 52 | goog.inherits(Blockly.FieldCheckbox, Blockly.Field); 53 | 54 | /** 55 | * Clone this FieldCheckbox. 56 | * 57 | * @return {Blockly.FieldCheckbox} The result of calling the constructor again 58 | * with the current values of the arguments used during construction. 59 | */ 60 | Blockly.FieldCheckbox.prototype.clone = function() { 61 | return new Blockly.FieldCheckbox(this.getValue(), this.changeHandler_); 62 | } 63 | 64 | /** 65 | * Mouse cursor style when over the hotspot that initiates editability. 66 | */ 67 | Blockly.FieldCheckbox.prototype.CURSOR = 'default'; 68 | 69 | /** 70 | * Return 'TRUE' if the checkbox is checked, 'FALSE' otherwise. 71 | * @return {string} Current state. 72 | */ 73 | Blockly.FieldCheckbox.prototype.getValue = function() { 74 | return String(this.state_).toUpperCase(); 75 | }; 76 | 77 | /** 78 | * Set the checkbox to be checked if strBool is 'TRUE', unchecks otherwise. 79 | * @param {string} strBool New state. 80 | */ 81 | Blockly.FieldCheckbox.prototype.setValue = function(strBool) { 82 | var newState = (strBool == 'TRUE'); 83 | if (this.state_ !== newState) { 84 | this.state_ = newState; 85 | this.checkElement_.style.display = newState ? 'block' : 'none'; 86 | if (this.sourceBlock_ && this.sourceBlock_.rendered) { 87 | this.sourceBlock_.workspace.fireChangeEvent(); 88 | } 89 | } 90 | }; 91 | 92 | /** 93 | * Toggle the state of the checkbox. 94 | * @private 95 | */ 96 | Blockly.FieldCheckbox.prototype.showEditor_ = function() { 97 | var newState = !this.state_; 98 | if (this.changeHandler_) { 99 | // Call any change handler, and allow it to override. 100 | var override = this.changeHandler_(newState); 101 | if (override !== undefined) { 102 | newState = override; 103 | } 104 | } 105 | if (newState !== null) { 106 | this.setValue(String(newState).toUpperCase()); 107 | } 108 | }; 109 | -------------------------------------------------------------------------------- /core/field_colour.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Colour input field. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.FieldColour'); 27 | 28 | goog.require('Blockly.Field'); 29 | goog.require('goog.ui.ColorPicker'); 30 | 31 | 32 | /** 33 | * Class for a colour input field. 34 | * @param {string} colour The initial colour in '#rrggbb' format. 35 | * @param {Function} opt_changeHandler A function that is executed when a new 36 | * option is selected. 37 | * @extends {Blockly.Field} 38 | * @constructor 39 | */ 40 | Blockly.FieldColour = function(colour, opt_changeHandler) { 41 | Blockly.FieldColour.superClass_.constructor.call(this, '\u00A0\u00A0\u00A0'); 42 | 43 | this.changeHandler_ = opt_changeHandler; 44 | this.borderRect_.style.fillOpacity = 1; 45 | // Set the initial state. 46 | this.setValue(colour); 47 | }; 48 | goog.inherits(Blockly.FieldColour, Blockly.Field); 49 | 50 | /** 51 | * Clone this FieldColour. 52 | * 53 | * @return {Blockly.FieldColour} The result of calling the constructor again 54 | * with the current values of the arguments used during construction. 55 | */ 56 | Blockly.FieldColour.prototype.clone = function() { 57 | return new Blockly.FieldColour(this.getValue(), this.changeHandler_); 58 | }; 59 | 60 | /** 61 | * Mouse cursor style when over the hotspot that initiates the editor. 62 | */ 63 | Blockly.FieldColour.prototype.CURSOR = 'default'; 64 | 65 | /** 66 | * Dispose of all DOM objects belonging to this editable field. 67 | */ 68 | Blockly.FieldColour.prototype.dispose = function() { 69 | Blockly.WidgetDiv.hideIfField(this); 70 | Blockly.FieldColour.superClass_.dispose.call(this); 71 | }; 72 | 73 | /** 74 | * Return the current colour. 75 | * @return {string} Current colour in '#rrggbb' format. 76 | */ 77 | Blockly.FieldColour.prototype.getValue = function() { 78 | return this.colour_; 79 | }; 80 | 81 | /** 82 | * Set the colour. 83 | * @param {string} colour The new colour in '#rrggbb' format. 84 | */ 85 | Blockly.FieldColour.prototype.setValue = function(colour) { 86 | this.colour_ = colour; 87 | this.borderRect_.style.fill = colour; 88 | if (this.sourceBlock_ && this.sourceBlock_.rendered) { 89 | this.sourceBlock_.workspace.fireChangeEvent(); 90 | } 91 | }; 92 | 93 | /** 94 | * An array of colour strings for the palette. 95 | * See bottom of this page for the default: 96 | * http://docs.closure-library.googlecode.com/git/closure_goog_ui_colorpicker.js.source.html 97 | * @type {!Array.} 98 | */ 99 | Blockly.FieldColour.COLOURS = goog.ui.ColorPicker.SIMPLE_GRID_COLORS; 100 | 101 | /** 102 | * Number of columns in the palette. 103 | */ 104 | Blockly.FieldColour.COLUMNS = 7; 105 | 106 | /** 107 | * Create a palette under the colour field. 108 | * @private 109 | */ 110 | Blockly.FieldColour.prototype.showEditor_ = function() { 111 | Blockly.WidgetDiv.show(this, Blockly.FieldColour.dispose_); 112 | var div = Blockly.WidgetDiv.DIV; 113 | // Create the palette using Closure. 114 | var picker = new goog.ui.ColorPicker(); 115 | picker.setSize(Blockly.FieldColour.COLUMNS); 116 | picker.setColors(Blockly.FieldColour.COLOURS); 117 | picker.render(div); 118 | picker.setSelectedColor(this.getValue()); 119 | 120 | // Position the palette to line up with the field. 121 | var xy = Blockly.getAbsoluteXY_(/** @type {!Element} */ (this.borderRect_)); 122 | var borderBBox = this.borderRect_.getBBox(); 123 | if (Blockly.RTL) { 124 | xy.x += borderBBox.width; 125 | } 126 | xy.y += borderBBox.height - 1; 127 | if (Blockly.RTL) { 128 | xy.x -= div.offsetWidth; 129 | } 130 | div.style.left = xy.x + 'px'; 131 | div.style.top = xy.y + 'px'; 132 | 133 | // Configure event handler. 134 | var thisObj = this; 135 | Blockly.FieldColour.changeEventKey_ = goog.events.listen(picker, 136 | goog.ui.ColorPicker.EventType.CHANGE, 137 | function(event) { 138 | var colour = event.target.getSelectedColor() || '#000000'; 139 | Blockly.WidgetDiv.hide(); 140 | if (thisObj.changeHandler_) { 141 | // Call any change handler, and allow it to override. 142 | var override = thisObj.changeHandler_(colour); 143 | if (override !== undefined) { 144 | colour = override; 145 | } 146 | } 147 | if (colour !== null) { 148 | thisObj.setValue(colour); 149 | } 150 | }); 151 | }; 152 | 153 | /** 154 | * Hide the colour palette. 155 | * @private 156 | */ 157 | Blockly.FieldColour.dispose_ = function() { 158 | if (Blockly.FieldColour.changeEventKey_) { 159 | goog.events.unlistenByKey(Blockly.FieldColour.changeEventKey_); 160 | } 161 | }; 162 | -------------------------------------------------------------------------------- /core/field_image.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Image field. Used for titles, labels, etc. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.FieldImage'); 27 | 28 | goog.require('Blockly.Field'); 29 | goog.require('goog.userAgent'); 30 | 31 | 32 | /** 33 | * Class for an image. 34 | * @param {string} src The URL of the image. 35 | * @param {number} width Width of the image. 36 | * @param {number} height Height of the image. 37 | * @extends {Blockly.Field} 38 | * @constructor 39 | */ 40 | Blockly.FieldImage = function(src, width, height) { 41 | this.sourceBlock_ = null; 42 | // Ensure height and width are numbers. Strings are bad at math. 43 | height = Number(height); 44 | width = Number(width); 45 | this.size_ = {height: height + 10, width: width}; 46 | // Build the DOM. 47 | var offsetY = 6 - Blockly.BlockSvg.TITLE_HEIGHT; 48 | this.fieldGroup_ = Blockly.createSvgElement('g', {}, null); 49 | this.imageElement_ = Blockly.createSvgElement('image', 50 | {'height': height + 'px', 51 | 'width': width + 'px', 52 | 'y': offsetY}, this.fieldGroup_); 53 | this.setText(src); 54 | if (goog.userAgent.GECKO) { 55 | // Due to a Firefox bug which eats mouse events on image elements, 56 | // a transparent rectangle needs to be placed on top of the image. 57 | this.rectElement_ = Blockly.createSvgElement('rect', 58 | {'height': height + 'px', 59 | 'width': width + 'px', 60 | 'y': offsetY, 61 | 'fill-opacity': 0}, this.fieldGroup_); 62 | } 63 | }; 64 | goog.inherits(Blockly.FieldImage, Blockly.Field); 65 | 66 | /** 67 | * Clone this FieldImage. 68 | * 69 | * @return {Blockly.FieldImage} The result of calling the constructor again 70 | * with the current values of the arguments used during construction. 71 | */ 72 | Blockly.FieldImage.prototype.clone = function() { 73 | return new Blockly.FieldImage(this.getText(), this.width, this.height); 74 | }; 75 | 76 | /** 77 | * Rectangular mask used by Firefox. 78 | * @type {Element} 79 | * @private 80 | */ 81 | Blockly.FieldImage.prototype.rectElement_ = null; 82 | 83 | /** 84 | * Editable fields are saved by the XML renderer, non-editable fields are not. 85 | */ 86 | Blockly.FieldImage.prototype.EDITABLE = false; 87 | 88 | /** 89 | * Install this text on a block. 90 | * @param {!Blockly.Block} block The block containing this text. 91 | */ 92 | Blockly.FieldImage.prototype.init = function(block) { 93 | if (this.sourceBlock_) { 94 | throw 'Image has already been initialized once.'; 95 | } 96 | this.sourceBlock_ = block; 97 | block.getSvgRoot().appendChild(this.fieldGroup_); 98 | 99 | // Configure the field to be transparent with respect to tooltips. 100 | var topElement = this.rectElement_ || this.imageElement_; 101 | topElement.tooltip = this.sourceBlock_; 102 | Blockly.Tooltip && Blockly.Tooltip.bindMouseEvents(topElement); 103 | }; 104 | 105 | /** 106 | * Dispose of all DOM objects belonging to this text. 107 | */ 108 | Blockly.FieldImage.prototype.dispose = function() { 109 | goog.dom.removeNode(this.fieldGroup_); 110 | this.fieldGroup_ = null; 111 | this.imageElement_ = null; 112 | this.rectElement_ = null; 113 | }; 114 | 115 | /** 116 | * Change the tooltip text for this field. 117 | * @param {string|!Element} newTip Text for tooltip or a parent element to 118 | * link to for its tooltip. 119 | */ 120 | Blockly.FieldImage.prototype.setTooltip = function(newTip) { 121 | var topElement = this.rectElement_ || this.imageElement_; 122 | topElement.tooltip = newTip; 123 | }; 124 | 125 | /** 126 | * Get the source URL of this image. 127 | * @return {string} Current text. 128 | * @override 129 | */ 130 | Blockly.FieldImage.prototype.getText = function() { 131 | return this.src_; 132 | }; 133 | 134 | /** 135 | * Set the source URL of this image. 136 | * @param {?string} src New source. 137 | * @override 138 | */ 139 | Blockly.FieldImage.prototype.setText = function(src) { 140 | if (src === null) { 141 | // No change if null. 142 | return; 143 | } 144 | this.src_ = src; 145 | this.imageElement_.setAttributeNS('http://www.w3.org/1999/xlink', 146 | 'xlink:href', goog.isString(src) ? src : ''); 147 | }; 148 | -------------------------------------------------------------------------------- /core/field_label.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Non-editable text field. Used for titles, labels, etc. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.FieldLabel'); 27 | 28 | goog.require('Blockly.Field'); 29 | goog.require('Blockly.Tooltip'); 30 | 31 | 32 | /** 33 | * Class for a non-editable field. 34 | * @param {string} text The initial content of the field. 35 | * @extends {Blockly.Field} 36 | * @constructor 37 | */ 38 | Blockly.FieldLabel = function(text) { 39 | this.sourceBlock_ = null; 40 | // Build the DOM. 41 | this.textElement_ = Blockly.createSvgElement('text', 42 | {'class': 'blocklyText'}, null); 43 | this.size_ = {height: 25, width: 0}; 44 | this.setText(text); 45 | }; 46 | goog.inherits(Blockly.FieldLabel, Blockly.Field); 47 | 48 | /** 49 | * Clone this FieldLabel. 50 | * 51 | * @return {Blockly.FieldLabel} The result of calling the constructor again 52 | * with the current values of the arguments used during construction. 53 | */ 54 | Blockly.FieldLabel.prototype.clone = function() { 55 | return new Blockly.FieldLabel(this.getText()); 56 | }; 57 | 58 | /** 59 | * Editable fields are saved by the XML renderer, non-editable fields are not. 60 | */ 61 | Blockly.FieldLabel.prototype.EDITABLE = false; 62 | 63 | /** 64 | * Install this text on a block. 65 | * @param {!Blockly.Block} block The block containing this text. 66 | */ 67 | Blockly.FieldLabel.prototype.init = function(block) { 68 | if (this.sourceBlock_) { 69 | throw 'Text has already been initialized once.'; 70 | } 71 | this.sourceBlock_ = block; 72 | block.getSvgRoot().appendChild(this.textElement_); 73 | 74 | // Configure the field to be transparent with respect to tooltips. 75 | this.textElement_.tooltip = this.sourceBlock_; 76 | Blockly.Tooltip && Blockly.Tooltip.bindMouseEvents(this.textElement_); 77 | }; 78 | 79 | /** 80 | * Dispose of all DOM objects belonging to this text. 81 | */ 82 | Blockly.FieldLabel.prototype.dispose = function() { 83 | goog.dom.removeNode(this.textElement_); 84 | this.textElement_ = null; 85 | }; 86 | 87 | /** 88 | * Gets the group element for this field. 89 | * Used for measuring the size and for positioning. 90 | * @return {!Element} The group element. 91 | */ 92 | Blockly.FieldLabel.prototype.getRootElement = function() { 93 | return /** @type {!Element} */ (this.textElement_); 94 | }; 95 | 96 | /** 97 | * Change the tooltip text for this field. 98 | * @param {string|!Element} newTip Text for tooltip or a parent element to 99 | * link to for its tooltip. 100 | */ 101 | Blockly.FieldLabel.prototype.setTooltip = function(newTip) { 102 | this.textElement_.tooltip = newTip; 103 | }; 104 | -------------------------------------------------------------------------------- /core/field_variable.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Variable input field. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.FieldVariable'); 27 | 28 | goog.require('Blockly.FieldDropdown'); 29 | goog.require('Blockly.Msg'); 30 | goog.require('Blockly.Variables'); 31 | 32 | 33 | /** 34 | * Class for a variable's dropdown field. 35 | * @param {!string} varname The default name for the variable. If null, 36 | * a unique variable name will be generated. 37 | * @extends {Blockly.FieldDropdown} 38 | * @constructor 39 | */ 40 | Blockly.FieldVariable = function(varname, opt_changeHandler) { 41 | Blockly.FieldVariable.superClass_.constructor.call( 42 | this, 43 | Blockly.FieldVariable.dropdownCreate, 44 | Blockly.FieldVariable.dropdownChange); 45 | 46 | if (varname) { 47 | this.setValue(varname); 48 | } else { 49 | this.setValue(Blockly.Variables.generateUniqueName()); 50 | } 51 | }; 52 | goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown); 53 | 54 | /** 55 | * Clone this FieldVariable. 56 | * 57 | * @return {Blockly.FieldVariable} The result of calling the constructor again 58 | * with the current values of the arguments used during construction. 59 | */ 60 | Blockly.FieldVariable.prototype.clone = function() { 61 | return new Blockly.FieldVariable(this.getValue(), this.changeHandler_); 62 | }; 63 | 64 | /** 65 | * Get the variable's name (use a variableDB to convert into a real name). 66 | * Unline a regular dropdown, variables are literal and have no neutral value. 67 | * @return {string} Current text. 68 | */ 69 | Blockly.FieldVariable.prototype.getValue = function() { 70 | return this.getText(); 71 | }; 72 | 73 | /** 74 | * Set the variable name. 75 | * @param {string} text New text. 76 | */ 77 | Blockly.FieldVariable.prototype.setValue = function(text) { 78 | this.value_ = text; 79 | this.setText(text); 80 | }; 81 | 82 | /** 83 | * Return a sorted list of variable names for variable dropdown menus. 84 | * Include a special option at the end for creating a new variable name. 85 | * @return {!Array.} Array of variable names. 86 | * @this {!Blockly.FieldVariable} 87 | */ 88 | Blockly.FieldVariable.dropdownCreate = function() { 89 | var variableList = Blockly.Variables.allVariables(); 90 | // Ensure that the currently selected variable is an option. 91 | var name = this.getText(); 92 | if (name && variableList.indexOf(name) == -1) { 93 | variableList.push(name); 94 | } 95 | variableList.sort(goog.string.caseInsensitiveCompare); 96 | variableList.push(Blockly.Msg.RENAME_VARIABLE); 97 | variableList.push(Blockly.Msg.NEW_VARIABLE); 98 | // Variables are not language-specific, use the name as both the user-facing 99 | // text and the internal representation. 100 | var options = []; 101 | for (var x = 0; x < variableList.length; x++) { 102 | options[x] = [variableList[x], variableList[x]]; 103 | } 104 | return options; 105 | }; 106 | 107 | /** 108 | * Event handler for a change in variable name. 109 | * Special case the 'New variable...' and 'Rename variable...' options. 110 | * In both of these special cases, prompt the user for a new name. 111 | * The entered name is stripped of leading and trailing whitespace. 112 | * All resulting names are acceptable except for '_' and the empty string. 113 | * @param {string} text The selected dropdown menu option. 114 | * @return {null|undefined|_string} One of: 115 | * - null if change is to be either aborted (cancel button or entered 116 | * illegal value) or has been already handled (rename). 117 | * - undefined if an existing variable was chosen. 118 | * - an acceptable variable name. 119 | * @this {!Blockly.FieldVariable} 120 | */ 121 | Blockly.FieldVariable.dropdownChange = function(text) { 122 | function promptName(promptText, defaultText) { 123 | Blockly.hideChaff(); 124 | var newVar = window.prompt(promptText, defaultText); 125 | // Merge runs of whitespace. Strip leading and trailing whitespace. 126 | if (newVar) { 127 | newVar = newVar.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, ''); 128 | // Any characters are legal except for a single underscore, which has 129 | // a special meaning (sink) in Lua. 130 | if (newVar == '_' || !newVar) { 131 | return null; 132 | } 133 | } 134 | return newVar; 135 | } 136 | if (text == Blockly.Msg.RENAME_VARIABLE) { 137 | var oldVar = this.getText(); 138 | text = promptName(Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', oldVar), 139 | oldVar); 140 | if (text) { 141 | Blockly.Variables.renameVariable(oldVar, text); 142 | } 143 | return null; 144 | } else if (text == Blockly.Msg.NEW_VARIABLE) { 145 | text = promptName(Blockly.Msg.NEW_VARIABLE_TITLE, ''); 146 | // Since variables are case-insensitive, ensure that if the new variable 147 | // matches with an existing variable, the new case prevails throughout. 148 | if (text) { 149 | Blockly.Variables.renameVariable(text, text); 150 | return text; 151 | } 152 | return null; 153 | } 154 | return undefined; 155 | }; 156 | -------------------------------------------------------------------------------- /core/icon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Object representing an icon on a block. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Icon'); 27 | 28 | /** 29 | * Class for an icon. 30 | * @param {Blockly.Block} block The block associated with this icon. 31 | * @constructor 32 | */ 33 | Blockly.Icon = function(block) { 34 | this.block_ = block; 35 | }; 36 | 37 | /** 38 | * Radius of icons. 39 | */ 40 | Blockly.Icon.RADIUS = 8; 41 | 42 | /** 43 | * Bubble UI (if visible). 44 | * @type {Blockly.Bubble} 45 | * @private 46 | */ 47 | Blockly.Icon.prototype.bubble_ = null; 48 | 49 | /** 50 | * Absolute X coordinate of icon's center. 51 | * @private 52 | */ 53 | Blockly.Icon.prototype.iconX_ = 0; 54 | 55 | /** 56 | * Absolute Y coordinate of icon's centre. 57 | * @private 58 | */ 59 | Blockly.Icon.prototype.iconY_ = 0; 60 | 61 | /** 62 | * Create the icon on the block. 63 | * @private 64 | */ 65 | Blockly.Icon.prototype.createIcon_ = function() { 66 | /* Here's the markup that will be generated: 67 | 68 | */ 69 | this.iconGroup_ = Blockly.createSvgElement('g', {}, null); 70 | this.block_.getSvgRoot().appendChild(this.iconGroup_); 71 | Blockly.bindEvent_(this.iconGroup_, 'mouseup', this, this.iconClick_); 72 | this.updateEditable(); 73 | }; 74 | 75 | /** 76 | * Dispose of this icon. 77 | */ 78 | Blockly.Icon.prototype.dispose = function() { 79 | // Dispose of and unlink the icon. 80 | goog.dom.removeNode(this.iconGroup_); 81 | this.iconGroup_ = null; 82 | // Dispose of and unlink the bubble. 83 | this.setVisible(false); 84 | this.block_ = null; 85 | }; 86 | 87 | /** 88 | * Add or remove the UI indicating if this icon may be clicked or not. 89 | */ 90 | Blockly.Icon.prototype.updateEditable = function() { 91 | if (this.block_.isEditable() && !this.block_.isInFlyout) { 92 | Blockly.addClass_(/** @type {!Element} */ (this.iconGroup_), 93 | 'blocklyIconGroup'); 94 | } else { 95 | Blockly.removeClass_(/** @type {!Element} */ (this.iconGroup_), 96 | 'blocklyIconGroup'); 97 | } 98 | }; 99 | 100 | /** 101 | * Is the associated bubble visible? 102 | * @return {boolean} True if the bubble is visible. 103 | */ 104 | Blockly.Icon.prototype.isVisible = function() { 105 | return !!this.bubble_; 106 | }; 107 | 108 | /** 109 | * Clicking on the icon toggles if the bubble is visible. 110 | * @param {!Event} e Mouse click event. 111 | * @private 112 | */ 113 | Blockly.Icon.prototype.iconClick_ = function(e) { 114 | if (this.block_.isEditable() && !this.block_.isInFlyout) { 115 | this.setVisible(!this.isVisible()); 116 | } 117 | }; 118 | 119 | /** 120 | * Change the colour of the associated bubble to match its block. 121 | */ 122 | Blockly.Icon.prototype.updateColour = function() { 123 | if (this.isVisible()) { 124 | var hexColour = Blockly.makeColour(this.block_.getColour()); 125 | this.bubble_.setColour(hexColour); 126 | } 127 | }; 128 | 129 | /** 130 | * Render the icon. 131 | * @param {number} cursorX Horizontal offset at which to position the icon. 132 | * @return {number} Horizontal offset for next item to draw. 133 | */ 134 | Blockly.Icon.prototype.renderIcon = function(cursorX) { 135 | if (this.block_.isCollapsed()) { 136 | this.iconGroup_.setAttribute('display', 'none'); 137 | return cursorX; 138 | } 139 | this.iconGroup_.setAttribute('display', 'block'); 140 | 141 | var TOP_MARGIN = 5; 142 | var diameter = 2 * Blockly.Icon.RADIUS; 143 | if (Blockly.RTL) { 144 | cursorX -= diameter; 145 | } 146 | this.iconGroup_.setAttribute('transform', 147 | 'translate(' + cursorX + ', ' + TOP_MARGIN + ')'); 148 | this.computeIconLocation(); 149 | if (Blockly.RTL) { 150 | cursorX -= Blockly.BlockSvg.SEP_SPACE_X; 151 | } else { 152 | cursorX += diameter + Blockly.BlockSvg.SEP_SPACE_X; 153 | } 154 | return cursorX; 155 | }; 156 | 157 | /** 158 | * Notification that the icon has moved. Update the arrow accordingly. 159 | * @param {number} x Absolute horizontal location. 160 | * @param {number} y Absolute vertical location. 161 | */ 162 | Blockly.Icon.prototype.setIconLocation = function(x, y) { 163 | this.iconX_ = x; 164 | this.iconY_ = y; 165 | if (this.isVisible()) { 166 | this.bubble_.setAnchorLocation(x, y); 167 | } 168 | }; 169 | 170 | /** 171 | * Notification that the icon has moved, but we don't really know where. 172 | * Recompute the icon's location from scratch. 173 | */ 174 | Blockly.Icon.prototype.computeIconLocation = function() { 175 | // Find coordinates for the centre of the icon and update the arrow. 176 | var blockXY = this.block_.getRelativeToSurfaceXY(); 177 | var iconXY = Blockly.getRelativeXY_(this.iconGroup_); 178 | var newX = blockXY.x + iconXY.x + Blockly.Icon.RADIUS; 179 | var newY = blockXY.y + iconXY.y + Blockly.Icon.RADIUS; 180 | if (newX !== this.iconX_ || newY !== this.iconY_) { 181 | this.setIconLocation(newX, newY); 182 | } 183 | }; 184 | 185 | /** 186 | * Returns the center of the block's icon relative to the surface. 187 | * @return {!Object} Object with x and y properties. 188 | */ 189 | Blockly.Icon.prototype.getIconLocation = function() { 190 | return {x: this.iconX_, y: this.iconY_}; 191 | }; 192 | -------------------------------------------------------------------------------- /core/input.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Object representing an input (value, statement, or dummy). 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Input'); 27 | 28 | // TODO(scr): Fix circular dependencies 29 | // goog.require('Blockly.Block'); 30 | goog.require('Blockly.Connection'); 31 | goog.require('Blockly.FieldLabel'); 32 | 33 | 34 | /** 35 | * Class for an input with an optional title. 36 | * @param {number} type The type of the input. 37 | * @param {string} name Language-neutral identifier which may used to find this 38 | * input again. 39 | * @param {!Blockly.Block} block The block containing this input. 40 | * @param {Blockly.Connection} connection Optional connection for this input. 41 | * @constructor 42 | */ 43 | Blockly.Input = function(type, name, block, connection) { 44 | this.type = type; 45 | this.name = name; 46 | this.sourceBlock_ = block; 47 | this.connection = connection; 48 | this.titleRow = []; 49 | this.align = Blockly.ALIGN_LEFT; 50 | 51 | this.visible_ = true; 52 | }; 53 | 54 | /** 55 | * Add an item to the end of the input's title row. 56 | * @param {*} title Something to add as a title. 57 | * @param {string} opt_name Language-neutral identifier which may used to find 58 | * this title again. Should be unique to the host block. 59 | * @return {!Blockly.Input} The input being append to (to allow chaining). 60 | */ 61 | Blockly.Input.prototype.appendTitle = function(title, opt_name) { 62 | // Empty string, Null or undefined generates no title, unless title is named. 63 | if (!title && !opt_name) { 64 | return this; 65 | } 66 | // Generate a FieldLabel when given a plain text title. 67 | if (goog.isString(title)) { 68 | title = new Blockly.FieldLabel(/** @type {string} */ (title)); 69 | } 70 | if (this.sourceBlock_.svg_) { 71 | title.init(this.sourceBlock_); 72 | } 73 | title.name = opt_name; 74 | 75 | if (title.prefixTitle) { 76 | // Add any prefix. 77 | this.appendTitle(title.prefixTitle); 78 | } 79 | // Add the title to the title row. 80 | this.titleRow.push(title); 81 | if (title.suffixTitle) { 82 | // Add any suffix. 83 | this.appendTitle(title.suffixTitle); 84 | } 85 | 86 | if (this.sourceBlock_.rendered) { 87 | this.sourceBlock_.render(); 88 | // Adding a title will cause the block to change shape. 89 | this.sourceBlock_.bumpNeighbours_(); 90 | } 91 | return this; 92 | }; 93 | 94 | /** 95 | * Gets whether this input is visible or not. 96 | * @return {boolean} True if visible. 97 | */ 98 | Blockly.Input.prototype.isVisible = function() { 99 | return this.visible_; 100 | }; 101 | 102 | /** 103 | * Sets whether this input is visible or not. 104 | * @param {boolean} visible True if visible. 105 | * @return {!Array.} List of blocks to render. 106 | */ 107 | Blockly.Input.prototype.setVisible = function(visible) { 108 | var renderList = []; 109 | if (this.visible_ == visible) { 110 | return renderList; 111 | } 112 | this.visible_ = visible; 113 | 114 | var display = visible ? 'block' : 'none'; 115 | for (var y = 0, title; title = this.titleRow[y]; y++) { 116 | title.setVisible(visible); 117 | } 118 | if (this.connection) { 119 | // Has a connection. 120 | if (visible) { 121 | renderList = this.connection.unhideAll(); 122 | } else { 123 | renderList = this.connection.hideAll(); 124 | } 125 | var child = this.connection.targetBlock(); 126 | if (child) { 127 | child.svg_.getRootElement().style.display = display; 128 | if (!visible) { 129 | child.rendered = false; 130 | } 131 | } 132 | } 133 | return renderList; 134 | }; 135 | 136 | /** 137 | * Change a connection's compatibility. 138 | * @param {string|Array.|null} check Compatible value type or 139 | * list of value types. Null if all types are compatible. 140 | * @return {!Blockly.Input} The input being modified (to allow chaining). 141 | */ 142 | Blockly.Input.prototype.setCheck = function(check) { 143 | if (!this.connection) { 144 | throw 'This input does not have a connection.'; 145 | } 146 | this.connection.setCheck(check); 147 | return this; 148 | }; 149 | 150 | /** 151 | * Change the alignment of the connection's title(s). 152 | * @param {number} align One of Blockly.ALIGN_LEFT, ALIGN_CENTRE, ALIGN_RIGHT. 153 | * In RTL mode directions are reversed, and ALIGN_RIGHT aligns to the left. 154 | * @return {!Blockly.Input} The input being modified (to allow chaining). 155 | */ 156 | Blockly.Input.prototype.setAlign = function(align) { 157 | this.align = align; 158 | if (this.sourceBlock_.rendered) { 159 | this.sourceBlock_.render(); 160 | } 161 | return this; 162 | }; 163 | 164 | /** 165 | * Initialize the titles on this input. 166 | */ 167 | Blockly.Input.prototype.init = function() { 168 | for (var x = 0; x < this.titleRow.length; x++) { 169 | this.titleRow[x].init(this.sourceBlock_); 170 | } 171 | }; 172 | 173 | /** 174 | * Sever all links to this input. 175 | */ 176 | Blockly.Input.prototype.dispose = function() { 177 | for (var i = 0, title; title = this.titleRow[i]; i++) { 178 | title.dispose(); 179 | } 180 | if (this.connection) { 181 | this.connection.dispose(); 182 | } 183 | this.sourceBlock_ = null; 184 | }; 185 | -------------------------------------------------------------------------------- /core/msg.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Core JavaScript library for Blockly. 22 | * @author scr@google.com (Sheridan Rawlins) 23 | */ 24 | 'use strict'; 25 | 26 | /** 27 | * Name space for the Msg singleton. 28 | * Msg gets populated in the message files. 29 | */ 30 | goog.provide('Blockly.Msg'); 31 | -------------------------------------------------------------------------------- /core/names.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Utility functions for handling variables and procedure names. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Names'); 27 | 28 | 29 | /** 30 | * Class for a database of entity names (variables, functions, etc). 31 | * @param {string} reservedWords A comma-separated string of words that are 32 | * illegal for use as names in a language (e.g. 'new,if,this,...'). 33 | * @constructor 34 | */ 35 | Blockly.Names = function(reservedWords) { 36 | this.reservedDict_ = {}; 37 | if (reservedWords) { 38 | var splitWords = reservedWords.split(','); 39 | for (var x = 0; x < splitWords.length; x++) { 40 | this.reservedDict_[Blockly.Names.PREFIX_ + splitWords[x]] = true; 41 | } 42 | } 43 | this.reset(); 44 | }; 45 | 46 | /** 47 | * When JavaScript (or most other languages) is generated, variable 'foo' and 48 | * procedure 'foo' would collide. However, Blockly has no such problems since 49 | * variable get 'foo' and procedure call 'foo' are unambiguous. 50 | * Therefore, Blockly keeps a separate type name to disambiguate. 51 | * getName('foo', 'variable') -> 'foo' 52 | * getName('foo', 'procedure') -> 'foo2' 53 | */ 54 | 55 | /** 56 | * JavaScript doesn't have a true hashtable, it uses object properties. 57 | * Since even clean objects have a few properties, prepend this prefix onto 58 | * names so that they don't collide with any builtins. 59 | * @const 60 | * @private 61 | */ 62 | Blockly.Names.PREFIX_ = '$_'; 63 | 64 | /** 65 | * Empty the database and start from scratch. The reserved words are kept. 66 | */ 67 | Blockly.Names.prototype.reset = function() { 68 | this.db_ = {}; 69 | this.dbReverse_ = {}; 70 | }; 71 | 72 | /** 73 | * Convert a Blockly entity name to a legal exportable entity name. 74 | * @param {string} name The Blockly entity name (no constraints). 75 | * @param {string} type The type of entity in Blockly 76 | * ('VARIABLE', 'PROCEDURE', 'BUILTIN', etc...). 77 | * @return {string} An entity name legal for the exported language. 78 | */ 79 | Blockly.Names.prototype.getName = function(name, type) { 80 | var normalized = Blockly.Names.PREFIX_ + name.toLowerCase() + '_' + type; 81 | if (normalized in this.db_) { 82 | return this.db_[normalized]; 83 | } 84 | var safeName = this.getDistinctName(name, type); 85 | this.db_[normalized] = safeName; 86 | return safeName; 87 | }; 88 | 89 | /** 90 | * Convert a Blockly entity name to a legal exportable entity name. 91 | * Ensure that this is a new name not overlapping any previously defined name. 92 | * Also check against list of reserved words for the current language and 93 | * ensure name doesn't collide. 94 | * @param {string} name The Blockly entity name (no constraints). 95 | * @param {string} type The type of entity in Blockly 96 | * ('VARIABLE', 'PROCEDURE', 'BUILTIN', etc...). 97 | * @return {string} An entity name legal for the exported language. 98 | */ 99 | Blockly.Names.prototype.getDistinctName = function(name, type) { 100 | var safeName = this.safeName_(name); 101 | var i = ''; 102 | while (this.dbReverse_[Blockly.Names.PREFIX_ + safeName + i] || 103 | (Blockly.Names.PREFIX_ + safeName + i) in this.reservedDict_) { 104 | // Collision with existing name. Create a unique name. 105 | i = i ? i + 1 : 2; 106 | } 107 | safeName += i; 108 | this.dbReverse_[Blockly.Names.PREFIX_ + safeName] = true; 109 | return safeName; 110 | }; 111 | 112 | /** 113 | * Given a proposed entity name, generate a name that conforms to the 114 | * [_A-Za-z][_A-Za-z0-9]* format that most languages consider legal for 115 | * variables. 116 | * @param {string} name Potentially illegal entity name. 117 | * @return {string} Safe entity name. 118 | * @private 119 | */ 120 | Blockly.Names.prototype.safeName_ = function(name) { 121 | if (!name) { 122 | name = 'unnamed'; 123 | } else { 124 | // Unfortunately names in non-latin characters will look like 125 | // _E9_9F_B3_E4_B9_90 which is pretty meaningless. 126 | name = encodeURI(name.replace(/ /g, '_')).replace(/[^\w]/g, '_'); 127 | // Most languages don't allow names with leading numbers. 128 | if ('0123456789'.indexOf(name[0]) != -1) { 129 | name = 'my_' + name; 130 | } 131 | } 132 | return name; 133 | }; 134 | 135 | /** 136 | * Do the given two entity names refer to the same entity? 137 | * Blockly names are case-insensitive. 138 | * @param {string} name1 First name. 139 | * @param {string} name2 Second name. 140 | * @return {boolean} True if names are the same. 141 | */ 142 | Blockly.Names.equals = function(name1, name2) { 143 | return name1.toLowerCase() == name2.toLowerCase(); 144 | }; 145 | -------------------------------------------------------------------------------- /core/variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Utility functions for handling variables and procedure names. 22 | * Note that variables and procedures share the same name space, meaning that 23 | * one can't have a variable and a procedure of the same name. 24 | * @author fraser@google.com (Neil Fraser) 25 | */ 26 | 'use strict'; 27 | 28 | goog.provide('Blockly.Variables'); 29 | 30 | // TODO(scr): Fix circular dependencies 31 | // goog.require('Blockly.Block'); 32 | goog.require('Blockly.Toolbox'); 33 | goog.require('Blockly.Workspace'); 34 | 35 | 36 | /** 37 | * Category to separate variable names from procedures and generated functions. 38 | */ 39 | Blockly.Variables.NAME_TYPE = 'VARIABLE'; 40 | 41 | /** 42 | * Find all user-created variables. 43 | * @param {Blockly.Block=} opt_block Optional root block. 44 | * @return {!Array.} Array of variable names. 45 | */ 46 | Blockly.Variables.allVariables = function(opt_block) { 47 | var blocks; 48 | if (opt_block) { 49 | blocks = opt_block.getDescendants(); 50 | } else { 51 | blocks = Blockly.mainWorkspace.getAllBlocks(); 52 | } 53 | var variableHash = {}; 54 | // Iterate through every block and add each variable to the hash. 55 | for (var x = 0; x < blocks.length; x++) { 56 | var func = blocks[x].getVars; 57 | if (func) { 58 | var blockVariables = func.call(blocks[x]); 59 | for (var y = 0; y < blockVariables.length; y++) { 60 | var varName = blockVariables[y]; 61 | // Variable name may be null if the block is only half-built. 62 | if (varName) { 63 | variableHash[Blockly.Names.PREFIX_ + 64 | varName.toLowerCase()] = varName; 65 | } 66 | } 67 | } 68 | } 69 | // Flatten the hash into a list. 70 | var variableList = []; 71 | for (var name in variableHash) { 72 | variableList.push(variableHash[name]); 73 | } 74 | return variableList; 75 | }; 76 | 77 | /** 78 | * Find all instances of the specified variable and rename them. 79 | * @param {string} oldName Variable to rename. 80 | * @param {string} newName New variable name. 81 | */ 82 | Blockly.Variables.renameVariable = function(oldName, newName) { 83 | var blocks = Blockly.mainWorkspace.getAllBlocks(); 84 | // Iterate through every block. 85 | for (var x = 0; x < blocks.length; x++) { 86 | var func = blocks[x].renameVar; 87 | if (func) { 88 | func.call(blocks[x], oldName, newName); 89 | } 90 | } 91 | }; 92 | 93 | /** 94 | * Construct the blocks required by the flyout for the variable category. 95 | * @param {!Array.} blocks List of blocks to show. 96 | * @param {!Array.} gaps List of widths between blocks. 97 | * @param {number} margin Standard margin width for calculating gaps. 98 | * @param {!Blockly.Workspace} workspace The flyout's workspace. 99 | */ 100 | Blockly.Variables.flyoutCategory = function(blocks, gaps, margin, workspace) { 101 | var variableList = Blockly.Variables.allVariables(); 102 | variableList.sort(goog.string.caseInsensitiveCompare); 103 | // In addition to the user's variables, we also want to display the default 104 | // variable name at the top. We also don't want this duplicated if the 105 | // user has created a variable of the same name. 106 | variableList.unshift(null); 107 | var defaultVariable = undefined; 108 | for (var i = 0; i < variableList.length; i++) { 109 | if (variableList[i] === defaultVariable) { 110 | continue; 111 | } 112 | var getBlock = Blockly.Blocks['variables_get'] ? 113 | new Blockly.Block(workspace, 'variables_get') : null; 114 | getBlock && getBlock.initSvg(); 115 | var setBlock = Blockly.Blocks['variables_set'] ? 116 | new Blockly.Block(workspace, 'variables_set') : null; 117 | setBlock && setBlock.initSvg(); 118 | if (variableList[i] === null) { 119 | defaultVariable = (getBlock || setBlock).getVars()[0]; 120 | } else { 121 | getBlock && getBlock.setTitleValue(variableList[i], 'VAR'); 122 | setBlock && setBlock.setTitleValue(variableList[i], 'VAR'); 123 | } 124 | setBlock && blocks.push(setBlock); 125 | getBlock && blocks.push(getBlock); 126 | if (getBlock && setBlock) { 127 | gaps.push(margin, margin * 3); 128 | } else { 129 | gaps.push(margin * 2); 130 | } 131 | } 132 | // Provide multiple block setters, if defined. 133 | if (Blockly.Blocks['variables_set_two']) { 134 | var block = new Blockly.Block(workspace, 'variables_set_two'); 135 | block.initSvg(); 136 | blocks.push(block); 137 | } 138 | gaps.push(margin, margin * 3); 139 | if (Blockly.Blocks['variables_set_three']) { 140 | var block = new Blockly.Block(workspace, 'variables_set_three'); 141 | block.initSvg(); 142 | blocks.push(block); 143 | } 144 | 145 | }; 146 | 147 | /** 148 | * Return a new variable name that is not yet being used. This will try to 149 | * generate single letter variable names in the range 'i' to 'z' to start with. 150 | * If no unique name is located it will try 'i1' to 'z1', then 'i2' to 'z2' etc. 151 | * @return {string} New variable name. 152 | */ 153 | Blockly.Variables.generateUniqueName = function() { 154 | var variableList = Blockly.Variables.allVariables(); 155 | var newName = ''; 156 | if (variableList.length) { 157 | variableList.sort(goog.string.caseInsensitiveCompare); 158 | var nameSuffix = 0, potName = 'i', i = 0, inUse = false; 159 | while (!newName) { 160 | i = 0; 161 | inUse = false; 162 | while (i < variableList.length && !inUse) { 163 | if (variableList[i].toLowerCase() == potName) { 164 | // This potential name is already used. 165 | inUse = true; 166 | } 167 | i++; 168 | } 169 | if (inUse) { 170 | // Try the next potential name. 171 | if (potName[0] === 'z') { 172 | // Reached the end of the character sequence so back to 'a' but with 173 | // a new suffix. 174 | nameSuffix++; 175 | potName = 'a'; 176 | } else { 177 | potName = String.fromCharCode(potName.charCodeAt(0) + 1); 178 | if (potName[0] == 'l') { 179 | // Avoid using variable 'l' because of ambiguity with '1'. 180 | potName = String.fromCharCode(potName.charCodeAt(0) + 1); 181 | } 182 | } 183 | if (nameSuffix > 0) { 184 | potName += nameSuffix; 185 | } 186 | } else { 187 | // We can use the current potential name. 188 | newName = potName; 189 | } 190 | } 191 | } else { 192 | newName = 'i'; 193 | } 194 | return newName; 195 | }; 196 | -------------------------------------------------------------------------------- /core/warning.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Object representing a warning. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Warning'); 27 | 28 | goog.require('Blockly.Bubble'); 29 | goog.require('Blockly.Icon'); 30 | 31 | 32 | /** 33 | * Class for a warning. 34 | * @param {!Blockly.Block} block The block associated with this warning. 35 | * @extends {Blockly.Icon} 36 | * @constructor 37 | */ 38 | Blockly.Warning = function(block) { 39 | Blockly.Warning.superClass_.constructor.call(this, block); 40 | this.createIcon_(); 41 | }; 42 | goog.inherits(Blockly.Warning, Blockly.Icon); 43 | 44 | /** 45 | * Warning text (if bubble is not visible). 46 | * @private 47 | */ 48 | Blockly.Warning.prototype.text_ = ''; 49 | 50 | /** 51 | * Create the icon on the block. 52 | * @private 53 | */ 54 | Blockly.Warning.prototype.createIcon_ = function() { 55 | Blockly.Icon.prototype.createIcon_.call(this); 56 | /* Here's the markup that will be generated: 57 | 58 | ! 59 | */ 60 | var iconShield = Blockly.createSvgElement('path', 61 | {'class': 'blocklyIconShield', 62 | 'd': 'M 2,15 Q -1,15 0.5,12 L 6.5,1.7 Q 8,-1 9.5,1.7 L 15.5,12 ' + 63 | 'Q 17,15 14,15 z'}, 64 | this.iconGroup_); 65 | this.iconMark_ = Blockly.createSvgElement('text', 66 | {'class': 'blocklyIconMark', 67 | 'x': Blockly.Icon.RADIUS, 68 | 'y': 2 * Blockly.Icon.RADIUS - 3}, this.iconGroup_); 69 | this.iconMark_.appendChild(document.createTextNode('!')); 70 | }; 71 | 72 | /** 73 | * Create the text for the warning's bubble. 74 | * @param {string} text The text to display. 75 | * @return {!SVGTextElement} The top-level node of the text. 76 | * @private 77 | */ 78 | Blockly.Warning.prototype.textToDom_ = function(text) { 79 | var paragraph = /** @type {!SVGTextElement} */ ( 80 | Blockly.createSvgElement( 81 | 'text', {'class': 'blocklyText', 'y': Blockly.Bubble.BORDER_WIDTH}, 82 | null)); 83 | var lines = text.split('\n'); 84 | for (var i = 0; i < lines.length; i++) { 85 | var tspanElement = Blockly.createSvgElement('tspan', 86 | {'dy': '1em', 'x': Blockly.Bubble.BORDER_WIDTH}, paragraph); 87 | var textNode = document.createTextNode(lines[i]); 88 | tspanElement.appendChild(textNode); 89 | } 90 | return paragraph; 91 | }; 92 | 93 | /** 94 | * Show or hide the warning bubble. 95 | * @param {boolean} visible True if the bubble should be visible. 96 | */ 97 | Blockly.Warning.prototype.setVisible = function(visible) { 98 | if (visible == this.isVisible()) { 99 | // No change. 100 | return; 101 | } 102 | if (visible) { 103 | // Create the bubble. 104 | var paragraph = this.textToDom_(this.text_); 105 | this.bubble_ = new Blockly.Bubble( 106 | /** @type {!Blockly.Workspace} */ (this.block_.workspace), 107 | paragraph, this.block_.svg_.svgGroup_, 108 | this.iconX_, this.iconY_, null, null); 109 | if (Blockly.RTL) { 110 | // Right-align the paragraph. 111 | // This cannot be done until the bubble is rendered on screen. 112 | var maxWidth = paragraph.getBBox().width; 113 | for (var x = 0, textElement; textElement = paragraph.childNodes[x]; x++) { 114 | textElement.setAttribute('text-anchor', 'end'); 115 | textElement.setAttribute('x', maxWidth + Blockly.Bubble.BORDER_WIDTH); 116 | } 117 | } 118 | this.updateColour(); 119 | // Bump the warning into the right location. 120 | var size = this.bubble_.getBubbleSize(); 121 | this.bubble_.setBubbleSize(size.width, size.height); 122 | } else { 123 | // Dispose of the bubble. 124 | this.bubble_.dispose(); 125 | this.bubble_ = null; 126 | this.body_ = null; 127 | this.foreignObject_ = null; 128 | } 129 | }; 130 | 131 | /** 132 | * Bring the warning to the top of the stack when clicked on. 133 | * @param {!Event} e Mouse up event. 134 | * @private 135 | */ 136 | Blockly.Warning.prototype.bodyFocus_ = function(e) { 137 | this.bubble_.promote_(); 138 | }; 139 | 140 | /** 141 | * Set this warning's text. 142 | * @param {string} text Warning text. 143 | */ 144 | Blockly.Warning.prototype.setText = function(text) { 145 | this.text_ = text; 146 | if (this.isVisible()) { 147 | this.setVisible(false); 148 | this.setVisible(true); 149 | } 150 | }; 151 | 152 | /** 153 | * Dispose of this warning. 154 | */ 155 | Blockly.Warning.prototype.dispose = function() { 156 | this.block_.warning = null; 157 | Blockly.Icon.prototype.dispose.call(this); 158 | }; 159 | -------------------------------------------------------------------------------- /core/widgetdiv.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2013 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview A div that floats on top of Blockly. This singleton contains 22 | * temporary HTML UI widgets that the user is currently interacting with. 23 | * E.g. text input areas, colour pickers. 24 | * @author fraser@google.com (Neil Fraser) 25 | */ 26 | 'use strict'; 27 | 28 | goog.provide('Blockly.WidgetDiv'); 29 | 30 | goog.require('Blockly.Css'); 31 | goog.require('goog.dom'); 32 | 33 | 34 | /** 35 | * The HTML container. Set once by inject.js's Blockly.createDom_. 36 | * @type Element 37 | */ 38 | Blockly.WidgetDiv.DIV = null; 39 | 40 | /** 41 | * The field currently using this container. 42 | * @private 43 | * @type Blockly.Field 44 | */ 45 | Blockly.WidgetDiv.field_ = null; 46 | 47 | /** 48 | * Optional cleanup function set by whichever field uses the widget. 49 | * @private 50 | * @type Function 51 | */ 52 | Blockly.WidgetDiv.dispose_ = null; 53 | 54 | /** 55 | * Initialize and display the widget div. Close the old one if needed. 56 | * @param {!Blockly.Field} newField The field that will be using this container. 57 | * @param {Function} dispose Optional cleanup function to be run when the widget 58 | * is closed. 59 | */ 60 | Blockly.WidgetDiv.show = function(newField, dispose) { 61 | Blockly.WidgetDiv.hide(); 62 | Blockly.WidgetDiv.field_ = newField; 63 | Blockly.WidgetDiv.dispose_ = dispose; 64 | Blockly.WidgetDiv.DIV.style.display = 'block'; 65 | }; 66 | 67 | /** 68 | * Destroy the widget and hide the div. 69 | */ 70 | Blockly.WidgetDiv.hide = function() { 71 | if (Blockly.WidgetDiv.field_) { 72 | Blockly.WidgetDiv.DIV.style.display = 'none'; 73 | Blockly.WidgetDiv.dispose_ && Blockly.WidgetDiv.dispose_(); 74 | Blockly.WidgetDiv.field_ = null; 75 | Blockly.WidgetDiv.dispose_ = null; 76 | goog.dom.removeChildren(Blockly.WidgetDiv.DIV); 77 | } 78 | }; 79 | 80 | /** 81 | * Destroy the widget and hide the div if it is being used by the specified 82 | * field. 83 | * @param {!Blockly.Field} oldField The field that was using this container. 84 | */ 85 | Blockly.WidgetDiv.hideIfField = function(oldField) { 86 | if (Blockly.WidgetDiv.field_ == oldField) { 87 | Blockly.WidgetDiv.hide(); 88 | } 89 | }; 90 | -------------------------------------------------------------------------------- /generators/lua/colour.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Language 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Generating Lua for colour blocks. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Lua.colour'); 27 | 28 | goog.require('Blockly.Lua'); 29 | 30 | 31 | Blockly.Lua['colour_picker'] = function(block) { 32 | // Colour picker. 33 | var code = '\'' + block.getTitleValue('COLOUR') + '\''; 34 | return [code, Blockly.Lua.ORDER_ATOMIC]; 35 | }; 36 | 37 | Blockly.Lua['colour_random'] = function(block) { 38 | // Generate a random colour. 39 | var code = 'string.format("#%06x", math.random(0, 2^24 - 1))'; 40 | return [code, Blockly.Lua.ORDER_HIGH]; 41 | }; 42 | 43 | Blockly.Lua['colour_rgb'] = function(block) { 44 | // Compose a colour from RGB components. 45 | var functionName = Blockly.Lua.provideFunction_( 46 | 'colour_rgb', 47 | [ 'function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(r, g, b)', 48 | ' r = math.floor(math.min(100, math.max(0, r)) * 2.55 + .5)', 49 | ' g = math.floor(math.min(100, math.max(0, g)) * 2.55 + .5)', 50 | ' b = math.floor(math.min(100, math.max(0, b)) * 2.55 + .5)', 51 | ' return string.format("#%02x%02x%02x", (r, g, b)', 52 | 'end']); 53 | var r = Blockly.Lua.valueToCode(block, 'RED', 54 | Blockly.Lua.ORDER_NONE) || 0; 55 | var g = Blockly.Lua.valueToCode(block, 'GREEN', 56 | Blockly.Lua.ORDER_NONE) || 0; 57 | var b = Blockly.Lua.valueToCode(block, 'BLUE', 58 | Blockly.Lua.ORDER_NONE) || 0; 59 | var code = functionName + '(' + r + ', ' + g + ', ' + b + ')'; 60 | return [code, Blockly.Lua.ORDER_HIGH]; 61 | }; 62 | 63 | Blockly.Lua['colour_blend'] = function(block) { 64 | // Blend two colours together. 65 | var functionName = Blockly.Lua.provideFunction_( 66 | 'colour_blend', 67 | ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + 68 | '(colour1, colour2, ratio)', 69 | ' local r1 = tonumber(string.sub(colour1, 2, 3), 16)', 70 | ' local r2 = tonumber(string.sub(colour2, 2, 3), 16)', 71 | ' local g1 = tonumber(string.sub(colour1, 4, 5), 16)', 72 | ' local g2 = tonumber(string.sub(colour2, 4, 5), 16)', 73 | ' local b1 = tonumber(string.sub(colour1, 6, 7), 16)', 74 | ' local b2 = tonumber(string.sub(colour2, 6, 7), 16)', 75 | ' local ratio = math.min(1, math.max(0, ratio))', 76 | ' local r = math.floor(r1 * (1 - ratio) + r2 * ratio + .5)', 77 | ' local g = math.floor(g1 * (1 - ratio) + g2 * ratio + .5)', 78 | ' local b = math.floor(b1 * (1 - ratio) + b2 * ratio + .5)', 79 | ' return string.format("#%02x%02x%02x", r, g, b)', 80 | 'end']); 81 | var colour1 = Blockly.Lua.valueToCode(block, 'COLOUR1', 82 | Blockly.Lua.ORDER_NONE) || '\'#000000\''; 83 | var colour2 = Blockly.Lua.valueToCode(block, 'COLOUR2', 84 | Blockly.Lua.ORDER_NONE) || '\'#000000\''; 85 | var ratio = Blockly.Lua.valueToCode(block, 'RATIO', 86 | Blockly.Lua.ORDER_NONE) || 0; 87 | var code = functionName + '(' + colour1 + ', ' + colour2 + ', ' + ratio + ')'; 88 | return [code, Blockly.Lua.ORDER_HIGH]; 89 | }; 90 | -------------------------------------------------------------------------------- /generators/lua/logic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Language 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Generating Lua for logic blocks. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Lua.logic'); 27 | 28 | goog.require('Blockly.Lua'); 29 | 30 | 31 | Blockly.Lua['controls_if'] = function(block) { 32 | // If/elseif/else condition. 33 | var n = 0; 34 | var argument = Blockly.Lua.valueToCode(block, 'IF' + n, 35 | Blockly.Lua.ORDER_NONE) || 'False'; 36 | var branch = Blockly.Lua.statementToCode(block, 'DO' + n) || ''; 37 | var code = 'if ' + argument + ' then\n' + branch; 38 | for (n = 1; n <= block.elseifCount_; n++) { 39 | argument = Blockly.Lua.valueToCode(block, 'IF' + n, 40 | Blockly.Lua.ORDER_NONE) || 'False'; 41 | branch = Blockly.Lua.statementToCode(block, 'DO' + n) || ''; 42 | code += 'elseif ' + argument + ' then\n' + branch; 43 | } 44 | if (block.elseCount_) { 45 | branch = Blockly.Lua.statementToCode(block, 'ELSE') || ' pass\n'; 46 | code += 'else\n' + branch; 47 | } 48 | code += 'end\n'; 49 | return code; 50 | }; 51 | 52 | Blockly.Lua['logic_compare'] = function(block) { 53 | // Comparison operator. 54 | var OPERATORS = { 55 | EQ: '==', 56 | NEQ: '~=', 57 | LT: '<', 58 | LTE: '<=', 59 | GT: '>', 60 | GTE: '>=' 61 | }; 62 | var operator = OPERATORS[block.getTitleValue('OP')]; 63 | var order = Blockly.Lua.ORDER_RELATIONAL; 64 | var argument0 = Blockly.Lua.valueToCode(block, 'A', order) || '0'; 65 | var argument1 = Blockly.Lua.valueToCode(block, 'B', order) || '0'; 66 | var code = argument0 + ' ' + operator + ' ' + argument1; 67 | return [code, order]; 68 | }; 69 | 70 | Blockly.Lua['logic_operation'] = function(block) { 71 | // Operations 'and', 'or'. 72 | var operator = (block.getTitleValue('OP') == 'AND') ? 'and' : 'or'; 73 | var order = (operator == 'and') ? Blockly.Lua.ORDER_AND : 74 | Blockly.Lua.ORDER_OR; 75 | var argument0 = Blockly.Lua.valueToCode(block, 'A', order); 76 | var argument1 = Blockly.Lua.valueToCode(block, 'B', order); 77 | if (!argument0 && !argument1) { 78 | // If there are no arguments, then the return value is false. 79 | argument0 = 'false'; 80 | argument1 = 'false'; 81 | } else { 82 | // Single missing arguments have no effect on the return value. 83 | var defaultArgument = (operator == 'and') ? 'true' : 'false'; 84 | if (!argument0) { 85 | argument0 = defaultArgument; 86 | } 87 | if (!argument1) { 88 | argument1 = defaultArgument; 89 | } 90 | } 91 | var code = argument0 + ' ' + operator + ' ' + argument1; 92 | return [code, order]; 93 | }; 94 | 95 | Blockly.Lua['logic_negate'] = function(block) { 96 | // Negation. 97 | var argument0 = Blockly.Lua.valueToCode(block, 'BOOL', 98 | Blockly.Lua.ORDER_UNARY) || 'true'; 99 | var code = 'not ' + argument0; 100 | return [code, Blockly.Lua.ORDER_UNARY]; 101 | }; 102 | 103 | Blockly.Lua['logic_boolean'] = function(block) { 104 | // Boolean values true and false. 105 | var code = (block.getTitleValue('BOOL') == 'TRUE') ? 'true' : 'false'; 106 | return [code, Blockly.Lua.ORDER_ATOMIC]; 107 | }; 108 | 109 | Blockly.Lua['logic_null'] = function(block) { 110 | // Null data type. 111 | return ['nil', Blockly.Lua.ORDER_ATOMIC]; 112 | }; 113 | 114 | Blockly.Lua['logic_ternary'] = function(block) { 115 | // Ternary operator. 116 | var value_if = Blockly.Lua.valueToCode(block, 'IF', 117 | Blockly.Lua.ORDER_AND) || 'false'; 118 | var value_then = Blockly.Lua.valueToCode(block, 'THEN', 119 | Blockly.Lua.ORDER_OR) || 'nil'; 120 | var value_else = Blockly.Lua.valueToCode(block, 'ELSE', 121 | Blockly.Lua.ORDER_OR) || 'nil'; 122 | var code = value_if + ' and ' + value_then + ' or ' + value_else; 123 | return [code, Blockly.Lua.ORDER_OR]; 124 | }; 125 | -------------------------------------------------------------------------------- /generators/lua/loops.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Language 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Generating Lua for loop blocks. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Lua.loops'); 27 | 28 | goog.require('Blockly.Lua'); 29 | 30 | 31 | Blockly.Lua['controls_repeat'] = function(block) { 32 | // Repeat n times (internal number). 33 | var repeats = parseInt(block.getTitleValue('TIMES'), 10); 34 | var branch = Blockly.Lua.statementToCode(block, 'DO') || ''; 35 | var loopVar = Blockly.Lua.variableDB_.getDistinctName( 36 | 'count', Blockly.Variables.NAME_TYPE); 37 | var code = 'for ' + loopVar + '= 1, ' + repeats + ' do\n' + branch + 'end'; 38 | return code; 39 | }; 40 | 41 | Blockly.Lua['controls_repeat_ext'] = function(block) { 42 | // Repeat n times (external number). 43 | var repeats = Blockly.Lua.valueToCode(block, 'TIMES', 44 | Blockly.Lua.ORDER_NONE) || '0'; 45 | if (Blockly.isNumber(repeats)) { 46 | repeats = parseInt(repeats, 10); 47 | } else { 48 | repeats = 'math.floor(' + repeats + ')'; 49 | } 50 | var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n'; 51 | var loopVar = Blockly.Lua.variableDB_.getDistinctName( 52 | 'count', Blockly.Variables.NAME_TYPE); 53 | var code = 'for ' + loopVar + ' = 1, ' + repeats + ' do\n' + 54 | branch + 'end\n'; 55 | return code; 56 | }; 57 | 58 | Blockly.Lua['controls_whileUntil'] = function(block) { 59 | // Do while/until loop. 60 | var until = block.getTitleValue('MODE') == 'UNTIL'; 61 | var argument0 = Blockly.Lua.valueToCode(block, 'BOOL', 62 | until ? Blockly.Lua.ORDER_UNARY : 63 | Blockly.Lua.ORDER_NONE) || 'False'; 64 | var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n'; 65 | if (block.getTitleValue('MODE') == 'UNTIL') { 66 | if (!argument0.match(/^\w+$/)) { 67 | argument0 = '(' + argument0 + ')'; 68 | } 69 | argument0 = 'not ' + argument0; 70 | } 71 | return 'while ' + argument0 + ' do\n' + branch + 'end\n'; 72 | }; 73 | 74 | Blockly.Lua['controls_for'] = function(block) { 75 | // For loop. 76 | var variable0 = Blockly.Lua.variableDB_.getName( 77 | block.getTitleValue('VAR'), Blockly.Variables.NAME_TYPE); 78 | var argument0 = Blockly.Lua.valueToCode(block, 'FROM', 79 | Blockly.Lua.ORDER_NONE) || '0'; 80 | var argument1 = Blockly.Lua.valueToCode(block, 'TO', 81 | Blockly.Lua.ORDER_NONE) || '0'; 82 | var increment = Blockly.Lua.valueToCode(block, 'BY', 83 | Blockly.Lua.ORDER_NONE) || '1'; 84 | var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n'; 85 | 86 | var code = 'for ' + variable0 + ' = ' + argument0 + ', ' + argument1; 87 | // Increment amount may be omitted if 1. 88 | if (!Blockly.isNumber(increment) || Math.abs(parseFloat(increment)) != 1) { 89 | code += ', ' + increment; 90 | } 91 | code += ' do\n' + branch + 'end\n'; 92 | return code; 93 | }; 94 | 95 | Blockly.Lua['controls_forEach'] = function(block) { 96 | // For each loop. 97 | var variable0 = Blockly.Lua.variableDB_.getName( 98 | block.getTitleValue('VAR'), Blockly.Variables.NAME_TYPE); 99 | var argument0 = Blockly.Lua.valueToCode(block, 'LIST', 100 | Blockly.Lua.ORDER_RELATIONAL) || '[]'; 101 | var branch = Blockly.Lua.statementToCode(block, 'DO') || '\n'; 102 | var code = 'for _, ' + variable0 + ' in ipairs(' + argument0 + ') do \n' + 103 | branch + 'end\n'; 104 | return code; 105 | }; 106 | 107 | Blockly.Lua['controls_flow_statements'] = function(block) { 108 | // break; we eliminated "continue" 109 | return 'break\n'; 110 | }; 111 | -------------------------------------------------------------------------------- /generators/lua/procedures.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Language 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Generating Lua for procedure blocks. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | goog.provide('Blockly.Lua.procedures'); 27 | 28 | goog.require('Blockly.Lua'); 29 | 30 | 31 | Blockly.Lua['procedures_defreturn'] = function(block) { 32 | // Define a procedure with a return value. 33 | var funcName = Blockly.Lua.variableDB_.getName(block.getTitleValue('NAME'), 34 | Blockly.Procedures.NAME_TYPE); 35 | var branch = Blockly.Lua.statementToCode(block, 'STACK'); 36 | if (Blockly.Lua.INFINITE_LOOP_TRAP) { 37 | branch = Blockly.Lua.INFINITE_LOOP_TRAP.replace(/%1/g, 38 | '"' + block.id + '"') + branch; 39 | } 40 | var returnValue = Blockly.Lua.valueToCode(block, 'RETURN', 41 | Blockly.Lua.ORDER_NONE) || ''; 42 | if (returnValue) { 43 | returnValue = ' return ' + returnValue + '\n'; 44 | } else if (!branch) { 45 | branch = ''; 46 | } 47 | var args = []; 48 | for (var x = 0; x < block.arguments_.length; x++) { 49 | args[x] = Blockly.Lua.variableDB_.getName(block.arguments_[x], 50 | Blockly.Variables.NAME_TYPE); 51 | } 52 | var code = 'function ' + funcName + '(' + args.join(', ') + ')\n' + 53 | branch + returnValue + 'end\n'; 54 | code = Blockly.Lua.scrub_(block, code); 55 | Blockly.Lua.definitions_[funcName] = code; 56 | return null; 57 | }; 58 | 59 | // Defining a procedure without a return value uses the same generator as 60 | // a procedure with a return value. 61 | Blockly.Lua['procedures_defnoreturn'] = 62 | Blockly.Lua['procedures_defreturn']; 63 | 64 | Blockly.Lua['procedures_callreturn'] = function(block) { 65 | // Call a procedure with a return value. 66 | var funcName = Blockly.Lua.variableDB_.getName(block.getTitleValue('NAME'), 67 | Blockly.Procedures.NAME_TYPE); 68 | var args = []; 69 | for (var x = 0; x < block.arguments_.length; x++) { 70 | args[x] = Blockly.Lua.valueToCode(block, 'ARG' + x, 71 | Blockly.Lua.ORDER_NONE) || 'None'; 72 | } 73 | var code = funcName + '(' + args.join(', ') + ')'; 74 | return [code, Blockly.Lua.ORDER_HIGH]; 75 | }; 76 | 77 | Blockly.Lua['procedures_callnoreturn'] = function(block) { 78 | // Call a procedure with no return value. 79 | var funcName = Blockly.Lua.variableDB_.getName(block.getTitleValue('NAME'), 80 | Blockly.Procedures.NAME_TYPE); 81 | var args = []; 82 | for (var x = 0; x < block.arguments_.length; x++) { 83 | args[x] = Blockly.Lua.valueToCode(block, 'ARG' + x, 84 | Blockly.Lua.ORDER_NONE) || 'None'; 85 | } 86 | var code = funcName + '(' + args.join(', ') + ')\n'; 87 | return code; 88 | }; 89 | 90 | Blockly.Lua['procedures_ifreturn'] = function(block) { 91 | // Conditionally return value from a procedure. 92 | var condition = Blockly.Lua.valueToCode(block, 'CONDITION', 93 | Blockly.Lua.ORDER_NONE) || 'False'; 94 | var code = 'if ' + condition + ' then\n'; 95 | if (block.hasReturnValue_) { 96 | var value = Blockly.Lua.valueToCode(block, 'VALUE', 97 | Blockly.Lua.ORDER_NONE) || 'None'; 98 | code += ' return ' + value + '\n'; 99 | } else { 100 | code += ' return\n'; 101 | } 102 | code += 'end\n'; 103 | return code; 104 | }; 105 | -------------------------------------------------------------------------------- /generators/lua/variables.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Language 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Generating Lua for variable blocks. 22 | * 23 | * This is unchanged from the Python version, except for replacing "Python" 24 | * with "Lua" wherever it appeared. 25 | * 26 | * @author q.neutron@gmail.com (Quynh Neutron) 27 | */ 28 | 'use strict'; 29 | 30 | goog.provide('Blockly.Lua.variables'); 31 | 32 | goog.require('Blockly.Lua'); 33 | 34 | 35 | Blockly.Lua['variables_get'] = function(block) { 36 | // Variable getter. 37 | var code = Blockly.Lua.variableDB_.getName(block.getTitleValue('VAR'), 38 | Blockly.Variables.NAME_TYPE); 39 | return [code, Blockly.Lua.ORDER_ATOMIC]; 40 | }; 41 | 42 | Blockly.Lua['variables_set'] = function(block) { 43 | // Variable setter. 44 | var argument0 = Blockly.Lua.valueToCode(block, 'VALUE', 45 | Blockly.Lua.ORDER_NONE) || '0'; 46 | var varName = Blockly.Lua.variableDB_.getName(block.getTitleValue('VAR'), 47 | Blockly.Variables.NAME_TYPE); 48 | return varName + ' = ' + argument0 + '\n'; 49 | }; 50 | 51 | Blockly.Lua['variables_set_two'] = function(block) { 52 | // Set two variables to a function's return value. 53 | // If the input is not a procedure returning mulltiple values, the 54 | // user will have been warned both when the connection was made and when 55 | // changing to the Lua tab. 56 | var value = Blockly.Lua.valueToCode(block, 'VALUE', 57 | Blockly.Lua.ORDER_NONE) || 'nil, nil'; 58 | var varName1 = Blockly.Lua.variableDB_.getName(block.getTitleValue('VAR1'), 59 | Blockly.Variables.NAME_TYPE); 60 | var varName2 = Blockly.Lua.variableDB_.getName(block.getTitleValue('VAR2'), 61 | Blockly.Variables.NAME_TYPE); 62 | return varName1 + ', ' + varName2 + ' = ' + value + '\n'; 63 | }; 64 | 65 | Blockly.Lua['variables_set_three'] = function(block) { 66 | // Set three variables to a function's return value. 67 | // If the input is not a procedure returning at least three values, the 68 | // user will have been warned both when the connection was made and when 69 | // changing to the Lua tab. 70 | var value = Blockly.Lua.valueToCode(block, 'VALUE', 71 | Blockly.Lua.ORDER_NONE) || 'nil, nil, nil'; 72 | var varName1 = Blockly.Lua.variableDB_.getName(block.getTitleValue('VAR1'), 73 | Blockly.Variables.NAME_TYPE); 74 | var varName2 = Blockly.Lua.variableDB_.getName(block.getTitleValue('VAR2'), 75 | Blockly.Variables.NAME_TYPE); 76 | var varName3 = Blockly.Lua.variableDB_.getName(block.getTitleValue('VAR3'), 77 | Blockly.Variables.NAME_TYPE); 78 | return varName1 + ', ' + varName2 + ', ' + varName3 + ' = ' + value + '\n'; 79 | }; 80 | -------------------------------------------------------------------------------- /media/1x1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/1x1.gif -------------------------------------------------------------------------------- /media/click.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/click.mp3 -------------------------------------------------------------------------------- /media/click.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/click.ogg -------------------------------------------------------------------------------- /media/click.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/click.wav -------------------------------------------------------------------------------- /media/delete.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/delete.mp3 -------------------------------------------------------------------------------- /media/delete.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/delete.ogg -------------------------------------------------------------------------------- /media/delete.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/delete.wav -------------------------------------------------------------------------------- /media/handclosed.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/handclosed.cur -------------------------------------------------------------------------------- /media/handopen.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/handopen.cur -------------------------------------------------------------------------------- /media/quote0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/quote0.png -------------------------------------------------------------------------------- /media/quote1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/quote1.png -------------------------------------------------------------------------------- /media/trashbody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/trashbody.png -------------------------------------------------------------------------------- /media/trashlid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/trashlid.png -------------------------------------------------------------------------------- /media/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/espertus/blockly-lua/a3fe3f0a273a3e3d494b983d0afdba8cb2b2dff9/media/tree.png -------------------------------------------------------------------------------- /msg/json/keys.json: -------------------------------------------------------------------------------- 1 | { 2 | -------------------------------------------------------------------------------- /msg/json/synonyms.json: -------------------------------------------------------------------------------- 1 | {"PROCEDURES_DEFRETURN_TITLE": "PROCEDURES_DEFNORETURN_TITLE", "CONTROLS_IF_IF_TITLE_IF": "CONTROLS_IF_MSG_IF", "CONTROLS_WHILEUNTIL_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "CONTROLS_IF_MSG_THEN": "CONTROLS_REPEAT_INPUT_DO", "PROCEDURES_CALLRETURN_CALL": "PROCEDURES_CALLNORETURN_CALL", "CONTROLS_IF_ELSE_TITLE_ELSE": "CONTROLS_IF_MSG_ELSE", "PROCEDURES_DEFRETURN_PROCEDURE": "PROCEDURES_DEFNORETURN_PROCEDURE", "LISTS_GET_SUBLIST_INPUT_IN_LIST": "LISTS_INLIST", "LISTS_GET_INDEX_INPUT_IN_LIST": "LISTS_INLIST", "CONTROLS_IF_ELSEIF_TITLE_ELSEIF": "CONTROLS_IF_MSG_ELSEIF", "VARIABLES_SET_ITEM": "VARIABLES_DEFAULT_NAME", "PROCEDURES_DEFRETURN_DO": "PROCEDURES_DEFNORETURN_DO", "CONTROLS_FOR_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "LISTS_GET_INDEX_HELPURL": "LISTS_INDEX_OF_HELPURL", "CONTROLS_FOREACH_INPUT_DO": "CONTROLS_REPEAT_INPUT_DO", "VARIABLES_GET_ITEM": "VARIABLES_DEFAULT_NAME", "LISTS_INDEX_OF_INPUT_IN_LIST": "LISTS_INLIST", "LISTS_SET_INDEX_INPUT_IN_LIST": "LISTS_INLIST"} -------------------------------------------------------------------------------- /msg/json/zh_tw.json: -------------------------------------------------------------------------------- 1 | {"DUPLICATE_BLOCK": "複製", 2 | "REMOVE_COMMENT": "移除註解", 3 | "ADD_COMMENT": "加入註解", 4 | "EXTERNAL_INPUTS": "多行輸入", 5 | "INLINE_INPUTS": "單行輸入", 6 | "DELETE_BLOCK": "刪除積木", 7 | "DELETE_X_BLOCKS": "刪除 %1 塊積木", 8 | "COLLAPSE_BLOCK": "收合積木", 9 | "EXPAND_BLOCK": "展開積木", 10 | "DISABLE_BLOCK": "停用積木", 11 | "ENABLE_BLOCK": "啟用積木", 12 | "HELP": "說明", 13 | "CHANGE_VALUE_TITLE": "修改值:", 14 | "NEW_VARIABLE": "新變量...", 15 | "NEW_VARIABLE_TITLE": "新變量名稱:", 16 | "RENAME_VARIABLE": "重新命名變量...", 17 | "RENAME_VARIABLE_TITLE": "將所有 \"%1\" 變量重新命名為:", 18 | "CONTROLS_REPEAT_TITLE": "重複 %1 次數", 19 | "CONTROLS_REPEAT_TITLE_REPEAT": "重複", 20 | "CONTROLS_REPEAT_TITLE_TIMES": "次數", 21 | "CONTROLS_REPEAT_INPUT_DO": "執行", 22 | "CONTROLS_WHILEUNTIL_OPERATOR_WHILE": "重複 當", 23 | "CONTROLS_WHILEUNTIL_OPERATOR_UNTIL": "重複 直到", 24 | "CONTROLS_FOR_INPUT_WITH": "使用", 25 | "VARIABLES_DEFAULT_NAME": "變量", 26 | "CONTROLS_FOR_INPUT_FROM_TO_BY": "從範圍 %1 到 %2 每隔 %3", 27 | "CONTROLS_FOREACH_INPUT_ITEM": "取出每個", 28 | "CONTROLS_FOREACH_INPUT_INLIST": "自列表", 29 | "CONTROLS_FOREACH_INPUT_INLIST_TAIL": "", 30 | "CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK": "停止 迴圈", 31 | "CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE": "繼續下一個 迴圈", 32 | "CONTROLS_IF_MSG_ELSEIF": "否則如果", 33 | "CONTROLS_IF_MSG_ELSE": "否則", 34 | "LOGIC_OPERATION_AND": "且", 35 | "LOGIC_OPERATION_OR": "或", 36 | "LOGIC_NEGATE_TITLE": "非 %1", 37 | "LOGIC_BOOLEAN_TRUE": "是", 38 | "LOGIC_BOOLEAN_FALSE": "否", 39 | "LOGIC_NULL": "空", 40 | "MATH_SINGLE_OP_ROOT": "開根號", 41 | "MATH_SINGLE_OP_ABSOLUTE": "絕對值", 42 | "MATH_CHANGE_TITLE_CHANGE": "修改", 43 | "MATH_CHANGE_TITLE_ITEM": "變量", 44 | "MATH_CHANGE_INPUT_BY": "自", 45 | "MATH_ROUND_OPERATOR_ROUND": "四捨五入", 46 | "MATH_ROUND_OPERATOR_ROUNDUP": "無條件進位", 47 | "MATH_ROUND_OPERATOR_ROUNDDOWN": "無條件捨去", 48 | "MATH_ONLIST_OPERATOR_SUM": "總和 自列表", 49 | "MATH_ONLIST_OPERATOR_MIN": "最小值 自列表", 50 | "MATH_ONLIST_OPERATOR_MAX": "最大值 自列表", 51 | "MATH_ONLIST_OPERATOR_AVERAGE": "平均值 自列表", 52 | "MATH_ONLIST_OPERATOR_MEDIAN": "中位數 自列表", 53 | "MATH_ONLIST_OPERATOR_MODE": "比較眾數 自列表", 54 | "MATH_ONLIST_OPERATOR_STD_DEV": "標準差 自列表", 55 | "MATH_ONLIST_OPERATOR_RANDOM": "隨機抽取 自列表", 56 | "MATH_MODULO_TITLE": "取餘數自 %1 \u00f7 %2", 57 | "MATH_CONSTRAIN_TITLE": "限制數字 %1 介於 (低) %2 到 (高) %3", 58 | "MATH_RANDOM_INT_TITLE": "取隨機整數介於 (低) %1 到 %2", 59 | "MATH_RANDOM_FLOAT_TITLE_RANDOM": "取隨機分數", 60 | "TEXT_JOIN_TITLE_CREATEWITH": "建立字串使用", 61 | "TEXT_CREATE_JOIN_TITLE_JOIN": "加入", 62 | "TEXT_CREATE_JOIN_ITEM_TITLE_ITEM": "字串", 63 | "TEXT_APPEND_TO": "在", 64 | "TEXT_APPEND_APPENDTEXT": "後加入文字", 65 | "TEXT_APPEND_VARIABLE": "變量", 66 | "TEXT_LENGTH_TITLE": "長度 %1", 67 | "TEXT_ISEMPTY_TITLE": "%1 為空", 68 | "TEXT_INDEXOF_INPUT_INTEXT": "在字串", 69 | "TEXT_INDEXOF_OPERATOR_FIRST": "尋找 第一個 出現的字串", 70 | "TEXT_INDEXOF_OPERATOR_LAST": "尋找 最後一個 出現的字串", 71 | "TEXT_CHARAT_INPUT_INTEXT": "的字元在字串", 72 | "TEXT_CHANGECASE_OPERATOR_UPPERCASE": "改成 轉大寫", 73 | "TEXT_CHANGECASE_OPERATOR_LOWERCASE": "改成 轉小寫", 74 | "TEXT_CHANGECASE_OPERATOR_TITLECASE": "改成 頭字母大寫", 75 | "TEXT_TRIM_OPERATOR_BOTH": "從 兩側 消除空格", 76 | "TEXT_TRIM_OPERATOR_LEFT": "從 左側 消除空格", 77 | "TEXT_TRIM_OPERATOR_RIGHT": "從 右側 消除空格", 78 | "TEXT_PRINT_TITLE": "印出 %1", 79 | "TEXT_PROMPT_TYPE_TEXT": "輸入 文字 並顯示提示訊息", 80 | "TEXT_PROMPT_TYPE_NUMBER": "輸入 數字 並顯示提示訊息", 81 | "LISTS_CREATE_EMPTY_TITLE": "建立空列表", 82 | "LISTS_CREATE_WITH_INPUT_WITH": "使用這些值建立列表", 83 | "LISTS_CREATE_WITH_CONTAINER_TITLE_ADD": "加入", 84 | "LISTS_CREATE_WITH_ITEM_TITLE": "項目", 85 | "LISTS_REPEAT_TITLE": "建立列表使用項目 %1 重複 %2 次數", 86 | "LISTS_LENGTH_TITLE": "長度 %1", 87 | "LISTS_IS_EMPTY_TITLE": "%1 值為空", 88 | "LISTS_INDEX_OF_FIRST": "找出 第一個 項目出現", 89 | "LISTS_INDEX_OF_LAST": "找出 最後一個 項目出現", 90 | "VARIABLES_GET_TITLE": "", 91 | "VARIABLES_GET_TAIL": "", 92 | "VARIABLES_SET_TITLE": "賦值", 93 | "VARIABLES_SET_TAIL": "", 94 | "PROCEDURES_DEFNORETURN_PROCEDURE": "流程", 95 | "PROCEDURES_DEFRETURN_RETURN": "回傳", 96 | "PROCEDURES_CALLNORETURN_CALL": "呼叫", 97 | "PROCEDURES_MUTATORCONTAINER_TITLE": "參數", 98 | "PROCEDURES_MUTATORARG_TITLE": "變量:" 99 | } 100 | -------------------------------------------------------------------------------- /tests/blockly_test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Unit tests for Blockly 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/blockly_test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Editor 3 | * 4 | * Copyright 2011 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 'use strict'; 20 | 21 | function verify_DB_(msg, expected, db) { 22 | var equal = (expected.length == db.length); 23 | if (equal) { 24 | for (var x = 0; x < expected.length; x++) { 25 | if (expected[x] != db[x]) { 26 | equal = false; 27 | break; 28 | } 29 | } 30 | } 31 | if (equal) { 32 | assertTrue(msg, true); 33 | } else { 34 | assertEquals(msg, expected, db); 35 | } 36 | } 37 | 38 | function test_DB_addConnection() { 39 | var db = new Blockly.ConnectionDB(); 40 | var o2 = {y_: 2}; 41 | db.addConnection_(o2); 42 | verify_DB_('Adding connection #2', [o2], db); 43 | 44 | var o4 = {y_: 4}; 45 | db.addConnection_(o4); 46 | verify_DB_('Adding connection #4', [o2, o4], db); 47 | 48 | var o1 = {y_: 1}; 49 | db.addConnection_(o1); 50 | verify_DB_('Adding connection #1', [o1, o2, o4], db); 51 | 52 | var o3a = {y_: 3}; 53 | db.addConnection_(o3a); 54 | verify_DB_('Adding connection #3a', [o1, o2, o3a, o4], db); 55 | 56 | var o3b = {y_: 3}; 57 | db.addConnection_(o3b); 58 | verify_DB_('Adding connection #3b', [o1, o2, o3b, o3a, o4], db); 59 | } 60 | 61 | function test_DB_removeConnection() { 62 | var db = new Blockly.ConnectionDB(); 63 | var o1 = {y_: 1}; 64 | var o2 = {y_: 2}; 65 | var o3a = {y_: 3}; 66 | var o3b = {y_: 3}; 67 | var o3c = {y_: 3}; 68 | var o4 = {y_: 4}; 69 | db.addConnection_(o1); 70 | db.addConnection_(o2); 71 | db.addConnection_(o3c); 72 | db.addConnection_(o3b); 73 | db.addConnection_(o3a); 74 | db.addConnection_(o4); 75 | verify_DB_('Adding connections 1-4', [o1, o2, o3a, o3b, o3c, o4], db); 76 | 77 | db.removeConnection_(o2); 78 | verify_DB_('Removing connection #2', [o1, o3a, o3b, o3c, o4], db); 79 | 80 | db.removeConnection_(o4); 81 | verify_DB_('Removing connection #4', [o1, o3a, o3b, o3c], db); 82 | 83 | db.removeConnection_(o1); 84 | verify_DB_('Removing connection #1', [o3a, o3b, o3c], db); 85 | 86 | db.removeConnection_(o3a); 87 | verify_DB_('Removing connection #3a', [o3b, o3c], db); 88 | 89 | db.removeConnection_(o3c); 90 | verify_DB_('Removing connection #3c', [o3b], db); 91 | 92 | db.removeConnection_(o3b); 93 | verify_DB_('Removing connection #3b', [], db); 94 | } 95 | 96 | function test_addClass() { 97 | var p = document.createElement('p'); 98 | Blockly.addClass_(p, 'one'); 99 | assertEquals('Adding "one"', 'one', p.className); 100 | Blockly.addClass_(p, 'one'); 101 | assertEquals('Adding duplicate "one"', 'one', p.className); 102 | Blockly.addClass_(p, 'two'); 103 | assertEquals('Adding "two"', 'one two', p.className); 104 | Blockly.addClass_(p, 'two'); 105 | assertEquals('Adding duplicate "two"', 'one two', p.className); 106 | Blockly.addClass_(p, 'three'); 107 | assertEquals('Adding "three"', 'one two three', p.className); 108 | } 109 | 110 | function test_removeClass() { 111 | var p = document.createElement('p'); 112 | p.className = ' one three two three '; 113 | Blockly.removeClass_(p, 'two'); 114 | assertEquals('Removing "two"', 'one three three', p.className); 115 | Blockly.removeClass_(p, 'four'); 116 | assertEquals('Removing "four"', 'one three three', p.className); 117 | Blockly.removeClass_(p, 'three'); 118 | assertEquals('Removing "three"', 'one', p.className); 119 | Blockly.removeClass_(p, 'ne'); 120 | assertEquals('Removing "ne"', 'one', p.className); 121 | Blockly.removeClass_(p, 'one'); 122 | assertEquals('Removing "one"', '', p.className); 123 | Blockly.removeClass_(p, 'zero'); 124 | assertEquals('Removing "zero"', '', p.className); 125 | } 126 | 127 | function test_shortestStringLength() { 128 | var len = Blockly.shortestStringLength('one,two,three,four,five'.split(',')); 129 | assertEquals('Length of "one"', 3, len); 130 | len = Blockly.shortestStringLength('one,two,three,four,five,'.split(',')); 131 | assertEquals('Length of ""', 0, len); 132 | len = Blockly.shortestStringLength(['Hello World']); 133 | assertEquals('List of one', 11, len); 134 | len = Blockly.shortestStringLength([]); 135 | assertEquals('Empty list', 0, len); 136 | } 137 | 138 | function test_commonWordPrefix() { 139 | var len = Blockly.commonWordPrefix('one,two,three,four,five'.split(',')); 140 | assertEquals('No prefix', 0, len); 141 | len = Blockly.commonWordPrefix('Xone,Xtwo,Xthree,Xfour,Xfive'.split(',')); 142 | assertEquals('No word prefix', 0, len); 143 | len = Blockly.commonWordPrefix('abc de,abc de,abc de,abc de'.split(',')); 144 | assertEquals('Full equality', 6, len); 145 | len = Blockly.commonWordPrefix('abc deX,abc deY'.split(',')); 146 | assertEquals('One word prefix', 4, len); 147 | len = Blockly.commonWordPrefix('abc de,abc deY'.split(',')); 148 | assertEquals('Overflow no', 4, len); 149 | len = Blockly.commonWordPrefix('abc de,abc de Y'.split(',')); 150 | assertEquals('Overflow yes', 6, len); 151 | len = Blockly.commonWordPrefix(['Hello World']); 152 | assertEquals('List of one', 11, len); 153 | len = Blockly.commonWordPrefix([]); 154 | assertEquals('Empty list', 0, len); 155 | len = Blockly.commonWordPrefix('turn left,turn right'.split(',')); 156 | assertEquals('No prefix due to &nbsp;', 0, len); 157 | len = Blockly.commonWordPrefix('turn\u00A0left,turn\u00A0right'.split(',')); 158 | assertEquals('No prefix due to \\u00A0', 0, len); 159 | } 160 | 161 | function test_commonWordSuffix() { 162 | var len = Blockly.commonWordSuffix('one,two,three,four,five'.split(',')); 163 | assertEquals('No prefix', 0, len); 164 | len = Blockly.commonWordSuffix('oneX,twoX,threeX,fourX,fiveX'.split(',')); 165 | assertEquals('No word prefix', 0, len); 166 | len = Blockly.commonWordSuffix('abc de,abc de,abc de,abc de'.split(',')); 167 | assertEquals('Full equality', 6, len); 168 | len = Blockly.commonWordSuffix('Xabc de,Yabc de'.split(',')); 169 | assertEquals('One word prefix', 3, len); 170 | len = Blockly.commonWordSuffix('abc de,Yabc de'.split(',')); 171 | assertEquals('Overflow no', 3, len); 172 | len = Blockly.commonWordSuffix('abc de,Y abc de'.split(',')); 173 | assertEquals('Overflow yes', 6, len); 174 | len = Blockly.commonWordSuffix(['Hello World']); 175 | assertEquals('List of one', 11, len); 176 | len = Blockly.commonWordSuffix([]); 177 | assertEquals('Empty list', 0, len); 178 | } 179 | -------------------------------------------------------------------------------- /tests/generator_test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Tests 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 'use strict'; 20 | 21 | function test_prefix() { 22 | var generator = new Blockly.Generator('INTERCAL'); 23 | assertEquals('Prefix nothing.', '', generator.prefixLines('', '')); 24 | assertEquals('Prefix a word.', '@Hello', generator.prefixLines('Hello', '@')); 25 | assertEquals('Prefix one line.', '12Hello\n', generator.prefixLines('Hello\n', '12')); 26 | assertEquals('Prefix two lines.', '***Hello\n***World\n', generator.prefixLines('Hello\nWorld\n', '***')); 27 | } 28 | -------------------------------------------------------------------------------- /tests/generators/unittest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Language 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Unit test blocks for Blockly. 22 | * @author fraser@google.com (Neil Fraser) 23 | */ 24 | 'use strict'; 25 | 26 | Blockly.Blocks['unittest_main'] = { 27 | // Container for unit tests. 28 | init: function() { 29 | this.setColour(65); 30 | this.appendDummyInput() 31 | .appendTitle('run tests'); 32 | this.appendStatementInput('DO'); 33 | this.setTooltip('Executes the enclosed unit tests,\n' + 34 | 'then prints a summary.'); 35 | }, 36 | getVars: function() { 37 | return ['unittestResults']; 38 | } 39 | }; 40 | 41 | Blockly.Blocks['unittest_assertequals'] = { 42 | // Asserts that a value equals another value. 43 | init: function() { 44 | this.setColour(65); 45 | this.setPreviousStatement(true); 46 | this.setNextStatement(true); 47 | this.appendDummyInput() 48 | .appendTitle(new Blockly.FieldTextInput('test name'), 'MESSAGE'); 49 | this.appendValueInput('ACTUAL', null) 50 | .appendTitle('actual'); 51 | this.appendValueInput('EXPECTED', null) 52 | .appendTitle('expected'); 53 | this.setTooltip('Tests that "actual == expected".'); 54 | }, 55 | getVars: function() { 56 | return ['unittestResults']; 57 | } 58 | }; 59 | 60 | Blockly.Blocks['unittest_assertvalue'] = { 61 | // Asserts that a value is true, false, or null. 62 | init: function() { 63 | this.setColour(65); 64 | this.setPreviousStatement(true); 65 | this.setNextStatement(true); 66 | this.appendDummyInput() 67 | .appendTitle(new Blockly.FieldTextInput('test name'), 'MESSAGE'); 68 | this.appendValueInput('ACTUAL', Boolean) 69 | .appendTitle('assert') 70 | .appendTitle(new Blockly.FieldDropdown( 71 | [['true', 'TRUE'], ['false', 'FALSE'], ['null', 'NULL']]), 'EXPECTED'); 72 | this.setTooltip('Tests that the value is true, false, or null.'); 73 | }, 74 | getVars: function() { 75 | return ['unittestResults']; 76 | } 77 | }; 78 | 79 | Blockly.Blocks['unittest_fail'] = { 80 | // Always assert an error. 81 | init: function() { 82 | this.setColour(65); 83 | this.setPreviousStatement(true); 84 | this.setNextStatement(true); 85 | this.appendDummyInput() 86 | .appendTitle(new Blockly.FieldTextInput('test name'), 'MESSAGE') 87 | .appendTitle('fail'); 88 | this.setTooltip('Records an error.'); 89 | }, 90 | getVars: function() { 91 | return ['unittestResults']; 92 | } 93 | }; 94 | -------------------------------------------------------------------------------- /tests/generators/unittest_lua.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Visual Blocks Language 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | /** 21 | * @fileoverview Generating Lua for unit test blocks. 22 | * @author ellen.spertus@gmail.com (Ellen Spertus) 23 | */ 24 | 'use strict'; 25 | 26 | Blockly.Lua['unittest_main'] = function(block) { 27 | // Container for unit tests. 28 | var resultsVar = Blockly.Lua.variableDB_.getName('unittestResults', 29 | Blockly.Variables.NAME_TYPE); 30 | var functionName = Blockly.Lua.provideFunction_( 31 | 'unittest_report', 32 | ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '()', 33 | ' -- Create test report.', 34 | ' report = {}', 35 | ' summary = {}', 36 | ' fails = 0', 37 | ' for _, v in pairs(' + resultsVar + ') do', 38 | ' if v["success"] then', 39 | ' table.insert(summary, ".")', 40 | ' else', 41 | ' table.insert(summary, "F")', 42 | ' fails = fails + 1', 43 | ' table.insert(report, "FAIL: " .. v["title"])', 44 | ' table.insert(report, v["log"])', 45 | ' end', 46 | ' end', 47 | ' table.insert(report, 1, table.concat(summary, ""))', 48 | ' table.insert(report, "")', 49 | ' table.insert(report, "Number of tests run: " .. #' + resultsVar + ')', 50 | ' table.insert(report, "")', 51 | ' if fails > 0 then', 52 | ' table.insert(report, "FAILED (failures=" .. fails .. ")")', 53 | ' else', 54 | ' table.insert(report, "OK")', 55 | ' end', 56 | ' return table.concat(report, "\\n")', 57 | 'end']); 58 | // Setup global to hold test results. 59 | var code = resultsVar + ' = {}\n'; 60 | // Run tests (unindented). 61 | code += Blockly.Lua.statementToCode(block, 'DO') 62 | .replace(/^ /, '').replace(/\n /g, '\n'); 63 | var reportVar = Blockly.Lua.variableDB_.getDistinctName( 64 | 'report', Blockly.Variables.NAME_TYPE); 65 | code += reportVar + ' = ' + functionName + '()\n'; 66 | // Destroy results. 67 | code += resultsVar + ' = nil\n'; 68 | // Print the report. 69 | code += 'print(' + reportVar + ')\n'; 70 | return code; 71 | }; 72 | 73 | 74 | 75 | Blockly.Lua.unittest_main.defineAssert_ = function(block) { 76 | var resultsVar = Blockly.Lua.variableDB_.getName('unittestResults', 77 | Blockly.Variables.NAME_TYPE); 78 | var functionName = Blockly.Lua.provideFunction_( 79 | 'assertEquals', 80 | ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + 81 | '(actual, expected, message)', 82 | ' -- Asserts that a value equals another value.', 83 | ' assert(' + resultsVar + ' ~= nil, ' + 84 | '"Orphaned assert equals: " .. message)', 85 | ' if type(actual) == "table" and type(expected) == "table" then', 86 | // This comparison is not sufficiently strict for the general case, 87 | // where list entries contain commas, but our unit tests will not be 88 | // written by adversaries. 89 | ' expected = "{" .. table.concat(expected, ", ") .. "}"', 90 | ' actual = "{" .. table.concat(actual, ", ") .. "}"', 91 | ' end', 92 | ' if actual == expected then', 93 | ' table.insert(' + resultsVar + 94 | ', {success=true, log="OK", title=message})', 95 | ' else', 96 | ' table.insert(' + resultsVar + ', {success=false, ' + 97 | 'log=string.format("Expected: %s\\nActual: %s"' + 98 | ', expected, actual), title=message})', 99 | ' end', 100 | 'end']); 101 | return functionName; 102 | }; 103 | 104 | Blockly.Lua['unittest_assertequals'] = function(block) { 105 | // Asserts that a value equals another value. 106 | var message = Blockly.Lua.quote_(block.getTitleValue('MESSAGE')); 107 | var actual = Blockly.Lua.valueToCode(block, 'ACTUAL', 108 | Blockly.Lua.ORDER_NONE) || 'nil'; 109 | var expected = Blockly.Lua.valueToCode(block, 'EXPECTED', 110 | Blockly.Lua.ORDER_NONE) || 'nil'; 111 | return Blockly.Lua.unittest_main.defineAssert_() + 112 | '(' + actual + ', ' + expected + ', ' + message + ')\n'; 113 | }; 114 | 115 | Blockly.Lua['unittest_assertvalue'] = function(block) { 116 | // Asserts that a value is true, false, or null. 117 | var message = Blockly.Lua.quote_(block.getTitleValue('MESSAGE')); 118 | var actual = Blockly.Lua.valueToCode(block, 'ACTUAL', 119 | Blockly.Lua.ORDER_NONE) || 'nil'; 120 | var expected = block.getTitleValue('EXPECTED'); 121 | if (expected == 'TRUE') { 122 | expected = 'true'; 123 | } else if (expected == 'FALSE') { 124 | expected = 'false'; 125 | } else if (expected == 'NULL') { 126 | expected = 'nil'; 127 | } 128 | return Blockly.Lua.unittest_main.defineAssert_() + 129 | '(' + actual + ', ' + expected + ', ' + message + ')\n'; 130 | }; 131 | 132 | Blockly.Lua['unittest_fail'] = function(block) { 133 | // Always assert an error. 134 | var resultsVar = Blockly.Lua.variableDB_.getName('unittestResults', 135 | Blockly.Variables.NAME_TYPE); 136 | var message = Blockly.Lua.quote_(block.getTitleValue('MESSAGE')); 137 | if (!Blockly.Lua.unittest_fail.assert) { 138 | var functionName = Blockly.Lua.provideFunction_( 139 | 'fail', 140 | ['function ' + Blockly.Lua.FUNCTION_NAME_PLACEHOLDER_ + '(message)', 141 | ' -- Always assert an error.', 142 | ' assert(resultsVar ~= nil, "Orphaned assert equals: " .. message)', 143 | ' table.insert(' + resultsVar + 144 | ', {success=false, log="Fail.", title=message})', 145 | 'end']); 146 | Blockly.Lua.unittest_fail.assert = functionName; 147 | } 148 | return Blockly.Lua.unittest_fail.assert + '(' + message + ')\n'; 149 | }; 150 | -------------------------------------------------------------------------------- /tests/generators/variables.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | item 6 | 7 | 8 | 123 9 | 10 | 11 | 12 | 13 | variable 14 | 15 | 16 | item 17 | 18 | 19 | 20 | 21 | 123 22 | 23 | 24 | 25 | 26 | if 27 | 28 | 29 | 123 30 | 31 | 32 | 33 | 34 | reserved variable 35 | 36 | 37 | if 38 | 39 | 40 | 41 | 42 | 123 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /tests/names_test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Blockly Tests 3 | * 4 | * Copyright 2012 Google Inc. 5 | * http://blockly.googlecode.com/ 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 'use strict'; 20 | 21 | function test_safeName() { 22 | var varDB = new Blockly.Names('window,door'); 23 | assertEquals('SafeName empty.', 'unnamed', varDB.safeName_('')); 24 | assertEquals('SafeName ok.', 'foobar', varDB.safeName_('foobar')); 25 | assertEquals('SafeName number start.', 'my_9lives', 26 | varDB.safeName_('9lives')); 27 | assertEquals('SafeName number end.', 'lives9', varDB.safeName_('lives9')); 28 | assertEquals('SafeName special chars.', '____', varDB.safeName_('!@#$')); 29 | assertEquals('SafeName reserved.', 'door', varDB.safeName_('door')); 30 | } 31 | 32 | function test_getName() { 33 | var varDB = new Blockly.Names('window,door'); 34 | assertEquals('Name add #1.', 'Foo_bar', varDB.getName('Foo.bar', 'var')); 35 | assertEquals('Name get #1.', 'Foo_bar', varDB.getName('Foo.bar', 'var')); 36 | assertEquals('Name add #2.', 'Foo_bar2', varDB.getName('Foo bar', 'var')); 37 | assertEquals('Name get #2.', 'Foo_bar2', varDB.getName('foo BAR', 'var')); 38 | assertEquals('Name add #3.', 'door2', varDB.getName('door', 'var')); 39 | assertEquals('Name add #4.', 'Foo_bar3', varDB.getName('Foo.bar', 'proc')); 40 | assertEquals('Name get #1b.', 'Foo_bar', varDB.getName('Foo.bar', 'var')); 41 | assertEquals('Name get #4.', 'Foo_bar3', varDB.getName('Foo.bar', 'proc')); 42 | } 43 | 44 | function test_getDistinctName() { 45 | var varDB = new Blockly.Names('window,door'); 46 | assertEquals('Name distinct #1.', 'Foo_bar', 47 | varDB.getDistinctName('Foo.bar', 'var')); 48 | assertEquals('Name distinct #2.', 'Foo_bar2', 49 | varDB.getDistinctName('Foo.bar', 'var')); 50 | assertEquals('Name distinct #3.', 'Foo_bar3', 51 | varDB.getDistinctName('Foo.bar', 'proc')); 52 | varDB.reset(); 53 | assertEquals('Name distinct #4.', 'Foo_bar', 54 | varDB.getDistinctName('Foo.bar', 'var')); 55 | } 56 | 57 | function test_nameEquals() { 58 | assertTrue('Name equals #1.', Blockly.Names.equals('Foo.bar', 'Foo.bar')); 59 | assertFalse('Name equals #2.', Blockly.Names.equals('Foo.bar', 'Foo_bar')); 60 | assertTrue('Name equals #3.', Blockly.Names.equals('Foo.bar', 'FOO.BAR')); 61 | } 62 | --------------------------------------------------------------------------------