pxt-core
Version:
Microsoft MakeCode provides Blocks / JavaScript / Python tools and editors
1,096 lines (1,089 loc) • 5.26 MB
JavaScript
(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",