mirror of
https://github.com/google/blockly.git
synced 2026-01-06 16:40:07 +01:00
343 lines
9.9 KiB
JavaScript
343 lines
9.9 KiB
JavaScript
/**
|
|
* @license
|
|
* Visual Blocks Editor
|
|
*
|
|
* Copyright 2012 Google Inc.
|
|
* https://developers.google.com/blockly/
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @fileoverview Loop blocks for Blockly.
|
|
*
|
|
* This file is scraped to extract a .json file of block definitions. The array
|
|
* passed to defineBlocksWithJsonArray(..) must be strict JSON: double quotes
|
|
* only, no outside references, no functions, no trailing commas, etc. The one
|
|
* exception is end-of-line comments, which the scraper will remove.
|
|
* @author fraser@google.com (Neil Fraser)
|
|
*/
|
|
'use strict';
|
|
|
|
goog.provide('Blockly.Blocks.loops'); // Deprecated
|
|
goog.provide('Blockly.Constants.Loops');
|
|
|
|
goog.require('Blockly.Blocks');
|
|
goog.require('Blockly');
|
|
|
|
|
|
/**
|
|
* Unused constant for the common HSV hue for all blocks in this category.
|
|
* @deprecated Use Blockly.Msg['LOOPS_HUE']. (2018 April 5)
|
|
*/
|
|
Blockly.Constants.Loops.HUE = 120;
|
|
|
|
Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
|
// Block for repeat n times (external number).
|
|
{
|
|
"type": "controls_repeat_ext",
|
|
"message0": "%{BKY_CONTROLS_REPEAT_TITLE}",
|
|
"args0": [{
|
|
"type": "input_value",
|
|
"name": "TIMES",
|
|
"check": "Number"
|
|
}],
|
|
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
|
"args1": [{
|
|
"type": "input_statement",
|
|
"name": "DO"
|
|
}],
|
|
"previousStatement": null,
|
|
"nextStatement": null,
|
|
"colour": "%{BKY_LOOPS_HUE}",
|
|
"tooltip": "%{BKY_CONTROLS_REPEAT_TOOLTIP}",
|
|
"helpUrl": "%{BKY_CONTROLS_REPEAT_HELPURL}"
|
|
},
|
|
// Block for repeat n times (internal number).
|
|
// The 'controls_repeat_ext' block is preferred as it is more flexible.
|
|
{
|
|
"type": "controls_repeat",
|
|
"message0": "%{BKY_CONTROLS_REPEAT_TITLE}",
|
|
"args0": [{
|
|
"type": "field_number",
|
|
"name": "TIMES",
|
|
"value": 10,
|
|
"min": 0,
|
|
"precision": 1
|
|
}],
|
|
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
|
"args1": [{
|
|
"type": "input_statement",
|
|
"name": "DO"
|
|
}],
|
|
"previousStatement": null,
|
|
"nextStatement": null,
|
|
"colour": "%{BKY_LOOPS_HUE}",
|
|
"tooltip": "%{BKY_CONTROLS_REPEAT_TOOLTIP}",
|
|
"helpUrl": "%{BKY_CONTROLS_REPEAT_HELPURL}"
|
|
},
|
|
// Block for 'do while/until' loop.
|
|
{
|
|
"type": "controls_whileUntil",
|
|
"message0": "%1 %2",
|
|
"args0": [
|
|
{
|
|
"type": "field_dropdown",
|
|
"name": "MODE",
|
|
"options": [
|
|
["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_WHILE}", "WHILE"],
|
|
["%{BKY_CONTROLS_WHILEUNTIL_OPERATOR_UNTIL}", "UNTIL"]
|
|
]
|
|
},
|
|
{
|
|
"type": "input_value",
|
|
"name": "BOOL",
|
|
"check": "Boolean"
|
|
}
|
|
],
|
|
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
|
"args1": [{
|
|
"type": "input_statement",
|
|
"name": "DO"
|
|
}],
|
|
"previousStatement": null,
|
|
"nextStatement": null,
|
|
"colour": "%{BKY_LOOPS_HUE}",
|
|
"helpUrl": "%{BKY_CONTROLS_WHILEUNTIL_HELPURL}",
|
|
"extensions": ["controls_whileUntil_tooltip"]
|
|
},
|
|
// Block for 'for' loop.
|
|
{
|
|
"type": "controls_for",
|
|
"message0": "%{BKY_CONTROLS_FOR_TITLE}",
|
|
"args0": [
|
|
{
|
|
"type": "field_variable",
|
|
"name": "VAR",
|
|
"variable": null
|
|
},
|
|
{
|
|
"type": "input_value",
|
|
"name": "FROM",
|
|
"check": "Number",
|
|
"align": "RIGHT"
|
|
},
|
|
{
|
|
"type": "input_value",
|
|
"name": "TO",
|
|
"check": "Number",
|
|
"align": "RIGHT"
|
|
},
|
|
{
|
|
"type": "input_value",
|
|
"name": "BY",
|
|
"check": "Number",
|
|
"align": "RIGHT"
|
|
}
|
|
],
|
|
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
|
"args1": [{
|
|
"type": "input_statement",
|
|
"name": "DO"
|
|
}],
|
|
"inputsInline": true,
|
|
"previousStatement": null,
|
|
"nextStatement": null,
|
|
"colour": "%{BKY_LOOPS_HUE}",
|
|
"helpUrl": "%{BKY_CONTROLS_FOR_HELPURL}",
|
|
"extensions": [
|
|
"contextMenu_newGetVariableBlock",
|
|
"controls_for_tooltip"
|
|
]
|
|
},
|
|
// Block for 'for each' loop.
|
|
{
|
|
"type": "controls_forEach",
|
|
"message0": "%{BKY_CONTROLS_FOREACH_TITLE}",
|
|
"args0": [
|
|
{
|
|
"type": "field_variable",
|
|
"name": "VAR",
|
|
"variable": null
|
|
},
|
|
{
|
|
"type": "input_value",
|
|
"name": "LIST",
|
|
"check": "Array"
|
|
}
|
|
],
|
|
"message1": "%{BKY_CONTROLS_REPEAT_INPUT_DO} %1",
|
|
"args1": [{
|
|
"type": "input_statement",
|
|
"name": "DO"
|
|
}],
|
|
"previousStatement": null,
|
|
"nextStatement": null,
|
|
"colour": "%{BKY_LOOPS_HUE}",
|
|
"helpUrl": "%{BKY_CONTROLS_FOREACH_HELPURL}",
|
|
"extensions": [
|
|
"contextMenu_newGetVariableBlock",
|
|
"controls_forEach_tooltip"
|
|
]
|
|
},
|
|
// Block for flow statements: continue, break.
|
|
{
|
|
"type": "controls_flow_statements",
|
|
"message0": "%1",
|
|
"args0": [{
|
|
"type": "field_dropdown",
|
|
"name": "FLOW",
|
|
"options": [
|
|
["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_BREAK}", "BREAK"],
|
|
["%{BKY_CONTROLS_FLOW_STATEMENTS_OPERATOR_CONTINUE}", "CONTINUE"]
|
|
]
|
|
}],
|
|
"previousStatement": null,
|
|
"colour": "%{BKY_LOOPS_HUE}",
|
|
"helpUrl": "%{BKY_CONTROLS_FLOW_STATEMENTS_HELPURL}",
|
|
"extensions": [
|
|
"controls_flow_tooltip",
|
|
"controls_flow_in_loop_check"
|
|
]
|
|
}
|
|
]); // END JSON EXTRACT (Do not delete this comment.)
|
|
|
|
/**
|
|
* Tooltips for the 'controls_whileUntil' block, keyed by MODE value.
|
|
* @see {Blockly.Extensions#buildTooltipForDropdown}
|
|
* @package
|
|
* @readonly
|
|
*/
|
|
Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS = {
|
|
'WHILE': '%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_WHILE}',
|
|
'UNTIL': '%{BKY_CONTROLS_WHILEUNTIL_TOOLTIP_UNTIL}'
|
|
};
|
|
|
|
Blockly.Extensions.register('controls_whileUntil_tooltip',
|
|
Blockly.Extensions.buildTooltipForDropdown(
|
|
'MODE', Blockly.Constants.Loops.WHILE_UNTIL_TOOLTIPS));
|
|
|
|
/**
|
|
* Tooltips for the 'controls_flow_statements' block, keyed by FLOW value.
|
|
* @see {Blockly.Extensions#buildTooltipForDropdown}
|
|
* @package
|
|
* @readonly
|
|
*/
|
|
Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS = {
|
|
'BREAK': '%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_BREAK}',
|
|
'CONTINUE': '%{BKY_CONTROLS_FLOW_STATEMENTS_TOOLTIP_CONTINUE}'
|
|
};
|
|
|
|
Blockly.Extensions.register('controls_flow_tooltip',
|
|
Blockly.Extensions.buildTooltipForDropdown(
|
|
'FLOW', Blockly.Constants.Loops.BREAK_CONTINUE_TOOLTIPS));
|
|
|
|
/**
|
|
* Mixin to add a context menu item to create a 'variables_get' block.
|
|
* Used by blocks 'controls_for' and 'controls_forEach'.
|
|
* @mixin
|
|
* @augments Blockly.Block
|
|
* @package
|
|
* @readonly
|
|
*/
|
|
Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN = {
|
|
/**
|
|
* Add context menu option to create getter block for the loop's variable.
|
|
* (customContextMenu support limited to web BlockSvg.)
|
|
* @param {!Array} options List of menu options to add to.
|
|
* @this Blockly.Block
|
|
*/
|
|
customContextMenu: function(options) {
|
|
if (this.isInFlyout){
|
|
return;
|
|
}
|
|
var variable = this.getField('VAR').getVariable();
|
|
var varName = variable.name;
|
|
if (!this.isCollapsed() && varName != null) {
|
|
var option = {enabled: true};
|
|
option.text =
|
|
Blockly.Msg['VARIABLES_SET_CREATE_GET'].replace('%1', varName);
|
|
var xmlField = Blockly.Variables.generateVariableFieldDom(variable);
|
|
var xmlBlock = goog.dom.createDom('block', null, xmlField);
|
|
xmlBlock.setAttribute('type', 'variables_get');
|
|
option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
|
|
options.push(option);
|
|
}
|
|
}
|
|
};
|
|
|
|
Blockly.Extensions.registerMixin('contextMenu_newGetVariableBlock',
|
|
Blockly.Constants.Loops.CUSTOM_CONTEXT_MENU_CREATE_VARIABLES_GET_MIXIN);
|
|
|
|
Blockly.Extensions.register('controls_for_tooltip',
|
|
Blockly.Extensions.buildTooltipWithFieldText(
|
|
'%{BKY_CONTROLS_FOR_TOOLTIP}', 'VAR'));
|
|
|
|
Blockly.Extensions.register('controls_forEach_tooltip',
|
|
Blockly.Extensions.buildTooltipWithFieldText(
|
|
'%{BKY_CONTROLS_FOREACH_TOOLTIP}', 'VAR'));
|
|
|
|
/**
|
|
* This mixin adds a check to make sure the 'controls_flow_statements' block
|
|
* is contained in a loop. Otherwise a warning is added to the block.
|
|
* @mixin
|
|
* @augments Blockly.Block
|
|
* @package
|
|
* @readonly
|
|
*/
|
|
Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = {
|
|
/**
|
|
* List of block types that are loops and thus do not need warnings.
|
|
* To add a new loop type add this to your code:
|
|
* Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES.push('custom_loop');
|
|
*/
|
|
LOOP_TYPES: ['controls_repeat', 'controls_repeat_ext', 'controls_forEach',
|
|
'controls_for', 'controls_whileUntil'],
|
|
|
|
/**
|
|
* Called whenever anything on the workspace changes.
|
|
* Add warning if this flow block is not nested inside a loop.
|
|
* @param {!Blockly.Events.Abstract} e Change event.
|
|
* @this Blockly.Block
|
|
*/
|
|
onchange: function(/* e */) {
|
|
if (!this.workspace.isDragging || this.workspace.isDragging()) {
|
|
return; // Don't change state at the start of a drag.
|
|
}
|
|
var legal = false;
|
|
// Is the block nested in a loop?
|
|
var block = this;
|
|
do {
|
|
if (this.LOOP_TYPES.indexOf(block.type) != -1) {
|
|
legal = true;
|
|
break;
|
|
}
|
|
block = block.getSurroundParent();
|
|
} while (block);
|
|
if (legal) {
|
|
this.setWarningText(null);
|
|
if (!this.isInFlyout) {
|
|
this.setDisabled(false);
|
|
}
|
|
} else {
|
|
this.setWarningText(Blockly.Msg['CONTROLS_FLOW_STATEMENTS_WARNING']);
|
|
if (!this.isInFlyout && !this.getInheritedDisabled()) {
|
|
this.setDisabled(true);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
Blockly.Extensions.registerMixin('controls_flow_in_loop_check',
|
|
Blockly.Constants.Loops.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN);
|