Initial commit

This commit is contained in:
pasketti
2026-04-05 16:14:49 -04:00
commit ebee3a5534
14059 changed files with 2588797 additions and 0 deletions

134
node_modules/node-blockly/blockly/blocks/colour.js generated vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);

View 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);