Initial commit
This commit is contained in:
134
node_modules/node-blockly/blockly/blocks/colour.js
generated
vendored
Normal file
134
node_modules/node-blockly/blockly/blocks/colour.js
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* 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 Colour blocks for Blockly.
|
||||
*
|
||||
* This file is scraped to extract a .json file of block definitions. The array
|
||||
* passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes
|
||||
* only, no outside references, no functions, no trailing commas, etc. The one
|
||||
* exception is end-of-line comments, which the scraper will remove.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.colour'); // Deprecated
|
||||
goog.provide('Blockly.Constants.Colour');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly');
|
||||
|
||||
|
||||
/**
|
||||
* Unused constant for the common HSV hue for all blocks in this category.
|
||||
* @deprecated Use Blockly.Msg.COLOUR_HUE. (2018 April 5)
|
||||
*/
|
||||
Blockly.Constants.Colour.HUE = 20;
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
// Block for colour picker.
|
||||
{
|
||||
"type": "colour_picker",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_colour",
|
||||
"name": "COLOUR",
|
||||
"colour": "#ff0000"
|
||||
}
|
||||
],
|
||||
"output": "Colour",
|
||||
"colour": "%{BKY_COLOUR_HUE}",
|
||||
"helpUrl": "%{BKY_COLOUR_PICKER_HELPURL}",
|
||||
"tooltip": "%{BKY_COLOUR_PICKER_TOOLTIP}",
|
||||
"extensions": ["parent_tooltip_when_inline"]
|
||||
},
|
||||
|
||||
// Block for random colour.
|
||||
{
|
||||
"type": "colour_random",
|
||||
"message0": "%{BKY_COLOUR_RANDOM_TITLE}",
|
||||
"output": "Colour",
|
||||
"colour": "%{BKY_COLOUR_HUE}",
|
||||
"helpUrl": "%{BKY_COLOUR_RANDOM_HELPURL}",
|
||||
"tooltip": "%{BKY_COLOUR_RANDOM_TOOLTIP}"
|
||||
},
|
||||
|
||||
// Block for composing a colour from RGB components.
|
||||
{
|
||||
"type": "colour_rgb",
|
||||
"message0": "%{BKY_COLOUR_RGB_TITLE} %{BKY_COLOUR_RGB_RED} %1 %{BKY_COLOUR_RGB_GREEN} %2 %{BKY_COLOUR_RGB_BLUE} %3",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "RED",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "GREEN",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "BLUE",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
}
|
||||
],
|
||||
"output": "Colour",
|
||||
"colour": "%{BKY_COLOUR_HUE}",
|
||||
"helpUrl": "%{BKY_COLOUR_RGB_HELPURL}",
|
||||
"tooltip": "%{BKY_COLOUR_RGB_TOOLTIP}"
|
||||
},
|
||||
|
||||
// Block for blending two colours together.
|
||||
{
|
||||
"type": "colour_blend",
|
||||
"message0": "%{BKY_COLOUR_BLEND_TITLE} %{BKY_COLOUR_BLEND_COLOUR1} " +
|
||||
"%1 %{BKY_COLOUR_BLEND_COLOUR2} %2 %{BKY_COLOUR_BLEND_RATIO} %3",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "COLOUR1",
|
||||
"check": "Colour",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "COLOUR2",
|
||||
"check": "Colour",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "RATIO",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
}
|
||||
],
|
||||
"output": "Colour",
|
||||
"colour": "%{BKY_COLOUR_HUE}",
|
||||
"helpUrl": "%{BKY_COLOUR_BLEND_HELPURL}",
|
||||
"tooltip": "%{BKY_COLOUR_BLEND_TOOLTIP}"
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
858
node_modules/node-blockly/blockly/blocks/lists.js
generated
vendored
Normal file
858
node_modules/node-blockly/blockly/blocks/lists.js
generated
vendored
Normal file
@@ -0,0 +1,858 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* 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 List blocks for Blockly.
|
||||
*
|
||||
* This file is scraped to extract a .json file of block definitions. The array
|
||||
* passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes
|
||||
* only, no outside references, no functions, no trailing commas, etc. The one
|
||||
* exception is end-of-line comments, which the scraper will remove.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.lists'); // Deprecated
|
||||
goog.provide('Blockly.Constants.Lists');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly');
|
||||
|
||||
/**
|
||||
* Unused constant for the common HSV hue for all blocks in this category.
|
||||
* @deprecated Use Blockly.Msg.LISTS_HUE. (2018 April 5)
|
||||
*/
|
||||
Blockly.Constants.Lists.HUE = 260;
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
// Block for creating an empty list
|
||||
// The 'list_create_with' block is preferred as it is more flexible.
|
||||
// <block type="lists_create_with">
|
||||
// <mutation items="0"></mutation>
|
||||
// </block>
|
||||
{
|
||||
"type": "lists_create_empty",
|
||||
"message0": "%{BKY_LISTS_CREATE_EMPTY_TITLE}",
|
||||
"output": "Array",
|
||||
"colour": "%{BKY_LISTS_HUE}",
|
||||
"tooltip": "%{BKY_LISTS_CREATE_EMPTY_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LISTS_CREATE_EMPTY_HELPURL}"
|
||||
},
|
||||
// Block for creating a list with one element repeated.
|
||||
{
|
||||
"type": "lists_repeat",
|
||||
"message0": "%{BKY_LISTS_REPEAT_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "ITEM"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "NUM",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"output": "Array",
|
||||
"colour": "%{BKY_LISTS_HUE}",
|
||||
"tooltip": "%{BKY_LISTS_REPEAT_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LISTS_REPEAT_HELPURL}"
|
||||
},
|
||||
// Block for reversing a list.
|
||||
{
|
||||
"type": "lists_reverse",
|
||||
"message0": "%{BKY_LISTS_REVERSE_MESSAGE0}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "LIST",
|
||||
"check": "Array"
|
||||
}
|
||||
],
|
||||
"output": "Array",
|
||||
"inputsInline": true,
|
||||
"colour": "%{BKY_LISTS_HUE}",
|
||||
"tooltip": "%{BKY_LISTS_REVERSE_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LISTS_REVERSE_HELPURL}"
|
||||
},
|
||||
// Block for checking if a list is empty
|
||||
{
|
||||
"type": "lists_isEmpty",
|
||||
"message0": "%{BKY_LISTS_ISEMPTY_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE",
|
||||
"check": ["String", "Array"]
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": "%{BKY_LISTS_HUE}",
|
||||
"tooltip": "%{BKY_LISTS_ISEMPTY_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LISTS_ISEMPTY_HELPURL}"
|
||||
},
|
||||
// Block for getting the list length
|
||||
{
|
||||
"type": "lists_length",
|
||||
"message0": "%{BKY_LISTS_LENGTH_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE",
|
||||
"check": ["String", "Array"]
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_LISTS_HUE}",
|
||||
"tooltip": "%{BKY_LISTS_LENGTH_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LISTS_LENGTH_HELPURL}"
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
|
||||
Blockly.Blocks['lists_create_with'] = {
|
||||
/**
|
||||
* Block for creating a list with any number of elements of any type.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_CREATE_WITH_HELPURL);
|
||||
this.setColour(Blockly.Msg.LISTS_HUE);
|
||||
this.itemCount_ = 3;
|
||||
this.updateShape_();
|
||||
this.setOutput(true, 'Array');
|
||||
this.setMutator(new Blockly.Mutator(['lists_create_with_item']));
|
||||
this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_TOOLTIP);
|
||||
},
|
||||
/**
|
||||
* Create XML to represent list inputs.
|
||||
* @return {!Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('items', this.itemCount_);
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the list inputs.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
|
||||
this.updateShape_();
|
||||
},
|
||||
/**
|
||||
* Populate the mutator's dialog with this block's components.
|
||||
* @param {!Blockly.Workspace} workspace Mutator's workspace.
|
||||
* @return {!Blockly.Block} Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
decompose: function(workspace) {
|
||||
var containerBlock = workspace.newBlock('lists_create_with_container');
|
||||
containerBlock.initSvg();
|
||||
var connection = containerBlock.getInput('STACK').connection;
|
||||
for (var i = 0; i < this.itemCount_; i++) {
|
||||
var itemBlock = workspace.newBlock('lists_create_with_item');
|
||||
itemBlock.initSvg();
|
||||
connection.connect(itemBlock.previousConnection);
|
||||
connection = itemBlock.nextConnection;
|
||||
}
|
||||
return containerBlock;
|
||||
},
|
||||
/**
|
||||
* Reconfigure this block based on the mutator dialog's components.
|
||||
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
compose: function(containerBlock) {
|
||||
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
// Count number of inputs.
|
||||
var connections = [];
|
||||
while (itemBlock) {
|
||||
connections.push(itemBlock.valueConnection_);
|
||||
itemBlock = itemBlock.nextConnection &&
|
||||
itemBlock.nextConnection.targetBlock();
|
||||
}
|
||||
// Disconnect any children that don't belong.
|
||||
for (var i = 0; i < this.itemCount_; i++) {
|
||||
var connection = this.getInput('ADD' + i).connection.targetConnection;
|
||||
if (connection && connections.indexOf(connection) == -1) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
this.itemCount_ = connections.length;
|
||||
this.updateShape_();
|
||||
// Reconnect any child blocks.
|
||||
for (var i = 0; i < this.itemCount_; i++) {
|
||||
Blockly.Mutator.reconnect(connections[i], this, 'ADD' + i);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Store pointers to any connected child blocks.
|
||||
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
saveConnections: function(containerBlock) {
|
||||
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
var i = 0;
|
||||
while (itemBlock) {
|
||||
var input = this.getInput('ADD' + i);
|
||||
itemBlock.valueConnection_ = input && input.connection.targetConnection;
|
||||
i++;
|
||||
itemBlock = itemBlock.nextConnection &&
|
||||
itemBlock.nextConnection.targetBlock();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Modify this block to have the correct number of inputs.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateShape_: function() {
|
||||
if (this.itemCount_ && this.getInput('EMPTY')) {
|
||||
this.removeInput('EMPTY');
|
||||
} else if (!this.itemCount_ && !this.getInput('EMPTY')) {
|
||||
this.appendDummyInput('EMPTY')
|
||||
.appendField(Blockly.Msg.LISTS_CREATE_EMPTY_TITLE);
|
||||
}
|
||||
// Add new inputs.
|
||||
for (var i = 0; i < this.itemCount_; i++) {
|
||||
if (!this.getInput('ADD' + i)) {
|
||||
var input = this.appendValueInput('ADD' + i);
|
||||
if (i == 0) {
|
||||
input.appendField(Blockly.Msg.LISTS_CREATE_WITH_INPUT_WITH);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove deleted inputs.
|
||||
while (this.getInput('ADD' + i)) {
|
||||
this.removeInput('ADD' + i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_create_with_container'] = {
|
||||
/**
|
||||
* Mutator block for list container.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.setColour(Blockly.Msg.LISTS_HUE);
|
||||
this.appendDummyInput()
|
||||
.appendField(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD);
|
||||
this.appendStatementInput('STACK');
|
||||
this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_CONTAINER_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_create_with_item'] = {
|
||||
/**
|
||||
* Mutator block for adding items.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.setColour(Blockly.Msg.LISTS_HUE);
|
||||
this.appendDummyInput()
|
||||
.appendField(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TITLE);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.LISTS_CREATE_WITH_ITEM_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_indexOf'] = {
|
||||
/**
|
||||
* Block for finding an item in the list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
var OPERATORS =
|
||||
[
|
||||
[Blockly.Msg.LISTS_INDEX_OF_FIRST, 'FIRST'],
|
||||
[Blockly.Msg.LISTS_INDEX_OF_LAST, 'LAST']
|
||||
];
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_INDEX_OF_HELPURL);
|
||||
this.setColour(Blockly.Msg.LISTS_HUE);
|
||||
this.setOutput(true, 'Number');
|
||||
this.appendValueInput('VALUE')
|
||||
.setCheck('Array')
|
||||
.appendField(Blockly.Msg.LISTS_INDEX_OF_INPUT_IN_LIST);
|
||||
this.appendValueInput('FIND')
|
||||
.appendField(new Blockly.FieldDropdown(OPERATORS), 'END');
|
||||
this.setInputsInline(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
return Blockly.Msg.LISTS_INDEX_OF_TOOLTIP.replace('%1',
|
||||
thisBlock.workspace.options.oneBasedIndex ? '0' : '-1');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_getIndex'] = {
|
||||
/**
|
||||
* Block for getting element at index.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
var MODE =
|
||||
[
|
||||
[Blockly.Msg.LISTS_GET_INDEX_GET, 'GET'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_GET_REMOVE, 'GET_REMOVE'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_REMOVE, 'REMOVE']
|
||||
];
|
||||
this.WHERE_OPTIONS =
|
||||
[
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FIRST, 'FIRST'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_LAST, 'LAST'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_RANDOM, 'RANDOM']
|
||||
];
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_GET_INDEX_HELPURL);
|
||||
this.setColour(Blockly.Msg.LISTS_HUE);
|
||||
var modeMenu = new Blockly.FieldDropdown(MODE, function(value) {
|
||||
var isStatement = (value == 'REMOVE');
|
||||
this.sourceBlock_.updateStatement_(isStatement);
|
||||
});
|
||||
this.appendValueInput('VALUE')
|
||||
.setCheck('Array')
|
||||
.appendField(Blockly.Msg.LISTS_GET_INDEX_INPUT_IN_LIST);
|
||||
this.appendDummyInput()
|
||||
.appendField(modeMenu, 'MODE')
|
||||
.appendField('', 'SPACE');
|
||||
this.appendDummyInput('AT');
|
||||
if (Blockly.Msg.LISTS_GET_INDEX_TAIL) {
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendField(Blockly.Msg.LISTS_GET_INDEX_TAIL);
|
||||
}
|
||||
this.setInputsInline(true);
|
||||
this.setOutput(true);
|
||||
this.updateAt_(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var mode = thisBlock.getFieldValue('MODE');
|
||||
var where = thisBlock.getFieldValue('WHERE');
|
||||
var tooltip = '';
|
||||
switch (mode + ' ' + where) {
|
||||
case 'GET FROM_START':
|
||||
case 'GET FROM_END':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FROM;
|
||||
break;
|
||||
case 'GET FIRST':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_FIRST;
|
||||
break;
|
||||
case 'GET LAST':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_LAST;
|
||||
break;
|
||||
case 'GET RANDOM':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_RANDOM;
|
||||
break;
|
||||
case 'GET_REMOVE FROM_START':
|
||||
case 'GET_REMOVE FROM_END':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FROM;
|
||||
break;
|
||||
case 'GET_REMOVE FIRST':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_FIRST;
|
||||
break;
|
||||
case 'GET_REMOVE LAST':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_LAST;
|
||||
break;
|
||||
case 'GET_REMOVE RANDOM':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_GET_REMOVE_RANDOM;
|
||||
break;
|
||||
case 'REMOVE FROM_START':
|
||||
case 'REMOVE FROM_END':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FROM;
|
||||
break;
|
||||
case 'REMOVE FIRST':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_FIRST;
|
||||
break;
|
||||
case 'REMOVE LAST':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_LAST;
|
||||
break;
|
||||
case 'REMOVE RANDOM':
|
||||
tooltip = Blockly.Msg.LISTS_GET_INDEX_TOOLTIP_REMOVE_RANDOM;
|
||||
break;
|
||||
}
|
||||
if (where == 'FROM_START' || where == 'FROM_END') {
|
||||
var msg = (where == 'FROM_START') ?
|
||||
Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP :
|
||||
Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP;
|
||||
tooltip += ' ' + msg.replace('%1',
|
||||
thisBlock.workspace.options.oneBasedIndex ? '#1' : '#0');
|
||||
}
|
||||
return tooltip;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Create XML to represent whether the block is a statement or a value.
|
||||
* Also represent whether there is an 'AT' input.
|
||||
* @return {Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
var isStatement = !this.outputConnection;
|
||||
container.setAttribute('statement', isStatement);
|
||||
var isAt = this.getInput('AT').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at', isAt);
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the 'AT' input.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
// Note: Until January 2013 this block did not have mutations,
|
||||
// so 'statement' defaults to false and 'at' defaults to true.
|
||||
var isStatement = (xmlElement.getAttribute('statement') == 'true');
|
||||
this.updateStatement_(isStatement);
|
||||
var isAt = (xmlElement.getAttribute('at') != 'false');
|
||||
this.updateAt_(isAt);
|
||||
},
|
||||
/**
|
||||
* Switch between a value block and a statement block.
|
||||
* @param {boolean} newStatement True if the block should be a statement.
|
||||
* False if the block should be a value.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateStatement_: function(newStatement) {
|
||||
var oldStatement = !this.outputConnection;
|
||||
if (newStatement != oldStatement) {
|
||||
this.unplug(true, true);
|
||||
if (newStatement) {
|
||||
this.setOutput(false);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
} else {
|
||||
this.setPreviousStatement(false);
|
||||
this.setNextStatement(false);
|
||||
this.setOutput(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Create or delete an input for the numeric index.
|
||||
* @param {boolean} isAt True if the input should exist.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateAt_: function(isAt) {
|
||||
// Destroy old 'AT' and 'ORDINAL' inputs.
|
||||
this.removeInput('AT');
|
||||
this.removeInput('ORDINAL', true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT').setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL')
|
||||
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
} else {
|
||||
this.appendDummyInput('AT');
|
||||
}
|
||||
var menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
// The 'isAt' variable is available due to this function being a closure.
|
||||
if (newAt != isAt) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt_(newAt);
|
||||
// This menu has been destroyed and replaced. Update the replacement.
|
||||
block.setFieldValue(value, 'WHERE');
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.getInput('AT').appendField(menu, 'WHERE');
|
||||
if (Blockly.Msg.LISTS_GET_INDEX_TAIL) {
|
||||
this.moveInputBefore('TAIL', null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_setIndex'] = {
|
||||
/**
|
||||
* Block for setting the element at index.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
var MODE =
|
||||
[
|
||||
[Blockly.Msg.LISTS_SET_INDEX_SET, 'SET'],
|
||||
[Blockly.Msg.LISTS_SET_INDEX_INSERT, 'INSERT']
|
||||
];
|
||||
this.WHERE_OPTIONS =
|
||||
[
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_FIRST, 'FIRST'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_LAST, 'LAST'],
|
||||
[Blockly.Msg.LISTS_GET_INDEX_RANDOM, 'RANDOM']
|
||||
];
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_SET_INDEX_HELPURL);
|
||||
this.setColour(Blockly.Msg.LISTS_HUE);
|
||||
this.appendValueInput('LIST')
|
||||
.setCheck('Array')
|
||||
.appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_IN_LIST);
|
||||
this.appendDummyInput()
|
||||
.appendField(new Blockly.FieldDropdown(MODE), 'MODE')
|
||||
.appendField('', 'SPACE');
|
||||
this.appendDummyInput('AT');
|
||||
this.appendValueInput('TO')
|
||||
.appendField(Blockly.Msg.LISTS_SET_INDEX_INPUT_TO);
|
||||
this.setInputsInline(true);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setTooltip(Blockly.Msg.LISTS_SET_INDEX_TOOLTIP);
|
||||
this.updateAt_(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var mode = thisBlock.getFieldValue('MODE');
|
||||
var where = thisBlock.getFieldValue('WHERE');
|
||||
var tooltip = '';
|
||||
switch (mode + ' ' + where) {
|
||||
case 'SET FROM_START':
|
||||
case 'SET FROM_END':
|
||||
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FROM;
|
||||
break;
|
||||
case 'SET FIRST':
|
||||
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_FIRST;
|
||||
break;
|
||||
case 'SET LAST':
|
||||
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_LAST;
|
||||
break;
|
||||
case 'SET RANDOM':
|
||||
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_SET_RANDOM;
|
||||
break;
|
||||
case 'INSERT FROM_START':
|
||||
case 'INSERT FROM_END':
|
||||
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FROM;
|
||||
break;
|
||||
case 'INSERT FIRST':
|
||||
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_FIRST;
|
||||
break;
|
||||
case 'INSERT LAST':
|
||||
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_LAST;
|
||||
break;
|
||||
case 'INSERT RANDOM':
|
||||
tooltip = Blockly.Msg.LISTS_SET_INDEX_TOOLTIP_INSERT_RANDOM;
|
||||
break;
|
||||
}
|
||||
if (where == 'FROM_START' || where == 'FROM_END') {
|
||||
tooltip += ' ' + Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP
|
||||
.replace('%1',
|
||||
thisBlock.workspace.options.oneBasedIndex ? '#1' : '#0');
|
||||
}
|
||||
return tooltip;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Create XML to represent whether there is an 'AT' input.
|
||||
* @return {Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
var isAt = this.getInput('AT').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at', isAt);
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the 'AT' input.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
// Note: Until January 2013 this block did not have mutations,
|
||||
// so 'at' defaults to true.
|
||||
var isAt = (xmlElement.getAttribute('at') != 'false');
|
||||
this.updateAt_(isAt);
|
||||
},
|
||||
/**
|
||||
* Create or delete an input for the numeric index.
|
||||
* @param {boolean} isAt True if the input should exist.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateAt_: function(isAt) {
|
||||
// Destroy old 'AT' and 'ORDINAL' input.
|
||||
this.removeInput('AT');
|
||||
this.removeInput('ORDINAL', true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT').setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL')
|
||||
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
} else {
|
||||
this.appendDummyInput('AT');
|
||||
}
|
||||
var menu = new Blockly.FieldDropdown(this.WHERE_OPTIONS, function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
// The 'isAt' variable is available due to this function being a closure.
|
||||
if (newAt != isAt) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt_(newAt);
|
||||
// This menu has been destroyed and replaced. Update the replacement.
|
||||
block.setFieldValue(value, 'WHERE');
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.moveInputBefore('AT', 'TO');
|
||||
if (this.getInput('ORDINAL')) {
|
||||
this.moveInputBefore('ORDINAL', 'TO');
|
||||
}
|
||||
|
||||
this.getInput('AT').appendField(menu, 'WHERE');
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_getSublist'] = {
|
||||
/**
|
||||
* Block for getting sublist.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this['WHERE_OPTIONS_1'] =
|
||||
[
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_START_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_START_FIRST, 'FIRST']
|
||||
];
|
||||
this['WHERE_OPTIONS_2'] =
|
||||
[
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_END_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.LISTS_GET_SUBLIST_END_LAST, 'LAST']
|
||||
];
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_GET_SUBLIST_HELPURL);
|
||||
this.setColour(Blockly.Msg.LISTS_HUE);
|
||||
this.appendValueInput('LIST')
|
||||
.setCheck('Array')
|
||||
.appendField(Blockly.Msg.LISTS_GET_SUBLIST_INPUT_IN_LIST);
|
||||
this.appendDummyInput('AT1');
|
||||
this.appendDummyInput('AT2');
|
||||
if (Blockly.Msg.LISTS_GET_SUBLIST_TAIL) {
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendField(Blockly.Msg.LISTS_GET_SUBLIST_TAIL);
|
||||
}
|
||||
this.setInputsInline(true);
|
||||
this.setOutput(true, 'Array');
|
||||
this.updateAt_(1, true);
|
||||
this.updateAt_(2, true);
|
||||
this.setTooltip(Blockly.Msg.LISTS_GET_SUBLIST_TOOLTIP);
|
||||
},
|
||||
/**
|
||||
* Create XML to represent whether there are 'AT' inputs.
|
||||
* @return {Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
var isAt1 = this.getInput('AT1').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at1', isAt1);
|
||||
var isAt2 = this.getInput('AT2').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at2', isAt2);
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the 'AT' inputs.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
var isAt1 = (xmlElement.getAttribute('at1') == 'true');
|
||||
var isAt2 = (xmlElement.getAttribute('at2') == 'true');
|
||||
this.updateAt_(1, isAt1);
|
||||
this.updateAt_(2, isAt2);
|
||||
},
|
||||
/**
|
||||
* Create or delete an input for a numeric index.
|
||||
* This block has two such inputs, independant of each other.
|
||||
* @param {number} n Specify first or second input (1 or 2).
|
||||
* @param {boolean} isAt True if the input should exist.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateAt_: function(n, isAt) {
|
||||
// Create or delete an input for the numeric index.
|
||||
// Destroy old 'AT' and 'ORDINAL' inputs.
|
||||
this.removeInput('AT' + n);
|
||||
this.removeInput('ORDINAL' + n, true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT' + n).setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL' + n)
|
||||
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
} else {
|
||||
this.appendDummyInput('AT' + n);
|
||||
}
|
||||
var menu = new Blockly.FieldDropdown(this['WHERE_OPTIONS_' + n],
|
||||
function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
// The 'isAt' variable is available due to this function being a
|
||||
// closure.
|
||||
if (newAt != isAt) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt_(n, newAt);
|
||||
// This menu has been destroyed and replaced.
|
||||
// Update the replacement.
|
||||
block.setFieldValue(value, 'WHERE' + n);
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.getInput('AT' + n)
|
||||
.appendField(menu, 'WHERE' + n);
|
||||
if (n == 1) {
|
||||
this.moveInputBefore('AT1', 'AT2');
|
||||
if (this.getInput('ORDINAL1')) {
|
||||
this.moveInputBefore('ORDINAL1', 'AT2');
|
||||
}
|
||||
}
|
||||
if (Blockly.Msg.LISTS_GET_SUBLIST_TAIL) {
|
||||
this.moveInputBefore('TAIL', null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_sort'] = {
|
||||
/**
|
||||
* Block for sorting a list.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.LISTS_SORT_TITLE,
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "TYPE",
|
||||
"options": [
|
||||
[Blockly.Msg.LISTS_SORT_TYPE_NUMERIC, "NUMERIC"],
|
||||
[Blockly.Msg.LISTS_SORT_TYPE_TEXT, "TEXT"],
|
||||
[Blockly.Msg.LISTS_SORT_TYPE_IGNORECASE, "IGNORE_CASE"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "DIRECTION",
|
||||
"options": [
|
||||
[Blockly.Msg.LISTS_SORT_ORDER_ASCENDING, "1"],
|
||||
[Blockly.Msg.LISTS_SORT_ORDER_DESCENDING, "-1"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "LIST",
|
||||
"check": "Array"
|
||||
}
|
||||
],
|
||||
"output": "Array",
|
||||
"colour": Blockly.Msg.LISTS_HUE,
|
||||
"tooltip": Blockly.Msg.LISTS_SORT_TOOLTIP,
|
||||
"helpUrl": Blockly.Msg.LISTS_SORT_HELPURL
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['lists_split'] = {
|
||||
/**
|
||||
* Block for splitting text into a list, or joining a list into text.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
// Assign 'this' to a variable for use in the closures below.
|
||||
var thisBlock = this;
|
||||
var dropdown = new Blockly.FieldDropdown(
|
||||
[
|
||||
[Blockly.Msg.LISTS_SPLIT_LIST_FROM_TEXT, 'SPLIT'],
|
||||
[Blockly.Msg.LISTS_SPLIT_TEXT_FROM_LIST, 'JOIN']
|
||||
],
|
||||
function(newMode) {
|
||||
thisBlock.updateType_(newMode);
|
||||
});
|
||||
this.setHelpUrl(Blockly.Msg.LISTS_SPLIT_HELPURL);
|
||||
this.setColour(Blockly.Msg.LISTS_HUE);
|
||||
this.appendValueInput('INPUT')
|
||||
.setCheck('String')
|
||||
.appendField(dropdown, 'MODE');
|
||||
this.appendValueInput('DELIM')
|
||||
.setCheck('String')
|
||||
.appendField(Blockly.Msg.LISTS_SPLIT_WITH_DELIMITER);
|
||||
this.setInputsInline(true);
|
||||
this.setOutput(true, 'Array');
|
||||
this.setTooltip(function() {
|
||||
var mode = thisBlock.getFieldValue('MODE');
|
||||
if (mode == 'SPLIT') {
|
||||
return Blockly.Msg.LISTS_SPLIT_TOOLTIP_SPLIT;
|
||||
} else if (mode == 'JOIN') {
|
||||
return Blockly.Msg.LISTS_SPLIT_TOOLTIP_JOIN;
|
||||
}
|
||||
throw 'Unknown mode: ' + mode;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Modify this block to have the correct input and output types.
|
||||
* @param {string} newMode Either 'SPLIT' or 'JOIN'.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateType_: function(newMode) {
|
||||
if (newMode == 'SPLIT') {
|
||||
this.outputConnection.setCheck('Array');
|
||||
this.getInput('INPUT').setCheck('String');
|
||||
} else {
|
||||
this.outputConnection.setCheck('String');
|
||||
this.getInput('INPUT').setCheck('Array');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Create XML to represent the input and output types.
|
||||
* @return {!Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('mode', this.getFieldValue('MODE'));
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the input and output types.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
this.updateType_(xmlElement.getAttribute('mode'));
|
||||
}
|
||||
};
|
||||
630
node_modules/node-blockly/blockly/blocks/logic.js
generated
vendored
Normal file
630
node_modules/node-blockly/blockly/blocks/logic.js
generated
vendored
Normal file
@@ -0,0 +1,630 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* 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 Logic blocks for Blockly.
|
||||
*
|
||||
* This file is scraped to extract a .json file of block definitions. The array
|
||||
* passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes
|
||||
* only, no outside references, no functions, no trailing commas, etc. The one
|
||||
* exception is end-of-line comments, which the scraper will remove.
|
||||
* @author q.neutron@gmail.com (Quynh Neutron)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.logic'); // Deprecated
|
||||
goog.provide('Blockly.Constants.Logic');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly');
|
||||
|
||||
/**
|
||||
* Unused constant for the common HSV hue for all blocks in this category.
|
||||
* @deprecated Use Blockly.Msg.LOGIC_HUE. (2018 April 5)
|
||||
*/
|
||||
Blockly.Constants.Logic.HUE = 210;
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
// Block for boolean data type: true and false.
|
||||
{
|
||||
"type": "logic_boolean",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "BOOL",
|
||||
"options": [
|
||||
["%{BKY_LOGIC_BOOLEAN_TRUE}", "TRUE"],
|
||||
["%{BKY_LOGIC_BOOLEAN_FALSE}", "FALSE"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"tooltip": "%{BKY_LOGIC_BOOLEAN_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LOGIC_BOOLEAN_HELPURL}"
|
||||
},
|
||||
// Block for if/elseif/else condition.
|
||||
{
|
||||
"type": "controls_if",
|
||||
"message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "IF0",
|
||||
"check": "Boolean"
|
||||
}
|
||||
],
|
||||
"message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1",
|
||||
"args1": [
|
||||
{
|
||||
"type": "input_statement",
|
||||
"name": "DO0"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"helpUrl": "%{BKY_CONTROLS_IF_HELPURL}",
|
||||
"mutator": "controls_if_mutator",
|
||||
"extensions": ["controls_if_tooltip"]
|
||||
},
|
||||
// If/else block that does not use a mutator.
|
||||
{
|
||||
"type": "controls_ifelse",
|
||||
"message0": "%{BKY_CONTROLS_IF_MSG_IF} %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "IF0",
|
||||
"check": "Boolean"
|
||||
}
|
||||
],
|
||||
"message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1",
|
||||
"args1": [
|
||||
{
|
||||
"type": "input_statement",
|
||||
"name": "DO0"
|
||||
}
|
||||
],
|
||||
"message2": "%{BKY_CONTROLS_IF_MSG_ELSE} %1",
|
||||
"args2": [
|
||||
{
|
||||
"type": "input_statement",
|
||||
"name": "ELSE"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"tooltip": "%{BKYCONTROLS_IF_TOOLTIP_2}",
|
||||
"helpUrl": "%{BKY_CONTROLS_IF_HELPURL}",
|
||||
"extensions": ["controls_if_tooltip"]
|
||||
},
|
||||
// Block for comparison operator.
|
||||
{
|
||||
"type": "logic_compare",
|
||||
"message0": "%1 %2 %3",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "A"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "OP",
|
||||
"options": [
|
||||
["=", "EQ"],
|
||||
["\u2260", "NEQ"],
|
||||
["<", "LT"],
|
||||
["\u2264", "LTE"],
|
||||
[">", "GT"],
|
||||
["\u2265", "GTE"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "B"
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"output": "Boolean",
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"helpUrl": "%{BKY_LOGIC_COMPARE_HELPURL}",
|
||||
"extensions": ["logic_compare", "logic_op_tooltip"]
|
||||
},
|
||||
// Block for logical operations: 'and', 'or'.
|
||||
{
|
||||
"type": "logic_operation",
|
||||
"message0": "%1 %2 %3",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "A",
|
||||
"check": "Boolean"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "OP",
|
||||
"options": [
|
||||
["%{BKY_LOGIC_OPERATION_AND}", "AND"],
|
||||
["%{BKY_LOGIC_OPERATION_OR}", "OR"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "B",
|
||||
"check": "Boolean"
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"output": "Boolean",
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"helpUrl": "%{BKY_LOGIC_OPERATION_HELPURL}",
|
||||
"extensions": ["logic_op_tooltip"]
|
||||
},
|
||||
// Block for negation.
|
||||
{
|
||||
"type": "logic_negate",
|
||||
"message0": "%{BKY_LOGIC_NEGATE_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "BOOL",
|
||||
"check": "Boolean"
|
||||
}
|
||||
],
|
||||
"output": "Boolean",
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"tooltip": "%{BKY_LOGIC_NEGATE_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LOGIC_NEGATE_HELPURL}"
|
||||
},
|
||||
// Block for null data type.
|
||||
{
|
||||
"type": "logic_null",
|
||||
"message0": "%{BKY_LOGIC_NULL}",
|
||||
"output": null,
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"tooltip": "%{BKY_LOGIC_NULL_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LOGIC_NULL_HELPURL}"
|
||||
},
|
||||
// Block for ternary operator.
|
||||
{
|
||||
"type": "logic_ternary",
|
||||
"message0": "%{BKY_LOGIC_TERNARY_CONDITION} %1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "IF",
|
||||
"check": "Boolean"
|
||||
}
|
||||
],
|
||||
"message1": "%{BKY_LOGIC_TERNARY_IF_TRUE} %1",
|
||||
"args1": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "THEN"
|
||||
}
|
||||
],
|
||||
"message2": "%{BKY_LOGIC_TERNARY_IF_FALSE} %1",
|
||||
"args2": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "ELSE"
|
||||
}
|
||||
],
|
||||
"output": null,
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"tooltip": "%{BKY_LOGIC_TERNARY_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LOGIC_TERNARY_HELPURL}",
|
||||
"extensions": ["logic_ternary"]
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([ // Mutator blocks. Do not extract.
|
||||
// Block representing the if statement in the controls_if mutator.
|
||||
{
|
||||
"type": "controls_if_if",
|
||||
"message0": "%{BKY_CONTROLS_IF_IF_TITLE_IF}",
|
||||
"nextStatement": null,
|
||||
"enableContextMenu": false,
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"tooltip": "%{BKY_CONTROLS_IF_IF_TOOLTIP}"
|
||||
},
|
||||
// Block representing the else-if statement in the controls_if mutator.
|
||||
{
|
||||
"type": "controls_if_elseif",
|
||||
"message0": "%{BKY_CONTROLS_IF_ELSEIF_TITLE_ELSEIF}",
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"enableContextMenu": false,
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"tooltip": "%{BKY_CONTROLS_IF_ELSEIF_TOOLTIP}"
|
||||
},
|
||||
// Block representing the else statement in the controls_if mutator.
|
||||
{
|
||||
"type": "controls_if_else",
|
||||
"message0": "%{BKY_CONTROLS_IF_ELSE_TITLE_ELSE}",
|
||||
"previousStatement": null,
|
||||
"enableContextMenu": false,
|
||||
"colour": "%{BKY_LOGIC_HUE}",
|
||||
"tooltip": "%{BKY_CONTROLS_IF_ELSE_TOOLTIP}"
|
||||
}
|
||||
]);
|
||||
|
||||
/**
|
||||
* Tooltip text, keyed by block OP value. Used by logic_compare and
|
||||
* logic_operation blocks.
|
||||
* @see {Blockly.Extensions#buildTooltipForDropdown}
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Logic.TOOLTIPS_BY_OP = {
|
||||
// logic_compare
|
||||
'EQ': '%{BKY_LOGIC_COMPARE_TOOLTIP_EQ}',
|
||||
'NEQ': '%{BKY_LOGIC_COMPARE_TOOLTIP_NEQ}',
|
||||
'LT': '%{BKY_LOGIC_COMPARE_TOOLTIP_LT}',
|
||||
'LTE': '%{BKY_LOGIC_COMPARE_TOOLTIP_LTE}',
|
||||
'GT': '%{BKY_LOGIC_COMPARE_TOOLTIP_GT}',
|
||||
'GTE': '%{BKY_LOGIC_COMPARE_TOOLTIP_GTE}',
|
||||
|
||||
// logic_operation
|
||||
'AND': '%{BKY_LOGIC_OPERATION_TOOLTIP_AND}',
|
||||
'OR': '%{BKY_LOGIC_OPERATION_TOOLTIP_OR}'
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('logic_op_tooltip',
|
||||
Blockly.Extensions.buildTooltipForDropdown(
|
||||
'OP', Blockly.Constants.Logic.TOOLTIPS_BY_OP));
|
||||
|
||||
/**
|
||||
* Mutator methods added to controls_if blocks.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = {
|
||||
elseifCount_: 0,
|
||||
elseCount_: 0,
|
||||
|
||||
/**
|
||||
* Create XML to represent the number of else-if and else inputs.
|
||||
* @return {Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
if (!this.elseifCount_ && !this.elseCount_) {
|
||||
return null;
|
||||
}
|
||||
var container = document.createElement('mutation');
|
||||
if (this.elseifCount_) {
|
||||
container.setAttribute('elseif', this.elseifCount_);
|
||||
}
|
||||
if (this.elseCount_) {
|
||||
container.setAttribute('else', 1);
|
||||
}
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the else-if and else inputs.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
this.elseifCount_ = parseInt(xmlElement.getAttribute('elseif'), 10) || 0;
|
||||
this.elseCount_ = parseInt(xmlElement.getAttribute('else'), 10) || 0;
|
||||
this.updateShape_();
|
||||
},
|
||||
/**
|
||||
* Populate the mutator's dialog with this block's components.
|
||||
* @param {!Blockly.Workspace} workspace Mutator's workspace.
|
||||
* @return {!Blockly.Block} Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
decompose: function(workspace) {
|
||||
var containerBlock = workspace.newBlock('controls_if_if');
|
||||
containerBlock.initSvg();
|
||||
var connection = containerBlock.nextConnection;
|
||||
for (var i = 1; i <= this.elseifCount_; i++) {
|
||||
var elseifBlock = workspace.newBlock('controls_if_elseif');
|
||||
elseifBlock.initSvg();
|
||||
connection.connect(elseifBlock.previousConnection);
|
||||
connection = elseifBlock.nextConnection;
|
||||
}
|
||||
if (this.elseCount_) {
|
||||
var elseBlock = workspace.newBlock('controls_if_else');
|
||||
elseBlock.initSvg();
|
||||
connection.connect(elseBlock.previousConnection);
|
||||
}
|
||||
return containerBlock;
|
||||
},
|
||||
/**
|
||||
* Reconfigure this block based on the mutator dialog's components.
|
||||
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
compose: function(containerBlock) {
|
||||
var clauseBlock = containerBlock.nextConnection.targetBlock();
|
||||
// Count number of inputs.
|
||||
this.elseifCount_ = 0;
|
||||
this.elseCount_ = 0;
|
||||
var valueConnections = [null];
|
||||
var statementConnections = [null];
|
||||
var elseStatementConnection = null;
|
||||
while (clauseBlock) {
|
||||
switch (clauseBlock.type) {
|
||||
case 'controls_if_elseif':
|
||||
this.elseifCount_++;
|
||||
valueConnections.push(clauseBlock.valueConnection_);
|
||||
statementConnections.push(clauseBlock.statementConnection_);
|
||||
break;
|
||||
case 'controls_if_else':
|
||||
this.elseCount_++;
|
||||
elseStatementConnection = clauseBlock.statementConnection_;
|
||||
break;
|
||||
default:
|
||||
throw 'Unknown block type.';
|
||||
}
|
||||
clauseBlock = clauseBlock.nextConnection &&
|
||||
clauseBlock.nextConnection.targetBlock();
|
||||
}
|
||||
this.updateShape_();
|
||||
// Reconnect any child blocks.
|
||||
for (var i = 1; i <= this.elseifCount_; i++) {
|
||||
Blockly.Mutator.reconnect(valueConnections[i], this, 'IF' + i);
|
||||
Blockly.Mutator.reconnect(statementConnections[i], this, 'DO' + i);
|
||||
}
|
||||
Blockly.Mutator.reconnect(elseStatementConnection, this, 'ELSE');
|
||||
},
|
||||
/**
|
||||
* Store pointers to any connected child blocks.
|
||||
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
saveConnections: function(containerBlock) {
|
||||
var clauseBlock = containerBlock.nextConnection.targetBlock();
|
||||
var i = 1;
|
||||
while (clauseBlock) {
|
||||
switch (clauseBlock.type) {
|
||||
case 'controls_if_elseif':
|
||||
var inputIf = this.getInput('IF' + i);
|
||||
var inputDo = this.getInput('DO' + i);
|
||||
clauseBlock.valueConnection_ =
|
||||
inputIf && inputIf.connection.targetConnection;
|
||||
clauseBlock.statementConnection_ =
|
||||
inputDo && inputDo.connection.targetConnection;
|
||||
i++;
|
||||
break;
|
||||
case 'controls_if_else':
|
||||
var inputDo = this.getInput('ELSE');
|
||||
clauseBlock.statementConnection_ =
|
||||
inputDo && inputDo.connection.targetConnection;
|
||||
break;
|
||||
default:
|
||||
throw 'Unknown block type.';
|
||||
}
|
||||
clauseBlock = clauseBlock.nextConnection &&
|
||||
clauseBlock.nextConnection.targetBlock();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Modify this block to have the correct number of inputs.
|
||||
* @this Blockly.Block
|
||||
* @private
|
||||
*/
|
||||
updateShape_: function() {
|
||||
// Delete everything.
|
||||
if (this.getInput('ELSE')) {
|
||||
this.removeInput('ELSE');
|
||||
}
|
||||
var i = 1;
|
||||
while (this.getInput('IF' + i)) {
|
||||
this.removeInput('IF' + i);
|
||||
this.removeInput('DO' + i);
|
||||
i++;
|
||||
}
|
||||
// Rebuild block.
|
||||
for (var i = 1; i <= this.elseifCount_; i++) {
|
||||
this.appendValueInput('IF' + i)
|
||||
.setCheck('Boolean')
|
||||
.appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSEIF);
|
||||
this.appendStatementInput('DO' + i)
|
||||
.appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN);
|
||||
}
|
||||
if (this.elseCount_) {
|
||||
this.appendStatementInput('ELSE')
|
||||
.appendField(Blockly.Msg.CONTROLS_IF_MSG_ELSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMutator('controls_if_mutator',
|
||||
Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN, null,
|
||||
['controls_if_elseif', 'controls_if_else']);
|
||||
/**
|
||||
* "controls_if" extension function. Adds mutator, shape updating methods, and
|
||||
* dynamic tooltip to "controls_if" blocks.
|
||||
* @this Blockly.Block
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION = function() {
|
||||
|
||||
this.setTooltip(function() {
|
||||
if (!this.elseifCount_ && !this.elseCount_) {
|
||||
return Blockly.Msg.CONTROLS_IF_TOOLTIP_1;
|
||||
} else if (!this.elseifCount_ && this.elseCount_) {
|
||||
return Blockly.Msg.CONTROLS_IF_TOOLTIP_2;
|
||||
} else if (this.elseifCount_ && !this.elseCount_) {
|
||||
return Blockly.Msg.CONTROLS_IF_TOOLTIP_3;
|
||||
} else if (this.elseifCount_ && this.elseCount_) {
|
||||
return Blockly.Msg.CONTROLS_IF_TOOLTIP_4;
|
||||
}
|
||||
return '';
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('controls_if_tooltip',
|
||||
Blockly.Constants.Logic.CONTROLS_IF_TOOLTIP_EXTENSION);
|
||||
|
||||
/**
|
||||
* Corrects the logic_compare dropdown label with respect to language direction.
|
||||
* @this Blockly.Block
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Logic.fixLogicCompareRtlOpLabels =
|
||||
function() {
|
||||
var rtlOpLabels = {
|
||||
'LT': '\u200F<\u200F',
|
||||
'LTE': '\u200F\u2264\u200F',
|
||||
'GT': '\u200F>\u200F',
|
||||
'GTE': '\u200F\u2265\u200F'
|
||||
};
|
||||
var opDropdown = this.getField('OP');
|
||||
if (opDropdown) {
|
||||
var options = opDropdown.getOptions();
|
||||
for (var i = 0; i < options.length; ++i) {
|
||||
var tuple = options[i];
|
||||
var op = tuple[1];
|
||||
var rtlLabel = rtlOpLabels[op];
|
||||
if (goog.isString(tuple[0]) && rtlLabel) {
|
||||
// Replace LTR text label
|
||||
tuple[0] = rtlLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds dynamic type validation for the left and right sides of a logic_compare block.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN = {
|
||||
/**
|
||||
* Called whenever anything on the workspace changes.
|
||||
* Prevent mismatched types from being compared.
|
||||
* @param {!Blockly.Events.Abstract} e Change event.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
onchange: function(e) {
|
||||
if (!this.prevBlocks_) {
|
||||
this.prevBlocks_ = [null, null];
|
||||
}
|
||||
|
||||
var blockA = this.getInputTargetBlock('A');
|
||||
var blockB = this.getInputTargetBlock('B');
|
||||
// Disconnect blocks that existed prior to this change if they don't match.
|
||||
if (blockA && blockB &&
|
||||
!blockA.outputConnection.checkType_(blockB.outputConnection)) {
|
||||
// Mismatch between two inputs. Revert the block connections,
|
||||
// bumping away the newly connected block(s).
|
||||
Blockly.Events.setGroup(e.group);
|
||||
var prevA = this.prevBlocks_[0];
|
||||
if (prevA !== blockA) {
|
||||
blockA.unplug();
|
||||
if (prevA && !prevA.isShadow()) {
|
||||
// The shadow block is automatically replaced during unplug().
|
||||
this.getInput('A').connection.connect(prevA.outputConnection);
|
||||
}
|
||||
}
|
||||
var prevB = this.prevBlocks_[1];
|
||||
if (prevB !== blockB) {
|
||||
blockB.unplug();
|
||||
if (prevB && !prevB.isShadow()) {
|
||||
// The shadow block is automatically replaced during unplug().
|
||||
this.getInput('B').connection.connect(prevB.outputConnection);
|
||||
}
|
||||
}
|
||||
this.bumpNeighbours_();
|
||||
Blockly.Events.setGroup(false);
|
||||
}
|
||||
this.prevBlocks_[0] = this.getInputTargetBlock('A');
|
||||
this.prevBlocks_[1] = this.getInputTargetBlock('B');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* "logic_compare" extension function. Corrects direction of operators in the
|
||||
* dropdown labels, and adds type left and right side type checking to
|
||||
* "logic_compare" blocks.
|
||||
* @this Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION = function() {
|
||||
// Fix operator labels in RTL.
|
||||
if (this.RTL) {
|
||||
Blockly.Constants.Logic.fixLogicCompareRtlOpLabels.apply(this);
|
||||
}
|
||||
|
||||
// Add onchange handler to ensure types are compatible.
|
||||
this.mixin(Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN);
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('logic_compare',
|
||||
Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION);
|
||||
|
||||
/**
|
||||
* Adds type coordination between inputs and output.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN = {
|
||||
prevParentConnection_: null,
|
||||
|
||||
/**
|
||||
* Called whenever anything on the workspace changes.
|
||||
* Prevent mismatched types.
|
||||
* @param {!Blockly.Events.Abstract} e Change event.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
onchange: function(e) {
|
||||
var blockA = this.getInputTargetBlock('THEN');
|
||||
var blockB = this.getInputTargetBlock('ELSE');
|
||||
var parentConnection = this.outputConnection.targetConnection;
|
||||
// Disconnect blocks that existed prior to this change if they don't match.
|
||||
if ((blockA || blockB) && parentConnection) {
|
||||
for (var i = 0; i < 2; i++) {
|
||||
var block = (i == 1) ? blockA : blockB;
|
||||
if (block && !block.outputConnection.checkType_(parentConnection)) {
|
||||
// Ensure that any disconnections are grouped with the causing event.
|
||||
Blockly.Events.setGroup(e.group);
|
||||
if (parentConnection === this.prevParentConnection_) {
|
||||
this.unplug();
|
||||
parentConnection.getSourceBlock().bumpNeighbours_();
|
||||
} else {
|
||||
block.unplug();
|
||||
block.bumpNeighbours_();
|
||||
}
|
||||
Blockly.Events.setGroup(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.prevParentConnection_ = parentConnection;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMixin('logic_ternary',
|
||||
Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN);
|
||||
342
node_modules/node-blockly/blockly/blocks/loops.js
generated
vendored
Normal file
342
node_modules/node-blockly/blockly/blocks/loops.js
generated
vendored
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* 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 Loop blocks for Blockly.
|
||||
*
|
||||
* This file is scraped to extract a .json file of block definitions. The array
|
||||
* passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes
|
||||
* only, no outside references, no functions, no trailing commas, etc. The one
|
||||
* exception is end-of-line comments, which the scraper will remove.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.loops'); // Deprecated
|
||||
goog.provide('Blockly.Constants.Loops');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly');
|
||||
|
||||
|
||||
/**
|
||||
* Unused constant for the common HSV hue for all blocks in this category.
|
||||
* @deprecated Use Blockly.Msg.LOOPS_HUE. (2018 April 5)
|
||||
*/
|
||||
Blockly.Constants.Loops.HUE = 120;
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
// Block for repeat n times (external number).
|
||||
{
|
||||
"type": "controls_repeat_ext",
|
||||
"message0": "%{BKY_CONTROLS_REPEAT_TITLE}",
|
||||
"args0": [{
|
||||
"type": "input_value",
|
||||
"name": "TIMES",
|
||||
"check": "Number"
|
||||
}],
|
||||
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
||||
"args1": [{
|
||||
"type": "input_statement",
|
||||
"name": "DO"
|
||||
}],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_LOOPS_HUE}",
|
||||
"tooltip": "%{BKY_CONTROLS_REPEAT_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_CONTROLS_REPEAT_HELPURL}"
|
||||
},
|
||||
// Block for repeat n times (internal number).
|
||||
// The 'controls_repeat_ext' block is preferred as it is more flexible.
|
||||
{
|
||||
"type": "controls_repeat",
|
||||
"message0": "%{BKY_CONTROLS_REPEAT_TITLE}",
|
||||
"args0": [{
|
||||
"type": "field_number",
|
||||
"name": "TIMES",
|
||||
"value": 10,
|
||||
"min": 0,
|
||||
"precision": 1
|
||||
}],
|
||||
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
||||
"args1": [{
|
||||
"type": "input_statement",
|
||||
"name": "DO"
|
||||
}],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_LOOPS_HUE}",
|
||||
"tooltip": "%{BKY_CONTROLS_REPEAT_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_CONTROLS_REPEAT_HELPURL}"
|
||||
},
|
||||
// Block for 'do while/until' loop.
|
||||
{
|
||||
"type": "controls_whileUntil",
|
||||
"message0": "%1 %2",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "MODE",
|
||||
"options": [
|
||||
["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_WHILE}", "WHILE"],
|
||||
["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_UNTIL}", "UNTIL"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "BOOL",
|
||||
"check": "Boolean"
|
||||
}
|
||||
],
|
||||
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
||||
"args1": [{
|
||||
"type": "input_statement",
|
||||
"name": "DO"
|
||||
}],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_LOOPS_HUE}",
|
||||
"helpUrl": "%{BKY_CONTROLS_WHILEUNTIL_HELPURL}",
|
||||
"extensions": ["controls_whileUntil_tooltip"]
|
||||
},
|
||||
// Block for 'for' loop.
|
||||
{
|
||||
"type": "controls_for",
|
||||
"message0": "%{BKY_CONTROLS_FOR_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
"variable": null
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FROM",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TO",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "BY",
|
||||
"check": "Number",
|
||||
"align": "RIGHT"
|
||||
}
|
||||
],
|
||||
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
||||
"args1": [{
|
||||
"type": "input_statement",
|
||||
"name": "DO"
|
||||
}],
|
||||
"inputsInline": true,
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_LOOPS_HUE}",
|
||||
"helpUrl": "%{BKY_CONTROLS_FOR_HELPURL}",
|
||||
"extensions": [
|
||||
"contextMenu_newGetVariableBlock",
|
||||
"controls_for_tooltip"
|
||||
]
|
||||
},
|
||||
// Block for 'for each' loop.
|
||||
{
|
||||
"type": "controls_forEach",
|
||||
"message0": "%{BKY_CONTROLS_FOREACH_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
"variable": null
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "LIST",
|
||||
"check": "Array"
|
||||
}
|
||||
],
|
||||
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
||||
"args1": [{
|
||||
"type": "input_statement",
|
||||
"name": "DO"
|
||||
}],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_LOOPS_HUE}",
|
||||
"helpUrl": "%{BKY_CONTROLS_FOREACH_HELPURL}",
|
||||
"extensions": [
|
||||
"contextMenu_newGetVariableBlock",
|
||||
"controls_forEach_tooltip"
|
||||
]
|
||||
},
|
||||
// Block for flow statements: continue, break.
|
||||
{
|
||||
"type": "controls_flow_statements",
|
||||
"message0": "%1",
|
||||
"args0": [{
|
||||
"type": "field_dropdown",
|
||||
"name": "FLOW",
|
||||
"options": [
|
||||
["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK}", "BREAK"],
|
||||
["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE}", "CONTINUE"]
|
||||
]
|
||||
}],
|
||||
"previousStatement": null,
|
||||
"colour": "%{BKY_LOOPS_HUE}",
|
||||
"helpUrl": "%{BKY_CONTROLS_FLOW_STATEMENTS_HELPURL}",
|
||||
"extensions": [
|
||||
"controls_flow_tooltip",
|
||||
"controls_flow_in_loop_check"
|
||||
]
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
|
||||
/**
|
||||
* Tooltips for the 'controls_whileUntil' block, keyed by MODE value.
|
||||
* @see {Blockly.Extensions#buildTooltipForDropdown}
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS = {
|
||||
'WHILE': '%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_WHILE}',
|
||||
'UNTIL': '%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}'
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('controls_whileUntil_tooltip',
|
||||
Blockly.Extensions.buildTooltipForDropdown(
|
||||
'MODE', Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS));
|
||||
|
||||
/**
|
||||
* Tooltips for the 'controls_flow_statements' block, keyed by FLOW value.
|
||||
* @see {Blockly.Extensions#buildTooltipForDropdown}
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS = {
|
||||
'BREAK': '%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK}',
|
||||
'CONTINUE': '%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE}'
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('controls_flow_tooltip',
|
||||
Blockly.Extensions.buildTooltipForDropdown(
|
||||
'FLOW', Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS));
|
||||
|
||||
/**
|
||||
* Mixin to add a context menu item to create a 'variables_get' block.
|
||||
* Used by blocks 'controls_for' and 'controls_forEach'.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN = {
|
||||
/**
|
||||
* Add context menu option to create getter block for the loop's variable.
|
||||
* (customContextMenu support limited to web BlockSvg.)
|
||||
* @param {!Array} options List of menu options to add to.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
customContextMenu: function(options) {
|
||||
if (this.isInFlyout){
|
||||
return;
|
||||
}
|
||||
var variable = this.getField('VAR').getVariable();
|
||||
var varName = variable.name;
|
||||
if (!this.isCollapsed() && varName != null) {
|
||||
var option = {enabled: true};
|
||||
option.text =
|
||||
Blockly.Msg.VARIABLES_SET_CREATE_GET.replace('%1', varName);
|
||||
var xmlField = Blockly.Variables.generateVariableFieldDom(variable);
|
||||
var xmlBlock = goog.dom.createDom('block', null, xmlField);
|
||||
xmlBlock.setAttribute('type', 'variables_get');
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMixin('contextMenu_newGetVariableBlock',
|
||||
Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN);
|
||||
|
||||
Blockly.Extensions.register('controls_for_tooltip',
|
||||
Blockly.Extensions.buildTooltipWithFieldText(
|
||||
'%{BKY_CONTROLS_FOR_TOOLTIP}', 'VAR'));
|
||||
|
||||
Blockly.Extensions.register('controls_forEach_tooltip',
|
||||
Blockly.Extensions.buildTooltipWithFieldText(
|
||||
'%{BKY_CONTROLS_FOREACH_TOOLTIP}', 'VAR'));
|
||||
|
||||
/**
|
||||
* This mixin adds a check to make sure the 'controls_flow_statements' block
|
||||
* is contained in a loop. Otherwise a warning is added to the block.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = {
|
||||
/**
|
||||
* List of block types that are loops and thus do not need warnings.
|
||||
* To add a new loop type add this to your code:
|
||||
* Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES.push('custom_loop');
|
||||
*/
|
||||
LOOP_TYPES: ['controls_repeat', 'controls_repeat_ext', 'controls_forEach',
|
||||
'controls_for', 'controls_whileUntil'],
|
||||
|
||||
/**
|
||||
* Called whenever anything on the workspace changes.
|
||||
* Add warning if this flow block is not nested inside a loop.
|
||||
* @param {!Blockly.Events.Abstract} e Change event.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
onchange: function(/* e */) {
|
||||
if (!this.workspace.isDragging || this.workspace.isDragging()) {
|
||||
return; // Don't change state at the start of a drag.
|
||||
}
|
||||
var legal = false;
|
||||
// Is the block nested in a loop?
|
||||
var block = this;
|
||||
do {
|
||||
if (this.LOOP_TYPES.indexOf(block.type) != -1) {
|
||||
legal = true;
|
||||
break;
|
||||
}
|
||||
block = block.getSurroundParent();
|
||||
} while (block);
|
||||
if (legal) {
|
||||
this.setWarningText(null);
|
||||
if (!this.isInFlyout) {
|
||||
this.setDisabled(false);
|
||||
}
|
||||
} else {
|
||||
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
|
||||
if (!this.isInFlyout && !this.getInheritedDisabled()) {
|
||||
this.setDisabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMixin('controls_flow_in_loop_check',
|
||||
Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN);
|
||||
553
node_modules/node-blockly/blockly/blocks/math.js
generated
vendored
Normal file
553
node_modules/node-blockly/blockly/blocks/math.js
generated
vendored
Normal file
@@ -0,0 +1,553 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* 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 Math blocks for Blockly.
|
||||
*
|
||||
* This file is scraped to extract a .json file of block definitions. The array
|
||||
* passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes
|
||||
* only, no outside references, no functions, no trailing commas, etc. The one
|
||||
* exception is end-of-line comments, which the scraper will remove.
|
||||
* @author q.neutron@gmail.com (Quynh Neutron)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.math'); // Deprecated
|
||||
goog.provide('Blockly.Constants.Math');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly');
|
||||
|
||||
|
||||
/**
|
||||
* Unused constant for the common HSV hue for all blocks in this category.
|
||||
* @deprecated Use Blockly.Msg.MATH_HUE. (2018 April 5)
|
||||
*/
|
||||
Blockly.Constants.Math.HUE = 230;
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
// Block for numeric value.
|
||||
{
|
||||
"type": "math_number",
|
||||
"message0": "%1",
|
||||
"args0": [{
|
||||
"type": "field_number",
|
||||
"name": "NUM",
|
||||
"value": 0
|
||||
}],
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"helpUrl": "%{BKY_MATH_NUMBER_HELPURL}",
|
||||
"tooltip": "%{BKY_MATH_NUMBER_TOOLTIP}",
|
||||
"extensions": ["parent_tooltip_when_inline"]
|
||||
},
|
||||
|
||||
// Block for basic arithmetic operator.
|
||||
{
|
||||
"type": "math_arithmetic",
|
||||
"message0": "%1 %2 %3",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "A",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "OP",
|
||||
"options": [
|
||||
["%{BKY_MATH_ADDITION_SYMBOL}", "ADD"],
|
||||
["%{BKY_MATH_SUBTRACTION_SYMBOL}", "MINUS"],
|
||||
["%{BKY_MATH_MULTIPLICATION_SYMBOL}", "MULTIPLY"],
|
||||
["%{BKY_MATH_DIVISION_SYMBOL}", "DIVIDE"],
|
||||
["%{BKY_MATH_POWER_SYMBOL}", "POWER"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "B",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"helpUrl": "%{BKY_MATH_ARITHMETIC_HELPURL}",
|
||||
"extensions": ["math_op_tooltip"]
|
||||
},
|
||||
|
||||
// Block for advanced math operators with single operand.
|
||||
{
|
||||
"type": "math_single",
|
||||
"message0": "%1 %2",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "OP",
|
||||
"options": [
|
||||
["%{BKY_MATH_SINGLE_OP_ROOT}", 'ROOT'],
|
||||
["%{BKY_MATH_SINGLE_OP_ABSOLUTE}", 'ABS'],
|
||||
['-', 'NEG'],
|
||||
['ln', 'LN'],
|
||||
['log10', 'LOG10'],
|
||||
['e^', 'EXP'],
|
||||
['10^', 'POW10']
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "NUM",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"helpUrl": "%{BKY_MATH_SINGLE_HELPURL}",
|
||||
"extensions": ["math_op_tooltip"]
|
||||
},
|
||||
|
||||
// Block for trigonometry operators.
|
||||
{
|
||||
"type": "math_trig",
|
||||
"message0": "%1 %2",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "OP",
|
||||
"options": [
|
||||
["%{BKY_MATH_TRIG_SIN}", "SIN"],
|
||||
["%{BKY_MATH_TRIG_COS}", "COS"],
|
||||
["%{BKY_MATH_TRIG_TAN}", "TAN"],
|
||||
["%{BKY_MATH_TRIG_ASIN}", "ASIN"],
|
||||
["%{BKY_MATH_TRIG_ACOS}", "ACOS"],
|
||||
["%{BKY_MATH_TRIG_ATAN}", "ATAN"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "NUM",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"helpUrl": "%{BKY_MATH_TRIG_HELPURL}",
|
||||
"extensions": ["math_op_tooltip"]
|
||||
},
|
||||
|
||||
// Block for constants: PI, E, the Golden Ratio, sqrt(2), 1/sqrt(2), INFINITY.
|
||||
{
|
||||
"type": "math_constant",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "CONSTANT",
|
||||
"options": [
|
||||
["\u03c0", "PI"],
|
||||
["e", "E"],
|
||||
["\u03c6", "GOLDEN_RATIO"],
|
||||
["sqrt(2)", "SQRT2"],
|
||||
["sqrt(\u00bd)", "SQRT1_2"],
|
||||
["\u221e", "INFINITY"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"tooltip": "%{BKY_MATH_CONSTANT_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_MATH_CONSTANT_HELPURL}"
|
||||
},
|
||||
|
||||
// Block for checking if a number is even, odd, prime, whole, positive,
|
||||
// negative or if it is divisible by certain number.
|
||||
{
|
||||
"type": "math_number_property",
|
||||
"message0": "%1 %2",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "NUMBER_TO_CHECK",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "PROPERTY",
|
||||
"options": [
|
||||
["%{BKY_MATH_IS_EVEN}", "EVEN"],
|
||||
["%{BKY_MATH_IS_ODD}", "ODD"],
|
||||
["%{BKY_MATH_IS_PRIME}", "PRIME"],
|
||||
["%{BKY_MATH_IS_WHOLE}", "WHOLE"],
|
||||
["%{BKY_MATH_IS_POSITIVE}", "POSITIVE"],
|
||||
["%{BKY_MATH_IS_NEGATIVE}", "NEGATIVE"],
|
||||
["%{BKY_MATH_IS_DIVISIBLE_BY}", "DIVISIBLE_BY"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"output": "Boolean",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"tooltip": "%{BKY_MATH_IS_TOOLTIP}",
|
||||
"mutator": "math_is_divisibleby_mutator"
|
||||
},
|
||||
|
||||
// Block for adding to a variable in place.
|
||||
{
|
||||
"type": "math_change",
|
||||
"message0": "%{BKY_MATH_CHANGE_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
"variable": "%{BKY_MATH_CHANGE_TITLE_ITEM}"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "DELTA",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_VARIABLES_HUE}",
|
||||
"helpUrl": "%{BKY_MATH_CHANGE_HELPURL}",
|
||||
"extensions": ["math_change_tooltip"]
|
||||
},
|
||||
|
||||
// Block for rounding functions.
|
||||
{
|
||||
"type": "math_round",
|
||||
"message0": "%1 %2",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "OP",
|
||||
"options": [
|
||||
["%{BKY_MATH_ROUND_OPERATOR_ROUND}", "ROUND"],
|
||||
["%{BKY_MATH_ROUND_OPERATOR_ROUNDUP}", "ROUNDUP"],
|
||||
["%{BKY_MATH_ROUND_OPERATOR_ROUNDDOWN}", "ROUNDDOWN"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "NUM",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"helpUrl": "%{BKY_MATH_ROUND_HELPURL}",
|
||||
"tooltip": "%{BKY_MATH_ROUND_TOOLTIP}"
|
||||
},
|
||||
|
||||
// Block for evaluating a list of numbers to return sum, average, min, max,
|
||||
// etc. Some functions also work on text (min, max, mode, median).
|
||||
{
|
||||
"type": "math_on_list",
|
||||
"message0": "%1 %2",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "OP",
|
||||
"options": [
|
||||
["%{BKY_MATH_ONLIST_OPERATOR_SUM}", "SUM"],
|
||||
["%{BKY_MATH_ONLIST_OPERATOR_MIN}", "MIN"],
|
||||
["%{BKY_MATH_ONLIST_OPERATOR_MAX}", "MAX"],
|
||||
["%{BKY_MATH_ONLIST_OPERATOR_AVERAGE}", "AVERAGE"],
|
||||
["%{BKY_MATH_ONLIST_OPERATOR_MEDIAN}", "MEDIAN"],
|
||||
["%{BKY_MATH_ONLIST_OPERATOR_MODE}", "MODE"],
|
||||
["%{BKY_MATH_ONLIST_OPERATOR_STD_DEV}", "STD_DEV"],
|
||||
["%{BKY_MATH_ONLIST_OPERATOR_RANDOM}", "RANDOM"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "LIST",
|
||||
"check": "Array"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"helpUrl": "%{BKY_MATH_ONLIST_HELPURL}",
|
||||
"mutator": "math_modes_of_list_mutator",
|
||||
"extensions": ["math_op_tooltip"]
|
||||
},
|
||||
|
||||
// Block for remainder of a division.
|
||||
{
|
||||
"type": "math_modulo",
|
||||
"message0": "%{BKY_MATH_MODULO_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "DIVIDEND",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "DIVISOR",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"tooltip": "%{BKY_MATH_MODULO_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_MATH_MODULO_HELPURL}"
|
||||
},
|
||||
|
||||
// Block for constraining a number between two limits.
|
||||
{
|
||||
"type": "math_constrain",
|
||||
"message0": "%{BKY_MATH_CONSTRAIN_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "LOW",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "HIGH",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"tooltip": "%{BKY_MATH_CONSTRAIN_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_MATH_CONSTRAIN_HELPURL}"
|
||||
},
|
||||
|
||||
// Block for random integer between [X] and [Y].
|
||||
{
|
||||
"type": "math_random_int",
|
||||
"message0": "%{BKY_MATH_RANDOM_INT_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FROM",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TO",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"tooltip": "%{BKY_MATH_RANDOM_INT_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_MATH_RANDOM_INT_HELPURL}"
|
||||
},
|
||||
|
||||
// Block for random integer between [X] and [Y].
|
||||
{
|
||||
"type": "math_random_float",
|
||||
"message0": "%{BKY_MATH_RANDOM_FLOAT_TITLE_RANDOM}",
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_MATH_HUE}",
|
||||
"tooltip": "%{BKY_MATH_RANDOM_FLOAT_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_MATH_RANDOM_FLOAT_HELPURL}"
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
|
||||
/**
|
||||
* Mapping of math block OP value to tooltip message for blocks
|
||||
* math_arithmetic, math_simple, math_trig, and math_on_lists.
|
||||
* @see {Blockly.Extensions#buildTooltipForDropdown}
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Math.TOOLTIPS_BY_OP = {
|
||||
// math_arithmetic
|
||||
'ADD': '%{BKY_MATH_ARITHMETIC_TOOLTIP_ADD}',
|
||||
'MINUS': '%{BKY_MATH_ARITHMETIC_TOOLTIP_MINUS}',
|
||||
'MULTIPLY': '%{BKY_MATH_ARITHMETIC_TOOLTIP_MULTIPLY}',
|
||||
'DIVIDE': '%{BKY_MATH_ARITHMETIC_TOOLTIP_DIVIDE}',
|
||||
'POWER': '%{BKY_MATH_ARITHMETIC_TOOLTIP_POWER}',
|
||||
|
||||
// math_simple
|
||||
'ROOT': '%{BKY_MATH_SINGLE_TOOLTIP_ROOT}',
|
||||
'ABS': '%{BKY_MATH_SINGLE_TOOLTIP_ABS}',
|
||||
'NEG': '%{BKY_MATH_SINGLE_TOOLTIP_NEG}',
|
||||
'LN': '%{BKY_MATH_SINGLE_TOOLTIP_LN}',
|
||||
'LOG10': '%{BKY_MATH_SINGLE_TOOLTIP_LOG10}',
|
||||
'EXP': '%{BKY_MATH_SINGLE_TOOLTIP_EXP}',
|
||||
'POW10': '%{BKY_MATH_SINGLE_TOOLTIP_POW10}',
|
||||
|
||||
// math_trig
|
||||
'SIN': '%{BKY_MATH_TRIG_TOOLTIP_SIN}',
|
||||
'COS': '%{BKY_MATH_TRIG_TOOLTIP_COS}',
|
||||
'TAN': '%{BKY_MATH_TRIG_TOOLTIP_TAN}',
|
||||
'ASIN': '%{BKY_MATH_TRIG_TOOLTIP_ASIN}',
|
||||
'ACOS': '%{BKY_MATH_TRIG_TOOLTIP_ACOS}',
|
||||
'ATAN': '%{BKY_MATH_TRIG_TOOLTIP_ATAN}',
|
||||
|
||||
// math_on_lists
|
||||
'SUM': '%{BKY_MATH_ONLIST_TOOLTIP_SUM}',
|
||||
'MIN': '%{BKY_MATH_ONLIST_TOOLTIP_MIN}',
|
||||
'MAX': '%{BKY_MATH_ONLIST_TOOLTIP_MAX}',
|
||||
'AVERAGE': '%{BKY_MATH_ONLIST_TOOLTIP_AVERAGE}',
|
||||
'MEDIAN': '%{BKY_MATH_ONLIST_TOOLTIP_MEDIAN}',
|
||||
'MODE': '%{BKY_MATH_ONLIST_TOOLTIP_MODE}',
|
||||
'STD_DEV': '%{BKY_MATH_ONLIST_TOOLTIP_STD_DEV}',
|
||||
'RANDOM': '%{BKY_MATH_ONLIST_TOOLTIP_RANDOM}'
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('math_op_tooltip',
|
||||
Blockly.Extensions.buildTooltipForDropdown(
|
||||
'OP', Blockly.Constants.Math.TOOLTIPS_BY_OP));
|
||||
|
||||
|
||||
/**
|
||||
* Mixin for mutator functions in the 'math_is_divisibleby_mutator'
|
||||
* extension.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN = {
|
||||
/**
|
||||
* Create XML to represent whether the 'divisorInput' should be present.
|
||||
* @return {Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
var divisorInput = (this.getFieldValue('PROPERTY') == 'DIVISIBLE_BY');
|
||||
container.setAttribute('divisor_input', divisorInput);
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the 'divisorInput'.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
var divisorInput = (xmlElement.getAttribute('divisor_input') == 'true');
|
||||
this.updateShape_(divisorInput);
|
||||
},
|
||||
/**
|
||||
* Modify this block to have (or not have) an input for 'is divisible by'.
|
||||
* @param {boolean} divisorInput True if this block has a divisor input.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateShape_: function(divisorInput) {
|
||||
// Add or remove a Value Input.
|
||||
var inputExists = this.getInput('DIVISOR');
|
||||
if (divisorInput) {
|
||||
if (!inputExists) {
|
||||
this.appendValueInput('DIVISOR')
|
||||
.setCheck('Number');
|
||||
}
|
||||
} else if (inputExists) {
|
||||
this.removeInput('DIVISOR');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 'math_is_divisibleby_mutator' extension to the 'math_property' block that
|
||||
* can update the block shape (add/remove divisor input) based on whether
|
||||
* property is "divisble by".
|
||||
* @this Blockly.Block
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION = function() {
|
||||
this.getField('PROPERTY').setValidator(function(option) {
|
||||
var divisorInput = (option == 'DIVISIBLE_BY');
|
||||
this.sourceBlock_.updateShape_(divisorInput);
|
||||
});
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMutator('math_is_divisibleby_mutator',
|
||||
Blockly.Constants.Math.IS_DIVISIBLEBY_MUTATOR_MIXIN,
|
||||
Blockly.Constants.Math.IS_DIVISIBLE_MUTATOR_EXTENSION);
|
||||
|
||||
// Update the tooltip of 'math_change' block to reference the variable.
|
||||
Blockly.Extensions.register('math_change_tooltip',
|
||||
Blockly.Extensions.buildTooltipWithFieldText(
|
||||
'%{BKY_MATH_CHANGE_TOOLTIP}', 'VAR'));
|
||||
|
||||
/**
|
||||
* Mixin with mutator methods to support alternate output based if the
|
||||
* 'math_on_list' block uses the 'MODE' operation.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN = {
|
||||
/**
|
||||
* Modify this block to have the correct output type.
|
||||
* @param {string} newOp Either 'MODE' or some op than returns a number.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateType_: function(newOp) {
|
||||
if (newOp == 'MODE') {
|
||||
this.outputConnection.setCheck('Array');
|
||||
} else {
|
||||
this.outputConnection.setCheck('Number');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Create XML to represent the output type.
|
||||
* @return {Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('op', this.getFieldValue('OP'));
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the output type.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
this.updateType_(xmlElement.getAttribute('op'));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extension to 'math_on_list' blocks that allows support of
|
||||
* modes operation (outputs a list of numbers).
|
||||
* @this Blockly.Block
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION = function() {
|
||||
this.getField('OP').setValidator(function(newOp) {
|
||||
this.updateType_(newOp);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMutator('math_modes_of_list_mutator',
|
||||
Blockly.Constants.Math.LIST_MODES_MUTATOR_MIXIN,
|
||||
Blockly.Constants.Math.LIST_MODES_MUTATOR_EXTENSION);
|
||||
993
node_modules/node-blockly/blockly/blocks/procedures.js
generated
vendored
Normal file
993
node_modules/node-blockly/blockly/blocks/procedures.js
generated
vendored
Normal file
@@ -0,0 +1,993 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* 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 Procedure blocks for Blockly.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.procedures');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly');
|
||||
|
||||
|
||||
Blockly.Blocks['procedures_defnoreturn'] = {
|
||||
/**
|
||||
* Block for defining a procedure with no return value.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
var nameField = new Blockly.FieldTextInput('',
|
||||
Blockly.Procedures.rename);
|
||||
nameField.setSpellcheck(false);
|
||||
this.appendDummyInput()
|
||||
.appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE)
|
||||
.appendField(nameField, 'NAME')
|
||||
.appendField('', 'PARAMS');
|
||||
this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
|
||||
if ((this.workspace.options.comments ||
|
||||
(this.workspace.options.parentWorkspace &&
|
||||
this.workspace.options.parentWorkspace.options.comments)) &&
|
||||
Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT) {
|
||||
this.setCommentText(Blockly.Msg.PROCEDURES_DEFNORETURN_COMMENT);
|
||||
}
|
||||
this.setColour(Blockly.Msg.PROCEDURES_HUE);
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_DEFNORETURN_TOOLTIP);
|
||||
this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFNORETURN_HELPURL);
|
||||
this.arguments_ = [];
|
||||
this.argumentVarModels_ = [];
|
||||
this.setStatements_(true);
|
||||
this.statementConnection_ = null;
|
||||
},
|
||||
/**
|
||||
* Add or remove the statement block from this function definition.
|
||||
* @param {boolean} hasStatements True if a statement block is needed.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
setStatements_: function(hasStatements) {
|
||||
if (this.hasStatements_ === hasStatements) {
|
||||
return;
|
||||
}
|
||||
if (hasStatements) {
|
||||
this.appendStatementInput('STACK')
|
||||
.appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_DO);
|
||||
if (this.getInput('RETURN')) {
|
||||
this.moveInputBefore('STACK', 'RETURN');
|
||||
}
|
||||
} else {
|
||||
this.removeInput('STACK', true);
|
||||
}
|
||||
this.hasStatements_ = hasStatements;
|
||||
},
|
||||
/**
|
||||
* Update the display of parameters for this procedure definition block.
|
||||
* Display a warning if there are duplicately named parameters.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateParams_: function() {
|
||||
// Check for duplicated arguments.
|
||||
var badArg = false;
|
||||
var hash = {};
|
||||
for (var i = 0; i < this.arguments_.length; i++) {
|
||||
if (hash['arg_' + this.arguments_[i].toLowerCase()]) {
|
||||
badArg = true;
|
||||
break;
|
||||
}
|
||||
hash['arg_' + this.arguments_[i].toLowerCase()] = true;
|
||||
}
|
||||
if (badArg) {
|
||||
this.setWarningText(Blockly.Msg.PROCEDURES_DEF_DUPLICATE_WARNING);
|
||||
} else {
|
||||
this.setWarningText(null);
|
||||
}
|
||||
// Merge the arguments into a human-readable list.
|
||||
var paramString = '';
|
||||
if (this.arguments_.length) {
|
||||
paramString = Blockly.Msg.PROCEDURES_BEFORE_PARAMS +
|
||||
' ' + this.arguments_.join(', ');
|
||||
}
|
||||
// The params field is deterministic based on the mutation,
|
||||
// no need to fire a change event.
|
||||
Blockly.Events.disable();
|
||||
try {
|
||||
this.setFieldValue(paramString, 'PARAMS');
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Create XML to represent the argument inputs.
|
||||
* @param {boolean=} opt_paramIds If true include the IDs of the parameter
|
||||
* quarks. Used by Blockly.Procedures.mutateCallers for reconnection.
|
||||
* @return {!Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function(opt_paramIds) {
|
||||
var container = document.createElement('mutation');
|
||||
if (opt_paramIds) {
|
||||
container.setAttribute('name', this.getFieldValue('NAME'));
|
||||
}
|
||||
for (var i = 0; i < this.argumentVarModels_.length; i++) {
|
||||
var parameter = document.createElement('arg');
|
||||
var argModel = this.argumentVarModels_[i];
|
||||
parameter.setAttribute('name', argModel.name);
|
||||
parameter.setAttribute('varId', argModel.getId());
|
||||
if (opt_paramIds && this.paramIds_) {
|
||||
parameter.setAttribute('paramId', this.paramIds_[i]);
|
||||
}
|
||||
container.appendChild(parameter);
|
||||
}
|
||||
|
||||
// Save whether the statement input is visible.
|
||||
if (!this.hasStatements_) {
|
||||
container.setAttribute('statements', 'false');
|
||||
}
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the argument inputs.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
this.arguments_ = [];
|
||||
this.argumentVarModels_ = [];
|
||||
for (var i = 0, childNode; childNode = xmlElement.childNodes[i]; i++) {
|
||||
if (childNode.nodeName.toLowerCase() == 'arg') {
|
||||
var varName = childNode.getAttribute('name');
|
||||
var varId = childNode.getAttribute('varId');
|
||||
this.arguments_.push(varName);
|
||||
var variable = Blockly.Variables.getOrCreateVariablePackage(
|
||||
this.workspace, varId, varName, '');
|
||||
this.argumentVarModels_.push(variable);
|
||||
}
|
||||
}
|
||||
this.updateParams_();
|
||||
Blockly.Procedures.mutateCallers(this);
|
||||
|
||||
// Show or hide the statement input.
|
||||
this.setStatements_(xmlElement.getAttribute('statements') !== 'false');
|
||||
},
|
||||
/**
|
||||
* Populate the mutator's dialog with this block's components.
|
||||
* @param {!Blockly.Workspace} workspace Mutator's workspace.
|
||||
* @return {!Blockly.Block} Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
decompose: function(workspace) {
|
||||
var containerBlock = workspace.newBlock('procedures_mutatorcontainer');
|
||||
containerBlock.initSvg();
|
||||
|
||||
// Check/uncheck the allow statement box.
|
||||
if (this.getInput('RETURN')) {
|
||||
containerBlock.setFieldValue(
|
||||
this.hasStatements_ ? 'TRUE' : 'FALSE', 'STATEMENTS');
|
||||
} else {
|
||||
containerBlock.getInput('STATEMENT_INPUT').setVisible(false);
|
||||
}
|
||||
|
||||
// Parameter list.
|
||||
var connection = containerBlock.getInput('STACK').connection;
|
||||
for (var i = 0; i < this.arguments_.length; i++) {
|
||||
var paramBlock = workspace.newBlock('procedures_mutatorarg');
|
||||
paramBlock.initSvg();
|
||||
paramBlock.setFieldValue(this.arguments_[i], 'NAME');
|
||||
// Store the old location.
|
||||
paramBlock.oldLocation = i;
|
||||
connection.connect(paramBlock.previousConnection);
|
||||
connection = paramBlock.nextConnection;
|
||||
}
|
||||
// Initialize procedure's callers with blank IDs.
|
||||
Blockly.Procedures.mutateCallers(this);
|
||||
return containerBlock;
|
||||
},
|
||||
/**
|
||||
* Reconfigure this block based on the mutator dialog's components.
|
||||
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
compose: function(containerBlock) {
|
||||
// Parameter list.
|
||||
this.arguments_ = [];
|
||||
this.paramIds_ = [];
|
||||
this.argumentVarModels_ = [];
|
||||
var paramBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
while (paramBlock) {
|
||||
var varName = paramBlock.getFieldValue('NAME');
|
||||
this.arguments_.push(varName);
|
||||
var variable = this.workspace.getVariable(varName, '');
|
||||
this.argumentVarModels_.push(variable);
|
||||
this.paramIds_.push(paramBlock.id);
|
||||
paramBlock = paramBlock.nextConnection &&
|
||||
paramBlock.nextConnection.targetBlock();
|
||||
}
|
||||
this.updateParams_();
|
||||
Blockly.Procedures.mutateCallers(this);
|
||||
|
||||
// Show/hide the statement input.
|
||||
var hasStatements = containerBlock.getFieldValue('STATEMENTS');
|
||||
if (hasStatements !== null) {
|
||||
hasStatements = hasStatements == 'TRUE';
|
||||
if (this.hasStatements_ != hasStatements) {
|
||||
if (hasStatements) {
|
||||
this.setStatements_(true);
|
||||
// Restore the stack, if one was saved.
|
||||
Blockly.Mutator.reconnect(this.statementConnection_, this, 'STACK');
|
||||
this.statementConnection_ = null;
|
||||
} else {
|
||||
// Save the stack, then disconnect it.
|
||||
var stackConnection = this.getInput('STACK').connection;
|
||||
this.statementConnection_ = stackConnection.targetConnection;
|
||||
if (this.statementConnection_) {
|
||||
var stackBlock = stackConnection.targetBlock();
|
||||
stackBlock.unplug();
|
||||
stackBlock.bumpNeighbours_();
|
||||
}
|
||||
this.setStatements_(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Return the signature of this procedure definition.
|
||||
* @return {!Array} Tuple containing three elements:
|
||||
* - the name of the defined procedure,
|
||||
* - a list of all its arguments,
|
||||
* - that it DOES NOT have a return value.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
getProcedureDef: function() {
|
||||
return [this.getFieldValue('NAME'), this.arguments_, false];
|
||||
},
|
||||
/**
|
||||
* Return all variables referenced by this block.
|
||||
* @return {!Array.<string>} List of variable names.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
getVars: function() {
|
||||
return this.arguments_;
|
||||
},
|
||||
/**
|
||||
* Return all variables referenced by this block.
|
||||
* @return {!Array.<!Blockly.VariableModel>} List of variable models.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
getVarModels: function() {
|
||||
return this.argumentVarModels_;
|
||||
},
|
||||
/**
|
||||
* Notification that a variable is renaming.
|
||||
* If the ID matches one of this block's variables, rename it.
|
||||
* @param {string} oldId ID of variable to rename.
|
||||
* @param {string} newId ID of new variable. May be the same as oldId, but
|
||||
* with an updated name. Guaranteed to be the same type as the old
|
||||
* variable.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
renameVarById: function(oldId, newId) {
|
||||
var oldVariable = this.workspace.getVariableById(oldId);
|
||||
if (oldVariable.type != '') {
|
||||
// Procedure arguments always have the empty type.
|
||||
return;
|
||||
}
|
||||
var oldName = oldVariable.name;
|
||||
var newVar = this.workspace.getVariableById(newId);
|
||||
|
||||
var change = false;
|
||||
for (var i = 0; i < this.argumentVarModels_.length; i++) {
|
||||
if (this.argumentVarModels_[i].getId() == oldId) {
|
||||
this.arguments_[i] = newVar.name;
|
||||
this.argumentVarModels_[i] = newVar;
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
if (change) {
|
||||
this.displayRenamedVar_(oldName, newVar.name);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Notification that a variable is renaming but keeping the same ID. If the
|
||||
* variable is in use on this block, rerender to show the new name.
|
||||
* @param {!Blockly.VariableModel} variable The variable being renamed.
|
||||
* @package
|
||||
*/
|
||||
updateVarName: function(variable) {
|
||||
var newName = variable.name;
|
||||
var change = false;
|
||||
for (var i = 0; i < this.argumentVarModels_.length; i++) {
|
||||
if (this.argumentVarModels_[i].getId() == variable.getId()) {
|
||||
var oldName = this.arguments_[i];
|
||||
this.arguments_[i] = newName;
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
if (change) {
|
||||
this.displayRenamedVar_(oldName, newName);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Update the display to reflect a newly renamed argument.
|
||||
* @param {string} oldName The old display name of the argument.
|
||||
* @param {string} newName The new display name of the argument.
|
||||
* @private
|
||||
*/
|
||||
displayRenamedVar_: function(oldName, newName) {
|
||||
this.updateParams_();
|
||||
// Update the mutator's variables if the mutator is open.
|
||||
if (this.mutator.isVisible()) {
|
||||
var blocks = this.mutator.workspace_.getAllBlocks();
|
||||
for (var i = 0, block; block = blocks[i]; i++) {
|
||||
if (block.type == 'procedures_mutatorarg' &&
|
||||
Blockly.Names.equals(oldName, block.getFieldValue('NAME'))) {
|
||||
block.setFieldValue(newName, 'NAME');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Add custom menu options to this block's context menu.
|
||||
* @param {!Array} options List of menu options to add to.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
customContextMenu: function(options) {
|
||||
if (this.isInFlyout){
|
||||
return;
|
||||
}
|
||||
// Add option to create caller.
|
||||
var option = {enabled: true};
|
||||
var name = this.getFieldValue('NAME');
|
||||
option.text = Blockly.Msg.PROCEDURES_CREATE_DO.replace('%1', name);
|
||||
var xmlMutation = goog.dom.createDom('mutation');
|
||||
xmlMutation.setAttribute('name', name);
|
||||
for (var i = 0; i < this.arguments_.length; i++) {
|
||||
var xmlArg = goog.dom.createDom('arg');
|
||||
xmlArg.setAttribute('name', this.arguments_[i]);
|
||||
xmlMutation.appendChild(xmlArg);
|
||||
}
|
||||
var xmlBlock = goog.dom.createDom('block', null, xmlMutation);
|
||||
xmlBlock.setAttribute('type', this.callType_);
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
|
||||
// Add options to create getters for each parameter.
|
||||
if (!this.isCollapsed()) {
|
||||
for (var i = 0; i < this.argumentVarModels_.length; i++) {
|
||||
var option = {enabled: true};
|
||||
var argVar = this.argumentVarModels_[i];
|
||||
var name = argVar.name;
|
||||
option.text = Blockly.Msg.VARIABLES_SET_CREATE_GET.replace('%1', name);
|
||||
|
||||
var xmlField = Blockly.Variables.generateVariableFieldDom(argVar);
|
||||
var xmlBlock = goog.dom.createDom('block', null, xmlField);
|
||||
xmlBlock.setAttribute('type', 'variables_get');
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
}
|
||||
}
|
||||
},
|
||||
callType_: 'procedures_callnoreturn'
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_defreturn'] = {
|
||||
/**
|
||||
* Block for defining a procedure with a return value.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
var nameField = new Blockly.FieldTextInput('',
|
||||
Blockly.Procedures.rename);
|
||||
nameField.setSpellcheck(false);
|
||||
this.appendDummyInput()
|
||||
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_TITLE)
|
||||
.appendField(nameField, 'NAME')
|
||||
.appendField('', 'PARAMS');
|
||||
this.appendValueInput('RETURN')
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
this.setMutator(new Blockly.Mutator(['procedures_mutatorarg']));
|
||||
if ((this.workspace.options.comments ||
|
||||
(this.workspace.options.parentWorkspace &&
|
||||
this.workspace.options.parentWorkspace.options.comments)) &&
|
||||
Blockly.Msg.PROCEDURES_DEFRETURN_COMMENT) {
|
||||
this.setCommentText(Blockly.Msg.PROCEDURES_DEFRETURN_COMMENT);
|
||||
}
|
||||
this.setColour(Blockly.Msg.PROCEDURES_HUE);
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_DEFRETURN_TOOLTIP);
|
||||
this.setHelpUrl(Blockly.Msg.PROCEDURES_DEFRETURN_HELPURL);
|
||||
this.arguments_ = [];
|
||||
this.argumentVarModels_ = [];
|
||||
this.setStatements_(true);
|
||||
this.statementConnection_ = null;
|
||||
},
|
||||
setStatements_: Blockly.Blocks['procedures_defnoreturn'].setStatements_,
|
||||
updateParams_: Blockly.Blocks['procedures_defnoreturn'].updateParams_,
|
||||
mutationToDom: Blockly.Blocks['procedures_defnoreturn'].mutationToDom,
|
||||
domToMutation: Blockly.Blocks['procedures_defnoreturn'].domToMutation,
|
||||
decompose: Blockly.Blocks['procedures_defnoreturn'].decompose,
|
||||
compose: Blockly.Blocks['procedures_defnoreturn'].compose,
|
||||
/**
|
||||
* Return the signature of this procedure definition.
|
||||
* @return {!Array} Tuple containing three elements:
|
||||
* - the name of the defined procedure,
|
||||
* - a list of all its arguments,
|
||||
* - that it DOES have a return value.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
getProcedureDef: function() {
|
||||
return [this.getFieldValue('NAME'), this.arguments_, true];
|
||||
},
|
||||
getVars: Blockly.Blocks['procedures_defnoreturn'].getVars,
|
||||
getVarModels: Blockly.Blocks['procedures_defnoreturn'].getVarModels,
|
||||
renameVarById: Blockly.Blocks['procedures_defnoreturn'].renameVarById,
|
||||
updateVarName: Blockly.Blocks['procedures_defnoreturn'].updateVarName,
|
||||
displayRenamedVar_: Blockly.Blocks['procedures_defnoreturn'].displayRenamedVar_,
|
||||
customContextMenu: Blockly.Blocks['procedures_defnoreturn'].customContextMenu,
|
||||
callType_: 'procedures_callreturn'
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_mutatorcontainer'] = {
|
||||
/**
|
||||
* Mutator block for procedure container.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.appendDummyInput()
|
||||
.appendField(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TITLE);
|
||||
this.appendStatementInput('STACK');
|
||||
this.appendDummyInput('STATEMENT_INPUT')
|
||||
.appendField(Blockly.Msg.PROCEDURES_ALLOW_STATEMENTS)
|
||||
.appendField(new Blockly.FieldCheckbox('TRUE'), 'STATEMENTS');
|
||||
this.setColour(Blockly.Msg.PROCEDURES_HUE);
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORCONTAINER_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_mutatorarg'] = {
|
||||
/**
|
||||
* Mutator block for procedure argument.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
var field = new Blockly.FieldTextInput('x', this.validator_);
|
||||
// Hack: override showEditor to do just a little bit more work.
|
||||
// We don't have a good place to hook into the start of a text edit.
|
||||
field.oldShowEditorFn_ = field.showEditor_;
|
||||
var newShowEditorFn = function() {
|
||||
this.createdVariables_ = [];
|
||||
this.oldShowEditorFn_();
|
||||
};
|
||||
field.showEditor_ = newShowEditorFn;
|
||||
|
||||
this.appendDummyInput()
|
||||
.appendField(Blockly.Msg.PROCEDURES_MUTATORARG_TITLE)
|
||||
.appendField(field, 'NAME');
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setColour(Blockly.Msg.PROCEDURES_HUE);
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_MUTATORARG_TOOLTIP);
|
||||
this.contextMenu = false;
|
||||
|
||||
// Create the default variable when we drag the block in from the flyout.
|
||||
// Have to do this after installing the field on the block.
|
||||
field.onFinishEditing_ = this.deleteIntermediateVars_;
|
||||
// Create an empty list so onFinishEditing_ has something to look at, even
|
||||
// though the editor was never opened.
|
||||
field.createdVariables_ = [];
|
||||
field.onFinishEditing_('x');
|
||||
},
|
||||
/**
|
||||
* Obtain a valid name for the procedure argument. Create a variable if
|
||||
* necessary.
|
||||
* Merge runs of whitespace. Strip leading and trailing whitespace.
|
||||
* Beyond this, all names are legal.
|
||||
* @param {string} varName User-supplied name.
|
||||
* @return {?string} Valid name, or null if a name was not specified.
|
||||
* @private
|
||||
* @this Blockly.FieldTextInput
|
||||
*/
|
||||
validator_: function(varName) {
|
||||
var outerWs = Blockly.Mutator.findParentWs(this.sourceBlock_.workspace);
|
||||
varName = varName.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, '');
|
||||
if (!varName) {
|
||||
return null;
|
||||
}
|
||||
var model = outerWs.getVariable(varName, '');
|
||||
if (model && model.name != varName) {
|
||||
// Rename the variable (case change)
|
||||
outerWs.renameVarById(model.getId(), varName);
|
||||
}
|
||||
if (!model) {
|
||||
model = outerWs.createVariable(varName, '');
|
||||
if (model && this.createdVariables_) {
|
||||
this.createdVariables_.push(model);
|
||||
}
|
||||
}
|
||||
return varName;
|
||||
},
|
||||
/**
|
||||
* Called when focusing away from the text field.
|
||||
* Deletes all variables that were created as the user typed their intended
|
||||
* variable name.
|
||||
* @param {string} newText The new variable name.
|
||||
* @private
|
||||
* @this Blockly.FieldTextInput
|
||||
*/
|
||||
deleteIntermediateVars_: function(newText) {
|
||||
var outerWs = Blockly.Mutator.findParentWs(this.sourceBlock_.workspace);
|
||||
if (!outerWs) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < this.createdVariables_.length; i++) {
|
||||
var model = this.createdVariables_[i];
|
||||
if (model.name != newText) {
|
||||
outerWs.deleteVariableById(model.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_callnoreturn'] = {
|
||||
/**
|
||||
* Block for calling a procedure with no return value.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.appendDummyInput('TOPROW')
|
||||
.appendField(this.id, 'NAME');
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setColour(Blockly.Msg.PROCEDURES_HUE);
|
||||
// Tooltip is set in renameProcedure.
|
||||
this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLNORETURN_HELPURL);
|
||||
this.arguments_ = [];
|
||||
this.argumentVarModels_ = [];
|
||||
this.quarkConnections_ = {};
|
||||
this.quarkIds_ = null;
|
||||
},
|
||||
/**
|
||||
* Returns the name of the procedure this block calls.
|
||||
* @return {string} Procedure name.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
getProcedureCall: function() {
|
||||
// The NAME field is guaranteed to exist, null will never be returned.
|
||||
return /** @type {string} */ (this.getFieldValue('NAME'));
|
||||
},
|
||||
/**
|
||||
* Notification that a procedure is renaming.
|
||||
* If the name matches this block's procedure, rename it.
|
||||
* @param {string} oldName Previous name of procedure.
|
||||
* @param {string} newName Renamed procedure.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
renameProcedure: function(oldName, newName) {
|
||||
if (Blockly.Names.equals(oldName, this.getProcedureCall())) {
|
||||
this.setFieldValue(newName, 'NAME');
|
||||
var baseMsg = this.outputConnection ?
|
||||
Blockly.Msg.PROCEDURES_CALLRETURN_TOOLTIP :
|
||||
Blockly.Msg.PROCEDURES_CALLNORETURN_TOOLTIP;
|
||||
this.setTooltip(baseMsg.replace('%1', newName));
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Notification that the procedure's parameters have changed.
|
||||
* @param {!Array.<string>} paramNames New param names, e.g. ['x', 'y', 'z'].
|
||||
* @param {!Array.<string>} paramIds IDs of params (consistent for each
|
||||
* parameter through the life of a mutator, regardless of param renaming),
|
||||
* e.g. ['piua', 'f8b_', 'oi.o'].
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
setProcedureParameters_: function(paramNames, paramIds) {
|
||||
// Data structures:
|
||||
// this.arguments = ['x', 'y']
|
||||
// Existing param names.
|
||||
// this.quarkConnections_ {piua: null, f8b_: Blockly.Connection}
|
||||
// Look-up of paramIds to connections plugged into the call block.
|
||||
// this.quarkIds_ = ['piua', 'f8b_']
|
||||
// Existing param IDs.
|
||||
// Note that quarkConnections_ may include IDs that no longer exist, but
|
||||
// which might reappear if a param is reattached in the mutator.
|
||||
var defBlock = Blockly.Procedures.getDefinition(this.getProcedureCall(),
|
||||
this.workspace);
|
||||
var mutatorOpen = defBlock && defBlock.mutator &&
|
||||
defBlock.mutator.isVisible();
|
||||
if (!mutatorOpen) {
|
||||
this.quarkConnections_ = {};
|
||||
this.quarkIds_ = null;
|
||||
}
|
||||
if (!paramIds) {
|
||||
// Reset the quarks (a mutator is about to open).
|
||||
return;
|
||||
}
|
||||
if (goog.array.equals(this.arguments_, paramNames)) {
|
||||
// No change.
|
||||
this.quarkIds_ = paramIds;
|
||||
return;
|
||||
}
|
||||
if (paramIds.length != paramNames.length) {
|
||||
throw 'Error: paramNames and paramIds must be the same length.';
|
||||
}
|
||||
this.setCollapsed(false);
|
||||
if (!this.quarkIds_) {
|
||||
// Initialize tracking for this block.
|
||||
this.quarkConnections_ = {};
|
||||
if (paramNames.join('\n') == this.arguments_.join('\n')) {
|
||||
// No change to the parameters, allow quarkConnections_ to be
|
||||
// populated with the existing connections.
|
||||
this.quarkIds_ = paramIds;
|
||||
} else {
|
||||
this.quarkIds_ = [];
|
||||
}
|
||||
}
|
||||
// Switch off rendering while the block is rebuilt.
|
||||
var savedRendered = this.rendered;
|
||||
this.rendered = false;
|
||||
// Update the quarkConnections_ with existing connections.
|
||||
for (var i = 0; i < this.arguments_.length; i++) {
|
||||
var input = this.getInput('ARG' + i);
|
||||
if (input) {
|
||||
var connection = input.connection.targetConnection;
|
||||
this.quarkConnections_[this.quarkIds_[i]] = connection;
|
||||
if (mutatorOpen && connection &&
|
||||
paramIds.indexOf(this.quarkIds_[i]) == -1) {
|
||||
// This connection should no longer be attached to this block.
|
||||
connection.disconnect();
|
||||
connection.getSourceBlock().bumpNeighbours_();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Rebuild the block's arguments.
|
||||
this.arguments_ = [].concat(paramNames);
|
||||
// And rebuild the argument model list.
|
||||
this.argumentVarModels_ = [];
|
||||
for (var i = 0; i < this.arguments_.length; i++) {
|
||||
var variable = Blockly.Variables.getOrCreateVariablePackage(
|
||||
this.workspace, null, this.arguments_[i], '');
|
||||
this.argumentVarModels_.push(variable);
|
||||
}
|
||||
|
||||
this.updateShape_();
|
||||
this.quarkIds_ = paramIds;
|
||||
// Reconnect any child blocks.
|
||||
if (this.quarkIds_) {
|
||||
for (var i = 0; i < this.arguments_.length; i++) {
|
||||
var quarkId = this.quarkIds_[i];
|
||||
if (quarkId in this.quarkConnections_) {
|
||||
var connection = this.quarkConnections_[quarkId];
|
||||
if (!Blockly.Mutator.reconnect(connection, this, 'ARG' + i)) {
|
||||
// Block no longer exists or has been attached elsewhere.
|
||||
delete this.quarkConnections_[quarkId];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Restore rendering and show the changes.
|
||||
this.rendered = savedRendered;
|
||||
if (this.rendered) {
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Modify this block to have the correct number of arguments.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateShape_: function() {
|
||||
for (var i = 0; i < this.arguments_.length; i++) {
|
||||
var field = this.getField('ARGNAME' + i);
|
||||
if (field) {
|
||||
// Ensure argument name is up to date.
|
||||
// The argument name field is deterministic based on the mutation,
|
||||
// no need to fire a change event.
|
||||
Blockly.Events.disable();
|
||||
try {
|
||||
field.setValue(this.arguments_[i]);
|
||||
} finally {
|
||||
Blockly.Events.enable();
|
||||
}
|
||||
} else {
|
||||
// Add new input.
|
||||
field = new Blockly.FieldLabel(this.arguments_[i]);
|
||||
var input = this.appendValueInput('ARG' + i)
|
||||
.setAlign(Blockly.ALIGN_RIGHT)
|
||||
.appendField(field, 'ARGNAME' + i);
|
||||
input.init();
|
||||
}
|
||||
}
|
||||
// Remove deleted inputs.
|
||||
while (this.getInput('ARG' + i)) {
|
||||
this.removeInput('ARG' + i);
|
||||
i++;
|
||||
}
|
||||
// Add 'with:' if there are parameters, remove otherwise.
|
||||
var topRow = this.getInput('TOPROW');
|
||||
if (topRow) {
|
||||
if (this.arguments_.length) {
|
||||
if (!this.getField('WITH')) {
|
||||
topRow.appendField(Blockly.Msg.PROCEDURES_CALL_BEFORE_PARAMS, 'WITH');
|
||||
topRow.init();
|
||||
}
|
||||
} else {
|
||||
if (this.getField('WITH')) {
|
||||
topRow.removeField('WITH');
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Create XML to represent the (non-editable) name and arguments.
|
||||
* @return {!Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('name', this.getProcedureCall());
|
||||
for (var i = 0; i < this.arguments_.length; i++) {
|
||||
var parameter = document.createElement('arg');
|
||||
parameter.setAttribute('name', this.arguments_[i]);
|
||||
container.appendChild(parameter);
|
||||
}
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the (non-editable) name and parameters.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
var name = xmlElement.getAttribute('name');
|
||||
this.renameProcedure(this.getProcedureCall(), name);
|
||||
var args = [];
|
||||
var paramIds = [];
|
||||
for (var i = 0, childNode; childNode = xmlElement.childNodes[i]; i++) {
|
||||
if (childNode.nodeName.toLowerCase() == 'arg') {
|
||||
args.push(childNode.getAttribute('name'));
|
||||
paramIds.push(childNode.getAttribute('paramId'));
|
||||
}
|
||||
}
|
||||
this.setProcedureParameters_(args, paramIds);
|
||||
},
|
||||
/**
|
||||
* Return all variables referenced by this block.
|
||||
* @return {!Array.<!Blockly.VariableModel>} List of variable models.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
getVarModels: function() {
|
||||
return this.argumentVarModels_;
|
||||
},
|
||||
/**
|
||||
* Procedure calls cannot exist without the corresponding procedure
|
||||
* definition. Enforce this link whenever an event is fired.
|
||||
* @param {!Blockly.Events.Abstract} event Change event.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
onchange: function(event) {
|
||||
if (!this.workspace || this.workspace.isFlyout) {
|
||||
// Block is deleted or is in a flyout.
|
||||
return;
|
||||
}
|
||||
if (event.type == Blockly.Events.BLOCK_CREATE &&
|
||||
event.ids.indexOf(this.id) != -1) {
|
||||
// Look for the case where a procedure call was created (usually through
|
||||
// paste) and there is no matching definition. In this case, create
|
||||
// an empty definition block with the correct signature.
|
||||
var name = this.getProcedureCall();
|
||||
var def = Blockly.Procedures.getDefinition(name, this.workspace);
|
||||
if (def && (def.type != this.defType_ ||
|
||||
JSON.stringify(def.arguments_) != JSON.stringify(this.arguments_))) {
|
||||
// The signatures don't match.
|
||||
def = null;
|
||||
}
|
||||
if (!def) {
|
||||
Blockly.Events.setGroup(event.group);
|
||||
/**
|
||||
* Create matching definition block.
|
||||
* <xml>
|
||||
* <block type="procedures_defreturn" x="10" y="20">
|
||||
* <mutation name="test">
|
||||
* <arg name="x"></arg>
|
||||
* </mutation>
|
||||
* <field name="NAME">test</field>
|
||||
* </block>
|
||||
* </xml>
|
||||
*/
|
||||
var xml = goog.dom.createDom('xml');
|
||||
var block = goog.dom.createDom('block');
|
||||
block.setAttribute('type', this.defType_);
|
||||
var xy = this.getRelativeToSurfaceXY();
|
||||
var x = xy.x + Blockly.SNAP_RADIUS * (this.RTL ? -1 : 1);
|
||||
var y = xy.y + Blockly.SNAP_RADIUS * 2;
|
||||
block.setAttribute('x', x);
|
||||
block.setAttribute('y', y);
|
||||
var mutation = this.mutationToDom();
|
||||
block.appendChild(mutation);
|
||||
var field = goog.dom.createDom('field');
|
||||
field.setAttribute('name', 'NAME');
|
||||
field.appendChild(document.createTextNode(this.getProcedureCall()));
|
||||
block.appendChild(field);
|
||||
xml.appendChild(block);
|
||||
Blockly.Xml.domToWorkspace(xml, this.workspace);
|
||||
Blockly.Events.setGroup(false);
|
||||
}
|
||||
} else if (event.type == Blockly.Events.BLOCK_DELETE) {
|
||||
// Look for the case where a procedure definition has been deleted,
|
||||
// leaving this block (a procedure call) orphaned. In this case, delete
|
||||
// the orphan.
|
||||
var name = this.getProcedureCall();
|
||||
var def = Blockly.Procedures.getDefinition(name, this.workspace);
|
||||
if (!def) {
|
||||
Blockly.Events.setGroup(event.group);
|
||||
this.dispose(true, false);
|
||||
Blockly.Events.setGroup(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Add menu option to find the definition block for this call.
|
||||
* @param {!Array} options List of menu options to add to.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
customContextMenu: function(options) {
|
||||
var option = {enabled: true};
|
||||
option.text = Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF;
|
||||
var name = this.getProcedureCall();
|
||||
var workspace = this.workspace;
|
||||
option.callback = function() {
|
||||
var def = Blockly.Procedures.getDefinition(name, workspace);
|
||||
if (def) {
|
||||
workspace.centerOnBlock(def.id);
|
||||
def.select();
|
||||
}
|
||||
};
|
||||
options.push(option);
|
||||
},
|
||||
defType_: 'procedures_defnoreturn'
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_callreturn'] = {
|
||||
/**
|
||||
* Block for calling a procedure with a return value.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.appendDummyInput('TOPROW')
|
||||
.appendField('', 'NAME');
|
||||
this.setOutput(true);
|
||||
this.setColour(Blockly.Msg.PROCEDURES_HUE);
|
||||
// Tooltip is set in domToMutation.
|
||||
this.setHelpUrl(Blockly.Msg.PROCEDURES_CALLRETURN_HELPURL);
|
||||
this.arguments_ = [];
|
||||
this.quarkConnections_ = {};
|
||||
this.quarkIds_ = null;
|
||||
},
|
||||
getProcedureCall: Blockly.Blocks['procedures_callnoreturn'].getProcedureCall,
|
||||
renameProcedure: Blockly.Blocks['procedures_callnoreturn'].renameProcedure,
|
||||
setProcedureParameters_:
|
||||
Blockly.Blocks['procedures_callnoreturn'].setProcedureParameters_,
|
||||
updateShape_: Blockly.Blocks['procedures_callnoreturn'].updateShape_,
|
||||
mutationToDom: Blockly.Blocks['procedures_callnoreturn'].mutationToDom,
|
||||
domToMutation: Blockly.Blocks['procedures_callnoreturn'].domToMutation,
|
||||
getVarModels: Blockly.Blocks['procedures_callnoreturn'].getVarModels,
|
||||
onchange: Blockly.Blocks['procedures_callnoreturn'].onchange,
|
||||
customContextMenu:
|
||||
Blockly.Blocks['procedures_callnoreturn'].customContextMenu,
|
||||
defType_: 'procedures_defreturn'
|
||||
};
|
||||
|
||||
Blockly.Blocks['procedures_ifreturn'] = {
|
||||
/**
|
||||
* Block for conditionally returning a value from a procedure.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.appendValueInput('CONDITION')
|
||||
.setCheck('Boolean')
|
||||
.appendField(Blockly.Msg.CONTROLS_IF_MSG_IF);
|
||||
this.appendValueInput('VALUE')
|
||||
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
this.setInputsInline(true);
|
||||
this.setPreviousStatement(true);
|
||||
this.setNextStatement(true);
|
||||
this.setColour(Blockly.Msg.PROCEDURES_HUE);
|
||||
this.setTooltip(Blockly.Msg.PROCEDURES_IFRETURN_TOOLTIP);
|
||||
this.setHelpUrl(Blockly.Msg.PROCEDURES_IFRETURN_HELPURL);
|
||||
this.hasReturnValue_ = true;
|
||||
},
|
||||
/**
|
||||
* Create XML to represent whether this block has a return value.
|
||||
* @return {!Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('value', Number(this.hasReturnValue_));
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore whether this block has a return value.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
var value = xmlElement.getAttribute('value');
|
||||
this.hasReturnValue_ = (value == 1);
|
||||
if (!this.hasReturnValue_) {
|
||||
this.removeInput('VALUE');
|
||||
this.appendDummyInput('VALUE')
|
||||
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Called whenever anything on the workspace changes.
|
||||
* Add warning if this flow block is not nested inside a loop.
|
||||
* @param {!Blockly.Events.Abstract} e Change event.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
onchange: function(/* e */) {
|
||||
if (!this.workspace.isDragging || this.workspace.isDragging()) {
|
||||
return; // Don't change state at the start of a drag.
|
||||
}
|
||||
var legal = false;
|
||||
// Is the block nested in a procedure?
|
||||
var block = this;
|
||||
do {
|
||||
if (this.FUNCTION_TYPES.indexOf(block.type) != -1) {
|
||||
legal = true;
|
||||
break;
|
||||
}
|
||||
block = block.getSurroundParent();
|
||||
} while (block);
|
||||
if (legal) {
|
||||
// If needed, toggle whether this block has a return value.
|
||||
if (block.type == 'procedures_defnoreturn' && this.hasReturnValue_) {
|
||||
this.removeInput('VALUE');
|
||||
this.appendDummyInput('VALUE')
|
||||
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
this.hasReturnValue_ = false;
|
||||
} else if (block.type == 'procedures_defreturn' &&
|
||||
!this.hasReturnValue_) {
|
||||
this.removeInput('VALUE');
|
||||
this.appendValueInput('VALUE')
|
||||
.appendField(Blockly.Msg.PROCEDURES_DEFRETURN_RETURN);
|
||||
this.hasReturnValue_ = true;
|
||||
}
|
||||
this.setWarningText(null);
|
||||
if (!this.isInFlyout) {
|
||||
this.setDisabled(false);
|
||||
}
|
||||
} else {
|
||||
this.setWarningText(Blockly.Msg.PROCEDURES_IFRETURN_WARNING);
|
||||
if (!this.isInFlyout && !this.getInheritedDisabled()) {
|
||||
this.setDisabled(true);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* List of block types that are functions and thus do not need warnings.
|
||||
* To add a new function type add this to your code:
|
||||
* Blockly.Blocks['procedures_ifreturn'].FUNCTION_TYPES.push('custom_func');
|
||||
*/
|
||||
FUNCTION_TYPES: ['procedures_defnoreturn', 'procedures_defreturn']
|
||||
};
|
||||
904
node_modules/node-blockly/blockly/blocks/text.js
generated
vendored
Normal file
904
node_modules/node-blockly/blockly/blocks/text.js
generated
vendored
Normal file
@@ -0,0 +1,904 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* 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 Text blocks for Blockly.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.texts'); // Deprecated
|
||||
goog.provide('Blockly.Constants.Text');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly');
|
||||
|
||||
|
||||
/**
|
||||
* Unused constant for the common HSV hue for all blocks in this category.
|
||||
* @deprecated Use Blockly.Msg.TEXTS_HUE. (2018 April 5)
|
||||
*/
|
||||
Blockly.Constants.Text.HUE = 160;
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
// Block for text value
|
||||
{
|
||||
"type": "text",
|
||||
"message0": "%1",
|
||||
"args0": [{
|
||||
"type": "field_input",
|
||||
"name": "TEXT",
|
||||
"text": ""
|
||||
}],
|
||||
"output": "String",
|
||||
"colour": "%{BKY_TEXTS_HUE}",
|
||||
"helpUrl": "%{BKY_TEXT_TEXT_HELPURL}",
|
||||
"tooltip": "%{BKY_TEXT_TEXT_TOOLTIP}",
|
||||
"extensions": [
|
||||
"text_quotes",
|
||||
"parent_tooltip_when_inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text_join",
|
||||
"message0": "",
|
||||
"output": "String",
|
||||
"colour": "%{BKY_TEXTS_HUE}",
|
||||
"helpUrl": "%{BKY_TEXT_JOIN_HELPURL}",
|
||||
"tooltip": "%{BKY_TEXT_JOIN_TOOLTIP}",
|
||||
"mutator": "text_join_mutator"
|
||||
|
||||
},
|
||||
{
|
||||
"type": "text_create_join_container",
|
||||
"message0": "%{BKY_TEXT_CREATE_JOIN_TITLE_JOIN} %1 %2",
|
||||
"args0": [{
|
||||
"type": "input_dummy"
|
||||
},
|
||||
{
|
||||
"type": "input_statement",
|
||||
"name": "STACK"
|
||||
}],
|
||||
"colour": "%{BKY_TEXTS_HUE}",
|
||||
"tooltip": "%{BKY_TEXT_CREATE_JOIN_TOOLTIP}",
|
||||
"enableContextMenu": false
|
||||
},
|
||||
{
|
||||
"type": "text_create_join_item",
|
||||
"message0": "%{BKY_TEXT_CREATE_JOIN_ITEM_TITLE_ITEM}",
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_TEXTS_HUE}",
|
||||
"tooltip": "%{BKY_TEXT_CREATE_JOIN_ITEM_TOOLTIP}",
|
||||
"enableContextMenu": false
|
||||
},
|
||||
{
|
||||
"type": "text_append",
|
||||
"message0": "%{BKY_TEXT_APPEND_TITLE}",
|
||||
"args0": [{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
"variable": "%{BKY_TEXT_APPEND_VARIABLE}"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TEXT"
|
||||
}],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_TEXTS_HUE}",
|
||||
"extensions": [
|
||||
"text_append_tooltip"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text_length",
|
||||
"message0": "%{BKY_TEXT_LENGTH_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE",
|
||||
"check": ['String', 'Array']
|
||||
}
|
||||
],
|
||||
"output": 'Number',
|
||||
"colour": "%{BKY_TEXTS_HUE}",
|
||||
"tooltip": "%{BKY_TEXT_LENGTH_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_TEXT_LENGTH_HELPURL}"
|
||||
},
|
||||
{
|
||||
"type": "text_isEmpty",
|
||||
"message0": "%{BKY_TEXT_ISEMPTY_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE",
|
||||
"check": ['String', 'Array']
|
||||
}
|
||||
],
|
||||
"output": 'Boolean',
|
||||
"colour": "%{BKY_TEXTS_HUE}",
|
||||
"tooltip": "%{BKY_TEXT_ISEMPTY_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_TEXT_ISEMPTY_HELPURL}"
|
||||
},
|
||||
{
|
||||
"type": "text_indexOf",
|
||||
"message0": "%{BKY_TEXT_INDEXOF_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE",
|
||||
"check": "String"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "END",
|
||||
"options": [
|
||||
[
|
||||
"%{BKY_TEXT_INDEXOF_OPERATOR_FIRST}",
|
||||
"FIRST"
|
||||
],
|
||||
[
|
||||
"%{BKY_TEXT_INDEXOF_OPERATOR_LAST}",
|
||||
"LAST"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FIND",
|
||||
"check": "String"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"colour": "%{BKY_TEXTS_HUE}",
|
||||
"helpUrl": "%{BKY_TEXT_INDEXOF_HELPURL}",
|
||||
"inputsInline": true,
|
||||
"extensions": [
|
||||
"text_indexOf_tooltip"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text_charAt",
|
||||
"message0": "%{BKY_TEXT_CHARAT_TITLE}", // "in text %1 %2"
|
||||
"args0": [
|
||||
{
|
||||
"type":"input_value",
|
||||
"name": "VALUE",
|
||||
"check": "String"
|
||||
},
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "WHERE",
|
||||
"options": [
|
||||
["%{BKY_TEXT_CHARAT_FROM_START}", "FROM_START"],
|
||||
["%{BKY_TEXT_CHARAT_FROM_END}", "FROM_END"],
|
||||
["%{BKY_TEXT_CHARAT_FIRST}", "FIRST"],
|
||||
["%{BKY_TEXT_CHARAT_LAST}", "LAST"],
|
||||
["%{BKY_TEXT_CHARAT_RANDOM}", "RANDOM"]
|
||||
]
|
||||
}
|
||||
],
|
||||
"output": "String",
|
||||
"colour": "%{BKY_TEXTS_HUE}",
|
||||
"helpUrl": "%{BKY_TEXT_CHARAT_HELPURL}",
|
||||
"inputsInline": true,
|
||||
"mutator": "text_charAt_mutator"
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
|
||||
Blockly.Blocks['text_getSubstring'] = {
|
||||
/**
|
||||
* Block for getting substring.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this['WHERE_OPTIONS_1'] = [
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_START_FIRST, 'FIRST']
|
||||
];
|
||||
this['WHERE_OPTIONS_2'] = [
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_START, 'FROM_START'],
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_END, 'FROM_END'],
|
||||
[Blockly.Msg.TEXT_GET_SUBSTRING_END_LAST, 'LAST']
|
||||
];
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_GET_SUBSTRING_HELPURL);
|
||||
this.setColour(Blockly.Msg.TEXTS_HUE);
|
||||
this.appendValueInput('STRING')
|
||||
.setCheck('String')
|
||||
.appendField(Blockly.Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT);
|
||||
this.appendDummyInput('AT1');
|
||||
this.appendDummyInput('AT2');
|
||||
if (Blockly.Msg.TEXT_GET_SUBSTRING_TAIL) {
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendField(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL);
|
||||
}
|
||||
this.setInputsInline(true);
|
||||
this.setOutput(true, 'String');
|
||||
this.updateAt_(1, true);
|
||||
this.updateAt_(2, true);
|
||||
this.setTooltip(Blockly.Msg.TEXT_GET_SUBSTRING_TOOLTIP);
|
||||
},
|
||||
/**
|
||||
* Create XML to represent whether there are 'AT' inputs.
|
||||
* @return {!Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
var isAt1 = this.getInput('AT1').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at1', isAt1);
|
||||
var isAt2 = this.getInput('AT2').type == Blockly.INPUT_VALUE;
|
||||
container.setAttribute('at2', isAt2);
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the 'AT' inputs.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
var isAt1 = (xmlElement.getAttribute('at1') == 'true');
|
||||
var isAt2 = (xmlElement.getAttribute('at2') == 'true');
|
||||
this.updateAt_(1, isAt1);
|
||||
this.updateAt_(2, isAt2);
|
||||
},
|
||||
/**
|
||||
* Create or delete an input for a numeric index.
|
||||
* This block has two such inputs, independant of each other.
|
||||
* @param {number} n Specify first or second input (1 or 2).
|
||||
* @param {boolean} isAt True if the input should exist.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateAt_: function(n, isAt) {
|
||||
// Create or delete an input for the numeric index.
|
||||
// Destroy old 'AT' and 'ORDINAL' inputs.
|
||||
this.removeInput('AT' + n);
|
||||
this.removeInput('ORDINAL' + n, true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT' + n).setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL' + n)
|
||||
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
} else {
|
||||
this.appendDummyInput('AT' + n);
|
||||
}
|
||||
// Move tail, if present, to end of block.
|
||||
if (n == 2 && Blockly.Msg.TEXT_GET_SUBSTRING_TAIL) {
|
||||
this.removeInput('TAIL', true);
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendField(Blockly.Msg.TEXT_GET_SUBSTRING_TAIL);
|
||||
}
|
||||
var menu = new Blockly.FieldDropdown(this['WHERE_OPTIONS_' + n],
|
||||
function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
// The 'isAt' variable is available due to this function being a
|
||||
// closure.
|
||||
if (newAt != isAt) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt_(n, newAt);
|
||||
// This menu has been destroyed and replaced.
|
||||
// Update the replacement.
|
||||
block.setFieldValue(value, 'WHERE' + n);
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
this.getInput('AT' + n)
|
||||
.appendField(menu, 'WHERE' + n);
|
||||
if (n == 1) {
|
||||
this.moveInputBefore('AT1', 'AT2');
|
||||
if (this.getInput('ORDINAL1')) {
|
||||
this.moveInputBefore('ORDINAL1', 'AT2');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_changeCase'] = {
|
||||
/**
|
||||
* Block for changing capitalization.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
var OPERATORS = [
|
||||
[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_UPPERCASE, 'UPPERCASE'],
|
||||
[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_LOWERCASE, 'LOWERCASE'],
|
||||
[Blockly.Msg.TEXT_CHANGECASE_OPERATOR_TITLECASE, 'TITLECASE']
|
||||
];
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_CHANGECASE_HELPURL);
|
||||
this.setColour(Blockly.Msg.TEXTS_HUE);
|
||||
this.appendValueInput('TEXT')
|
||||
.setCheck('String')
|
||||
.appendField(new Blockly.FieldDropdown(OPERATORS), 'CASE');
|
||||
this.setOutput(true, 'String');
|
||||
this.setTooltip(Blockly.Msg.TEXT_CHANGECASE_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_trim'] = {
|
||||
/**
|
||||
* Block for trimming spaces.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
var OPERATORS = [
|
||||
[Blockly.Msg.TEXT_TRIM_OPERATOR_BOTH, 'BOTH'],
|
||||
[Blockly.Msg.TEXT_TRIM_OPERATOR_LEFT, 'LEFT'],
|
||||
[Blockly.Msg.TEXT_TRIM_OPERATOR_RIGHT, 'RIGHT']
|
||||
];
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_TRIM_HELPURL);
|
||||
this.setColour(Blockly.Msg.TEXTS_HUE);
|
||||
this.appendValueInput('TEXT')
|
||||
.setCheck('String')
|
||||
.appendField(new Blockly.FieldDropdown(OPERATORS), 'MODE');
|
||||
this.setOutput(true, 'String');
|
||||
this.setTooltip(Blockly.Msg.TEXT_TRIM_TOOLTIP);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_print'] = {
|
||||
/**
|
||||
* Block for print statement.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.TEXT_PRINT_TITLE,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TEXT"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": Blockly.Msg.TEXTS_HUE,
|
||||
"tooltip": Blockly.Msg.TEXT_PRINT_TOOLTIP,
|
||||
"helpUrl": Blockly.Msg.TEXT_PRINT_HELPURL
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_prompt_ext'] = {
|
||||
/**
|
||||
* Block for prompt function (external message).
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
var TYPES = [
|
||||
[Blockly.Msg.TEXT_PROMPT_TYPE_TEXT, 'TEXT'],
|
||||
[Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER, 'NUMBER']
|
||||
];
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_PROMPT_HELPURL);
|
||||
this.setColour(Blockly.Msg.TEXTS_HUE);
|
||||
// Assign 'this' to a variable for use in the closures below.
|
||||
var thisBlock = this;
|
||||
var dropdown = new Blockly.FieldDropdown(TYPES, function(newOp) {
|
||||
thisBlock.updateType_(newOp);
|
||||
});
|
||||
this.appendValueInput('TEXT')
|
||||
.appendField(dropdown, 'TYPE');
|
||||
this.setOutput(true, 'String');
|
||||
this.setTooltip(function() {
|
||||
return (thisBlock.getFieldValue('TYPE') == 'TEXT') ?
|
||||
Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT :
|
||||
Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Modify this block to have the correct output type.
|
||||
* @param {string} newOp Either 'TEXT' or 'NUMBER'.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateType_: function(newOp) {
|
||||
this.outputConnection.setCheck(newOp == 'NUMBER' ? 'Number' : 'String');
|
||||
},
|
||||
/**
|
||||
* Create XML to represent the output type.
|
||||
* @return {!Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('type', this.getFieldValue('TYPE'));
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the output type.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
this.updateType_(xmlElement.getAttribute('type'));
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_prompt'] = {
|
||||
/**
|
||||
* Block for prompt function (internal message).
|
||||
* The 'text_prompt_ext' block is preferred as it is more flexible.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);
|
||||
var TYPES = [
|
||||
[Blockly.Msg.TEXT_PROMPT_TYPE_TEXT, 'TEXT'],
|
||||
[Blockly.Msg.TEXT_PROMPT_TYPE_NUMBER, 'NUMBER']
|
||||
];
|
||||
|
||||
// Assign 'this' to a variable for use in the closures below.
|
||||
var thisBlock = this;
|
||||
this.setHelpUrl(Blockly.Msg.TEXT_PROMPT_HELPURL);
|
||||
this.setColour(Blockly.Msg.TEXTS_HUE);
|
||||
var dropdown = new Blockly.FieldDropdown(TYPES, function(newOp) {
|
||||
thisBlock.updateType_(newOp);
|
||||
});
|
||||
this.appendDummyInput()
|
||||
.appendField(dropdown, 'TYPE')
|
||||
.appendField(this.newQuote_(true))
|
||||
.appendField(new Blockly.FieldTextInput(''), 'TEXT')
|
||||
.appendField(this.newQuote_(false));
|
||||
this.setOutput(true, 'String');
|
||||
this.setTooltip(function() {
|
||||
return (thisBlock.getFieldValue('TYPE') == 'TEXT') ?
|
||||
Blockly.Msg.TEXT_PROMPT_TOOLTIP_TEXT :
|
||||
Blockly.Msg.TEXT_PROMPT_TOOLTIP_NUMBER;
|
||||
});
|
||||
},
|
||||
updateType_: Blockly.Blocks['text_prompt_ext'].updateType_,
|
||||
mutationToDom: Blockly.Blocks['text_prompt_ext'].mutationToDom,
|
||||
domToMutation: Blockly.Blocks['text_prompt_ext'].domToMutation
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_count'] = {
|
||||
/**
|
||||
* Block for counting how many times one string appears within another string.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.TEXT_COUNT_MESSAGE0,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "SUB",
|
||||
"check": "String"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TEXT",
|
||||
"check": "String"
|
||||
}
|
||||
],
|
||||
"output": "Number",
|
||||
"inputsInline": true,
|
||||
"colour": Blockly.Msg.TEXTS_HUE,
|
||||
"tooltip": Blockly.Msg.TEXT_COUNT_TOOLTIP,
|
||||
"helpUrl": Blockly.Msg.TEXT_COUNT_HELPURL
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_replace'] = {
|
||||
/**
|
||||
* Block for replacing one string with another in the text.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.TEXT_REPLACE_MESSAGE0,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "FROM",
|
||||
"check": "String"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TO",
|
||||
"check": "String"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TEXT",
|
||||
"check": "String"
|
||||
}
|
||||
],
|
||||
"output": "String",
|
||||
"inputsInline": true,
|
||||
"colour": Blockly.Msg.TEXTS_HUE,
|
||||
"tooltip": Blockly.Msg.TEXT_REPLACE_TOOLTIP,
|
||||
"helpUrl": Blockly.Msg.TEXT_REPLACE_HELPURL
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['text_reverse'] = {
|
||||
/**
|
||||
* Block for reversing a string.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
init: function() {
|
||||
this.jsonInit({
|
||||
"message0": Blockly.Msg.TEXT_REVERSE_MESSAGE0,
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "TEXT",
|
||||
"check": "String"
|
||||
}
|
||||
],
|
||||
"output": "String",
|
||||
"inputsInline": true,
|
||||
"colour": Blockly.Msg.TEXTS_HUE,
|
||||
"tooltip": Blockly.Msg.TEXT_REVERSE_TOOLTIP,
|
||||
"helpUrl": Blockly.Msg.TEXT_REVERSE_HELPURL
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @mixin
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Text.QUOTE_IMAGE_MIXIN = {
|
||||
/**
|
||||
* Image data URI of an LTR opening double quote (same as RTL closing double quote).
|
||||
* @readonly
|
||||
*/
|
||||
QUOTE_IMAGE_LEFT_DATAURI:
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAA' +
|
||||
'n0lEQVQI1z3OMa5BURSF4f/cQhAKjUQhuQmFNwGJEUi0RKN5rU7FHKhpjEH3TEMtkdBSCY' +
|
||||
'1EIv8r7nFX9e29V7EBAOvu7RPjwmWGH/VuF8CyN9/OAdvqIXYLvtRaNjx9mMTDyo+NjAN1' +
|
||||
'HNcl9ZQ5oQMM3dgDUqDo1l8DzvwmtZN7mnD+PkmLa+4mhrxVA9fRowBWmVBhFy5gYEjKMf' +
|
||||
'z9AylsaRRgGzvZAAAAAElFTkSuQmCC',
|
||||
/**
|
||||
* Image data URI of an LTR closing double quote (same as RTL opening double quote).
|
||||
* @readonly
|
||||
*/
|
||||
QUOTE_IMAGE_RIGHT_DATAURI:
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAKCAQAAAAqJXdxAAAA' +
|
||||
'qUlEQVQI1z3KvUpCcRiA8ef9E4JNHhI0aFEacm1o0BsI0Slx8wa8gLauoDnoBhq7DcfWhg' +
|
||||
'gONDmJJgqCPA7neJ7p934EOOKOnM8Q7PDElo/4x4lFb2DmuUjcUzS3URnGib9qaPNbuXvB' +
|
||||
'O3sGPHJDRG6fGVdMSeWDP2q99FQdFrz26Gu5Tq7dFMzUvbXy8KXeAj57cOklgA+u1B5Aos' +
|
||||
'lLtGIHQMaCVnwDnADZIFIrXsoXrgAAAABJRU5ErkJggg==',
|
||||
/**
|
||||
* Pixel width of QUOTE_IMAGE_LEFT_DATAURI and QUOTE_IMAGE_RIGHT_DATAURI.
|
||||
* @readonly
|
||||
*/
|
||||
QUOTE_IMAGE_WIDTH: 12,
|
||||
/**
|
||||
* Pixel height of QUOTE_IMAGE_LEFT_DATAURI and QUOTE_IMAGE_RIGHT_DATAURI.
|
||||
* @readonly
|
||||
*/
|
||||
QUOTE_IMAGE_HEIGHT: 12,
|
||||
|
||||
/**
|
||||
* Inserts appropriate quote images before and after the named field.
|
||||
* @param {string} fieldName The name of the field to wrap with quotes.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
quoteField_: function(fieldName) {
|
||||
for (var i = 0, input; input = this.inputList[i]; i++) {
|
||||
for (var j = 0, field; field = input.fieldRow[j]; j++) {
|
||||
if (fieldName == field.name) {
|
||||
input.insertFieldAt(j, this.newQuote_(true));
|
||||
input.insertFieldAt(j + 2, this.newQuote_(false));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
console.warn('field named "' + fieldName + '" not found in ' + this.toDevString());
|
||||
},
|
||||
|
||||
/**
|
||||
* A helper function that generates a FieldImage of an opening or
|
||||
* closing double quote. The selected quote will be adapted for RTL blocks.
|
||||
* @param {boolean} open If the image should be open quote (“ in LTR).
|
||||
* Otherwise, a closing quote is used (” in LTR).
|
||||
* @returns {!Blockly.FieldImage} The new field.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
newQuote_: function(open) {
|
||||
var isLeft = this.RTL? !open : open;
|
||||
var dataUri = isLeft ?
|
||||
this.QUOTE_IMAGE_LEFT_DATAURI :
|
||||
this.QUOTE_IMAGE_RIGHT_DATAURI;
|
||||
return new Blockly.FieldImage(
|
||||
dataUri,
|
||||
this.QUOTE_IMAGE_WIDTH,
|
||||
this.QUOTE_IMAGE_HEIGHT,
|
||||
isLeft ? '\u201C' : '\u201D');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wraps TEXT field with images of double quote characters.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
Blockly.Constants.Text.TEXT_QUOTES_EXTENSION = function() {
|
||||
this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);
|
||||
this.quoteField_('TEXT');
|
||||
};
|
||||
|
||||
/**
|
||||
* Mixin for mutator functions in the 'text_join_mutator' extension.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN = {
|
||||
/**
|
||||
* Create XML to represent number of text inputs.
|
||||
* @return {!Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('items', this.itemCount_);
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the text inputs.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
|
||||
this.updateShape_();
|
||||
},
|
||||
/**
|
||||
* Populate the mutator's dialog with this block's components.
|
||||
* @param {!Blockly.Workspace} workspace Mutator's workspace.
|
||||
* @return {!Blockly.Block} Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
decompose: function(workspace) {
|
||||
var containerBlock = workspace.newBlock('text_create_join_container');
|
||||
containerBlock.initSvg();
|
||||
var connection = containerBlock.getInput('STACK').connection;
|
||||
for (var i = 0; i < this.itemCount_; i++) {
|
||||
var itemBlock = workspace.newBlock('text_create_join_item');
|
||||
itemBlock.initSvg();
|
||||
connection.connect(itemBlock.previousConnection);
|
||||
connection = itemBlock.nextConnection;
|
||||
}
|
||||
return containerBlock;
|
||||
},
|
||||
/**
|
||||
* Reconfigure this block based on the mutator dialog's components.
|
||||
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
compose: function(containerBlock) {
|
||||
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
// Count number of inputs.
|
||||
var connections = [];
|
||||
while (itemBlock) {
|
||||
connections.push(itemBlock.valueConnection_);
|
||||
itemBlock = itemBlock.nextConnection &&
|
||||
itemBlock.nextConnection.targetBlock();
|
||||
}
|
||||
// Disconnect any children that don't belong.
|
||||
for (var i = 0; i < this.itemCount_; i++) {
|
||||
var connection = this.getInput('ADD' + i).connection.targetConnection;
|
||||
if (connection && connections.indexOf(connection) == -1) {
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
this.itemCount_ = connections.length;
|
||||
this.updateShape_();
|
||||
// Reconnect any child blocks.
|
||||
for (var i = 0; i < this.itemCount_; i++) {
|
||||
Blockly.Mutator.reconnect(connections[i], this, 'ADD' + i);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Store pointers to any connected child blocks.
|
||||
* @param {!Blockly.Block} containerBlock Root block in mutator.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
saveConnections: function(containerBlock) {
|
||||
var itemBlock = containerBlock.getInputTargetBlock('STACK');
|
||||
var i = 0;
|
||||
while (itemBlock) {
|
||||
var input = this.getInput('ADD' + i);
|
||||
itemBlock.valueConnection_ = input && input.connection.targetConnection;
|
||||
i++;
|
||||
itemBlock = itemBlock.nextConnection &&
|
||||
itemBlock.nextConnection.targetBlock();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Modify this block to have the correct number of inputs.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateShape_: function() {
|
||||
if (this.itemCount_ && this.getInput('EMPTY')) {
|
||||
this.removeInput('EMPTY');
|
||||
} else if (!this.itemCount_ && !this.getInput('EMPTY')) {
|
||||
this.appendDummyInput('EMPTY')
|
||||
.appendField(this.newQuote_(true))
|
||||
.appendField(this.newQuote_(false));
|
||||
}
|
||||
// Add new inputs.
|
||||
for (var i = 0; i < this.itemCount_; i++) {
|
||||
if (!this.getInput('ADD' + i)) {
|
||||
var input = this.appendValueInput('ADD' + i);
|
||||
if (i == 0) {
|
||||
input.appendField(Blockly.Msg.TEXT_JOIN_TITLE_CREATEWITH);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove deleted inputs.
|
||||
while (this.getInput('ADD' + i)) {
|
||||
this.removeInput('ADD' + i);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Performs final setup of a text_join block.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
Blockly.Constants.Text.TEXT_JOIN_EXTENSION = function() {
|
||||
// Add the quote mixin for the itemCount_ = 0 case.
|
||||
this.mixin(Blockly.Constants.Text.QUOTE_IMAGE_MIXIN);
|
||||
// Initialize the mutator values.
|
||||
this.itemCount_ = 2;
|
||||
this.updateShape_();
|
||||
// Configure the mutator UI.
|
||||
this.setMutator(new Blockly.Mutator(['text_create_join_item']));
|
||||
};
|
||||
|
||||
// Update the tooltip of 'text_append' block to reference the variable.
|
||||
Blockly.Extensions.register('text_append_tooltip',
|
||||
Blockly.Extensions.buildTooltipWithFieldText(
|
||||
'%{BKY_TEXT_APPEND_TOOLTIP}', 'VAR'));
|
||||
|
||||
/**
|
||||
* Update the tooltip of 'text_append' block to reference the variable.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
Blockly.Constants.Text.TEXT_INDEXOF_TOOLTIP_EXTENSION = function() {
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
return Blockly.Msg.TEXT_INDEXOF_TOOLTIP.replace('%1',
|
||||
thisBlock.workspace.options.oneBasedIndex ? '0' : '-1');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Mixin for mutator functions in the 'text_charAt_mutator' extension.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
*/
|
||||
Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN = {
|
||||
/**
|
||||
* Create XML to represent whether there is an 'AT' input.
|
||||
* @return {!Element} XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
mutationToDom: function() {
|
||||
var container = document.createElement('mutation');
|
||||
container.setAttribute('at', !!this.isAt_);
|
||||
return container;
|
||||
},
|
||||
/**
|
||||
* Parse XML to restore the 'AT' input.
|
||||
* @param {!Element} xmlElement XML storage element.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
domToMutation: function(xmlElement) {
|
||||
// Note: Until January 2013 this block did not have mutations,
|
||||
// so 'at' defaults to true.
|
||||
var isAt = (xmlElement.getAttribute('at') != 'false');
|
||||
this.updateAt_(isAt);
|
||||
},
|
||||
/**
|
||||
* Create or delete an input for the numeric index.
|
||||
* @param {boolean} isAt True if the input should exist.
|
||||
* @private
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
updateAt_: function(isAt) {
|
||||
// Destroy old 'AT' and 'ORDINAL' inputs.
|
||||
this.removeInput('AT', true);
|
||||
this.removeInput('ORDINAL', true);
|
||||
// Create either a value 'AT' input or a dummy input.
|
||||
if (isAt) {
|
||||
this.appendValueInput('AT').setCheck('Number');
|
||||
if (Blockly.Msg.ORDINAL_NUMBER_SUFFIX) {
|
||||
this.appendDummyInput('ORDINAL')
|
||||
.appendField(Blockly.Msg.ORDINAL_NUMBER_SUFFIX);
|
||||
}
|
||||
}
|
||||
if (Blockly.Msg.TEXT_CHARAT_TAIL) {
|
||||
this.removeInput('TAIL', true);
|
||||
this.appendDummyInput('TAIL')
|
||||
.appendField(Blockly.Msg.TEXT_CHARAT_TAIL);
|
||||
}
|
||||
|
||||
this.isAt_ = isAt;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Does the initial mutator update of text_charAt and adds the tooltip
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
Blockly.Constants.Text.TEXT_CHARAT_EXTENSION = function() {
|
||||
var dropdown = this.getField('WHERE');
|
||||
dropdown.setValidator(function(value) {
|
||||
var newAt = (value == 'FROM_START') || (value == 'FROM_END');
|
||||
if (newAt != this.isAt_) {
|
||||
var block = this.sourceBlock_;
|
||||
block.updateAt_(newAt);
|
||||
// This menu has been destroyed and replaced. Update the replacement.
|
||||
block.setFieldValue(value, 'WHERE');
|
||||
return null;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this.updateAt_(true);
|
||||
// Assign 'this' to a variable for use in the tooltip closure below.
|
||||
var thisBlock = this;
|
||||
this.setTooltip(function() {
|
||||
var where = thisBlock.getFieldValue('WHERE');
|
||||
var tooltip = Blockly.Msg.TEXT_CHARAT_TOOLTIP;
|
||||
if (where == 'FROM_START' || where == 'FROM_END') {
|
||||
var msg = (where == 'FROM_START') ?
|
||||
Blockly.Msg.LISTS_INDEX_FROM_START_TOOLTIP :
|
||||
Blockly.Msg.LISTS_INDEX_FROM_END_TOOLTIP;
|
||||
if (msg) {
|
||||
tooltip += ' ' + msg.replace('%1',
|
||||
thisBlock.workspace.options.oneBasedIndex ? '#1' : '#0');
|
||||
}
|
||||
}
|
||||
return tooltip;
|
||||
});
|
||||
};
|
||||
|
||||
Blockly.Extensions.register('text_indexOf_tooltip',
|
||||
Blockly.Constants.Text.TEXT_INDEXOF_TOOLTIP_EXTENSION);
|
||||
|
||||
Blockly.Extensions.register('text_quotes',
|
||||
Blockly.Constants.Text.TEXT_QUOTES_EXTENSION);
|
||||
|
||||
Blockly.Extensions.registerMutator('text_join_mutator',
|
||||
Blockly.Constants.Text.TEXT_JOIN_MUTATOR_MIXIN,
|
||||
Blockly.Constants.Text.TEXT_JOIN_EXTENSION);
|
||||
|
||||
Blockly.Extensions.registerMutator('text_charAt_mutator',
|
||||
Blockly.Constants.Text.TEXT_CHARAT_MUTATOR_MIXIN,
|
||||
Blockly.Constants.Text.TEXT_CHARAT_EXTENSION);
|
||||
128
node_modules/node-blockly/blockly/blocks/variables.js
generated
vendored
Normal file
128
node_modules/node-blockly/blockly/blocks/variables.js
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* 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 Variable blocks for Blockly.
|
||||
|
||||
* This file is scraped to extract a .json file of block definitions. The array
|
||||
* passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes
|
||||
* only, no outside references, no functions, no trailing commas, etc. The one
|
||||
* exception is end-of-line comments, which the scraper will remove.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Blocks.variables'); // Deprecated.
|
||||
goog.provide('Blockly.Constants.Variables');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly');
|
||||
|
||||
|
||||
/**
|
||||
* Unused constant for the common HSV hue for all blocks in this category.
|
||||
* @deprecated Use Blockly.Msg.VARIABLES_HUE. (2018 April 5)
|
||||
*/
|
||||
Blockly.Constants.Variables.HUE = 330;
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
// Block for variable getter.
|
||||
{
|
||||
"type": "variables_get",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
"variable": "%{BKY_VARIABLES_DEFAULT_NAME}"
|
||||
}
|
||||
],
|
||||
"output": null,
|
||||
"colour": "%{BKY_VARIABLES_HUE}",
|
||||
"helpUrl": "%{BKY_VARIABLES_GET_HELPURL}",
|
||||
"tooltip": "%{BKY_VARIABLES_GET_TOOLTIP}",
|
||||
"extensions": ["contextMenu_variableSetterGetter"]
|
||||
},
|
||||
// Block for variable setter.
|
||||
{
|
||||
"type": "variables_set",
|
||||
"message0": "%{BKY_VARIABLES_SET}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
"variable": "%{BKY_VARIABLES_DEFAULT_NAME}"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_VARIABLES_HUE}",
|
||||
"tooltip": "%{BKY_VARIABLES_SET_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_VARIABLES_SET_HELPURL}",
|
||||
"extensions": ["contextMenu_variableSetterGetter"]
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
|
||||
/**
|
||||
* Mixin to add context menu items to create getter/setter blocks for this
|
||||
* setter/getter.
|
||||
* Used by blocks 'variables_set' and 'variables_get'.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = {
|
||||
/**
|
||||
* Add menu option to create getter/setter block for this setter/getter.
|
||||
* @param {!Array} options List of menu options to add to.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
customContextMenu: function(options) {
|
||||
if (this.isInFlyout){
|
||||
return;
|
||||
}
|
||||
// Getter blocks have the option to create a setter block, and vice versa.
|
||||
if (this.type == 'variables_get') {
|
||||
var opposite_type = 'variables_set';
|
||||
var contextMenuMsg = Blockly.Msg.VARIABLES_GET_CREATE_SET;
|
||||
} else {
|
||||
var opposite_type = 'variables_get';
|
||||
var contextMenuMsg = Blockly.Msg.VARIABLES_SET_CREATE_GET;
|
||||
}
|
||||
|
||||
var option = {enabled: this.workspace.remainingCapacity() > 0};
|
||||
var name = this.getField('VAR').getText();
|
||||
option.text = contextMenuMsg.replace('%1', name);
|
||||
var xmlField = goog.dom.createDom('field', null, name);
|
||||
xmlField.setAttribute('name', 'VAR');
|
||||
var xmlBlock = goog.dom.createDom('block', null, xmlField);
|
||||
xmlBlock.setAttribute('type', opposite_type);
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMixin('contextMenu_variableSetterGetter',
|
||||
Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);
|
||||
135
node_modules/node-blockly/blockly/blocks/variables_dynamic.js
generated
vendored
Normal file
135
node_modules/node-blockly/blockly/blocks/variables_dynamic.js
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2017 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 Variable blocks for Blockly.
|
||||
|
||||
* This file is scraped to extract a .json file of block definitions. The array
|
||||
* passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes
|
||||
* only, no outside references, no functions, no trailing commas, etc. The one
|
||||
* exception is end-of-line comments, which the scraper will remove.
|
||||
* @author duzc2dtw@gmail.com (Du Tian Wei)
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
goog.provide('Blockly.Constants.VariablesDynamic');
|
||||
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly');
|
||||
|
||||
|
||||
/**
|
||||
* Unused constant for the common HSV hue for all blocks in this category.
|
||||
* @deprecated Use Blockly.Msg.VARIABLES_DYNAMIC_HUE. (2018 April 5)
|
||||
*/
|
||||
Blockly.Constants.VariablesDynamic.HUE = 310;
|
||||
|
||||
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
// Block for variable getter.
|
||||
{
|
||||
"type": "variables_get_dynamic",
|
||||
"message0": "%1",
|
||||
"args0": [{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
"variable": "%{BKY_VARIABLES_DEFAULT_NAME}"
|
||||
}],
|
||||
"output": null,
|
||||
"colour": "%{BKY_VARIABLES_DYNAMIC_HUE}",
|
||||
"helpUrl": "%{BKY_VARIABLES_GET_HELPURL}",
|
||||
"tooltip": "%{BKY_VARIABLES_GET_TOOLTIP}",
|
||||
"extensions": ["contextMenu_variableDynamicSetterGetter"]
|
||||
},
|
||||
// Block for variable setter.
|
||||
{
|
||||
"type": "variables_set_dynamic",
|
||||
"message0": "%{BKY_VARIABLES_SET}",
|
||||
"args0": [{
|
||||
"type": "field_variable",
|
||||
"name": "VAR",
|
||||
"variable": "%{BKY_VARIABLES_DEFAULT_NAME}"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE"
|
||||
}
|
||||
],
|
||||
"previousStatement": null,
|
||||
"nextStatement": null,
|
||||
"colour": "%{BKY_VARIABLES_DYNAMIC_HUE}",
|
||||
"tooltip": "%{BKY_VARIABLES_SET_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_VARIABLES_SET_HELPURL}",
|
||||
"extensions": ["contextMenu_variableDynamicSetterGetter"]
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
|
||||
/**
|
||||
* Mixin to add context menu items to create getter/setter blocks for this
|
||||
* setter/getter.
|
||||
* Used by blocks 'variables_set_dynamic' and 'variables_get_dynamic'.
|
||||
* @mixin
|
||||
* @augments Blockly.Block
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN = {
|
||||
/**
|
||||
* Add menu option to create getter/setter block for this setter/getter.
|
||||
* @param {!Array} options List of menu options to add to.
|
||||
* @this Blockly.Block
|
||||
*/
|
||||
customContextMenu: function(options) {
|
||||
// Getter blocks have the option to create a setter block, and vice versa.
|
||||
if (this.isInFlyout) {
|
||||
return;
|
||||
}
|
||||
var opposite_type;
|
||||
var contextMenuMsg;
|
||||
if (this.type == 'variables_get_dynamic') {
|
||||
opposite_type = 'variables_set_dynamic';
|
||||
contextMenuMsg = Blockly.Msg.VARIABLES_GET_CREATE_SET;
|
||||
} else {
|
||||
opposite_type = 'variables_get_dynamic';
|
||||
contextMenuMsg = Blockly.Msg.VARIABLES_SET_CREATE_GET;
|
||||
}
|
||||
|
||||
var option = {enabled: this.workspace.remainingCapacity() > 0};
|
||||
var name = this.getField('VAR').getText();
|
||||
option.text = contextMenuMsg.replace('%1', name);
|
||||
var xmlField = goog.dom.createDom('field', null, name);
|
||||
xmlField.setAttribute('name', 'VAR');
|
||||
var xmlBlock = goog.dom.createDom('block', null, xmlField);
|
||||
xmlBlock.setAttribute('type', opposite_type);
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
},
|
||||
onchange: function() {
|
||||
var id = this.getFieldValue('VAR');
|
||||
var variableModel = this.workspace.getVariableById(id);
|
||||
if (this.type == 'variables_get_dynamic') {
|
||||
this.outputConnection.setCheck(variableModel.type);
|
||||
} else {
|
||||
this.getInput('VALUE').connection.setCheck(variableModel.type);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMixin('contextMenu_variableDynamicSetterGetter',
|
||||
Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);
|
||||
Reference in New Issue
Block a user