UNPKG

pxt-core

Version:

Microsoft MakeCode provides Blocks / JavaScript / Python tools and editors

1,096 lines (1,089 loc) • 5.26 MB
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BlockDragger = void 0; const Blockly = require("blockly"); class BlockDragger extends Blockly.dragging.Dragger { onDrag(e, totalDelta) { super.onDrag(e, totalDelta); const blocklyToolboxDiv = document.getElementsByClassName('blocklyToolbox')[0]; const blocklyTreeRoot = document.getElementsByClassName('blocklyTreeRoot')[0] || document.getElementsByClassName('blocklyFlyout')[0]; const trashIcon = document.getElementById("blocklyTrashIcon"); if (blocklyTreeRoot && trashIcon) { const rect = blocklyTreeRoot.getBoundingClientRect(); const distance = calculateDistance(blocklyTreeRoot.getBoundingClientRect(), e.clientX); const isMouseDrag = Blockly.Gesture.inProgress(); if ((isMouseDrag && distance < 200) || (!isMouseDrag && isOverlappingRect(rect, e.clientX))) { const opacity = distance / 200; trashIcon.style.opacity = `${1 - opacity}`; trashIcon.style.display = 'block'; if (blocklyToolboxDiv) { blocklyTreeRoot.style.opacity = `${opacity}`; if (distance < 50) { pxt.BrowserUtils.addClass(blocklyToolboxDiv, 'blocklyToolboxDeleting'); } } } else { trashIcon.style.display = 'none'; blocklyTreeRoot.style.opacity = '1'; if (blocklyToolboxDiv) pxt.BrowserUtils.removeClass(blocklyToolboxDiv, 'blocklyToolboxDeleting'); } } } onDragEnd(e) { super.onDragEnd(e); const blocklyToolboxDiv = document.getElementsByClassName('blocklyToolbox')[0]; const blocklyTreeRoot = document.getElementsByClassName('blocklyTreeRoot')[0] || document.getElementsByClassName('blocklyFlyout')[0]; const trashIcon = document.getElementById("blocklyTrashIcon"); if (trashIcon && blocklyTreeRoot) { trashIcon.style.display = 'none'; blocklyTreeRoot.style.opacity = '1'; if (blocklyToolboxDiv) pxt.BrowserUtils.removeClass(blocklyToolboxDiv, 'blocklyToolboxDeleting'); } } } exports.BlockDragger = BlockDragger; function calculateDistance(elemBounds, mouseX) { return Math.abs(mouseX - (elemBounds.left + (elemBounds.width / 2))); } function isOverlappingRect(elemBounds, mouseX) { return (mouseX - (elemBounds.left + (elemBounds.width))) < 0; } },{"blockly":150}],2:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BreakpointIcon = void 0; const Blockly = require("blockly"); class BreakpointIcon extends Blockly.icons.Icon { constructor(sourceBlock, onStateChange) { super(sourceBlock); this.onStateChange = onStateChange; this.isSet_ = false; } getType() { return BreakpointIcon.type; } initView(pointerdownListener) { super.initView(pointerdownListener); if (this.breakpointSvg) return; // Red/Grey filled circle, for Set/Unset breakpoint respectively. this.breakpointSvg = Blockly.utils.dom.createSvgElement('circle', { 'class': 'blocklyBreakpointSymbol', 'stroke': 'white', 'stroke-width': 2, 'cx': 7, 'cy': 11.5, 'r': 8, }, this.svgRoot); this.updateColor(); } getSize() { return new Blockly.utils.Size(25, 25); } onClick() { this.isSet_ = !this.isSet_; this.updateColor(); this.onStateChange(this.sourceBlock, this.isSet_); } isEnabled() { return this.isSet_; } setEnabled(enabled) { this.isSet_ = enabled; this.updateColor(); } updateColor() { if (!this.breakpointSvg) return; this.breakpointSvg.setAttribute("fill", this.isSet_ ? "#FF0000" : "#CCCCCC"); } } exports.BreakpointIcon = BreakpointIcon; BreakpointIcon.type = new Blockly.icons.IconType("breakpoint"); },{"blockly":150}],3:[function(require,module,exports){ "use strict"; /// <reference path="../../built/pxtlib.d.ts" /> Object.defineProperty(exports, "__esModule", { value: true }); exports.initFunctions = void 0; const Blockly = require("blockly"); const help_1 = require("../help"); const functions_1 = require("../plugins/functions"); const toolbox_1 = require("../toolbox"); const fields_1 = require("../fields"); const loader_1 = require("../loader"); const importer_1 = require("../importer"); const field_imagenotext_1 = require("../fields/field_imagenotext"); function initFunctions() { const msg = Blockly.Msg; // New functions implementation messages msg.FUNCTION_CREATE_NEW = lf("Make a Function..."); msg.FUNCTION_WARNING_DUPLICATE_ARG = lf("Functions cannot use the same argument name more than once."); msg.FUNCTION_WARNING_ARG_NAME_IS_FUNCTION_NAME = lf("Argument names must not be the same as the function name."); msg.FUNCTION_WARNING_EMPTY_NAME = lf("Function and argument names cannot be empty."); msg.FUNCTIONS_DEFAULT_FUNCTION_NAME = lf("doSomething"); msg.FUNCTIONS_DEFAULT_BOOLEAN_ARG_NAME = lf("bool"); msg.FUNCTIONS_DEFAULT_STRING_ARG_NAME = lf("text"); msg.FUNCTIONS_DEFAULT_NUMBER_ARG_NAME = lf("num"); msg.FUNCTIONS_DEFAULT_CUSTOM_ARG_NAME = lf("arg"); msg.FUNCTION_FLYOUT_LABEL = lf("Your Functions"); msg.FUNCTIONS_CREATE_CALL_OPTION = lf("Create 'call {0}'", "%1"); msg.FUNCTIONS_DEFNORETURN_TITLE = lf("function"); msg.PROCEDURES_HUE = pxt.toolbox.getNamespaceColor("functions"); msg.REPORTERS_HUE = pxt.toolbox.getNamespaceColor("variables"); // builtin procedures_defnoreturn const proceduresDefId = "procedures_defnoreturn"; const proceduresDef = pxt.blocks.getBlockDefinition(proceduresDefId); msg.PROCEDURES_DEFNORETURN_TITLE = proceduresDef.block["PROCEDURES_DEFNORETURN_TITLE"]; msg.PROCEDURE_ALREADY_EXISTS = proceduresDef.block["PROCEDURE_ALREADY_EXISTS"]; (Blockly.Blocks['procedures_defnoreturn']).init = function () { let nameField = new Blockly.FieldTextInput('', Blockly.Procedures.rename); //nameField.setSpellcheck(false); //TODO this.appendDummyInput() .appendField(Blockly.Msg.PROCEDURES_DEFNORETURN_TITLE) .appendField(nameField, 'NAME') .appendField('', 'PARAMS'); this.setColour(pxt.toolbox.getNamespaceColor('functions')); this.arguments_ = []; this.argumentVarModels_ = []; this.hat = "cap"; this.setStatements_(true); this.statementConnection_ = null; }; (0, help_1.installBuiltinHelpInfo)(proceduresDefId); // builtin procedures_defnoreturn const proceduresCallId = "procedures_callnoreturn"; const proceduresCallDef = pxt.blocks.getBlockDefinition(proceduresCallId); msg.PROCEDURES_CALLRETURN_TOOLTIP = proceduresDef.tooltip.toString(); Blockly.Blocks['procedures_callnoreturn'] = { init: function () { let nameField = new fields_1.FieldProcedure(''); this.appendDummyInput('TOPROW') .appendField(proceduresCallDef.block['PROCEDURES_CALLNORETURN_TITLE']) .appendField(nameField, 'NAME'); this.setPreviousStatement(true); this.setNextStatement(true); this.setColour(pxt.toolbox.getNamespaceColor('functions')); this.arguments_ = []; this.quarkConnections_ = {}; this.quarkIds_ = null; }, /** * Returns the name of the procedure this block calls. * @return {string} Procedure name. * @this Blockly.Block */ getProcedureCall: function () { // The NAME field is guaranteed to exist, null will never be returned. return /** @type {string} */ (this.getFieldValue('NAME')); }, /** * Notification that a procedure is renaming. * If the name matches this block's procedure, rename it. * @param {string} oldName Previous name of procedure. * @param {string} newName Renamed procedure. * @this Blockly.Block */ renameProcedure: function (oldName, newName) { if (Blockly.Names.equals(oldName, this.getProcedureCall())) { this.setFieldValue(newName, 'NAME'); } }, /** * Procedure calls cannot exist without the corresponding procedure * definition. Enforce this link whenever an event is fired. * @param {!Blockly.Events.Abstract} event Change event. * @this Blockly.Block */ onchange: function (event) { if (!this.workspace || this.workspace.isFlyout || this.isInsertionMarker()) { // Block is deleted or is in a flyout or insertion marker. return; } if (event.type == Blockly.Events.CREATE && event.ids.indexOf(this.id) != -1) { // Look for the case where a procedure call was created (usually through // paste) and there is no matching definition. In this case, create // an empty definition block with the correct signature. let name = this.getProcedureCall(); let def = Blockly.Procedures.getDefinition(name, this.workspace); if (def && (def.type != this.defType_ || JSON.stringify(def.arguments_) != JSON.stringify(this.arguments_))) { // The signatures don't match. def = null; } if (!def) { Blockly.Events.setGroup(event.group); /** * Create matching definition block. * <xml> * <block type="procedures_defreturn" x="10" y="20"> * <field name="NAME">test</field> * </block> * </xml> */ let xml = Blockly.utils.xml.createElement('xml'); let block = Blockly.utils.xml.createElement('block'); block.setAttribute('type', this.defType_); let xy = this.getRelativeToSurfaceXY(); let x = xy.x + Blockly.SNAP_RADIUS * (this.RTL ? -1 : 1); let y = xy.y + Blockly.SNAP_RADIUS * 2; block.setAttribute('x', x); block.setAttribute('y', y); let field = Blockly.utils.xml.createElement('field'); field.setAttribute('name', 'NAME'); field.appendChild(document.createTextNode(this.getProcedureCall())); block.appendChild(field); xml.appendChild(block); (0, importer_1.domToWorkspaceNoEvents)(xml, this.workspace); Blockly.Events.setGroup(false); } } else if (event.type == Blockly.Events.DELETE) { // Look for the case where a procedure definition has been deleted, // leaving this block (a procedure call) orphaned. In this case, delete // the orphan. let name = this.getProcedureCall(); let def = Blockly.Procedures.getDefinition(name, this.workspace); if (!def) { Blockly.Events.setGroup(event.group); this.dispose(true, false); Blockly.Events.setGroup(false); } } }, mutationToDom: function () { const mutationElement = document.createElement("mutation"); mutationElement.setAttribute("name", this.getProcedureCall()); return mutationElement; }, domToMutation: function (element) { const name = element.getAttribute("name"); this.renameProcedure(this.getProcedureCall(), name); }, /** * Add menu option to find the definition block for this call. * @param {!Array} options List of menu options to add to. * @this Blockly.Block */ customContextMenu: function (options) { let option = { enabled: true }; option.text = Blockly.Msg.PROCEDURES_HIGHLIGHT_DEF; let name = this.getProcedureCall(); let workspace = this.workspace; option.callback = function () { let def = Blockly.Procedures.getDefinition(name, workspace); if (def) def.select(); }; options.push(option); }, defType_: 'procedures_defnoreturn' }; (0, help_1.installBuiltinHelpInfo)(proceduresCallId); // New functions implementation function_definition const functionDefinitionId = "function_definition"; const functionDefinition = pxt.blocks.getBlockDefinition(functionDefinitionId); msg.FUNCTIONS_EDIT_OPTION = functionDefinition.block["FUNCTIONS_EDIT_OPTION"]; (0, help_1.installBuiltinHelpInfo)(functionDefinitionId); // New functions implementation function_call const functionCallId = "function_call"; const functionCall = pxt.blocks.getBlockDefinition(functionCallId); msg.FUNCTIONS_CALL_TITLE = functionCall.block["FUNCTIONS_CALL_TITLE"]; msg.FUNCTIONS_GO_TO_DEFINITION_OPTION = functionCall.block["FUNCTIONS_GO_TO_DEFINITION_OPTION"]; (0, help_1.installBuiltinHelpInfo)(functionCallId); (0, help_1.installBuiltinHelpInfo)("function_call_output"); const functionReturnId = "function_return"; Blockly.Blocks[functionReturnId] = { init: function () { initReturnStatement(this); }, onchange: function (event) { const block = this; if (!block.workspace || block.workspace.isFlyout) { // Block is deleted or is in a flyout. return; } const thisWasCreated = event.type === Blockly.Events.BLOCK_CREATE && event.ids.indexOf(block.id) != -1; const thisWasDragged = event.type === Blockly.Events.BLOCK_DRAG && event.blocks.some(b => b.id === block.id); if (thisWasCreated || thisWasDragged) { const rootBlock = block.getRootBlock(); const isTopBlock = rootBlock.type === functionReturnId; if (isTopBlock || rootBlock.previousConnection != null) { // Statement is by itself on the workspace, or it is slotted into a // stack of statements that is not attached to a function or event. Let // it exist until it is connected to a function return; } if (rootBlock.type !== functionDefinitionId) { // Not a function block, so disconnect Blockly.Events.setGroup(event.group); block.previousConnection.disconnect(); Blockly.Events.setGroup(false); } } } }; (0, help_1.installBuiltinHelpInfo)(functionReturnId); Blockly.Procedures.flyoutCategory = flyoutCategory; // Configure function editor argument icons const iconsMap = { number: pxt.blocks.defaultIconForArgType("number"), boolean: pxt.blocks.defaultIconForArgType("boolean"), string: pxt.blocks.defaultIconForArgType("string"), Array: pxt.blocks.defaultIconForArgType("Array") }; const customNames = {}; const functionOptions = pxt.appTarget.runtime && pxt.appTarget.runtime.functionsOptions; if (functionOptions && functionOptions.extraFunctionEditorTypes) { functionOptions.extraFunctionEditorTypes.forEach(t => { iconsMap[t.typeName] = t.icon || pxt.blocks.defaultIconForArgType(); if (t.defaultName) { customNames[t.typeName] = t.defaultName; } }); } for (const type of Object.keys(iconsMap)) { functions_1.FunctionManager.getInstance().setIconForType(type, iconsMap[type]); } for (const type of Object.keys(customNames)) { functions_1.FunctionManager.getInstance().setArgumentNameForType(type, customNames[type]); } if (Blockly.Blocks["argument_reporter_custom"]) { // The logic for setting the output check relies on the internals of PXT // too much to be refactored into pxt-blockly, so we need to monkey patch // it here (Blockly.Blocks["argument_reporter_custom"]).domToMutation = function (xmlElement) { const typeName = xmlElement.getAttribute('typename'); this.typeName_ = typeName; (0, loader_1.setOutputCheck)(this, typeName, loader_1.cachedBlockInfo); }; } const makeCreateCallOptionOriginal = Blockly.Blocks["function_definition"].makeCallOption; Blockly.Blocks["function_definition"].makeCallOption = function () { const option = makeCreateCallOptionOriginal.call(this); const functionName = this.getName(); option.text = pxt.Util.lf("Create 'call {0}'", functionName); return option; }; } exports.initFunctions = initFunctions; function initReturnStatement(b) { const returnDef = pxt.blocks.getBlockDefinition("function_return"); const buttonAddName = "0_add_button"; const buttonRemName = "0_rem_button"; Blockly.Extensions.apply('inline-svgs', b, false); let returnValueVisible = true; // When the value input is removed, we disconnect the block that was connected to it. This // is the id of whatever block was last connected let lastConnectedId; updateShape(); b.domToMutation = saved => { if (saved.hasAttribute("last_connected_id")) { lastConnectedId = saved.getAttribute("last_connected_id"); } returnValueVisible = hasReturnValue(saved); updateShape(); }; b.mutationToDom = () => { const mutation = document.createElement("mutation"); setReturnValue(mutation, !!b.getInput("RETURN_VALUE")); if (lastConnectedId) { mutation.setAttribute("last_connected_id", lastConnectedId); } return mutation; }; function updateShape() { const returnValueInput = b.getInput("RETURN_VALUE"); if (returnValueVisible) { if (!returnValueInput) { // Remove any labels while (b.getInput("")) b.removeInput(""); b.jsonInit({ "message0": returnDef.block["message_with_value"], "args0": [ { "type": "input_value", "name": "RETURN_VALUE", "check": null } ], "previousStatement": null, "colour": pxt.toolbox.getNamespaceColor('functions') }); } if (b.getInput(buttonAddName)) { b.removeInput(buttonAddName); } if (!b.getInput(buttonRemName)) { addMinusButton(); } if (lastConnectedId) { const lastConnected = b.workspace.getBlockById(lastConnectedId); if (lastConnected && lastConnected.outputConnection && !lastConnected.outputConnection.targetBlock()) { b.getInput("RETURN_VALUE").connection.connect(lastConnected.outputConnection); } lastConnectedId = undefined; } } else { if (returnValueInput) { const target = returnValueInput.connection.targetBlock(); if (target) { if (target.isShadow()) target.setShadow(false); returnValueInput.connection.disconnect(); lastConnectedId = target.id; } b.removeInput("RETURN_VALUE"); b.jsonInit({ "message0": returnDef.block["message_no_value"], "args0": [], "previousStatement": null, "colour": pxt.toolbox.getNamespaceColor('functions') }); } if (b.getInput(buttonRemName)) { b.removeInput(buttonRemName); } if (!b.getInput(buttonAddName)) { addPlusButton(); } } b.setInputsInline(true); } function setReturnValue(mutation, hasReturnValue) { mutation.setAttribute("no_return_value", hasReturnValue ? "false" : "true"); } function hasReturnValue(mutation) { return mutation.getAttribute("no_return_value") !== "true"; } function addPlusButton() { addButton(buttonAddName, b.ADD_IMAGE_DATAURI, lf("Add return value")); } function addMinusButton() { addButton(buttonRemName, b.REMOVE_IMAGE_DATAURI, lf("Remove return value")); } function mutationString() { return Blockly.Xml.domToText(b.mutationToDom()); } function fireMutationChange(pre, post) { if (pre !== post) Blockly.Events.fire(new Blockly.Events.BlockChange(b, "mutation", null, pre, post)); } function addButton(name, uri, alt) { b.appendDummyInput(name) .appendField(new field_imagenotext_1.FieldImageNoText(uri, 24, 24, alt, () => { const oldMutation = mutationString(); returnValueVisible = !returnValueVisible; const preUpdate = mutationString(); fireMutationChange(oldMutation, preUpdate); updateShape(); const postUpdate = mutationString(); fireMutationChange(preUpdate, postUpdate); }, false)); } } function flyoutCategory(workspace, useXml) { if (!useXml) return []; let xmlList = []; if (!pxt.appTarget.appTheme.hideFlyoutHeadings) { // Add the Heading label let headingLabel = (0, toolbox_1.createFlyoutHeadingLabel)(lf("Functions"), pxt.toolbox.getNamespaceColor('functions'), pxt.toolbox.getNamespaceIcon('functions'), 'blocklyFlyoutIconfunctions'); xmlList.push(headingLabel); } const newFunction = lf("Make a Function..."); const newFunctionTitle = lf("New function name:"); // Add the "Make a function" button let button = Blockly.utils.xml.createElement('button'); button.setAttribute('text', newFunction); button.setAttribute('callbackKey', 'CREATE_FUNCTION'); let createFunction = (name) => { /** * Create matching definition block. * <xml> * <block type="procedures_defreturn" x="10" y="20"> * <field name="NAME">test</field> * </block> * </xml> */ let topBlock = workspace.getTopBlocks(true)[0]; let x = 10, y = 10; if (topBlock) { let xy = topBlock.getRelativeToSurfaceXY(); x = xy.x + Blockly.SNAP_RADIUS * (topBlock.RTL ? -1 : 1); y = xy.y + Blockly.SNAP_RADIUS * 2; } let xml = Blockly.utils.xml.createElement('xml'); let block = Blockly.utils.xml.createElement('block'); block.setAttribute('type', 'procedures_defnoreturn'); block.setAttribute('x', String(x)); block.setAttribute('y', String(y)); let field = Blockly.utils.xml.createElement('field'); field.setAttribute('name', 'NAME'); field.appendChild(document.createTextNode(name)); block.appendChild(field); xml.appendChild(block); let newBlockIds = (0, importer_1.domToWorkspaceNoEvents)(xml, workspace); // Close flyout and highlight block Blockly.hideChaff(); let newBlock = workspace.getBlockById(newBlockIds[0]); newBlock.select(); // Center on the new block so we know where it is workspace.centerOnBlock(newBlock.id, true); }; workspace.registerButtonCallback('CREATE_FUNCTION', function (button) { let promptAndCheckWithAlert = (defaultName) => { Blockly.dialog.prompt(newFunctionTitle, defaultName, function (newFunc) { pxt.tickEvent('blocks.makeafunction'); // Merge runs of whitespace. Strip leading and trailing whitespace. // Beyond this, all names are legal. if (newFunc) { newFunc = newFunc.replace(/[\s\xa0]+/g, ' ').replace(/^ | $/g, ''); if (newFunc == newFunction) { // Ok, not ALL names are legal... newFunc = null; } } if (newFunc) { if (workspace.getVariableMap().getVariable(newFunc)) { Blockly.dialog.alert(Blockly.Msg.VARIABLE_ALREADY_EXISTS.replace('%1', newFunc.toLowerCase()), function () { promptAndCheckWithAlert(newFunc); // Recurse }); } else if (!Blockly.Procedures.isNameUsed(newFunc, workspace)) { Blockly.dialog.alert(Blockly.Msg.PROCEDURE_ALREADY_EXISTS.replace('%1', newFunc.toLowerCase()), function () { promptAndCheckWithAlert(newFunc); // Recurse }); } else { createFunction(newFunc); } } }); }; promptAndCheckWithAlert('doSomething'); }); xmlList.push(button); function populateProcedures(procedureList, templateName) { for (let i = 0; i < procedureList.length; i++) { let name = procedureList[i][0]; let args = procedureList[i][1]; // <block type="procedures_callnoreturn" gap="16"> // <field name="NAME">name</field> // </block> let block = Blockly.utils.xml.createElement('block'); block.setAttribute('type', templateName); block.setAttribute('gap', '16'); block.setAttribute('colour', pxt.toolbox.getNamespaceColor('functions')); let field = Blockly.utils.xml.createElement('field'); field.textContent = name; field.setAttribute('name', 'NAME'); block.appendChild(field); xmlList.push(block); } } let tuple = Blockly.Procedures.allProcedures(workspace); populateProcedures(tuple[0], 'procedures_callnoreturn'); return xmlList; } },{"../fields":70,"../fields/field_imagenotext":38,"../help":72,"../importer":73,"../loader":77,"../plugins/functions":112,"../toolbox":140,"blockly":150}],4:[function(require,module,exports){ "use strict"; /// <reference path="../../built/pxtlib.d.ts" /> Object.defineProperty(exports, "__esModule", { value: true }); exports.initLists = void 0; const Blockly = require("blockly"); const help_1 = require("../help"); const constants_1 = require("../constants"); function initLists() { const msg = Blockly.Msg; // lists_create_with const listsCreateWithId = "lists_create_with"; const listsCreateWithDef = pxt.blocks.getBlockDefinition(listsCreateWithId); msg.LISTS_CREATE_EMPTY_TITLE = listsCreateWithDef.block["LISTS_CREATE_EMPTY_TITLE"]; msg.LISTS_CREATE_WITH_INPUT_WITH = listsCreateWithDef.block["LISTS_CREATE_WITH_INPUT_WITH"]; msg.LISTS_CREATE_WITH_CONTAINER_TITLE_ADD = listsCreateWithDef.block["LISTS_CREATE_WITH_CONTAINER_TITLE_ADD"]; msg.LISTS_CREATE_WITH_ITEM_TITLE = listsCreateWithDef.block["LISTS_CREATE_WITH_ITEM_TITLE"]; (0, help_1.installBuiltinHelpInfo)(listsCreateWithId); // lists_length const listsLengthId = "lists_length"; const listsLengthDef = pxt.blocks.getBlockDefinition(listsLengthId); msg.LISTS_LENGTH_TITLE = listsLengthDef.block["LISTS_LENGTH_TITLE"]; // We have to override this block definition because the builtin block // allows both Strings and Arrays in its input check and that confuses // our Blockly compiler let block = Blockly.Blocks[listsLengthId]; block.init = function () { this.jsonInit({ "message0": msg.LISTS_LENGTH_TITLE, "args0": [ { "type": "input_value", "name": "VALUE", "check": ['Array'] } ], "output": 'Number', "outputShape": constants_1.provider.SHAPES.ROUND }); }; (0, help_1.installBuiltinHelpInfo)(listsLengthId); // lists_index_get const listsIndexGetId = "lists_index_get"; const listsIndexGetDef = pxt.blocks.getBlockDefinition(listsIndexGetId); Blockly.Blocks["lists_index_get"] = { init: function () { this.jsonInit({ "message0": listsIndexGetDef.block["message0"], "args0": [ { "type": "input_value", "name": "LIST", "check": "Array" }, { "type": "input_value", "name": "INDEX", "check": "Number" } ], "colour": pxt.toolbox.blockColors['arrays'], "outputShape": constants_1.provider.SHAPES.ROUND, "inputsInline": true }); this.setPreviousStatement(false); this.setNextStatement(false); this.setOutput(true); (0, help_1.setBuiltinHelpInfo)(this, listsIndexGetId); } }; // lists_index_set const listsIndexSetId = "lists_index_set"; const listsIndexSetDef = pxt.blocks.getBlockDefinition(listsIndexSetId); Blockly.Blocks[listsIndexSetId] = { init: function () { this.jsonInit({ "message0": listsIndexSetDef.block["message0"], "args0": [ { "type": "input_value", "name": "LIST", "check": "Array" }, { "type": "input_value", "name": "INDEX", "check": "Number" }, { "type": "input_value", "name": "VALUE", "check": null } ], "previousStatement": null, "nextStatement": null, "colour": pxt.toolbox.blockColors['arrays'], "inputsInline": true }); (0, help_1.setBuiltinHelpInfo)(this, listsIndexSetId); } }; } exports.initLists = initLists; },{"../constants":18,"../help":72,"blockly":150}],5:[function(require,module,exports){ "use strict"; /// <reference path="../../built/pxtlib.d.ts" /> Object.defineProperty(exports, "__esModule", { value: true }); exports.initLogic = void 0; const Blockly = require("blockly"); const help_1 = require("../help"); function initLogic() { const msg = Blockly.Msg; // builtin controls_if const controlsIfId = "controls_if"; const controlsIfDef = pxt.blocks.getBlockDefinition(controlsIfId); const controlsIfTooltips = controlsIfDef.tooltip; msg.CONTROLS_IF_MSG_IF = controlsIfDef.block["CONTROLS_IF_MSG_IF"]; msg.CONTROLS_IF_MSG_THEN = controlsIfDef.block["CONTROLS_IF_MSG_THEN"]; msg.CONTROLS_IF_MSG_ELSE = controlsIfDef.block["CONTROLS_IF_MSG_ELSE"]; msg.CONTROLS_IF_MSG_ELSEIF = controlsIfDef.block["CONTROLS_IF_MSG_ELSEIF"]; msg.CONTROLS_IF_TOOLTIP_1 = controlsIfTooltips["CONTROLS_IF_TOOLTIP_1"]; msg.CONTROLS_IF_TOOLTIP_2 = controlsIfTooltips["CONTROLS_IF_TOOLTIP_2"]; msg.CONTROLS_IF_TOOLTIP_3 = controlsIfTooltips["CONTROLS_IF_TOOLTIP_3"]; msg.CONTROLS_IF_TOOLTIP_4 = controlsIfTooltips["CONTROLS_IF_TOOLTIP_4"]; (0, help_1.installBuiltinHelpInfo)(controlsIfId); // builtin logic_compare const logicCompareId = "logic_compare"; const logicCompareDef = pxt.blocks.getBlockDefinition(logicCompareId); const logicCompareTooltips = logicCompareDef.tooltip; msg.LOGIC_COMPARE_TOOLTIP_EQ = logicCompareTooltips["LOGIC_COMPARE_TOOLTIP_EQ"]; msg.LOGIC_COMPARE_TOOLTIP_NEQ = logicCompareTooltips["LOGIC_COMPARE_TOOLTIP_NEQ"]; msg.LOGIC_COMPARE_TOOLTIP_LT = logicCompareTooltips["LOGIC_COMPARE_TOOLTIP_LT"]; msg.LOGIC_COMPARE_TOOLTIP_LTE = logicCompareTooltips["LOGIC_COMPARE_TOOLTIP_LTE"]; msg.LOGIC_COMPARE_TOOLTIP_GT = logicCompareTooltips["LOGIC_COMPARE_TOOLTIP_GT"]; msg.LOGIC_COMPARE_TOOLTIP_GTE = logicCompareTooltips["LOGIC_COMPARE_TOOLTIP_GTE"]; (0, help_1.installBuiltinHelpInfo)(logicCompareId); // builtin logic_operation const logicOperationId = "logic_operation"; const logicOperationDef = pxt.blocks.getBlockDefinition(logicOperationId); const logicOperationTooltips = logicOperationDef.tooltip; msg.LOGIC_OPERATION_AND = logicOperationDef.block["LOGIC_OPERATION_AND"]; msg.LOGIC_OPERATION_OR = logicOperationDef.block["LOGIC_OPERATION_OR"]; msg.LOGIC_OPERATION_TOOLTIP_AND = logicOperationTooltips["LOGIC_OPERATION_TOOLTIP_AND"]; msg.LOGIC_OPERATION_TOOLTIP_OR = logicOperationTooltips["LOGIC_OPERATION_TOOLTIP_OR"]; (0, help_1.installBuiltinHelpInfo)(logicOperationId); // builtin logic_negate const logicNegateId = "logic_negate"; const logicNegateDef = pxt.blocks.getBlockDefinition(logicNegateId); msg.LOGIC_NEGATE_TITLE = logicNegateDef.block["LOGIC_NEGATE_TITLE"]; (0, help_1.installBuiltinHelpInfo)(logicNegateId); // builtin logic_boolean const logicBooleanId = "logic_boolean"; const logicBooleanDef = pxt.blocks.getBlockDefinition(logicBooleanId); msg.LOGIC_BOOLEAN_TRUE = logicBooleanDef.block["LOGIC_BOOLEAN_TRUE"]; msg.LOGIC_BOOLEAN_FALSE = logicBooleanDef.block["LOGIC_BOOLEAN_FALSE"]; (0, help_1.installBuiltinHelpInfo)(logicBooleanId); } exports.initLogic = initLogic; },{"../help":72,"blockly":150}],6:[function(require,module,exports){ "use strict"; /// <reference path="../../built/pxtlib.d.ts" /> Object.defineProperty(exports, "__esModule", { value: true }); exports.initLoops = void 0; const Blockly = require("blockly"); const help_1 = require("../help"); const duplicateOnDrag_1 = require("../plugins/duplicateOnDrag"); function initLoops() { const msg = Blockly.Msg; // controls_repeat_ext const controlsRepeatExtId = "controls_repeat_ext"; const controlsRepeatExtDef = pxt.blocks.getBlockDefinition(controlsRepeatExtId); msg.CONTROLS_REPEAT_TITLE = controlsRepeatExtDef.block["CONTROLS_REPEAT_TITLE"]; msg.CONTROLS_REPEAT_INPUT_DO = controlsRepeatExtDef.block["CONTROLS_REPEAT_INPUT_DO"]; (0, help_1.installBuiltinHelpInfo)(controlsRepeatExtId); // device_while const deviceWhileId = "device_while"; const deviceWhileDef = pxt.blocks.getBlockDefinition(deviceWhileId); Blockly.Blocks[deviceWhileId] = { init: function () { this.jsonInit({ "message0": deviceWhileDef.block["message0"], "args0": [ { "type": "input_value", "name": "COND", "check": "Boolean" } ], "previousStatement": null, "nextStatement": null, "colour": pxt.toolbox.getNamespaceColor('loops') }); this.appendStatementInput("DO") .appendField(deviceWhileDef.block["appendField"]); (0, help_1.setBuiltinHelpInfo)(this, deviceWhileId); } }; // pxt_controls_for const pxtControlsForId = "pxt_controls_for"; const pxtControlsForDef = pxt.blocks.getBlockDefinition(pxtControlsForId); Blockly.Blocks[pxtControlsForId] = { /** * Block for 'for' loop. * @this Blockly.Block */ init: function () { this.jsonInit({ "message0": pxtControlsForDef.block["message0"], "args0": [ { "type": "input_value", "name": "VAR", "variable": pxtControlsForDef.block["variable"], "check": "Variable" }, { "type": "input_value", "name": "TO", "check": "Number" } ], "previousStatement": null, "nextStatement": null, "colour": pxt.toolbox.getNamespaceColor('loops'), "inputsInline": true }); this.appendStatementInput('DO') .appendField(pxtControlsForDef.block["appendField"]); let thisBlock = this; (0, help_1.setHelpResources)(this, pxtControlsForId, pxtControlsForDef.name, function () { return pxt.U.rlf(pxtControlsForDef.tooltip, thisBlock.getInputTargetBlock('VAR') ? thisBlock.getInputTargetBlock('VAR').getField('VAR').getText() : ''); }, pxtControlsForDef.url, String(pxt.toolbox.getNamespaceColor('loops'))); }, /** * Return all variables referenced by this block. * @return {!Array.<string>} List of variable names. * @this Blockly.Block */ getVars: function () { return [this.getField('VAR').getText()]; }, /** * Notification that a variable is renaming. * If the name matches one of this block's variables, rename it. * @param {string} oldName Previous name of variable. * @param {string} newName Renamed variable. * @this Blockly.Block */ renameVar: function (oldName, newName) { const varField = this.getField('VAR'); if (Blockly.Names.equals(oldName, varField.getText())) { varField.setValue(newName); } } }; (0, duplicateOnDrag_1.setDuplicateOnDrag)(pxtControlsForId, "VAR"); // controls_simple_for const controlsSimpleForId = "controls_simple_for"; const controlsSimpleForDef = pxt.blocks.getBlockDefinition(controlsSimpleForId); Blockly.Blocks[controlsSimpleForId] = { /** * Block for 'for' loop. * @this Blockly.Block */ init: function () { this.jsonInit({ "message0": controlsSimpleForDef.block["message0"], "args0": [ { "type": "field_variable", "name": "VAR", "variable": controlsSimpleForDef.block["variable"], "variableTypes": [""], // Please note that most multilingual characters // cannot be used as variable name at this point. // Translate or decide the default variable name // with care. }, { "type": "input_value", "name": "TO", "check": "Number" } ], "previousStatement": null, "nextStatement": null, "colour": pxt.toolbox.getNamespaceColor('loops'), "inputsInline": true }); this.appendStatementInput('DO') .appendField(controlsSimpleForDef.block["appendField"]); let thisBlock = this; (0, help_1.setHelpResources)(this, controlsSimpleForId, controlsSimpleForDef.name, function () { return pxt.U.rlf(controlsSimpleForDef.tooltip, thisBlock.getField('VAR').getText()); }, controlsSimpleForDef.url, String(pxt.toolbox.getNamespaceColor('loops'))); }, /** * Return all variables referenced by this block. * @return {!Array.<string>} List of variable names. * @this Blockly.Block */ getVars: function () { return [this.getField('VAR').getText()]; }, /** * Notification that a variable is renaming. * If the name matches one of this block's variables, rename it. * @param {string} oldName Previous name of variable. * @param {string} newName Renamed variable. * @this Blockly.Block */ renameVar: function (oldName, newName) { const varField = this.getField('VAR'); if (Blockly.Names.equals(oldName, varField.getText())) { varField.setValue(newName); } }, /** * Add menu option to create getter block for loop variable. * @param {!Array} options List of menu options to add to. * @this Blockly.Block */ customContextMenu: function (options) { var _a, _b; if (!this.isCollapsed() && !((_b = (_a = this.workspace) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.readOnly)) { let option = { enabled: true }; let name = this.getField('VAR').getText(); option.text = lf("Create 'get {0}'", name); let xmlField = Blockly.utils.xml.createElement('field'); xmlField.textContent = name; xmlField.setAttribute('name', 'VAR'); let xmlBlock = Blockly.utils.xml.createElement('block'); xmlBlock.setAttribute('type', 'variables_get'); xmlBlock.appendChild(xmlField); option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock); options.push(option); } } }; // break statement const breakBlockDef = pxt.blocks.getBlockDefinition(ts.pxtc.TS_BREAK_TYPE); Blockly.Blocks[pxtc.TS_BREAK_TYPE] = { init: function () { const color = pxt.toolbox.getNamespaceColor('loops'); this.jsonInit({ "message0": breakBlockDef.block["message0"], "inputsInline": true, "previousStatement": null, "nextStatement": null, "colour": color }); (0, help_1.setHelpResources)(this, ts.pxtc.TS_BREAK_TYPE, breakBlockDef.name, breakBlockDef.tooltip, breakBlockDef.url, color, undefined /*colourSecondary*/, undefined /*colourTertiary*/, false /*undeletable*/); } }; // continue statement const continueBlockDef = pxt.blocks.getBlockDefinition(ts.pxtc.TS_CONTINUE_TYPE); Blockly.Blocks[pxtc.TS_CONTINUE_TYPE] = { init: function () { const color = pxt.toolbox.getNamespaceColor('loops'); this.jsonInit({ "message0": continueBlockDef.block["message0"], "inputsInline": true, "previousStatement": null, "nextStatement": null, "colour": color }); (0, help_1.setHelpResources)(this, ts.pxtc.TS_CONTINUE_TYPE, continueBlockDef.name, continueBlockDef.tooltip, continueBlockDef.url, color, undefined /*colourSecondary*/, undefined /*colourTertiary*/, false /*undeletable*/); } }; const collapsedColor = "#cccccc"; Blockly.Blocks[pxtc.COLLAPSED_BLOCK] = { init: function () { this.jsonInit({ "message0": "...", "inputsInline": true, "previousStatement": null, "nextStatement": null, "colour": collapsedColor }); (0, help_1.setHelpResources)(this, ts.pxtc.COLLAPSED_BLOCK, "...", lf("a few blocks"), undefined, collapsedColor, undefined /*colourSecondary*/, undefined /*colourTertiary*/, false /*undeletable*/); } }; // pxt_controls_for_of const pxtControlsForOfId = "pxt_controls_for_of"; const pxtControlsForOfDef = pxt.blocks.getBlockDefinition(pxtControlsForOfId); Blockly.Blocks[pxtControlsForOfId] = { init: function () { this.jsonInit({ "message0": pxtControlsForOfDef.block["message0"], "args0": [ { "type": "input_value", "name": "VAR", "variable": pxtControlsForOfDef.block["variable"], "check": "Variable" }, { "type": "input_value", "name": "LIST", "check": ["Array", "String"] } ], "previousStatement": null, "nextStatement": null, "colour": pxt.toolbox.blockColors['loops'], "inputsInline": true }); this.appendStatementInput('DO') .appendField(pxtControlsForOfDef.block["appendField"]); let thisBlock = this; (0, help_1.setHelpResources)(this, pxtControlsForOfId, pxtControlsForOfDef.name, function () { return pxt.Util.rlf(pxtControlsForOfDef.tooltip, thisBlock.getInputTargetBlock('VAR') ? thisBlock.getInputTargetBlock('VAR').getField('VAR').getText() : ''); }, pxtControlsForOfDef.url, String(pxt.toolbox.getNamespaceColor('loops'))); } }; (0, duplicateOnDrag_1.setDuplicateOnDrag)(pxtControlsForOfId, "VAR"); // controls_for_of const controlsForOfId = "controls_for_of"; const controlsForOfDef = pxt.blocks.getBlockDefinition(controlsForOfId); Blockly.Blocks[controlsForOfId] = { init: function () { this.jsonInit({ "message0": controlsForOfDef.block["message0"], "args0": [ { "type": "field_variable", "name": "VAR", "variable": controlsForOfDef.block["variable"], "variableTypes": [""], // Please note that most multilingual characters // cannot be used as variable name at this point. // Translate or decide the default variable name // with care. }, { "type": "input_value", "name": "LIST", "check": "Array" } ], "previousStatement": null, "nextStatement": null, "colour": pxt.toolbox.blockColors['loops'], "inputsInline": true }); this.appendStatementInput('DO') .appendField(controlsForOfDef.block["appendField"]); let thisBlock = this; (0, help_1.setHelpResources)(this, controlsForOfId, controlsForOfDef.name, function () { return pxt.Util.rlf(controlsForOfDef.tooltip, thisBlock.getField('VAR').getText()); }, controlsForOfDef.url, String(pxt.toolbox.getNamespaceColor('loops'))); } }; } exports.initLoops = initLoops; },{"../help":72,"../plugins/duplicateOnDrag":92,"blockly":150}],7:[function(require,module,exports){ "use strict"; /// <reference path="../../built/pxtlib.d.ts" /> Object.defineProperty(exports, "__esModule", { value: true }); exports.initMathRoundBlock = exports.initMathOpBlock = exports.initMath = void 0; const Blockly = require("blockly"); const help_1 = require("../help"); const constants_1 = require("../constants"); const composableMutations_1 = require("../composableMutations"); const field_dropdown_1 = require("../fields/field_dropdown"); function initMath(blockInfo) { // math_op2 const mathOp2Id = "math_op2"; const mathOp2qName = "Math.min"; // TODO: implement logic so that this changes based on which is used (min or max) const mathOp2Def = pxt.blocks.getBlockDefinition(mathOp2Id); const mathOp2Tooltips = mathOp2Def.tooltip; Blockly.Blocks[mathOp2Id] = { init: function () { this.jsonInit({ "message0": lf("%1 of %2 and %3"), "args0": [ { "type": "field_dropdown", "name": "op", "options": [ [lf("{id:op}min"), "min"], [lf("{id:op}max"), "max"] ] }, { "type": "input_value", "name": "x", "check": "Number" }, { "type": "input_value", "name": "y",