diff --git a/locales/en-us/blocks.json b/locales/en-us/blocks.json
index d8530c44..ca2b5f8f 100644
--- a/locales/en-us/blocks.json
+++ b/locales/en-us/blocks.json
@@ -40,6 +40,7 @@
"moveRight": "Move right",
"moveTo": "Move (with parameter)",
"moveUp": "Move up",
+ "comeToTheEnd": "Am I at the end?",
"canMoveDown": "Can I move down?",
"canMoveRight": "Can I move to the right?",
"canMoveUp": "Can I move up?",
diff --git a/locales/es-ar/blocks.json b/locales/es-ar/blocks.json
index a0d62291..f3be674e 100644
--- a/locales/es-ar/blocks.json
+++ b/locales/es-ar/blocks.json
@@ -40,6 +40,7 @@
"moveRight": "Mover a la derecha",
"moveTo": "Mover a (con parámetro)",
"moveUp": "Mover arriba",
+ "comeToTheEnd": "¿Llegué al final?",
"canMoveDown": "¿Puedo mover abajo?",
"canMoveLeft": "¿Puedo mover a la izquierda?",
"canMoveRight": "¿Puedo mover a la derecha?",
diff --git a/package-lock.json b/package-lock.json
index f4510ee6..573e015f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -32,6 +32,7 @@
"babel-preset-react-app": "^10.0.1",
"bfj": "^7.0.2",
"blockly": "^10.4.3",
+ "blockly-proceds": "^1.0.15",
"browserslist": "^4.18.1",
"camelcase": "^6.2.1",
"case-sensitive-paths-webpack-plugin": "^2.4.0",
@@ -7635,9 +7636,18 @@
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
},
+ "node_modules/blockly-proceds": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/blockly-proceds/-/blockly-proceds-1.0.15.tgz",
+ "integrity": "sha512-rrS2iuujX/0gUnbN3NZj5LBoPJct6POgh0S3ljcSXSMoUQ/cB6OP/h3X87VNlsFzaZyH2kv3Ige1kuS2GP6evw==",
+ "peerDependencies": {
+ "blockly": "^10.4.3"
+ }
+ },
"node_modules/blockly/node_modules/cssstyle": {
"version": "3.0.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
+ "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
"dependencies": {
"rrweb-cssom": "^0.6.0"
},
@@ -7647,7 +7657,8 @@
},
"node_modules/blockly/node_modules/data-urls": {
"version": "4.0.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz",
+ "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==",
"dependencies": {
"abab": "^2.0.6",
"whatwg-mimetype": "^3.0.0",
@@ -7659,7 +7670,8 @@
},
"node_modules/blockly/node_modules/jsdom": {
"version": "22.1.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
+ "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
"dependencies": {
"abab": "^2.0.6",
"cssstyle": "^3.0.0",
@@ -7699,7 +7711,8 @@
},
"node_modules/blockly/node_modules/tr46": {
"version": "4.1.1",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
+ "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
"dependencies": {
"punycode": "^2.3.0"
},
@@ -7709,7 +7722,8 @@
},
"node_modules/blockly/node_modules/whatwg-url": {
"version": "12.0.1",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
+ "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
"dependencies": {
"tr46": "^4.1.1",
"webidl-conversions": "^7.0.0"
@@ -23460,8 +23474,9 @@
}
},
"node_modules/punycode": {
- "version": "2.3.0",
- "license": "MIT",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
"engines": {
"node": ">=6"
}
@@ -33798,12 +33813,16 @@
"dependencies": {
"cssstyle": {
"version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
+ "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
"requires": {
"rrweb-cssom": "^0.6.0"
}
},
"data-urls": {
"version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz",
+ "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==",
"requires": {
"abab": "^2.0.6",
"whatwg-mimetype": "^3.0.0",
@@ -33812,6 +33831,8 @@
},
"jsdom": {
"version": "22.1.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz",
+ "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==",
"requires": {
"abab": "^2.0.6",
"cssstyle": "^3.0.0",
@@ -33840,12 +33861,16 @@
},
"tr46": {
"version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz",
+ "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==",
"requires": {
"punycode": "^2.3.0"
}
},
"whatwg-url": {
"version": "12.0.1",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz",
+ "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==",
"requires": {
"tr46": "^4.1.1",
"webidl-conversions": "^7.0.0"
@@ -34208,6 +34233,12 @@
}
}
},
+ "blockly-proceds": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/blockly-proceds/-/blockly-proceds-1.0.15.tgz",
+ "integrity": "sha512-rrS2iuujX/0gUnbN3NZj5LBoPJct6POgh0S3ljcSXSMoUQ/cB6OP/h3X87VNlsFzaZyH2kv3Ige1kuS2GP6evw==",
+ "requires": {}
+ },
"bluebird": {
"version": "3.7.2"
},
@@ -44328,7 +44359,9 @@
}
},
"punycode": {
- "version": "2.3.0"
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="
},
"pupa": {
"version": "3.1.0",
diff --git a/package.json b/package.json
index e4499a63..dbe2c182 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"babel-preset-react-app": "^10.0.1",
"bfj": "^7.0.2",
"blockly": "^10.4.3",
+ "blockly-proceds": "^1.0.15",
"browserslist": "^4.18.1",
"camelcase": "^6.2.1",
"case-sensitive-paths-webpack-plugin": "^2.4.0",
diff --git a/public/imagenes/iconos/icono.marcadorBlanco.png b/public/imagenes/iconos/icono.marcadorBlanco.png
new file mode 100644
index 00000000..8593bb15
Binary files /dev/null and b/public/imagenes/iconos/icono.marcadorBlanco.png differ
diff --git a/src/components/blockly/PBBlocklyWorkspace.tsx b/src/components/blockly/PBBlocklyWorkspace.tsx
index d5f95fb0..27786350 100644
--- a/src/components/blockly/PBBlocklyWorkspace.tsx
+++ b/src/components/blockly/PBBlocklyWorkspace.tsx
@@ -4,7 +4,7 @@ import { Toolbox, categorizedToolbox, setupBlockly, setupBlocklyBlocks, setXml,
import { PBCard } from "../PBCard";
import { Box, PaperProps, Typography } from "@mui/material";
import { useState } from "react";
-import Blockly from "blockly/core"
+import * as Blockly from 'blockly/core'
import { useThemeContext } from "../../theme/ThemeContext";
// inject options https://developers.google.com/blockly/reference/js/blockly.blocklyoptions_interface.md
@@ -31,7 +31,7 @@ export const PBBlocklyWorkspace = ({ blockIds, categorized, sx, title, ...props
setupBlocklyBlocks(t)
- if (blocklyContainer) setupBlockly(blocklyContainer, { theme: blocklyTheme, toolbox, ...props.workspaceConfiguration } )
+ if (blocklyContainer) setupBlockly(blocklyContainer, { theme: blocklyTheme, toolbox, ...props.workspaceConfiguration } )
if (blocklyContainer && props.initialXml) setXml(props.initialXml )
diff --git a/src/components/blockly/blockly.ts b/src/components/blockly/blockly.ts
index 66b4cab7..5c3698ed 100644
--- a/src/components/blockly/blockly.ts
+++ b/src/components/blockly/blockly.ts
@@ -32,7 +32,7 @@ export type BlocklyBlockDefinition = {
export type Toolbox = { kind: "categoryToolbox" | "flyoutToolbox", contents: ToolboxItem[] }
type ToolboxItem = ToolboxBlock | ToolBoxCategory
type ToolboxBlock = { kind: "block", type: string }
-type ToolBoxCategory = { kind: "category" | '', name: string, contents: ToolboxItem[] }
+type ToolBoxCategory = { kind: "category" | '', name: string, contents: ToolboxItem[], custom?: string }
export const xmlBloqueEmpezarAEjecutar = `
@@ -67,7 +67,8 @@ export const setXml = (xml: string) => {
export const setupBlockly = (container: Element, workspaceConfiguration: Blockly.BlocklyOptions) => {
container.replaceChildren() //Removes previous injection, otherwise it might keep inserting below the current workspace
container.ariaValueText = 'child-blockly'
- Blockly.inject(container, workspaceConfiguration)
+ const workspace = Blockly.inject(container, workspaceConfiguration)
+ workspace.addChangeListener(Blockly.Events.disableOrphans);
}
export const workspaceToCode = () => javascriptGenerator.workspaceToCode(Blockly.getMainWorkspace())
@@ -109,8 +110,9 @@ export const messageBlock = (message: string) => {
}
const createCommonCode = () => {
- javascriptGenerator.addReservedWords('main', 'hacer', 'out_hacer', 'evaluar');
+ javascriptGenerator.addReservedWords('main,hacer,out_hacer,evaluar');
+ /*
javascriptGenerator.required_value = function () {
return null
};
@@ -118,6 +120,7 @@ const createCommonCode = () => {
javascriptGenerator.required_statement = function () {
return null
};
+*/
javascriptGenerator.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
javascriptGenerator.addReservedWords('highlightBlock');
@@ -155,7 +158,6 @@ const defineBlocklyTranslations = (t: (key: string) => string) => {
Blockly.Msg.CLEAN_UP = t("contextMenu.cleanUp")
Blockly.Msg.EXTERNAL_INPUTS = t("contextMenu.externalInputs")
-
// ProcedsBlockly.init() needs all procedure blocks to work, so we need to put them back
// After calling init(), we disable unwanted toolbox blocks again
enableUnwantedProcedureBlocks()
@@ -167,10 +169,15 @@ export const categorizedToolbox = (t: (key: string) => string, blocks: BlockType
const categoryBlocksFor = (categoryId: string): ToolboxItem => {
const contents = blocks.filter(block => block.categoryId === categoryId).map(blockTypeToToolboxBlock)
- return contents.length ? {
+ return contents.length ? categoryId === 'myprocedures' ? {
+ kind: "category",
+ name: `${t(`categories.${categoryId}`)}`,
+ contents: contents,
+ custom: "PROCEDURE"
+ } : {
kind: "category",
name: `${t(`categories.${categoryId}`)}`,
- contents: contents
+ contents: contents,
} : {
kind: '',
name: '',
@@ -187,4 +194,4 @@ export const categorizedToolbox = (t: (key: string) => string, blocks: BlockType
export const uncategorizedToolbox = (blocks: BlockType[]): Toolbox => ({
kind: "flyoutToolbox",
contents: blocks.map(blockTypeToToolboxBlock)
-})
\ No newline at end of file
+})
diff --git a/src/components/blockly/blocksGallery/others.ts b/src/components/blockly/blocksGallery/others.ts
index c6070a77..afc92c80 100644
--- a/src/components/blockly/blocksGallery/others.ts
+++ b/src/components/blockly/blocksGallery/others.ts
@@ -1,7 +1,8 @@
-import { createCommonBlocklyBlocks } from "../utils";
+import { createCommonBlocklyBlocks, disableUnwantedProcedureBlocks, enableUnwantedProcedureBlocks } from "../utils";
import Blockly, { Block } from "blockly/core"
import { sensorsColor } from "./sensors";
import { javascriptGenerator, Order } from "blockly/javascript";
+import { procedsBlocklyInit } from 'blockly-proceds'
const othersColor = '#cc5b22';
const eventsColor = '#00a65a'; // == boton ejecutar
@@ -138,4 +139,10 @@ export const createOthersBlocks = (t: (key: string) => string) => {
init: Blockly.Blocks["logic_compare"].init,
categoryId: 'operators',
}
+
+ enableUnwantedProcedureBlocks()
+
+ procedsBlocklyInit(Blockly)
+
+ disableUnwantedProcedureBlocks()
}
\ No newline at end of file
diff --git a/src/components/blockly/utils.ts b/src/components/blockly/utils.ts
index f1d0f489..28844de8 100644
--- a/src/components/blockly/utils.ts
+++ b/src/components/blockly/utils.ts
@@ -1,4 +1,4 @@
-import Blockly from "blockly/core"
+import * as Blockly from 'blockly/core'
export type optionType = {
'comportamiento'?: string
@@ -48,8 +48,9 @@ export const isFlying = (block: { getRootBlock: () => any; }) =>
export const getParams = (procedureBlock: { getProcedureDef: () => any[]; }) =>
procedureBlock.getProcedureDef()[1]
-export const hasParam = (procedureBlock: { getProcedureDef: () => any[]; }, paramBlock: { getFieldValue: (arg0: string) => any; }) =>
- getParams(procedureBlock).includes(paramBlock.getFieldValue('VAR'))
+export const hasParam = (procedureBlock: { getProcedureDef: () => any[]; }, paramBlock: { getFieldValue: (arg0: string) => any; }) => {
+ return getParams(procedureBlock).includes(paramBlock.getFieldValue('VAR'))
+}
export const clearValidations = (workspace: Blockly.Workspace = Blockly.getMainWorkspace()) => {
workspace.getAllBlocks(false).forEach(clearValidationsFor)
@@ -94,10 +95,14 @@ const drawWarningIcon = (group: Element | null | undefined, colour: any, seconda
group);
};
-const setWarningColour = (block: { warning: { setVisible: (visible: any) => void; bubble_: { setColour: (arg0: any) => void; }; iconGroup_: Element | null | undefined; }; }, colour: any, secondaryColour: any) => {
+const setWarningColour = (block: { warning: { setVisible: (visible: any) => void; textBubble: { setColour: (arg0: any) => void; }; bubble_: { setColour: (arg0: any) => void; }; iconGroup_: Element | null | undefined; }; }, colour: any, secondaryColour: any) => {
const unBoundedSetVisible = block.warning.setVisible
const boundedSetVisible = unBoundedSetVisible.bind(block.warning)
- block.warning.setVisible = (visible) => { boundedSetVisible(visible); if (visible) block.warning.bubble_.setColour(colour) }
+ block.warning.setVisible = (visible) => {
+ boundedSetVisible(visible);
+ if (visible)
+ block.warning.textBubble.setColour(colour)
+ }
drawWarningIcon(block.warning.iconGroup_, colour, secondaryColour)
}
@@ -143,16 +148,14 @@ export const createCommonBlocklyBlocks = (t: (key: string) => string, color: str
"message0": "%1",
"args0": [
{
- "type": "field_variable",
+ "type": "field_label",
"name": "VAR",
- "variable": t("procedures.variableName")
- }
+ "variable": t("procedures.variableName") }
],
"output": null,
"style": "variable_blocks",
"tooltip": "",
"helpUrl": "",
- "extensions": ["contextMenu_variableSetterGetter"]
});
},
mutationToDom: function () {
@@ -177,7 +180,8 @@ export const createCommonBlocklyBlocks = (t: (key: string) => string, color: str
if (this.$parent) { // Este if sirve para las soluciones viejas que no tienen $parent
var procedureDef = this.workspace.getBlockById(this.$parent)
var ok = isInsideProcedureDef(this) && hasParam(procedureDef, this)
- this.setDisabled(!ok)
+ //this.setDisabled(!ok)
+ this.setEnabled(ok)
if (ok || isFlying(this) || !procedureDef) {
clearValidationsFor(this)
} else {
@@ -214,379 +218,6 @@ export const createCommonBlocklyBlocks = (t: (key: string) => string, color: str
}
}
- Blockly.Blocks['procedures_defnoreturn'] = {
- init: function () {
- var nameField = new Blockly.FieldTextInput(Blockly.Msg['PROCEDURES_DEFNORETURN_PROCEDURE'],
- Blockly.Procedures.rename);
- nameField.setSpellcheck(false);
- this.appendDummyInput()
- .appendField(Blockly.Msg['PROCEDURES_DEFNORETURN_TITLE'])
- .appendField(nameField, 'NAME')
- .appendField('', 'PARAMS');
- this.setMutator(new Blockly.icons.MutatorIcon(['procedures_mutatorarg'], this));
- if ((this.workspace.options.comments ||
- (this.workspace.options.parentWorkspace &&
- this.workspace.options.parentWorkspace.options.comments)) &&
- Blockly.Msg['PROCEDURES_DEFNORETURN_COMMENT']) {
- this.setCommentText(Blockly.Msg['PROCEDURES_DEFNORETURN_COMMENT']);
- }
- this.setStyle('procedure_blocks');
- this.setTooltip(Blockly.Msg['PROCEDURES_DEFNORETURN_TOOLTIP']);
- this.setHelpUrl(Blockly.Msg['PROCEDURES_DEFNORETURN_HELPURL']);
- this.arguments_ = [];
- this.argumentVarModels_ = [];
- this.setStatements_(true);
- this.statementConnection_ = null;
-
- },
- /**
- * Add or remove the statement block from this function definition.
- * @param {boolean} hasStatements True if a statement block is needed.
- * @this {Blockly.Block}
- */
- setStatements_: function (hasStatements: boolean) {
- if (this.hasStatements_ === hasStatements) {
- return;
- }
- if (hasStatements) {
- this.appendStatementInput('STACK')
- .appendField(Blockly.Msg['PROCEDURES_DEFNORETURN_DO']);
- if (this.getInput('RETURN')) {
- this.moveInputBefore('STACK', 'RETURN');
- }
- } else {
- this.removeInput('STACK', true);
- }
- this.hasStatements_ = hasStatements;
- },
- /**
- * Update the display of parameters for this procedure definition block.
- * @private
- * @this {Blockly.Block}
- */
- updateParams_: function () {
-
- // Merge the arguments into a human-readable list.
- var paramString = '';
- if (this.arguments_.length) {
- paramString = Blockly.Msg['PROCEDURES_BEFORE_PARAMS'] +
- ' ' + this.arguments_.join(', ');
- }
- // The params field is deterministic based on the mutation,
- // no need to fire a change event.
- Blockly.Events.disable();
- try {
- this.setFieldValue(paramString, 'PARAMS');
- } finally {
- Blockly.Events.enable();
- }
- },
- /**
- * Create XML to represent the argument inputs.
- * @param {boolean=} opt_paramIds If true include the IDs of the parameter
- * quarks. Used by Blockly.Procedures.mutateCallers for reconnection.
- * @return {!Element} XML storage element.
- * @this {Blockly.Block}
- */
- mutationToDom: function (opt_paramIds: any) {
- var container = Blockly.utils.xml.createElement('mutation');
- if (opt_paramIds) {
- container.setAttribute('name', this.getFieldValue('NAME'));
- }
- for (var i = 0; i < this.argumentVarModels_.length; i++) {
- var parameter = Blockly.utils.xml.createElement('arg');
- var argModel = this.argumentVarModels_[i];
- parameter.setAttribute('name', argModel.name);
- parameter.setAttribute('varid', argModel.getId());
- if (opt_paramIds && this.paramIds_) {
- parameter.setAttribute('paramId', this.paramIds_[i]);
- }
- container.appendChild(parameter);
- }
-
- // Save whether the statement input is visible.
- if (!this.hasStatements_) {
- container.setAttribute('statements', 'false');
- }
- return container;
- },
- /**
- * Parse XML to restore the argument inputs.
- * @param {!Element} xmlElement XML storage element.
- * @this {Blockly.Block}
- */
- domToMutation: function (xmlElement: { childNodes: any[]; getAttribute: (arg0: string) => string; }) {
- this.arguments_ = [];
- this.argumentVarModels_ = [];
- for (var i = 0, childNode; (childNode = xmlElement.childNodes[i]); i++) {
- if (childNode.nodeName.toLowerCase() == 'arg') {
- var varName = childNode.getAttribute('name');
- var varId = childNode.getAttribute('varid') || childNode.getAttribute('varId');
- this.arguments_.push(varName);
- var variable = Blockly.Variables.getOrCreateVariablePackage(
- this.workspace, varId, varName, '');
- if (variable != null) {
- this.argumentVarModels_.push(variable);
- } else {
- console.log('Failed to create a variable with name ' + varName + ', ignoring.');
- }
- }
- }
- this.updateParams_();
- Blockly.Procedures.mutateCallers(this);
-
- // Show or hide the statement input.
- this.setStatements_(xmlElement.getAttribute('statements') !== 'false');
- },
- /**
- * Populate the mutator's dialog with this block's components.
- * @param {!Blockly.Workspace} workspace Mutator's workspace.
- * @return {!Blockly.Block} Root block in mutator.
- * @this {Blockly.Block}
- */
- decompose: function (workspace: Blockly.Workspace) {
- /*
- * Creates the following XML:
- *
- *
- *
- * arg1_name
- * etc...
- *
- *
- *
- */
-
- var containerBlockNode = Blockly.utils.xml.createElement('block');
- containerBlockNode.setAttribute('type', 'procedures_mutatorcontainer');
- var statementNode = Blockly.utils.xml.createElement('statement');
- statementNode.setAttribute('name', 'STACK');
- containerBlockNode.appendChild(statementNode);
-
- var node = statementNode;
- for (var i = 0; i < this.arguments_.length; i++) {
- var argBlockNode = Blockly.utils.xml.createElement('block');
- argBlockNode.setAttribute('type', 'procedures_mutatorarg');
- var fieldNode = Blockly.utils.xml.createElement('field');
- fieldNode.setAttribute('name', 'NAME');
- var argumentName = Blockly.utils.xml.createTextNode(this.arguments_[i]);
- fieldNode.appendChild(argumentName);
- argBlockNode.appendChild(fieldNode);
- var nextNode = Blockly.utils.xml.createElement('next');
- argBlockNode.appendChild(nextNode);
-
- node.appendChild(argBlockNode);
- node = nextNode;
- }
-
- var containerBlock = Blockly.Xml.domToBlock(containerBlockNode, workspace);
-
- if (this.type == 'procedures_defreturn') {
- containerBlock.setFieldValue(this.hasStatements_, 'STATEMENTS');
- } else {
- containerBlock.removeInput('STATEMENT_INPUT');
- }
-
- // Initialize procedure's callers with blank IDs.
- Blockly.Procedures.mutateCallers(this);
- return containerBlock;
- },
- /**
- * Reconfigure this block based on the mutator dialog's components.
- * @param {!Blockly.Block} containerBlock Root block in mutator.
- * @this {Blockly.Block}
- */
- compose: function (containerBlock: { getInputTargetBlock: (arg0: string) => any; getFieldValue: (arg0: string) => any; }) {
- // Parameter list.
- this.arguments_ = [];
- this.paramIds_ = [];
- this.argumentVarModels_ = [];
- var paramBlock = containerBlock.getInputTargetBlock('STACK');
- while (paramBlock) {
- var varName = paramBlock.getFieldValue('NAME');
- this.arguments_.push(varName);
- var variable = this.workspace.getVariable(varName, '');
- this.argumentVarModels_.push(variable);
-
- this.paramIds_.push(paramBlock.id);
- paramBlock = paramBlock.nextConnection &&
- paramBlock.nextConnection.targetBlock();
- }
- this.updateParams_();
- Blockly.Procedures.mutateCallers(this);
-
- // Show/hide the statement input.
- var hasStatements = containerBlock.getFieldValue('STATEMENTS');
- if (hasStatements !== null) {
- hasStatements = hasStatements == 'TRUE';
- if (this.hasStatements_ != hasStatements) {
- if (hasStatements) {
- this.setStatements_(true);
- // Restore the stack, if one was saved.
- Blockly.icons.MutatorIcon.reconnect(this.statementConnection_, this, 'STACK');
- this.statementConnection_ = null;
- } else {
- // Save the stack, then disconnect it.
- var stackConnection = this.getInput('STACK').connection;
- this.statementConnection_ = stackConnection.targetConnection;
- if (this.statementConnection_) {
- var stackBlock = stackConnection.targetBlock();
- stackBlock.unplug();
- stackBlock.bumpNeighbours();
- }
- this.setStatements_(false);
- }
- }
- }
- },
- /**
- * Return the signature of this procedure definition.
- * @return {!Array} Tuple containing three elements:
- * - the name of the defined procedure,
- * - a list of all its arguments,
- * - that it DOES NOT have a return value.
- * @this {Blockly.Block}
- */
- getProcedureDef: function () {
- return [this.getFieldValue('NAME'), this.arguments_, false];
- },
- /**
- * Return all variables referenced by this block.
- * @return {!Array.} List of variable names.
- * @this {Blockly.Block}
- */
- getVars: function () {
- return this.arguments_;
- },
- /**
- * Return all variables referenced by this block.
- * @return {!Array.} List of variable models.
- * @this {Blockly.Block}
- */
- getVarModels: function () {
- return this.argumentVarModels_;
- },
- /**
- * Notification that a variable is renaming.
- * If the ID matches one of this block's variables, rename it.
- * @param {string} oldId ID of variable to rename.
- * @param {string} newId ID of new variable. May be the same as oldId, but
- * with an updated name. Guaranteed to be the same type as the old
- * variable.
- * @override
- * @this {Blockly.Block}
- */
- renameVarById: function (oldId: any, newId: any) {
- var oldVariable = this.workspace.getVariableById(oldId);
- if (oldVariable.type != '') {
- // Procedure arguments always have the empty type.
- return;
- }
- var oldName = oldVariable.name;
- var newVar = this.workspace.getVariableById(newId);
-
- var change = false;
- for (var i = 0; i < this.argumentVarModels_.length; i++) {
- if (this.argumentVarModels_[i].getId() == oldId) {
- this.arguments_[i] = newVar.name;
- this.argumentVarModels_[i] = newVar;
- change = true;
- }
- }
- if (change) {
- this.displayRenamedVar_(oldName, newVar.name);
- Blockly.Procedures.mutateCallers(this);
- }
- },
- /**
- * Notification that a variable is renaming but keeping the same ID. If the
- * variable is in use on this block, rerender to show the new name.
- * @param {!Blockly.VariableModel} variable The variable being renamed.
- * @package
- * @override
- * @this {Blockly.Block}
- */
- updateVarName: function (variable: { name: any; getId: () => any; }) {
- var newName = variable.name;
- var change = false;
- for (var i = 0; i < this.argumentVarModels_.length; i++) {
- if (this.argumentVarModels_[i].getId() == variable.getId()) {
- var oldName = this.arguments_[i];
- this.arguments_[i] = newName;
- change = true;
- }
- }
- if (change) {
- this.displayRenamedVar_(oldName, newName);
- Blockly.Procedures.mutateCallers(this);
- }
- },
- /**
- * Update the display to reflect a newly renamed argument.
- * @param {string} oldName The old display name of the argument.
- * @param {string} newName The new display name of the argument.
- * @private
- * @this {Blockly.Block}
- */
- displayRenamedVar_: function (oldName: string, newName: any) {
- this.updateParams_();
- // Update the mutator's variables if the mutator is open.
- if (this.mutator && this.mutator.isVisible()) {
- var blocks = this.mutator.workspace_.getAllBlocks(false);
- for (var i = 0, block; (block = blocks[i]); i++) {
- if (block.type == 'procedures_mutatorarg' &&
- Blockly.Names.equals(oldName, block.getFieldValue('NAME'))) {
- block.setFieldValue(newName, 'NAME');
- }
- }
- }
- },
- /**
- * Add custom menu options to this block's context menu.
- * @param {!Array} options List of menu options to add to.
- * @this {Blockly.Block}
- */
- customContextMenu: function (options: { enabled: boolean; }[]) {
- if (this.isInFlyout) {
- return;
- }
- // Add option to create caller.
- var option = { enabled: true, text: '', callback: () => { } };
- var name = this.getFieldValue('NAME');
- option.text = Blockly.Msg['PROCEDURES_CREATE_DO'].replace('%1', name);
- var xmlMutation = Blockly.utils.xml.createElement('mutation');
- xmlMutation.setAttribute('name', name);
- for (var i = 0; i < this.arguments_.length; i++) {
- var xmlArg = Blockly.utils.xml.createElement('arg');
- xmlArg.setAttribute('name', this.arguments_[i]);
- xmlMutation.appendChild(xmlArg);
- }
- var xmlBlock = Blockly.utils.xml.createElement('block');
- xmlBlock.setAttribute('type', this.callType_);
- xmlBlock.appendChild(xmlMutation);
- option.callback = Blockly.ContextMenu.callbackFactory(this, xmlBlock);
- options.push(option);
-
- // Add options to create getters for each parameter.
- if (!this.isCollapsed()) {
- for (var i = 0; i < this.argumentVarModels_.length; i++) {
- var argOption = { enabled: true, text: '', callback: () => { } };
- var argVar = this.argumentVarModels_[i];
- argOption.text = Blockly.Msg['VARIABLES_SET_CREATE_GET']
- .replace('%1', argVar.name);
-
- var argXmlField = Blockly.Variables.generateVariableFieldDom(argVar);
- var argXmlBlock = Blockly.utils.xml.createElement('block');
- argXmlBlock.setAttribute('type', 'variables_get');
- argXmlBlock.appendChild(argXmlField);
- argOption.callback =
- Blockly.ContextMenu.callbackFactory(this, argXmlBlock);
- options.push(argOption);
- }
- }
- },
- callType_: 'procedures_callnoreturn',
- }
Blockly.Blocks['procedures_defreturn'] = {
/**
diff --git a/src/test/integration/ChallengeView.cy.tsx b/src/test/integration/ChallengeView.cy.tsx
index c92b4fec..e00eb4dc 100644
--- a/src/test/integration/ChallengeView.cy.tsx
+++ b/src/test/integration/ChallengeView.cy.tsx
@@ -37,7 +37,7 @@ describe('Challenge view with blocks', () => {
//TODO - remove the skip once this issue is resolved: https://github.com/Program-AR/pilas-bloques-app/issues/312
const testExecutionWithBlocks = (name: string, solution: string, expected: any, skip = true) => {
- (skip ? it.skip: it)(name, () => {
+ (skip ? it.skip : it)(name, () => {
LocalStorage.saveCreatorChallenge(challenge(solution))
mount(
@@ -72,7 +72,7 @@ describe('Challenge view with blocks', () => {
`
-
+
const ifSolution = `
@@ -187,7 +187,7 @@ describe('Challenge view with blocks', () => {
`
-const aritmethicSolution = `
+ const aritmethicSolution = `
@@ -220,6 +220,60 @@ const aritmethicSolution = `
`
+
+ const procedureSolution = `
+
+
+
+
+
+
+
+
+
+
+ Hacer algo
+
+
+
+
+`
+
+ const procedureWithParameterSolution = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hacer algo
+ parámetro 1
+
+
+
+
+
+
+
+
+
+
+
+`
+
testExecutionWithBlocks('Execution of a solution has effect on scene view', simpleMoveSolution, 1, false)
//Code from blocks have effect
@@ -235,4 +289,9 @@ const aritmethicSolution = `
testExecutionWithBlocks('Code from blocks have effect - repeat', repeatSolution, 2)
testExecutionWithBlocks('Code from blocks have effect - repeat until', repeatUntilSolution, 1)
+
+ testExecutionWithBlocks('Code from blocks have effect - procedures', procedureSolution, 1)
+
+ testExecutionWithBlocks('Code from blocks have effect - procedures with parameter', procedureWithParameterSolution, 1)
+
})
diff --git a/src/theme/ThemeContext.tsx b/src/theme/ThemeContext.tsx
index af4d7922..e5ff5c94 100644
--- a/src/theme/ThemeContext.tsx
+++ b/src/theme/ThemeContext.tsx
@@ -3,8 +3,7 @@ import { createContext, FC, PropsWithChildren, useContext, useEffect, useMemo, u
import { getDesignTokens } from "./theme";
import { LocalStorage } from "../localStorage";
import { Ember } from "../emberCommunication";
-import Blockly, { Theme as BlocklyTheme } from 'blockly/core'
-
+import * as Blockly from 'blockly/core'
const BlocklyClassicTheme = Blockly.Theme.defineTheme('classicBlockly', {
base: Blockly.Themes.Classic,
@@ -43,7 +42,7 @@ type ThemeContextType = {
setSimpleReadModeEnabled: (mode: boolean) => void;
theme: Theme;
isSmallScreen: boolean;
- blocklyTheme: BlocklyTheme;
+ blocklyTheme: Blockly.Theme;
};
export const ThemeContext = createContext({