From 680fc4b6d3aeb640e5c4ffb3f103d547eeb06560 Mon Sep 17 00:00:00 2001 From: Andrew n marshall Date: Mon, 6 Feb 2017 13:40:05 -0800 Subject: [PATCH] Porting Logic blocks to JSON (#913) Extensions, mixins, mutators and constants now grouped under the new namespace Blockly.Constants.Logic. --- blocks/colour.js | 4 +- blocks/logic.js | 627 +++++++++++++++++++++++++++-------------------- blocks/math.js | 5 +- core/block.js | 4 + 4 files changed, 372 insertions(+), 268 deletions(-) diff --git a/blocks/colour.js b/blocks/colour.js index ca52a7b50..dbd87ca18 100644 --- a/blocks/colour.js +++ b/blocks/colour.js @@ -40,7 +40,7 @@ goog.require('Blockly.Blocks'); */ Blockly.Blocks.colour.HUE = 20; -Blockly.defineBlocksWithJsonArray([ +Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT // Block for colour picker. { "type": "colour_picker", @@ -128,4 +128,4 @@ Blockly.defineBlocksWithJsonArray([ "helpUrl": "%{BKY_COLOUR_BLEND_HELPURL}", "tooltip": "%{BKY_COLOUR_BLEND_TOOLTIP}" } -]); // End of defineBlocksWithJsonArray(...) (Do not delete this comment.) +]); // END JSON EXTRACT (Do not delete this comment.) diff --git a/blocks/logic.js b/blocks/logic.js index f3ec22cf3..bd91467f1 100644 --- a/blocks/logic.js +++ b/blocks/logic.js @@ -20,54 +20,291 @@ /** * @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'); +goog.provide('Blockly.Blocks.logic'); // Deprecated +goog.provide('Blockly.Constants.Logic'); goog.require('Blockly.Blocks'); /** * Common HSV hue for all blocks in this category. + * Should be the same as Blockly.Msg.LOGIC_HUE. + * @readonly */ -Blockly.Blocks.logic.HUE = 210; +Blockly.Constants.Logic.HUE = 210; +/** @deprecated Use Blockly.Constants.Logic.HUE */ +Blockly.Blocks.logic.HUE = Blockly.Constants.Logic.HUE; -Blockly.Blocks['controls_if'] = { - /** - * Block for if/elseif/else condition. - * @this Blockly.Block - */ - init: function() { - this.setHelpUrl(Blockly.Msg.CONTROLS_IF_HELPURL); - this.setColour(Blockly.Blocks.logic.HUE); - this.appendValueInput('IF0') - .setCheck('Boolean') - .appendField(Blockly.Msg.CONTROLS_IF_MSG_IF); - this.appendStatementInput('DO0') - .appendField(Blockly.Msg.CONTROLS_IF_MSG_THEN); - this.setPreviousStatement(true); - this.setNextStatement(true); - this.setMutator(new Blockly.Mutator(['controls_if_elseif', - 'controls_if_else'])); - // Assign 'this' to a variable for use in the tooltip closure below. - var thisBlock = this; - this.setTooltip(function() { - if (!thisBlock.elseifCount_ && !thisBlock.elseCount_) { - return Blockly.Msg.CONTROLS_IF_TOOLTIP_1; - } else if (!thisBlock.elseifCount_ && thisBlock.elseCount_) { - return Blockly.Msg.CONTROLS_IF_TOOLTIP_2; - } else if (thisBlock.elseifCount_ && !thisBlock.elseCount_) { - return Blockly.Msg.CONTROLS_IF_TOOLTIP_3; - } else if (thisBlock.elseifCount_ && thisBlock.elseCount_) { - return Blockly.Msg.CONTROLS_IF_TOOLTIP_4; +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"] + ] } - return ''; - }); - this.elseifCount_ = 0; - this.elseCount_ = 0; + ], + "output": "Boolean", + "colour": "%{BKY_LOGIC_HUE}", + "tooltip": "%{BKY_LOGIC_BOOLEAN_TOOLTIP}", + "helpUrl": "%{BKY_LOGIC_BOOLEAN_HELPURL}" }, + // Block for if/elseif/else condition. + { + "type": "controls_if", + "message0": "%{BKY_CONTROLS_IF_MSG_IF} %1", + "args0": [ + { + "type": "input_value", + "name": "IF0", + "check": "Boolean" + } + ], + "message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1", + "args1": [ + { + "type": "input_statement", + "name": "DO0" + } + ], + "previousStatement": null, + "nextStatement": null, + "colour": "%{BKY_LOGIC_HUE}", + "helpUrl": "%{BKY_CONTROLS_IF_HELPURL}", + "extensions": ["controls_if"] + }, + // If/else block that does not use a mutator. + { + "type": "controls_ifelse", + "message0": "%{BKY_CONTROLS_IF_MSG_IF} %1", + "args0": [ + { + "type": "input_value", + "name": "IF0", + "check": "Boolean" + } + ], + "message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1", + "args1": [ + { + "type": "input_statement", + "name": "DO0" + } + ], + "message2": "%{BKY_CONTROLS_IF_MSG_ELSE} %1", + "args2": [ + { + "type": "input_statement", + "name": "ELSE" + } + ], + "previousStatement": null, + "nextStatement": null, + "colour": "%{BKY_LOGIC_HUE}", + "tooltip": "%{BKYCONTROLS_IF_TOOLTIP_2}", + "helpUrl": "%{BKY_CONTROLS_IF_HELPURL}" + }, + // Block for comparison operator. + { + "type": "logic_compare", + "message0": "%1 %2 %3", + "args0": [ + { + "type": "input_value", + "name": "A" + }, + { + "type": "field_dropdown", + "name": "OP", + "options": [ + ["=", "EQ"], + ["\u2260", "NEQ"], + ["<", "LT"], + ["\u2264", "LTE"], + [">", "GT"], + ["\u2265", "GTE"] + ] + }, + { + "type": "input_value", + "name": "B" + } + ], + "inputsInline": true, + "output": "Boolean", + "colour": "%{BKY_LOGIC_HUE}", + "helpUrl": "%{BKY_LOGIC_COMPARE_HELPURL}", + "extensions": ["logic_compare", "logic_op_tooltip"] + }, + // Block for logical operations: 'and', 'or'. + { + "type": "logic_operation", + "message0": "%1 %2 %3", + "args0": [ + { + "type": "input_value", + "name": "A", + "check": "Boolean" + }, + { + "type": "field_dropdown", + "name": "OP", + "options": [ + ["%{BKY_LOGIC_OPERATION_AND}", "AND"], + ["%{BKY_LOGIC_OPERATION_OR}", "OR"] + ] + }, + { + "type": "input_value", + "name": "B", + "check": "Boolean" + } + ], + "inputsInline": true, + "output": "Boolean", + "colour": "%{BKY_LOGIC_HUE}", + "helpUrl": "%{BKY_LOGIC_OPERATION_HELPURL}", + "extensions": ["logic_op_tooltip"] + }, + // Block for negation. + { + "type": "logic_negate", + "message0": "%{BKY_LOGIC_NEGATE_TITLE}", + "args0": [ + { + "type": "input_value", + "name": "BOOL", + "check": "Boolean" + } + ], + "output": "Boolean", + "colour": "%{BKY_LOGIC_HUE}", + "tooltip": "%{BKY_LOGIC_NEGATE_TOOLTIP}", + "helpUrl": "%{BKY_LOGIC_NEGATE_HELPURL}" + }, + // Block for null data type. + { + "type": "logic_null", + "message0": "%{BKY_LOGIC_NULL}", + "output": "null", + "colour": "%{BKY_LOGIC_HUE}", + "tooltip": "%{BKY_LOGIC_NULL_TOOLTIP}", + "helpUrl": "%{BKY_LOGIC_NULL_HELPURL}" + }, + // Block for ternary operator. + { + "type": "logic_ternary", + "message0": "%{BKY_LOGIC_TERNARY_CONDITION} %1", + "args0": [ + { + "type": "input_value", + "name": "IF", + "check": "Boolean" + } + ], + "message1": "%{BKY_LOGIC_TERNARY_IF_TRUE} %1", + "args1": [ + { + "type": "input_value", + "name": "THEN" + } + ], + "message2": "%{BKY_LOGIC_TERNARY_IF_FALSE} %1", + "args2": [ + { + "type": "input_value", + "name": "ELSE" + } + ], + "output": true, + "colour": "%{BKY_LOGIC_HUE}", + "tooltip": "%{BKY_LOGIC_TERNARY_TOOLTIP}", + "helpUrl": "%{BKY_LOGIC_TERNARY_HELPURL}", + "extensions": ["logic_ternary"] + } +]); // END JSON EXTRACT (Do not delete this comment.) + +Blockly.defineBlocksWithJsonArray([ // Mutator blocks. Do not extract. + // Block representing the if statement in the controls_if mutator. + { + "type": "controls_if_if", + "message0": "%{BKY_CONTROLS_IF_IF_TITLE_IF}", + "nextStatement": null, + "enableContextMenu": false, + "colour": "%{BKY_LOGIC_HUE}", + "tooltip": "%{BKY_CONTROLS_IF_IF_TOOLTIP}" + }, + // Block representing the else-if statement in the controls_if mutator. + { + "type": "controls_if_elseif", + "message0": "%{BKY_CONTROLS_IF_ELSEIF_TITLE_ELSEIF}", + "previousStatement": null, + "nextStatement": null, + "enableContextMenu": false, + "colour": "%{BKY_LOGIC_HUE}", + "tooltip": "%{BKY_CONTROLS_IF_ELSEIF_TOOLTIP}" + }, + // Block representing the else statement in the controls_if mutator. + { + "type": "controls_if_else", + "message0": "%{BKY_CONTROLS_IF_ELSE_TITLE_ELSE}", + "previousStatement": null, + "enableContextMenu": false, + "colour": "%{BKY_LOGIC_HUE}", + "tooltip": "%{BKY_CONTROLS_IF_ELSE_TOOLTIP}" + } +]); + +/** + * Tooltip text, keyed by block OP value. Used by logic_compare and + * logic_operation blocks. + * + * Messages are not dereferenced here in order to capture possible language + * changes. + * @package + * @readonly + */ +Blockly.Constants.Logic.LOGIC_OP_TOOLTIPS = { + // 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.LOGIC_OP_TOOLTIPS)); + + +/** + * Mutator methods added to controls_if blocks. + * @mixin + * @package + * @readonly + */ +Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN = { /** * Create XML to represent the number of else-if and else inputs. * @return {Element} XML storage element. @@ -190,8 +427,8 @@ Blockly.Blocks['controls_if'] = { }, /** * Modify this block to have the correct number of inputs. - * @private * @this Blockly.Block + * @private */ updateShape_: function() { // Delete everything. @@ -219,136 +456,73 @@ Blockly.Blocks['controls_if'] = { } }; -Blockly.Blocks['controls_if_if'] = { - /** - * Mutator block for if container. - * @this Blockly.Block - */ - init: function() { - this.setColour(Blockly.Blocks.logic.HUE); - this.appendDummyInput() - .appendField(Blockly.Msg.CONTROLS_IF_IF_TITLE_IF); - this.setNextStatement(true); - this.setTooltip(Blockly.Msg.CONTROLS_IF_IF_TOOLTIP); - this.contextMenu = false; - } +/** + * "controls_if" extension function. Adds mutator, shape updating methods, and + * dynamic tooltip to "controls_if" blocks. + * @this Blockly.Block + * @mixes Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN + * @package + */ +Blockly.Constants.Logic.CONTROLS_IF_EXTENSION = function() { + this.setMutator(new Blockly.Mutator(['controls_if_elseif', 'controls_if_else'])); + this.mixin(Blockly.Constants.Logic.CONTROLS_IF_MUTATOR_MIXIN); + this.elseifCount_ = 0; + this.elseCount_ = 0; + + 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.Blocks['controls_if_elseif'] = { - /** - * Mutator block for else-if condition. - * @this Blockly.Block - */ - init: function() { - this.setColour(Blockly.Blocks.logic.HUE); - this.appendDummyInput() - .appendField(Blockly.Msg.CONTROLS_IF_ELSEIF_TITLE_ELSEIF); - this.setPreviousStatement(true); - this.setNextStatement(true); - this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSEIF_TOOLTIP); - this.contextMenu = false; - } -}; +Blockly.Extensions.register("controls_if", + Blockly.Constants.Logic.CONTROLS_IF_EXTENSION); -Blockly.Blocks['controls_if_else'] = { - /** - * Mutator block for else condition. - * @this Blockly.Block - */ - init: function() { - this.setColour(Blockly.Blocks.logic.HUE); - this.appendDummyInput() - .appendField(Blockly.Msg.CONTROLS_IF_ELSE_TITLE_ELSE); - this.setPreviousStatement(true); - this.setTooltip(Blockly.Msg.CONTROLS_IF_ELSE_TOOLTIP); - this.contextMenu = false; - } -}; - -Blockly.Blocks['controls_ifelse'] = { - /** - * If/else block that does not use a mutator. - * @this Blockly.Block - */ - init: function() { - this.jsonInit({ - "message0": "%{BKY_CONTROLS_IF_MSG_IF} %1", - "args0": [ - { - "type": "input_value", - "name": "IF0", - "check": "Boolean" +/** + * Corrects the logic_compate dropdown label with respect to language direction. + * @this Blockly.Block + * @package + */ +Blockly.Constants.Logic.fixLogicCompareRtlOpLabels = + function() { + var rtlOpLabels = { + 'LT': '\u200F<\u200F', + 'LTE': '\u200F\u2264\u200F', + 'GT': '\u200F>\u200F', + 'GTE': '\u200F\u2265\u200F' + }; + var opDropdown = this.getField('OP'); + if (opDropdown) { + var options = opDropdown.getOptions(); + for (var i = 0; i < options.length; ++i) { + var tuple = options[i]; + var op = tuple[1]; + var rtlLabel = rtlOpLabels[op]; + if (goog.isString(tuple[0]) && rtlLabel) { + // Replace LTR text label + tuple[0] = rtlLabel; } - ], - "message1": "%{BKY_CONTROLS_IF_MSG_THEN} %1", - "args1": [ - { - "type": "input_statement", - "name": "DO0" - } - ], - "message2": "%{BKY_CONTROLS_IF_MSG_ELSE} %1", - "args2": [ - { - "type": "input_statement", - "name": "ELSE" - } - ], - "previousStatement": null, - "nextStatement": null, - "colour": Blockly.Blocks.logic.HUE, - "tooltip": Blockly.Msg.CONTROLS_IF_TOOLTIP_2, - "helpUrl": Blockly.Msg.CONTROLS_IF_HELPURL - }); - } -}; + } + } + }; + +/** + * Adds dynamic type validation for the left and right sides of a logic_compate block. + * @mixin + * @package + * @readonly + */ +Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN = { + prevBlocks_: [null, null], -Blockly.Blocks['logic_compare'] = { - /** - * Block for comparison operator. - * @this Blockly.Block - */ - init: function() { - var rtlOperators = [ - ['=', 'EQ'], - ['\u2260', 'NEQ'], - ['\u200F<\u200F', 'LT'], - ['\u200F\u2264\u200F', 'LTE'], - ['\u200F>\u200F', 'GT'], - ['\u200F\u2265\u200F', 'GTE'] - ]; - var ltrOperators = [ - ['=', 'EQ'], - ['\u2260', 'NEQ'], - ['<', 'LT'], - ['\u2264', 'LTE'], - ['>', 'GT'], - ['\u2265', 'GTE'] - ]; - var OPERATORS = this.RTL ? rtlOperators : ltrOperators; - this.setHelpUrl(Blockly.Msg.LOGIC_COMPARE_HELPURL); - this.setColour(Blockly.Blocks.logic.HUE); - this.setOutput(true, 'Boolean'); - this.appendValueInput('A'); - this.appendValueInput('B') - .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP'); - this.setInputsInline(true); - // Assign 'this' to a variable for use in the tooltip closure below. - var thisBlock = this; - this.setTooltip(function() { - var op = thisBlock.getFieldValue('OP'); - var TOOLTIPS = { - 'EQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_EQ, - 'NEQ': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_NEQ, - 'LT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LT, - 'LTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_LTE, - 'GT': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GT, - 'GTE': Blockly.Msg.LOGIC_COMPARE_TOOLTIP_GTE - }; - return TOOLTIPS[op]; - }); - this.prevBlocks_ = [null, null]; - }, /** * Called whenever anything on the workspace changes. * Prevent mismatched types from being compared. @@ -378,115 +552,37 @@ Blockly.Blocks['logic_compare'] = { } }; -Blockly.Blocks['logic_operation'] = { - /** - * Block for logical operations: 'and', 'or'. - * @this Blockly.Block - */ - init: function() { - var OPERATORS = - [[Blockly.Msg.LOGIC_OPERATION_AND, 'AND'], - [Blockly.Msg.LOGIC_OPERATION_OR, 'OR']]; - this.setHelpUrl(Blockly.Msg.LOGIC_OPERATION_HELPURL); - this.setColour(Blockly.Blocks.logic.HUE); - this.setOutput(true, 'Boolean'); - this.appendValueInput('A') - .setCheck('Boolean'); - this.appendValueInput('B') - .setCheck('Boolean') - .appendField(new Blockly.FieldDropdown(OPERATORS), 'OP'); - this.setInputsInline(true); - // Assign 'this' to a variable for use in the tooltip closure below. - var thisBlock = this; - this.setTooltip(function() { - var op = thisBlock.getFieldValue('OP'); - var TOOLTIPS = { - 'AND': Blockly.Msg.LOGIC_OPERATION_TOOLTIP_AND, - 'OR': Blockly.Msg.LOGIC_OPERATION_TOOLTIP_OR - }; - return TOOLTIPS[op]; - }); +/** + * "logic_compare" extension function. Corrects direction of operators in the + * dropdown labels, and adds type left and right side type checking to + * "logic_compare" blocks. + * @this Blockly.Block + * @mixes Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN + * @package + * @readonly + */ +Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION = function() { + // Fix operator labels in RTL + if (this.RTL) { + Blockly.Constants.Logic.fixLogicCompareRtlOpLabels.apply(this); } + + // Add onchange handler to ensure types are compatable. + this.mixin(Blockly.Constants.Logic.LOGIC_COMPARE_ONCHANGE_MIXIN); }; -Blockly.Blocks['logic_negate'] = { - /** - * Block for negation. - * @this Blockly.Block - */ - init: function() { - this.jsonInit({ - "message0": Blockly.Msg.LOGIC_NEGATE_TITLE, - "args0": [ - { - "type": "input_value", - "name": "BOOL", - "check": "Boolean" - } - ], - "output": "Boolean", - "colour": Blockly.Blocks.logic.HUE, - "tooltip": Blockly.Msg.LOGIC_NEGATE_TOOLTIP, - "helpUrl": Blockly.Msg.LOGIC_NEGATE_HELPURL - }); - } -}; +Blockly.Extensions.register("logic_compare", + Blockly.Constants.Logic.LOGIC_COMPARE_EXTENSION); -// Block for boolean data type: true and false. -Blockly.defineBlocksWithJsonArray([{ - "type": "logic_boolean", - "message0": "%1", - "args0": [ - { - "type": "field_dropdown", - "name": "BOOL", - "options": [ - ["%{BKY_LOGIC_BOOLEAN_TRUE}", "TRUE"], - ["%{BKY_LOGIC_BOOLEAN_FALSE}", "FALSE"] - ] - } - ], - "output": "Boolean", - "colour": "%{BKY_LOGIC_HUE}", - "tooltip": "%{BKY_LOGIC_BOOLEAN_TOOLTIP}", - "helpUrl": "%{BKY_LOGIC_BOOLEAN_HELPURL}" -}]); +/** + * Adds type coordination between inputs and output. + * @mixin + * @package + * @readonly + */ +Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN = { + prevParentConnection_: null, -Blockly.Blocks['logic_null'] = { - /** - * Block for null data type. - * @this Blockly.Block - */ - init: function() { - this.jsonInit({ - "message0": Blockly.Msg.LOGIC_NULL, - "output": null, - "colour": Blockly.Blocks.logic.HUE, - "tooltip": Blockly.Msg.LOGIC_NULL_TOOLTIP, - "helpUrl": Blockly.Msg.LOGIC_NULL_HELPURL - }); - } -}; - -Blockly.Blocks['logic_ternary'] = { - /** - * Block for ternary operator. - * @this Blockly.Block - */ - init: function() { - this.setHelpUrl(Blockly.Msg.LOGIC_TERNARY_HELPURL); - this.setColour(Blockly.Blocks.logic.HUE); - this.appendValueInput('IF') - .setCheck('Boolean') - .appendField(Blockly.Msg.LOGIC_TERNARY_CONDITION); - this.appendValueInput('THEN') - .appendField(Blockly.Msg.LOGIC_TERNARY_IF_TRUE); - this.appendValueInput('ELSE') - .appendField(Blockly.Msg.LOGIC_TERNARY_IF_FALSE); - this.setOutput(true); - this.setTooltip(Blockly.Msg.LOGIC_TERNARY_TOOLTIP); - this.prevParentConnection_ = null; - }, /** * Called whenever anything on the workspace changes. * Prevent mismatched types. @@ -518,3 +614,6 @@ Blockly.Blocks['logic_ternary'] = { this.prevParentConnection_ = parentConnection; } }; + +Blockly.Extensions.registerMixin("logic_ternary", + Blockly.Constants.Logic.LOGIC_TERNARY_ONCHANGE_MIXIN); diff --git a/blocks/math.js b/blocks/math.js index ae2d0643d..aae9e0e3b 100644 --- a/blocks/math.js +++ b/blocks/math.js @@ -40,7 +40,7 @@ goog.require('Blockly.Blocks'); */ Blockly.Blocks.math.HUE = 230; -Blockly.defineBlocksWithJsonArray([ +Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT // Block for numeric value. { "type": "math_number", @@ -370,7 +370,7 @@ Blockly.defineBlocksWithJsonArray([ "tooltip": "%{BKY_MATH_RANDOM_FLOAT_TOOLTIP}", "helpUrl": "%{BKY_MATH_RANDOM_FLOAT_HELPURL}" } -]); // End of defineBlocksWithJsonArray(...) (Do not delete this comment.) +]); // END JSON EXTRACT (Do not delete this comment.) /** * Mapping of math block OP value to tooltip message for blocks @@ -378,6 +378,7 @@ Blockly.defineBlocksWithJsonArray([ * * Messages are not dereferenced here in order to capture possible language * changes. + * @private */ Blockly.Blocks.math.TOOLTIPS_BY_OP_ = { // math_arithmetic diff --git a/core/block.js b/core/block.js index a37851145..ff5907e43 100644 --- a/core/block.js +++ b/core/block.js @@ -1023,6 +1023,10 @@ Blockly.Block.prototype.jsonInit = function(json) { var localizedText = Blockly.utils.replaceMessageReferences(rawValue); this.setTooltip(localizedText); } + if (json['enableContextMenu'] !== undefined) { + var rawValue = json['enableContextMenu']; + this.contextMenu = !!rawValue; + } if (json['helpUrl'] !== undefined) { var rawValue = json['helpUrl']; var localizedValue = Blockly.utils.replaceMessageReferences(rawValue);