summaryrefslogtreecommitdiff
path: root/blockly/demos/blockfactory/blocks.js
diff options
context:
space:
mode:
Diffstat (limited to 'blockly/demos/blockfactory/blocks.js')
-rw-r--r--blockly/demos/blockfactory/blocks.js802
1 files changed, 802 insertions, 0 deletions
diff --git a/blockly/demos/blockfactory/blocks.js b/blockly/demos/blockfactory/blocks.js
new file mode 100644
index 0000000..3cd1dcd
--- /dev/null
+++ b/blockly/demos/blockfactory/blocks.js
@@ -0,0 +1,802 @@
+/**
+ * Blockly Demos: Block Factory Blocks
+ *
+ * Copyright 2012 Google Inc.
+ * https://developers.google.com/blockly/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview Blocks for Blockly's Block Factory application.
+ * @author fraser@google.com (Neil Fraser)
+ */
+'use strict';
+
+Blockly.Blocks['factory_base'] = {
+ // Base of new block.
+ init: function() {
+ this.setColour(120);
+ this.appendDummyInput()
+ .appendField('name')
+ .appendField(new Blockly.FieldTextInput('block_type'), 'NAME');
+ this.appendStatementInput('INPUTS')
+ .setCheck('Input')
+ .appendField('inputs');
+ var dropdown = new Blockly.FieldDropdown([
+ ['automatic inputs', 'AUTO'],
+ ['external inputs', 'EXT'],
+ ['inline inputs', 'INT']]);
+ this.appendDummyInput()
+ .appendField(dropdown, 'INLINE');
+ dropdown = new Blockly.FieldDropdown([
+ ['no connections', 'NONE'],
+ ['← left output', 'LEFT'],
+ ['↕ top+bottom connections', 'BOTH'],
+ ['↑ top connection', 'TOP'],
+ ['↓ bottom connection', 'BOTTOM']],
+ function(option) {
+ this.sourceBlock_.updateShape_(option);
+ });
+ this.appendDummyInput()
+ .appendField(dropdown, 'CONNECTIONS');
+ this.appendValueInput('COLOUR')
+ .setCheck('Colour')
+ .appendField('colour');
+ this.setTooltip('Build a custom block by plugging\n' +
+ 'fields, inputs and other blocks here.');
+ this.setHelpUrl(
+ 'https://developers.google.com/blockly/guides/create-custom-blocks/block-factory');
+ },
+ mutationToDom: function() {
+ var container = document.createElement('mutation');
+ container.setAttribute('connections', this.getFieldValue('CONNECTIONS'));
+ return container;
+ },
+ domToMutation: function(xmlElement) {
+ var connections = xmlElement.getAttribute('connections');
+ this.updateShape_(connections);
+ },
+ updateShape_: function(option) {
+ var outputExists = this.getInput('OUTPUTTYPE');
+ var topExists = this.getInput('TOPTYPE');
+ var bottomExists = this.getInput('BOTTOMTYPE');
+ if (option == 'LEFT') {
+ if (!outputExists) {
+ this.addTypeInput_('OUTPUTTYPE', 'output type');
+ }
+ } else if (outputExists) {
+ this.removeInput('OUTPUTTYPE');
+ }
+ if (option == 'TOP' || option == 'BOTH') {
+ if (!topExists) {
+ this.addTypeInput_('TOPTYPE', 'top type');
+ }
+ } else if (topExists) {
+ this.removeInput('TOPTYPE');
+ }
+ if (option == 'BOTTOM' || option == 'BOTH') {
+ if (!bottomExists) {
+ this.addTypeInput_('BOTTOMTYPE', 'bottom type');
+ }
+ } else if (bottomExists) {
+ this.removeInput('BOTTOMTYPE');
+ }
+ },
+ addTypeInput_: function(name, label) {
+ this.appendValueInput(name)
+ .setCheck('Type')
+ .appendField(label);
+ this.moveInputBefore(name, 'COLOUR');
+ var type = this.workspace.newBlock('type_null');
+ type.setShadow(true);
+ type.outputConnection.connect(this.getInput(name).connection);
+ type.initSvg();
+ type.render();
+ }
+};
+
+var FIELD_MESSAGE = 'fields %1 %2';
+var FIELD_ARGS = [
+ {
+ "type": "field_dropdown",
+ "name": "ALIGN",
+ "options": [['left', 'LEFT'], ['right', 'RIGHT'], ['centre', 'CENTRE']],
+ },
+ {
+ "type": "input_statement",
+ "name": "FIELDS",
+ "check": "Field"
+ }
+];
+
+var TYPE_MESSAGE = 'type %1';
+var TYPE_ARGS = [
+ {
+ "type": "input_value",
+ "name": "TYPE",
+ "check": "Type",
+ "align": "RIGHT"
+ }
+];
+
+Blockly.Blocks['input_value'] = {
+ // Value input.
+ init: function() {
+ this.jsonInit({
+ "message0": "value input %1 %2",
+ "args0": [
+ {
+ "type": "field_input",
+ "name": "INPUTNAME",
+ "text": "NAME"
+ },
+ {
+ "type": "input_dummy"
+ }
+ ],
+ "message1": FIELD_MESSAGE,
+ "args1": FIELD_ARGS,
+ "message2": TYPE_MESSAGE,
+ "args2": TYPE_ARGS,
+ "previousStatement": "Input",
+ "nextStatement": "Input",
+ "colour": 210,
+ "tooltip": "A value socket for horizontal connections.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=71"
+ });
+ },
+ onchange: function() {
+ inputNameCheck(this);
+ }
+};
+
+Blockly.Blocks['input_statement'] = {
+ // Statement input.
+ init: function() {
+ this.jsonInit({
+ "message0": "statement input %1 %2",
+ "args0": [
+ {
+ "type": "field_input",
+ "name": "INPUTNAME",
+ "text": "NAME"
+ },
+ {
+ "type": "input_dummy"
+ },
+ ],
+ "message1": FIELD_MESSAGE,
+ "args1": FIELD_ARGS,
+ "message2": TYPE_MESSAGE,
+ "args2": TYPE_ARGS,
+ "previousStatement": "Input",
+ "nextStatement": "Input",
+ "colour": 210,
+ "tooltip": "A statement socket for enclosed vertical stacks.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=246"
+ });
+ },
+ onchange: function() {
+ inputNameCheck(this);
+ }
+};
+
+Blockly.Blocks['input_dummy'] = {
+ // Dummy input.
+ init: function() {
+ this.jsonInit({
+ "message0": "dummy input",
+ "message1": FIELD_MESSAGE,
+ "args1": FIELD_ARGS,
+ "previousStatement": "Input",
+ "nextStatement": "Input",
+ "colour": 210,
+ "tooltip": "For adding fields on a separate row with no " +
+ "connections. Alignment options (left, right, centre) " +
+ "apply only to multi-line fields.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=293"
+ });
+ }
+};
+
+Blockly.Blocks['field_static'] = {
+ // Text value.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('text')
+ .appendField(new Blockly.FieldTextInput(''), 'TEXT');
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setTooltip('Static text that serves as a label.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=88');
+ }
+};
+
+Blockly.Blocks['field_input'] = {
+ // Text input.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('text input')
+ .appendField(new Blockly.FieldTextInput('default'), 'TEXT')
+ .appendField(',')
+ .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setTooltip('An input field for the user to enter text.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=319');
+ },
+ onchange: function() {
+ fieldNameCheck(this);
+ }
+};
+
+Blockly.Blocks['field_number'] = {
+ // Numeric input.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('numeric input')
+ .appendField(new Blockly.FieldNumber(0), 'VALUE')
+ .appendField(',')
+ .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
+ this.appendDummyInput()
+ .appendField('min')
+ .appendField(new Blockly.FieldNumber(-Infinity), 'MIN')
+ .appendField('max')
+ .appendField(new Blockly.FieldNumber(Infinity), 'MAX')
+ .appendField('precision')
+ .appendField(new Blockly.FieldNumber(0, 0), 'PRECISION');
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setTooltip('An input field for the user to enter a number.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=319');
+ },
+ onchange: function() {
+ fieldNameCheck(this);
+ }
+};
+
+Blockly.Blocks['field_angle'] = {
+ // Angle input.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('angle input')
+ .appendField(new Blockly.FieldAngle('90'), 'ANGLE')
+ .appendField(',')
+ .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setTooltip('An input field for the user to enter an angle.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=372');
+ },
+ onchange: function() {
+ fieldNameCheck(this);
+ }
+};
+
+Blockly.Blocks['field_dropdown'] = {
+ // Dropdown menu.
+ init: function() {
+ this.appendDummyInput()
+ .appendField('dropdown')
+ .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
+ this.optionCount_ = 3;
+ this.updateShape_();
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setMutator(new Blockly.Mutator(['field_dropdown_option']));
+ this.setColour(160);
+ this.setTooltip('Dropdown menu with a list of options.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
+ },
+ mutationToDom: function(workspace) {
+ // Create XML to represent menu options.
+ var container = document.createElement('mutation');
+ container.setAttribute('options', this.optionCount_);
+ return container;
+ },
+ domToMutation: function(container) {
+ // Parse XML to restore the menu options.
+ this.optionCount_ = parseInt(container.getAttribute('options'), 10);
+ this.updateShape_();
+ },
+ decompose: function(workspace) {
+ // Populate the mutator's dialog with this block's components.
+ var containerBlock = workspace.newBlock('field_dropdown_container');
+ containerBlock.initSvg();
+ var connection = containerBlock.getInput('STACK').connection;
+ for (var i = 0; i < this.optionCount_; i++) {
+ var optionBlock = workspace.newBlock('field_dropdown_option');
+ optionBlock.initSvg();
+ connection.connect(optionBlock.previousConnection);
+ connection = optionBlock.nextConnection;
+ }
+ return containerBlock;
+ },
+ compose: function(containerBlock) {
+ // Reconfigure this block based on the mutator dialog's components.
+ var optionBlock = containerBlock.getInputTargetBlock('STACK');
+ // Count number of inputs.
+ var data = [];
+ while (optionBlock) {
+ data.push([optionBlock.userData_, optionBlock.cpuData_]);
+ optionBlock = optionBlock.nextConnection &&
+ optionBlock.nextConnection.targetBlock();
+ }
+ this.optionCount_ = data.length;
+ this.updateShape_();
+ // Restore any data.
+ for (var i = 0; i < this.optionCount_; i++) {
+ this.setFieldValue(data[i][0] || 'option', 'USER' + i);
+ this.setFieldValue(data[i][1] || 'OPTIONNAME', 'CPU' + i);
+ }
+ },
+ saveConnections: function(containerBlock) {
+ // Store names and values for each option.
+ var optionBlock = containerBlock.getInputTargetBlock('STACK');
+ var i = 0;
+ while (optionBlock) {
+ optionBlock.userData_ = this.getFieldValue('USER' + i);
+ optionBlock.cpuData_ = this.getFieldValue('CPU' + i);
+ i++;
+ optionBlock = optionBlock.nextConnection &&
+ optionBlock.nextConnection.targetBlock();
+ }
+ },
+ updateShape_: function() {
+ // Modify this block to have the correct number of options.
+ // Add new options.
+ for (var i = 0; i < this.optionCount_; i++) {
+ if (!this.getInput('OPTION' + i)) {
+ this.appendDummyInput('OPTION' + i)
+ .appendField(new Blockly.FieldTextInput('option'), 'USER' + i)
+ .appendField(',')
+ .appendField(new Blockly.FieldTextInput('OPTIONNAME'), 'CPU' + i);
+ }
+ }
+ // Remove deleted options.
+ while (this.getInput('OPTION' + i)) {
+ this.removeInput('OPTION' + i);
+ i++;
+ }
+ },
+ onchange: function() {
+ if (this.workspace && this.optionCount_ < 1) {
+ this.setWarningText('Drop down menu must\nhave at least one option.');
+ } else {
+ fieldNameCheck(this);
+ }
+ }
+};
+
+Blockly.Blocks['field_dropdown_container'] = {
+ // Container.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('add options');
+ this.appendStatementInput('STACK');
+ this.setTooltip('Add, remove, or reorder options\n' +
+ 'to reconfigure this dropdown menu.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
+ this.contextMenu = false;
+ }
+};
+
+Blockly.Blocks['field_dropdown_option'] = {
+ // Add option.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('option');
+ this.setPreviousStatement(true);
+ this.setNextStatement(true);
+ this.setTooltip('Add a new option to the dropdown menu.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=386');
+ this.contextMenu = false;
+ }
+};
+
+Blockly.Blocks['field_checkbox'] = {
+ // Checkbox.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('checkbox')
+ .appendField(new Blockly.FieldCheckbox('TRUE'), 'CHECKED')
+ .appendField(',')
+ .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setTooltip('Checkbox field.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=485');
+ },
+ onchange: function() {
+ fieldNameCheck(this);
+ }
+};
+
+Blockly.Blocks['field_colour'] = {
+ // Colour input.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('colour')
+ .appendField(new Blockly.FieldColour('#ff0000'), 'COLOUR')
+ .appendField(',')
+ .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setTooltip('Colour input field.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=495');
+ },
+ onchange: function() {
+ fieldNameCheck(this);
+ }
+};
+
+Blockly.Blocks['field_date'] = {
+ // Date input.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('date')
+ .appendField(new Blockly.FieldDate(), 'DATE')
+ .appendField(',')
+ .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setTooltip('Date input field.');
+ },
+ onchange: function() {
+ fieldNameCheck(this);
+ }
+};
+
+Blockly.Blocks['field_variable'] = {
+ // Dropdown for variables.
+ init: function() {
+ this.setColour(160);
+ this.appendDummyInput()
+ .appendField('variable')
+ .appendField(new Blockly.FieldTextInput('item'), 'TEXT')
+ .appendField(',')
+ .appendField(new Blockly.FieldTextInput('NAME'), 'FIELDNAME');
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setTooltip('Dropdown menu for variable names.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=510');
+ },
+ onchange: function() {
+ fieldNameCheck(this);
+ }
+};
+
+Blockly.Blocks['field_image'] = {
+ // Image.
+ init: function() {
+ this.setColour(160);
+ var src = 'https://www.gstatic.com/codesite/ph/images/star_on.gif';
+ this.appendDummyInput()
+ .appendField('image')
+ .appendField(new Blockly.FieldTextInput(src), 'SRC');
+ this.appendDummyInput()
+ .appendField('width')
+ .appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'WIDTH')
+ .appendField('height')
+ .appendField(new Blockly.FieldNumber('15', 0, NaN, 1), 'HEIGHT')
+ .appendField('alt text')
+ .appendField(new Blockly.FieldTextInput('*'), 'ALT');
+ this.setPreviousStatement(true, 'Field');
+ this.setNextStatement(true, 'Field');
+ this.setTooltip('Static image (JPEG, PNG, GIF, SVG, BMP).\n' +
+ 'Retains aspect ratio regardless of height and width.\n' +
+ 'Alt text is for when collapsed.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=567');
+ }
+};
+
+Blockly.Blocks['type_group'] = {
+ // Group of types.
+ init: function() {
+ this.typeCount_ = 2;
+ this.updateShape_();
+ this.setOutput(true, 'Type');
+ this.setMutator(new Blockly.Mutator(['type_group_item']));
+ this.setColour(230);
+ this.setTooltip('Allows more than one type to be accepted.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677');
+ },
+ mutationToDom: function(workspace) {
+ // Create XML to represent a group of types.
+ var container = document.createElement('mutation');
+ container.setAttribute('types', this.typeCount_);
+ return container;
+ },
+ domToMutation: function(container) {
+ // Parse XML to restore the group of types.
+ this.typeCount_ = parseInt(container.getAttribute('types'), 10);
+ this.updateShape_();
+ for (var i = 0; i < this.typeCount_; i++) {
+ this.removeInput('TYPE' + i);
+ }
+ for (var i = 0; i < this.typeCount_; i++) {
+ var input = this.appendValueInput('TYPE' + i)
+ .setCheck('Type');
+ if (i == 0) {
+ input.appendField('any of');
+ }
+ }
+ },
+ decompose: function(workspace) {
+ // Populate the mutator's dialog with this block's components.
+ var containerBlock = workspace.newBlock('type_group_container');
+ containerBlock.initSvg();
+ var connection = containerBlock.getInput('STACK').connection;
+ for (var i = 0; i < this.typeCount_; i++) {
+ var typeBlock = workspace.newBlock('type_group_item');
+ typeBlock.initSvg();
+ connection.connect(typeBlock.previousConnection);
+ connection = typeBlock.nextConnection;
+ }
+ return containerBlock;
+ },
+ compose: function(containerBlock) {
+ // Reconfigure this block based on the mutator dialog's components.
+ var typeBlock = containerBlock.getInputTargetBlock('STACK');
+ // Count number of inputs.
+ var connections = [];
+ while (typeBlock) {
+ connections.push(typeBlock.valueConnection_);
+ typeBlock = typeBlock.nextConnection &&
+ typeBlock.nextConnection.targetBlock();
+ }
+ // Disconnect any children that don't belong.
+ for (var i = 0; i < this.typeCount_; i++) {
+ var connection = this.getInput('TYPE' + i).connection.targetConnection;
+ if (connection && connections.indexOf(connection) == -1) {
+ connection.disconnect();
+ }
+ }
+ this.typeCount_ = connections.length;
+ this.updateShape_();
+ // Reconnect any child blocks.
+ for (var i = 0; i < this.typeCount_; i++) {
+ Blockly.Mutator.reconnect(connections[i], this, 'TYPE' + i);
+ }
+ },
+ saveConnections: function(containerBlock) {
+ // Store a pointer to any connected child blocks.
+ var typeBlock = containerBlock.getInputTargetBlock('STACK');
+ var i = 0;
+ while (typeBlock) {
+ var input = this.getInput('TYPE' + i);
+ typeBlock.valueConnection_ = input && input.connection.targetConnection;
+ i++;
+ typeBlock = typeBlock.nextConnection &&
+ typeBlock.nextConnection.targetBlock();
+ }
+ },
+ updateShape_: function() {
+ // Modify this block to have the correct number of inputs.
+ // Add new inputs.
+ for (var i = 0; i < this.typeCount_; i++) {
+ if (!this.getInput('TYPE' + i)) {
+ var input = this.appendValueInput('TYPE' + i);
+ if (i == 0) {
+ input.appendField('any of');
+ }
+ }
+ }
+ // Remove deleted inputs.
+ while (this.getInput('TYPE' + i)) {
+ this.removeInput('TYPE' + i);
+ i++;
+ }
+ }
+};
+
+Blockly.Blocks['type_group_container'] = {
+ // Container.
+ init: function() {
+ this.jsonInit({
+ "message0": "add types %1 %2",
+ "args0": [
+ {"type": "input_dummy"},
+ {"type": "input_statement", "name": "STACK"}
+ ],
+ "colour": 230,
+ "tooltip": "Add, or remove allowed type.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677"
+ });
+ }
+};
+
+Blockly.Blocks['type_group_item'] = {
+ // Add type.
+ init: function() {
+ this.jsonInit({
+ "message0": "type",
+ "previousStatement": null,
+ "nextStatement": null,
+ "colour": 230,
+ "tooltip": "Add a new allowed type.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=677"
+ });
+ }
+};
+
+Blockly.Blocks['type_null'] = {
+ // Null type.
+ valueType: null,
+ init: function() {
+ this.jsonInit({
+ "message0": "any",
+ "output": "Type",
+ "colour": 230,
+ "tooltip": "Any type is allowed.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
+ });
+ }
+};
+
+Blockly.Blocks['type_boolean'] = {
+ // Boolean type.
+ valueType: 'Boolean',
+ init: function() {
+ this.jsonInit({
+ "message0": "Boolean",
+ "output": "Type",
+ "colour": 230,
+ "tooltip": "Booleans (true/false) are allowed.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
+ });
+ }
+};
+
+Blockly.Blocks['type_number'] = {
+ // Number type.
+ valueType: 'Number',
+ init: function() {
+ this.jsonInit({
+ "message0": "Number",
+ "output": "Type",
+ "colour": 230,
+ "tooltip": "Numbers (int/float) are allowed.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
+ });
+ }
+};
+
+Blockly.Blocks['type_string'] = {
+ // String type.
+ valueType: 'String',
+ init: function() {
+ this.jsonInit({
+ "message0": "String",
+ "output": "Type",
+ "colour": 230,
+ "tooltip": "Strings (text) are allowed.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
+ });
+ }
+};
+
+Blockly.Blocks['type_list'] = {
+ // List type.
+ valueType: 'Array',
+ init: function() {
+ this.jsonInit({
+ "message0": "Array",
+ "output": "Type",
+ "colour": 230,
+ "tooltip": "Arrays (lists) are allowed.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=602"
+ });
+ }
+};
+
+Blockly.Blocks['type_other'] = {
+ // Other type.
+ init: function() {
+ this.jsonInit({
+ "message0": "other %1",
+ "args0": [{"type": "field_input", "name": "TYPE", "text": ""}],
+ "output": "Type",
+ "colour": 230,
+ "tooltip": "Custom type to allow.",
+ "helpUrl": "https://www.youtube.com/watch?v=s2_xaEvcVI0#t=702"
+ });
+ }
+};
+
+Blockly.Blocks['colour_hue'] = {
+ // Set the colour of the block.
+ init: function() {
+ this.appendDummyInput()
+ .appendField('hue:')
+ .appendField(new Blockly.FieldAngle('0', this.validator), 'HUE');
+ this.setOutput(true, 'Colour');
+ this.setTooltip('Paint the block with this colour.');
+ this.setHelpUrl('https://www.youtube.com/watch?v=s2_xaEvcVI0#t=55');
+ },
+ validator: function(text) {
+ // Update the current block's colour to match.
+ var hue = parseInt(text, 10);
+ if (!isNaN(hue)) {
+ this.sourceBlock_.setColour(hue);
+ }
+ },
+ mutationToDom: function(workspace) {
+ var container = document.createElement('mutation');
+ container.setAttribute('colour', this.getColour());
+ return container;
+ },
+ domToMutation: function(container) {
+ this.setColour(container.getAttribute('colour'));
+ }
+};
+
+/**
+ * Check to see if more than one field has this name.
+ * Highly inefficient (On^2), but n is small.
+ * @param {!Blockly.Block} referenceBlock Block to check.
+ */
+function fieldNameCheck(referenceBlock) {
+ if (!referenceBlock.workspace) {
+ // Block has been deleted.
+ return;
+ }
+ var name = referenceBlock.getFieldValue('FIELDNAME').toLowerCase();
+ var count = 0;
+ var blocks = referenceBlock.workspace.getAllBlocks();
+ for (var i = 0, block; block = blocks[i]; i++) {
+ var otherName = block.getFieldValue('FIELDNAME');
+ if (!block.disabled && !block.getInheritedDisabled() &&
+ otherName && otherName.toLowerCase() == name) {
+ count++;
+ }
+ }
+ var msg = (count > 1) ?
+ 'There are ' + count + ' field blocks\n with this name.' : null;
+ referenceBlock.setWarningText(msg);
+}
+
+/**
+ * Check to see if more than one input has this name.
+ * Highly inefficient (On^2), but n is small.
+ * @param {!Blockly.Block} referenceBlock Block to check.
+ */
+function inputNameCheck(referenceBlock) {
+ if (!referenceBlock.workspace) {
+ // Block has been deleted.
+ return;
+ }
+ var name = referenceBlock.getFieldValue('INPUTNAME').toLowerCase();
+ var count = 0;
+ var blocks = referenceBlock.workspace.getAllBlocks();
+ for (var i = 0, block; block = blocks[i]; i++) {
+ var otherName = block.getFieldValue('INPUTNAME');
+ if (!block.disabled && !block.getInheritedDisabled() &&
+ otherName && otherName.toLowerCase() == name) {
+ count++;
+ }
+ }
+ var msg = (count > 1) ?
+ 'There are ' + count + ' input blocks\n with this name.' : null;
+ referenceBlock.setWarningText(msg);
+}