mixio 1.10.0
This commit is contained in:
122
blockly/blocks/colour.js
Normal file
122
blockly/blocks/colour.js
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2012 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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');
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.FieldColour');
|
||||
goog.require('Blockly.FieldLabel');
|
||||
|
||||
|
||||
/**
|
||||
* 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",
|
||||
"helpUrl": "%{BKY_COLOUR_PICKER_HELPURL}",
|
||||
"style": "colour_blocks",
|
||||
"tooltip": "%{BKY_COLOUR_PICKER_TOOLTIP}",
|
||||
"extensions": ["parent_tooltip_when_inline"]
|
||||
},
|
||||
|
||||
// Block for random colour.
|
||||
{
|
||||
"type": "colour_random",
|
||||
"message0": "%{BKY_COLOUR_RANDOM_TITLE}",
|
||||
"output": "Colour",
|
||||
"helpUrl": "%{BKY_COLOUR_RANDOM_HELPURL}",
|
||||
"style": "colour_blocks",
|
||||
"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",
|
||||
"helpUrl": "%{BKY_COLOUR_RGB_HELPURL}",
|
||||
"style": "colour_blocks",
|
||||
"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",
|
||||
"helpUrl": "%{BKY_COLOUR_BLEND_HELPURL}",
|
||||
"style": "colour_blocks",
|
||||
"tooltip": "%{BKY_COLOUR_BLEND_TOOLTIP}"
|
||||
}
|
||||
]); // END JSON EXTRACT (Do not delete this comment.)
|
||||
861
blockly/blocks/lists.js
Normal file
861
blockly/blocks/lists.js
Normal file
@@ -0,0 +1,861 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2012 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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.Constants.Lists');
|
||||
|
||||
goog.require('Blockly');
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.FieldDropdown');
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.Mutator');
|
||||
|
||||
|
||||
/**
|
||||
* 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",
|
||||
"style": "list_blocks",
|
||||
"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",
|
||||
"style": "list_blocks",
|
||||
"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,
|
||||
"style": "list_blocks",
|
||||
"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",
|
||||
"style": "list_blocks",
|
||||
"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",
|
||||
"style": "list_blocks",
|
||||
"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.setStyle('list_blocks');
|
||||
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 = Blockly.utils.xml.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 && !itemBlock.isInsertionMarker()) {
|
||||
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)
|
||||
.setAlign(Blockly.ALIGN_RIGHT);
|
||||
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.setStyle('list_blocks');
|
||||
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.setStyle('list_blocks');
|
||||
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.setStyle('list_blocks');
|
||||
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.setStyle('list_blocks');
|
||||
var modeMenu = new Blockly.FieldDropdown(MODE, function(value) {
|
||||
var isStatement = (value == 'REMOVE');
|
||||
this.getSourceBlock().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 = Blockly.utils.xml.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.getSourceBlock();
|
||||
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.setStyle('list_blocks');
|
||||
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 = Blockly.utils.xml.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.getSourceBlock();
|
||||
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.setStyle('list_blocks');
|
||||
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 = Blockly.utils.xml.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, independent 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.getSourceBlock();
|
||||
block.updateAt_(n, newAt);
|
||||
// This menu has been destroyed and replaced.
|
||||
// Update the replacement.
|
||||
block.setFieldValue(value, 'WHERE' + n);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
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",
|
||||
"style": "list_blocks",
|
||||
"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.setStyle('list_blocks');
|
||||
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 Error('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) {
|
||||
var mode = this.getFieldValue('MODE');
|
||||
if (mode != newMode) {
|
||||
var inputConnection = this.getInput('INPUT').connection;
|
||||
inputConnection.setShadowDom(null);
|
||||
var inputBlock = inputConnection.targetBlock();
|
||||
if (inputBlock) {
|
||||
inputConnection.disconnect();
|
||||
if (inputBlock.isShadow()) {
|
||||
inputBlock.dispose();
|
||||
} else {
|
||||
this.bumpNeighbours();
|
||||
}
|
||||
}
|
||||
}
|
||||
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 = Blockly.utils.xml.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'));
|
||||
}
|
||||
};
|
||||
635
blockly/blocks/logic.js
Normal file
635
blockly/blocks/logic.js
Normal file
@@ -0,0 +1,635 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2012 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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');
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.FieldDropdown');
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.Mutator');
|
||||
|
||||
|
||||
/**
|
||||
* 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",
|
||||
"style": "logic_blocks",
|
||||
"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,
|
||||
"style": "logic_blocks",
|
||||
"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,
|
||||
"style": "logic_blocks",
|
||||
"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"],
|
||||
["\u200F<", "LT"],
|
||||
["\u200F\u2264", "LTE"],
|
||||
["\u200F>", "GT"],
|
||||
["\u200F\u2265", "GTE"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "B"
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"output": "Boolean",
|
||||
"style": "logic_blocks",
|
||||
"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",
|
||||
"style": "logic_blocks",
|
||||
"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",
|
||||
"style": "logic_blocks",
|
||||
"tooltip": "%{BKY_LOGIC_NEGATE_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_LOGIC_NEGATE_HELPURL}"
|
||||
},
|
||||
// Block for null data type.
|
||||
{
|
||||
"type": "logic_null",
|
||||
"message0": "%{BKY_LOGIC_NULL}",
|
||||
"output": null,
|
||||
"style": "logic_blocks",
|
||||
"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,
|
||||
"style": "logic_blocks",
|
||||
"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,
|
||||
"style": "logic_blocks",
|
||||
"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,
|
||||
"style": "logic_blocks",
|
||||
"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,
|
||||
"style": "logic_blocks",
|
||||
"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,
|
||||
|
||||
/**
|
||||
* Don't automatically add STATEMENT_PREFIX and STATEMENT_SUFFIX to generated
|
||||
* code. These will be handled manually in this block's generators.
|
||||
*/
|
||||
suppressPrefixSuffix: true,
|
||||
|
||||
/**
|
||||
* 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 = Blockly.utils.xml.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.rebuildShape_();
|
||||
},
|
||||
/**
|
||||
* 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 && !clauseBlock.isInsertionMarker()) {
|
||||
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 TypeError('Unknown block type: ' + clauseBlock.type);
|
||||
}
|
||||
clauseBlock = clauseBlock.nextConnection &&
|
||||
clauseBlock.nextConnection.targetBlock();
|
||||
}
|
||||
this.updateShape_();
|
||||
// Reconnect any child blocks.
|
||||
this.reconnectChildBlocks_(valueConnections, statementConnections,
|
||||
elseStatementConnection);
|
||||
},
|
||||
/**
|
||||
* 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 TypeError('Unknown block type: ' + clauseBlock.type);
|
||||
}
|
||||
clauseBlock = clauseBlock.nextConnection &&
|
||||
clauseBlock.nextConnection.targetBlock();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Reconstructs the block with all child blocks attached.
|
||||
* @this {Blockly.Block}
|
||||
*/
|
||||
rebuildShape_: function() {
|
||||
var valueConnections = [null];
|
||||
var statementConnections = [null];
|
||||
var elseStatementConnection = null;
|
||||
|
||||
if (this.getInput('ELSE')) {
|
||||
elseStatementConnection = this.getInput('ELSE').connection.targetConnection;
|
||||
}
|
||||
var i = 1;
|
||||
while (this.getInput('IF' + i)) {
|
||||
var inputIf = this.getInput('IF' + i);
|
||||
var inputDo = this.getInput('DO' + i);
|
||||
valueConnections.push(inputIf.connection.targetConnection);
|
||||
statementConnections.push(inputDo.connection.targetConnection);
|
||||
i++;
|
||||
}
|
||||
this.updateShape_();
|
||||
this.reconnectChildBlocks_(valueConnections, statementConnections,
|
||||
elseStatementConnection);
|
||||
},
|
||||
/**
|
||||
* 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 (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']);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Reconnects child blocks.
|
||||
* @param {!Array<?Blockly.RenderedConnection>} valueConnections List of
|
||||
* value connections for 'if' input.
|
||||
* @param {!Array<?Blockly.RenderedConnection>} statementConnections List of
|
||||
* statement connections for 'do' input.
|
||||
* @param {?Blockly.RenderedConnection} elseStatementConnection Statement
|
||||
* connection for else input.
|
||||
* @this {Blockly.Block}
|
||||
*/
|
||||
reconnectChildBlocks_: function(valueConnections, statementConnections,
|
||||
elseStatementConnection) {
|
||||
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');
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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 &&
|
||||
!this.workspace.connectionChecker.doTypeChecks(
|
||||
blockA.outputConnection, 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.isDisposed() && !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.isDisposed() && !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. Adds type left and right side type
|
||||
* checking to "logic_compare" blocks.
|
||||
* @this {Blockly.Block}
|
||||
* @package
|
||||
* @readonly
|
||||
*/
|
||||
Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION = function() {
|
||||
// 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.workspace.connectionChecker.doTypeChecks(
|
||||
block.outputConnection, 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);
|
||||
356
blockly/blocks/loops.js
Normal file
356
blockly/blocks/loops.js
Normal file
@@ -0,0 +1,356 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2012 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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');
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.FieldDropdown');
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.FieldNumber');
|
||||
goog.require('Blockly.FieldVariable');
|
||||
goog.require('Blockly.Warning');
|
||||
|
||||
|
||||
/**
|
||||
* 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,
|
||||
"style": "loop_blocks",
|
||||
"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,
|
||||
"style": "loop_blocks",
|
||||
"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,
|
||||
"style": "loop_blocks",
|
||||
"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,
|
||||
"style": "loop_blocks",
|
||||
"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,
|
||||
"style": "loop_blocks",
|
||||
"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,
|
||||
"style": "loop_blocks",
|
||||
"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 = Blockly.utils.xml.createElement('block');
|
||||
xmlBlock.setAttribute('type', 'variables_get');
|
||||
xmlBlock.appendChild(xmlField);
|
||||
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'
|
||||
],
|
||||
|
||||
/**
|
||||
* Don't automatically add STATEMENT_PREFIX and STATEMENT_SUFFIX to generated
|
||||
* code. These will be handled manually in this block's generators.
|
||||
*/
|
||||
suppressPrefixSuffix: true,
|
||||
|
||||
/**
|
||||
* Is the given block enclosed (at any level) by a loop?
|
||||
* @param {!Blockly.Block} block Current block.
|
||||
* @return {Blockly.Block} The nearest surrounding loop, or null if none.
|
||||
*/
|
||||
getSurroundLoop: function(block) {
|
||||
// Is the block nested in a loop?
|
||||
do {
|
||||
if (Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES
|
||||
.indexOf(block.type) != -1) {
|
||||
return block;
|
||||
}
|
||||
block = block.getSurroundParent();
|
||||
} while (block);
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
// Don't change state if:
|
||||
// * It's at the start of a drag.
|
||||
// * It's not a move event.
|
||||
if (!this.workspace.isDragging || this.workspace.isDragging() ||
|
||||
e.type != Blockly.Events.BLOCK_MOVE) {
|
||||
return;
|
||||
}
|
||||
var enabled = Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN
|
||||
.getSurroundLoop(this);
|
||||
this.setWarningText(enabled ? null :
|
||||
Blockly.Msg['CONTROLS_FLOW_STATEMENTS_WARNING']);
|
||||
if (!this.isInFlyout) {
|
||||
var group = Blockly.Events.getGroup();
|
||||
// Makes it so the move and the disable event get undone together.
|
||||
Blockly.Events.setGroup(e.group);
|
||||
this.setEnabled(enabled);
|
||||
Blockly.Events.setGroup(group);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMixin('controls_flow_in_loop_check',
|
||||
Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN);
|
||||
566
blockly/blocks/math.js
Normal file
566
blockly/blocks/math.js
Normal file
@@ -0,0 +1,566 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2012 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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');
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.FieldDropdown');
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.FieldNumber');
|
||||
goog.require('Blockly.FieldVariable');
|
||||
|
||||
|
||||
/**
|
||||
* 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",
|
||||
"helpUrl": "%{BKY_MATH_NUMBER_HELPURL}",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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,
|
||||
"style": "variable_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"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",
|
||||
"style": "math_blocks",
|
||||
"tooltip": "%{BKY_MATH_RANDOM_FLOAT_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_MATH_RANDOM_FLOAT_HELPURL}"
|
||||
},
|
||||
|
||||
// Block for calculating atan2 of [X] and [Y].
|
||||
{
|
||||
"type": "math_atan2",
|
||||
"message0": "%{BKY_MATH_ATAN2_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "X",
|
||||
"check": "Number"
|
||||
},
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "Y",
|
||||
"check": "Number"
|
||||
}
|
||||
],
|
||||
"inputsInline": true,
|
||||
"output": "Number",
|
||||
"style": "math_blocks",
|
||||
"tooltip": "%{BKY_MATH_ATAN2_TOOLTIP}",
|
||||
"helpUrl": "%{BKY_MATH_ATAN2_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 = Blockly.utils.xml.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 "divisible 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.getSourceBlock().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 = Blockly.utils.xml.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);
|
||||
1080
blockly/blocks/procedures.js
Normal file
1080
blockly/blocks/procedures.js
Normal file
File diff suppressed because it is too large
Load Diff
923
blockly/blocks/text.js
Normal file
923
blockly/blocks/text.js
Normal file
@@ -0,0 +1,923 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2012 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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');
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.FieldDropdown');
|
||||
goog.require('Blockly.FieldImage');
|
||||
goog.require('Blockly.FieldMultilineInput');
|
||||
goog.require('Blockly.FieldTextInput');
|
||||
goog.require('Blockly.FieldVariable');
|
||||
goog.require('Blockly.Mutator');
|
||||
|
||||
|
||||
/**
|
||||
* 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",
|
||||
"style": "text_blocks",
|
||||
"helpUrl": "%{BKY_TEXT_TEXT_HELPURL}",
|
||||
"tooltip": "%{BKY_TEXT_TEXT_TOOLTIP}",
|
||||
"extensions": [
|
||||
"text_quotes",
|
||||
"parent_tooltip_when_inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text_multiline",
|
||||
"message0": "%1 %2",
|
||||
"args0": [{
|
||||
"type": "field_image",
|
||||
"src": 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAARCAYAAADpP' +
|
||||
'U2iAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAdhgAAHYYBXaITgQAAABh0RVh0' +
|
||||
'U29mdHdhcmUAcGFpbnQubmV0IDQuMS42/U4J6AAAAP1JREFUOE+Vks0KQUEYhjm' +
|
||||
'RIja4ABtZ2dm5A3t3Ia6AUm7CylYuQRaUhZSlLZJiQbFAyRnPN33y01HOW08z88' +
|
||||
'73zpwzM4F3GWOCruvGIE4/rLaV+Nq1hVGMBqzhqlxgCys4wJA65xnogMHsQ5luj' +
|
||||
'nYHTejBBCK2mE4abjCgMGhNxHgDFWjDSG07kdfVa2pZMf4ZyMAdWmpZMfYOsLiD' +
|
||||
'MYMjlMB+K613QISRhTnITnsYg5yUd0DETmEoMlkFOeIT/A58iyK5E18BuTBfgYX' +
|
||||
'fwNJv4P9/oEBerLylOnRhygmGdPpTTBZAPkde61lbQe4moWUvYUZYLfUNftIY4z' +
|
||||
'wA5X2Z9AYnQrEAAAAASUVORK5CYII=',
|
||||
"width": 12,
|
||||
"height": 17,
|
||||
"alt": '\u00B6'
|
||||
},{
|
||||
"type": "field_multilinetext",
|
||||
"name": "TEXT",
|
||||
"text": ""
|
||||
}],
|
||||
"output": "String",
|
||||
"style": "text_blocks",
|
||||
"helpUrl": "%{BKY_TEXT_TEXT_HELPURL}",
|
||||
"tooltip": "%{BKY_TEXT_TEXT_TOOLTIP}",
|
||||
"extensions": [
|
||||
"parent_tooltip_when_inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text_join",
|
||||
"message0": "",
|
||||
"output": "String",
|
||||
"style": "text_blocks",
|
||||
"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"
|
||||
}],
|
||||
"style": "text_blocks",
|
||||
"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,
|
||||
"style": "text_blocks",
|
||||
"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,
|
||||
"style": "text_blocks",
|
||||
"extensions": [
|
||||
"text_append_tooltip"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "text_length",
|
||||
"message0": "%{BKY_TEXT_LENGTH_TITLE}",
|
||||
"args0": [
|
||||
{
|
||||
"type": "input_value",
|
||||
"name": "VALUE",
|
||||
"check": ['String', 'Array']
|
||||
}
|
||||
],
|
||||
"output": 'Number',
|
||||
"style": "text_blocks",
|
||||
"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',
|
||||
"style": "text_blocks",
|
||||
"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",
|
||||
"style": "text_blocks",
|
||||
"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",
|
||||
"style": "text_blocks",
|
||||
"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.setStyle('text_blocks');
|
||||
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 = Blockly.utils.xml.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, independent 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.getSourceBlock();
|
||||
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.setStyle('text_blocks');
|
||||
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.setStyle('text_blocks');
|
||||
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,
|
||||
"style": "text_blocks",
|
||||
"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.setStyle('text_blocks');
|
||||
// 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 = Blockly.utils.xml.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.setStyle('text_blocks');
|
||||
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,
|
||||
"style": "text_blocks",
|
||||
"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,
|
||||
"style": "text_blocks",
|
||||
"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,
|
||||
"style": "text_blocks",
|
||||
"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).
|
||||
* @return {!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 = Blockly.utils.xml.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 && !itemBlock.isInsertionMarker()) {
|
||||
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)
|
||||
.setAlign(Blockly.ALIGN_RIGHT);
|
||||
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 = Blockly.utils.xml.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.getSourceBlock();
|
||||
block.updateAt_(newAt);
|
||||
}
|
||||
});
|
||||
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);
|
||||
163
blockly/blocks/variables.js
Normal file
163
blockly/blocks/variables.js
Normal file
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2012 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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');
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.FieldVariable');
|
||||
|
||||
|
||||
/**
|
||||
* 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,
|
||||
"style": "variable_blocks",
|
||||
"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,
|
||||
"style": "variable_blocks",
|
||||
"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) {
|
||||
// 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 = Blockly.utils.xml.createElement('field');
|
||||
xmlField.setAttribute('name', 'VAR');
|
||||
xmlField.appendChild(Blockly.utils.xml.createTextNode(name));
|
||||
var xmlBlock = Blockly.utils.xml.createElement('block');
|
||||
xmlBlock.setAttribute('type', opposite_type);
|
||||
xmlBlock.appendChild(xmlField);
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
// Getter blocks have the option to rename or delete that variable.
|
||||
} else {
|
||||
if (this.type == 'variables_get' || this.type == 'variables_get_reporter') {
|
||||
var renameOption = {
|
||||
text: Blockly.Msg.RENAME_VARIABLE,
|
||||
enabled: true,
|
||||
callback: Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY(this)
|
||||
};
|
||||
var name = this.getField('VAR').getText();
|
||||
var deleteOption = {
|
||||
text: Blockly.Msg.DELETE_VARIABLE.replace('%1', name),
|
||||
enabled: true,
|
||||
callback: Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY(this)
|
||||
};
|
||||
options.unshift(renameOption);
|
||||
options.unshift(deleteOption);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for rename variable dropdown menu option associated with a
|
||||
* variable getter block.
|
||||
* @param {!Blockly.Block} block The block with the variable to rename.
|
||||
* @return {!function()} A function that renames the variable.
|
||||
*/
|
||||
Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY = function(block) {
|
||||
return function() {
|
||||
var workspace = block.workspace;
|
||||
var variable = block.getField('VAR').getVariable();
|
||||
Blockly.Variables.renameVariable(workspace, variable);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for delete variable dropdown menu option associated with a
|
||||
* variable getter block.
|
||||
* @param {!Blockly.Block} block The block with the variable to delete.
|
||||
* @return {!function()} A function that deletes the variable.
|
||||
*/
|
||||
Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY = function(block) {
|
||||
return function() {
|
||||
var workspace = block.workspace;
|
||||
var variable = block.getField('VAR').getVariable();
|
||||
workspace.deleteVariableById(variable.getId());
|
||||
workspace.refreshToolboxSelection();
|
||||
};
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMixin('contextMenu_variableSetterGetter',
|
||||
Blockly.Constants.Variables.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);
|
||||
180
blockly/blocks/variables_dynamic.js
Normal file
180
blockly/blocks/variables_dynamic.js
Normal file
@@ -0,0 +1,180 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2017 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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');
|
||||
goog.require('Blockly.Blocks');
|
||||
goog.require('Blockly.FieldLabel');
|
||||
goog.require('Blockly.FieldVariable');
|
||||
|
||||
|
||||
/**
|
||||
* 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,
|
||||
"style": "variable_dynamic_blocks",
|
||||
"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,
|
||||
"style": "variable_dynamic_blocks",
|
||||
"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) {
|
||||
var opposite_type;
|
||||
var contextMenuMsg;
|
||||
var id = this.getFieldValue('VAR');
|
||||
var variableModel = this.workspace.getVariableById(id);
|
||||
var varType = variableModel.type;
|
||||
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 = Blockly.utils.xml.createElement('field');
|
||||
xmlField.setAttribute('name', 'VAR');
|
||||
xmlField.setAttribute('variabletype', varType);
|
||||
xmlField.appendChild(Blockly.utils.xml.createTextNode(name));
|
||||
var xmlBlock = Blockly.utils.xml.createElement('block');
|
||||
xmlBlock.setAttribute('type', opposite_type);
|
||||
xmlBlock.appendChild(xmlField);
|
||||
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
||||
options.push(option);
|
||||
} else {
|
||||
if (this.type == 'variables_get_dynamic' ||
|
||||
this.type == 'variables_get_reporter_dynamic') {
|
||||
var renameOption = {
|
||||
text: Blockly.Msg.RENAME_VARIABLE,
|
||||
enabled: true,
|
||||
callback: Blockly.Constants.Variables.RENAME_OPTION_CALLBACK_FACTORY(this)
|
||||
};
|
||||
var name = this.getField('VAR').getText();
|
||||
var deleteOption = {
|
||||
text: Blockly.Msg.DELETE_VARIABLE.replace('%1', name),
|
||||
enabled: true,
|
||||
callback: Blockly.Constants.Variables.DELETE_OPTION_CALLBACK_FACTORY(this)
|
||||
};
|
||||
options.unshift(renameOption);
|
||||
options.unshift(deleteOption);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Called whenever anything on the workspace changes.
|
||||
* Set the connection type for this block.
|
||||
* @param {!Blockly.Events.Abstract} _e Change event.
|
||||
* @this {Blockly.Block}
|
||||
*/
|
||||
onchange: function(_e) {
|
||||
var id = this.getFieldValue('VAR');
|
||||
var variableModel = Blockly.Variables.getVariable(this.workspace, id);
|
||||
if (this.type == 'variables_get_dynamic') {
|
||||
this.outputConnection.setCheck(variableModel.type);
|
||||
} else {
|
||||
this.getInput('VALUE').connection.setCheck(variableModel.type);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for rename variable dropdown menu option associated with a
|
||||
* variable getter block.
|
||||
* @param {!Blockly.Block} block The block with the variable to rename.
|
||||
* @return {!function()} A function that renames the variable.
|
||||
*/
|
||||
Blockly.Constants.VariablesDynamic.RENAME_OPTION_CALLBACK_FACTORY = function(block) {
|
||||
return function() {
|
||||
var workspace = block.workspace;
|
||||
var variable = block.getField('VAR').getVariable();
|
||||
Blockly.Variables.renameVariable(workspace, variable);
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for delete variable dropdown menu option associated with a
|
||||
* variable getter block.
|
||||
* @param {!Blockly.Block} block The block with the variable to delete.
|
||||
* @return {!function()} A function that deletes the variable.
|
||||
*/
|
||||
Blockly.Constants.VariablesDynamic.DELETE_OPTION_CALLBACK_FACTORY = function(block) {
|
||||
return function() {
|
||||
var workspace = block.workspace;
|
||||
var variable = block.getField('VAR').getVariable();
|
||||
workspace.deleteVariableById(variable.getId());
|
||||
workspace.refreshToolboxSelection();
|
||||
};
|
||||
};
|
||||
|
||||
Blockly.Extensions.registerMixin('contextMenu_variableDynamicSetterGetter',
|
||||
Blockly.Constants.VariablesDynamic.CUSTOM_CONTEXT_MENU_VARIABLE_GETTER_SETTER_MIXIN);
|
||||
Reference in New Issue
Block a user