/** * @license * Copyright 2012 Google LLC * SPDX-License-Identifier: Apache-2.0 */ /** * @fileoverview Loop blocks for Blockly. * @suppress {extraRequire|missingRequire|checkTypes} */ 'use strict'; goog.provide('Blockly.blocks.loops'); goog.provide('Blockly.Constants.Loops'); goog.require('Blockly'); goog.require('Blockly.FieldDropdown'); goog.require('Blockly.FieldLabel'); goog.require('Blockly.FieldNumber'); goog.require('Blockly.FieldVariable'); goog.require('Blockly.Warning'); goog.require('Blockly.loopMixin'); /** * 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([ // 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}", "suppressPrefixSuffix": true, "extensions": [ "controls_flow_tooltip", "controls_flow_in_loop_check", ], }, ]); /** * 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; } const variable = this.getField('VAR').getVariable(); const varName = variable.name; if (!this.isCollapsed() && varName !== null) { const option = {enabled: true}; option.text = Blockly.Msg['VARIABLES_SET_CREATE_GET'].replace('%1', varName); const xmlField = Blockly.Variables.generateVariableFieldDom(variable); const 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'));