Skip to content
This repository was archived by the owner on Feb 5, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions i18n/strings_to_json_mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@
"TEXT_BLOCK_LANGUAGE_FROM_CAMERA": "${formula_editor_function_text_block_from_camera}",
"DELETE": "${am_delete}",
"DELETE_BLOCK": "${brick_context_dialog_delete_brick}",
"BRICK_CONTEXT_DIALOG_COMMENT_OUT_SCRIPT": "${brick_context_dialog_comment_out_script}",
"BRICK_CONTEXT_DIALOG_COMMENT_IN_SCRIPT": "${brick_context_dialog_comment_in_script}",
"BRICK_CONTEXT_DIALOG_COMMENT_OUT": "${brick_context_dialog_comment_out}",
"BRICK_CONTEXT_DIALOG_COMMENT_IN": "${brick_context_dialog_comment_in}",
"HELP": "${main_menu_help}",
"EMBROIDERY_STITCH": "${brick_stitch}",
"EMBRIODERY_SEW_UP": "${brick_sew_up}",
Expand Down
3 changes: 3 additions & 0 deletions src/intern/ts/Testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ class MockAndroid implements IAndroid {
public duplicateBrick(brickID: string): string {
throw new Error('Method not implemented.');
}
public commentOutBrick(brickID: string): string {
throw new Error('Method not implemented.');
}
public getCurrentProject(): string {
throw new Error('Method not implemented.');
}
Expand Down
118 changes: 117 additions & 1 deletion src/library/js/integration/catroid.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import {
advancedModeAddParentheses,
advancedModeAddCurlyBrackets,
getFieldByCatroidFieldID,
advancedModeRemoveWhiteSpacesInFormulas
advancedModeRemoveWhiteSpacesInFormulas,
updateAdvancedModeCommentOutBricks,
updateAdvancedModeUncommentOutBricks
} from './utils';
import { CatBlocksMsgs } from '../../ts/i18n/CatBlocksMsgs';
import advancedTheme from '../advanced_theme.json';
Expand Down Expand Up @@ -122,6 +124,82 @@ export class Catroid {
return 'hidden';
};

Blockly.ContextMenuRegistry.registry.getItem('blockComment').callback = scope => {
const block = scope.block;
// TODO: Why should it be possible to disable a NoteBrick? (It is possible in 1D-View)
if (block && block.id) {
Android.commentOutBrick(scope.block.id);
if (block.disable) {
block.disable = false;
if (this.config.advancedMode) {
updateAdvancedModeUncommentOutBricks(block);
}
Blockly.utils.dom.removeClass(block.pathObject.svgRoot, 'catblocks-blockly-disabled');
if (Array.from(getBrickScriptMapping().values()).includes(block.type)) {
this.enableDisableAllBlocksAndNestedStatements(null, block.getChildren()[0], false);
}
if (block.statementInputCount > 0) {
const child = Array.from(block.getChildren().filter(c => c !== block.nextConnection.targetBlock()));
this.enableDisableAllBlocksAndNestedStatements(block, child, false);
}
} else {
block.disable = true;
if (this.config.advancedMode) {
updateAdvancedModeCommentOutBricks(block);
}
Blockly.utils.dom.addClass(block.pathObject.svgRoot, 'catblocks-blockly-disabled');
// Change CSS class of all blocks inside the script
if (Array.from(getBrickScriptMapping().values()).includes(block.type)) {
this.enableDisableAllBlocksAndNestedStatements(null, block.getChildren()[0], true);
}
if (block.statementInputCount > 0) {
// get all child of block, except the nextConnection
const child = Array.from(block.getChildren().filter(c => c !== block.nextConnection.targetBlock()));
this.enableDisableAllBlocksAndNestedStatements(block, child, true);
}
}
} else {
console.log('could not disable or enable brick - might be that it is a NoteBrick');
}
};

Blockly.ContextMenuRegistry.registry.getItem('blockComment').displayText = function (scope) {
const block = scope.block;
if (!block.isInFlyout && block.isDeletable() && block.isMovable()) {
if (Array.from(getBrickScriptMapping().values()).includes(block.type)) {
if (!block.disable) {
return CatBlocksMsgs.getCurrentLocaleValues()['BRICK_CONTEXT_DIALOG_COMMENT_OUT_SCRIPT'];
} else {
return CatBlocksMsgs.getCurrentLocaleValues()['BRICK_CONTEXT_DIALOG_COMMENT_IN_SCRIPT'];
}
}
if (!block.disable) {
return CatBlocksMsgs.getCurrentLocaleValues()['BRICK_CONTEXT_DIALOG_COMMENT_OUT'];
}
return CatBlocksMsgs.getCurrentLocaleValues()['BRICK_CONTEXT_DIALOG_COMMENT_IN'];
}
};

Blockly.ContextMenuRegistry.registry.getItem('blockComment').preconditionFn = function (scope) {
const block = scope.block;

if (
(block.type && block.type.endsWith('_UDB_CATBLOCKS_DEF')) ||
block.type === 'UserDefinedScript' ||
block.type === 'NoteBrick'
) {
return 'hidden';
}

if (!block.isInFlyout && block.isDeletable() && block.isMovable()) {
if (block.isDuplicatable()) {
return 'enabled';
}
return 'disabled';
}
return 'hidden';
};

Blockly.ContextMenuRegistry.registry.getItem('blockHelp').callback = function (scope) {
Android.helpBrick(scope.block.id);
};
Expand Down Expand Up @@ -695,4 +773,42 @@ export class Catroid {
this.workspace.scroll(this.workspace.scrollX - boundingRect.x, this.workspace.scrollY - boundingRect.y);
}
}

