Files
blockly/core/loop_mixin.js

97 lines
2.9 KiB
JavaScript

/**
* @license
* Copyright 2021 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @fileoverview The mixin that holds logic for setting a warning on a block if
* it is not inside a loop.
*/
'use strict';
goog.module('Blockly.loopMixin');
/* eslint-disable-next-line no-unused-vars */
const Abstract = goog.requireType('Blockly.Events.Abstract');
const Events = goog.require('Blockly.Events');
const Extensions = goog.require('Blockly.Extensions');
const Msg = goog.require('Blockly.Msg');
/* eslint-disable-next-line no-unused-vars */
const {Block} = goog.requireType('Blockly.Block');
/**
* 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 Block
* @readonly
*/
const 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.loopMixin.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES.push('custom_loop');
*
* Please leave a comment on this github issue
* https://github.com/mit-cml/appinventor-sources/issues/2032 if you end up
* needing to use this.
*/
LOOP_TYPES: [
'controls_repeat',
'controls_repeat_ext',
'controls_forEach',
'controls_for',
'controls_whileUntil',
],
/**
* Is the given block enclosed (at any level) by a loop?
* @param {!Block} block Current block.
* @return {?Block} The nearest surrounding loop, or null if none.
*/
getSurroundLoop: function(block) {
let searchBlock = block;
// Is the block nested in a loop?
do {
if (CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.LOOP_TYPES.indexOf(
searchBlock.type) !== -1) {
return searchBlock;
}
searchBlock = searchBlock.getSurroundParent();
} while (searchBlock);
return null;
},
/**
* Called whenever anything on the workspace changes.
* Add warning if this flow block is not nested inside a loop.
* @param {!Abstract} e Change event.
* @this {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 !== Events.BLOCK_MOVE) {
return;
}
const enabled = !!CONTROL_FLOW_IN_LOOP_CHECK_MIXIN.getSurroundLoop(this);
this.setWarningText(
enabled ? null : Msg['CONTROLS_FLOW_STATEMENTS_WARNING']);
if (!this.isInFlyout) {
const group = Events.getGroup();
// Makes it so the move and the disable event get undone together.
Events.setGroup(e.group);
this.setEnabled(enabled);
Events.setGroup(group);
}
},
};
exports.CONTROL_FLOW_IN_LOOP_CHECK_MIXIN = CONTROL_FLOW_IN_LOOP_CHECK_MIXIN;
Extensions.registerMixin(
'controls_flow_in_loop_check', CONTROL_FLOW_IN_LOOP_CHECK_MIXIN);