enableDisableAllBlocksAndNestedStatements(block, child, disable) {
if (block) {
child.forEach(child => {
child.disable = disable;
if (disable) {
if (this.config.advancedMode && child.type !== 'NoteBrick') {
updateAdvancedModeCommentOutBricks(child);
}
Blockly.utils.dom.addClass(child.pathObject.svgRoot, 'catblocks-blockly-disabled');
} else {
if (this.config.advancedMode && child.type !== 'NoteBrick') {
updateAdvancedModeUncommentOutBricks(child);
}
Blockly.utils.dom.removeClass(child.pathObject.svgRoot, 'catblocks-blockly-disabled');
}
child.getChildren().forEach(c => {
this.enableDisableAllBlocksAndNestedStatements(null, c, disable);
});
});
} else {
child.disable = disable;
if (disable) {
if (this.config.advancedMode && child.type !== 'NoteBrick') {
updateAdvancedModeCommentOutBricks(child);
}
Blockly.utils.dom.addClass(child.pathObject.svgRoot, 'catblocks-blockly-disabled');
} else {
if (this.config.advancedMode && child.type !== 'NoteBrick') {
updateAdvancedModeUncommentOutBricks(child);
}
Blockly.utils.dom.removeClass(child.pathObject.svgRoot, 'catblocks-blockly-disabled');
}
child.getChildren().forEach(c => {
this.enableDisableAllBlocksAndNestedStatements(null, c, disable);
});
}
}
}
72 changes: 72 additions & 0 deletions src/library/js/integration/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ export const renderBrick = (parentBrick, jsonBrick, brickListType, workspace, re
Blockly.utils.dom.addClass(childBrick.pathObject.svgRoot, 'catblockls-blockly-invisible');
} else if (jsonBrick.commentedOut) {
Blockly.utils.dom.addClass(childBrick.pathObject.svgRoot, 'catblocks-blockly-disabled');
childBrick.disable = true;
if (workspace.getTheme().name.toLowerCase() === 'advanced') {
childBrick.setStyle('disabled');
}
Expand Down Expand Up @@ -913,6 +914,77 @@ function advancedModeCommentOutBricks(childBrick) {
}
}

export function updateAdvancedModeCommentOutBricks(brick) {
if (!brick.inputList[0].fieldRow[0].getValue().startsWith('// ')) {
brick.inputList[0].fieldRow[0].setValue('// ' + brick.inputList[0].fieldRow[0].getValue());
}
if (
brick.type === 'IfLogicBeginBrick' ||
brick.type === 'PhiroIfLogicBeginBrick' ||
brick.type === 'RaspiIfLogicBeginBrick'
) {
if (!brick.inputList[2].fieldRow[0].getValue().startsWith('// ')) {
brick.inputList[2].fieldRow[0].setValue('// ' + brick.inputList[2].fieldRow[0].getValue());
brick.inputList[4].fieldRow[0].setValue('// ' + brick.inputList[4].fieldRow[0].getValue());
}
}
if (brick.inputList.length === 3 && !brick.inputList[2].fieldRow[0].getValue().startsWith('// ')) {
brick.inputList[2].fieldRow[0].setValue('// ' + brick.inputList[2].fieldRow[0].getValue());
}

const brickElements = document.getElementById(brick.pathObject.svgRoot.id).childNodes;
let count = 1;
while (
count < brickElements.length &&
(brickElements[count].id.includes(brick.getSvgRoot().id) || !brickElements[count].id)
) {
if (
brickElements[count].classList[0] !== 'blocklyNonEditableText' &&
brickElements[count].classList[0] !== 'blocklyEditableText'
) {
brickElements[count].style.opacity = 0.5;
}
count++;
}
}

export function updateAdvancedModeUncommentOutBricks(brick) {
if (brick.inputList[0].fieldRow[0].getValue().startsWith('// ')) {
brick.inputList[0].fieldRow[0].setValue(brick.inputList[0].fieldRow[0].getValue().slice(3));
}
if (
brick.type === 'IfLogicBeginBrick' ||
brick.type === 'PhiroIfLogicBeginBrick' ||
brick.type === 'RaspiIfLogicBeginBrick'
) {
if (
brick.inputList[2].fieldRow[0].getValue().startsWith('// ') &&
brick.inputList[4].fieldRow[0].getValue().startsWith('// ')
) {
brick.inputList[2].fieldRow[0].setValue(brick.inputList[2].fieldRow[0].getValue().slice(3));
brick.inputList[4].fieldRow[0].setValue(brick.inputList[4].fieldRow[0].getValue().slice(3));
}
}
if (brick.inputList.length === 3 && brick.inputList[2].fieldRow[0].getValue().startsWith('// ')) {
brick.inputList[2].fieldRow[0].setValue(brick.inputList[2].fieldRow[0].getValue().slice(3));
}

const brickElements = document.getElementById(brick.pathObject.svgRoot.id).childNodes;
let count = 1;
while (
count < brickElements.length &&
(brickElements[count].id.includes(brick.getSvgRoot().id) || !brickElements[count].id)
) {
if (
brickElements[count].classList[0] !== 'blocklyNonEditableText' &&
brickElements[count].classList[0] !== 'blocklyEditableText'
) {
brickElements[count].style.opacity = 1;
}
count++;
}
}

export const getFieldByCatroidFieldID = (brick, fieldID) => {
for (const input of brick.inputList) {
for (const field of input.fieldRow) {
Expand Down
1 change: 1 addition & 0 deletions src/library/ts/IAndroid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
interface IAndroid {
switchTo1D(brickID: string): void;
duplicateBrick(brickID: string): string;
commentOutBrick(brickID: string): void;
getCurrentProject(): string; // returns coeXML
updateScriptPosition(brickID: string, newX: number, newY: number): void;
helpBrick(brickID: string): void;
Expand Down
Loading