From 552873111f0e89acb6bcd5430e8979349de185af Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 5 Aug 2024 15:40:22 -0700 Subject: [PATCH 1/3] chore: format vertical_extensions.js --- blocks_vertical/vertical_extensions.js | 142 +++++++++++++++---------- 1 file changed, 88 insertions(+), 54 deletions(-) diff --git a/blocks_vertical/vertical_extensions.js b/blocks_vertical/vertical_extensions.js index 54378d5e46..866747d47e 100644 --- a/blocks_vertical/vertical_extensions.js +++ b/blocks_vertical/vertical_extensions.js @@ -25,9 +25,9 @@ * would have the "colours_operators" and "output_number" extensions. * @author fenichel@google.com (Rachel Fenichel) */ -import * as Blockly from 'blockly/core'; -import {Colours} from '../core/colours.js'; -import {ScratchProcedures} from '../src/procedures.js'; +import * as Blockly from "blockly/core"; +import { Colours } from "../core/colours.js"; +import { ScratchProcedures } from "../src/procedures.js"; const VerticalExtensions = {}; /** @@ -38,10 +38,17 @@ const VerticalExtensions = {}; * @return {function} An extension function that sets colours based on the given * category. */ -VerticalExtensions.colourHelper = function(category) { +VerticalExtensions.colourHelper = function (category) { var colours = Colours[category]; - if (!(colours && colours.primary && colours.secondary && colours.tertiary && - colours.quaternary)) { + if ( + !( + colours && + colours.primary && + colours.secondary && + colours.tertiary && + colours.quaternary + ) + ) { throw new Error('Could not find colours for category "' + category + '"'); } /** @@ -49,7 +56,7 @@ VerticalExtensions.colourHelper = function(category) { * the given category. * @this {Blockly.Block} */ - return function() { + return function () { this.setColour(colours.primary); // this.setColourFromRawValues_(colours.primary, colours.secondary, // colours.tertiary, colours.quaternary); @@ -59,7 +66,7 @@ VerticalExtensions.colourHelper = function(category) { /** * Extension to set the colours of a text field, which are all the same. */ -VerticalExtensions.COLOUR_TEXTFIELD = function() { +VerticalExtensions.COLOUR_TEXTFIELD = function () { this.setColour(colours.textField); // this.setColourFromRawValues_(Colours.textField, // Colours.textField, Colours.textField, @@ -73,7 +80,7 @@ VerticalExtensions.COLOUR_TEXTFIELD = function() { * @this {Blockly.Block} * @readonly */ -VerticalExtensions.SHAPE_STATEMENT = function() { +VerticalExtensions.SHAPE_STATEMENT = function () { this.setInputsInline(true); this.setPreviousStatement(true, null); this.setNextStatement(true, null); @@ -86,7 +93,7 @@ VerticalExtensions.SHAPE_STATEMENT = function() { * @this {Blockly.Block} * @readonly */ -VerticalExtensions.SHAPE_HAT = function() { +VerticalExtensions.SHAPE_HAT = function () { this.setInputsInline(true); this.setNextStatement(true, null); }; @@ -98,7 +105,7 @@ VerticalExtensions.SHAPE_HAT = function() { * @this {Blockly.Block} * @readonly */ -VerticalExtensions.SHAPE_END = function() { +VerticalExtensions.SHAPE_END = function () { this.setInputsInline(true); this.setPreviousStatement(true, null); }; @@ -110,10 +117,10 @@ VerticalExtensions.SHAPE_END = function() { * @this {Blockly.Block} * @readonly */ -VerticalExtensions.OUTPUT_NUMBER = function() { +VerticalExtensions.OUTPUT_NUMBER = function () { this.setInputsInline(true); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); - this.setOutput(true, 'Number'); + this.setOutput(true, "Number"); }; /** @@ -123,10 +130,10 @@ VerticalExtensions.OUTPUT_NUMBER = function() { * @this {Blockly.Block} * @readonly */ -VerticalExtensions.OUTPUT_STRING = function() { +VerticalExtensions.OUTPUT_STRING = function () { this.setInputsInline(true); this.setOutputShape(Blockly.OUTPUT_SHAPE_ROUND); - this.setOutput(true, 'String'); + this.setOutput(true, "String"); }; /** @@ -136,10 +143,10 @@ VerticalExtensions.OUTPUT_STRING = function() { * @this {Blockly.Block} * @readonly */ -VerticalExtensions.OUTPUT_BOOLEAN = function() { +VerticalExtensions.OUTPUT_BOOLEAN = function () { this.setInputsInline(true); this.setOutputShape(Blockly.OUTPUT_SHAPE_HEXAGONAL); - this.setOutput(true, 'Boolean'); + this.setOutput(true, "Boolean"); }; /** @@ -157,15 +164,15 @@ VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU = { * @param {!Array.} menuOptions List of menu options to edit. * @this Blockly.Block */ - customContextMenu: function(menuOptions) { + customContextMenu: function (menuOptions) { // Add the edit option at the end. menuOptions.push(ScratchProcedures.makeEditOption(this)); // Find the delete option and update its callback to be specific to // functions. - for (var i = 0, option; option = menuOptions[i]; i++) { + for (var i = 0, option; (option = menuOptions[i]); i++) { if (option.text == Blockly.Msg.DELETE_BLOCK) { - var input = this.getInput('custom_block'); + var input = this.getInput("custom_block"); // this is the root block, not the shadow block. if (input && input.connection && input.connection.targetBlock()) { var procCode = input.connection.targetBlock().getProcCode(); @@ -173,9 +180,11 @@ VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU = { return; } var rootBlock = this; - option.callback = function() { + option.callback = function () { var didDelete = ScratchProcedures.deleteProcedureDefCallback( - procCode, rootBlock); + procCode, + rootBlock + ); if (!didDelete) { alert(Blockly.Msg.PROCEDURE_USED); } @@ -183,13 +192,13 @@ VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU = { } } // Find and remove the duplicate option - for (var i = 0, option; option = menuOptions[i]; i++) { + for (var i = 0, option; (option = menuOptions[i]); i++) { if (option.text == Blockly.Msg.DUPLICATE) { menuOptions.splice(i, 1); break; } } - } + }, }; /** @@ -207,59 +216,84 @@ VerticalExtensions.PROCEDURE_CALL_CONTEXTMENU = { * @param {!Array.} menuOptions List of menu options to edit. * @this Blockly.Block */ - customContextMenu: function(menuOptions) { + customContextMenu: function (menuOptions) { menuOptions.push(ScratchProcedures.makeEditOption(this)); - } + }, }; - -VerticalExtensions.SCRATCH_EXTENSION = function() { +VerticalExtensions.SCRATCH_EXTENSION = function () { this.isScratchExtension = true; }; /** * Register all extensions for scratch-blocks. * @package */ -VerticalExtensions.registerAll = function() { - var categoryNames = - ['control', 'data', 'data_lists', 'sounds', 'motion', 'looks', 'event', - 'sensing', 'pen', 'operators', 'more']; +VerticalExtensions.registerAll = function () { + var categoryNames = [ + "control", + "data", + "data_lists", + "sounds", + "motion", + "looks", + "event", + "sensing", + "pen", + "operators", + "more", + ]; // Register functions for all category colours. for (var i = 0; i < categoryNames.length; i++) { var name = categoryNames[i]; - Blockly.Extensions.register('colours_' + name, - VerticalExtensions.colourHelper(name)); + Blockly.Extensions.register( + "colours_" + name, + VerticalExtensions.colourHelper(name) + ); } // Text fields transcend categories. - Blockly.Extensions.register('colours_textfield', - VerticalExtensions.COLOUR_TEXTFIELD); + Blockly.Extensions.register( + "colours_textfield", + VerticalExtensions.COLOUR_TEXTFIELD + ); // Register extensions for common block shapes. - Blockly.Extensions.register('shape_statement', - VerticalExtensions.SHAPE_STATEMENT); - Blockly.Extensions.register('shape_hat', - VerticalExtensions.SHAPE_HAT); - Blockly.Extensions.register('shape_end', - VerticalExtensions.SHAPE_END); + Blockly.Extensions.register( + "shape_statement", + VerticalExtensions.SHAPE_STATEMENT + ); + Blockly.Extensions.register("shape_hat", VerticalExtensions.SHAPE_HAT); + Blockly.Extensions.register("shape_end", VerticalExtensions.SHAPE_END); // Output shapes and types are related. - Blockly.Extensions.register('output_number', - VerticalExtensions.OUTPUT_NUMBER); - Blockly.Extensions.register('output_string', - VerticalExtensions.OUTPUT_STRING); - Blockly.Extensions.register('output_boolean', - VerticalExtensions.OUTPUT_BOOLEAN); + Blockly.Extensions.register( + "output_number", + VerticalExtensions.OUTPUT_NUMBER + ); + Blockly.Extensions.register( + "output_string", + VerticalExtensions.OUTPUT_STRING + ); + Blockly.Extensions.register( + "output_boolean", + VerticalExtensions.OUTPUT_BOOLEAN + ); // Custom procedures have interesting context menus. - Blockly.Extensions.registerMixin('procedure_def_contextmenu', - VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU); - Blockly.Extensions.registerMixin('procedure_call_contextmenu', - VerticalExtensions.PROCEDURE_CALL_CONTEXTMENU); + Blockly.Extensions.registerMixin( + "procedure_def_contextmenu", + VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU + ); + Blockly.Extensions.registerMixin( + "procedure_call_contextmenu", + VerticalExtensions.PROCEDURE_CALL_CONTEXTMENU + ); // Extension blocks have slightly different block rendering. - Blockly.Extensions.register('scratch_extension', - VerticalExtensions.SCRATCH_EXTENSION); + Blockly.Extensions.register( + "scratch_extension", + VerticalExtensions.SCRATCH_EXTENSION + ); }; VerticalExtensions.registerAll(); From 58abeb8ee2fae12d1f3460180e1e73a327f688fa Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 5 Aug 2024 15:41:14 -0700 Subject: [PATCH 2/3] chore: format procedures.js --- src/procedures.js | 161 ++++++++++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 69 deletions(-) diff --git a/src/procedures.js b/src/procedures.js index bc1c76c3b5..f826dc3f2b 100644 --- a/src/procedures.js +++ b/src/procedures.js @@ -23,9 +23,9 @@ * @author fraser@google.com (Neil Fraser) */ -import * as Blockly from 'blockly/core'; -import * as Constants from './constants.js'; -import * as scratchBlocksUtils from '../core/scratch_blocks_utils.js'; +import * as Blockly from "blockly/core"; +import * as Constants from "./constants.js"; +import * as scratchBlocksUtils from "../core/scratch_blocks_utils.js"; /** * Find all user-created procedure definition mutations in a workspace. @@ -57,9 +57,9 @@ function allProcedureMutations(root) { function sortProcedureMutations_(mutations) { var newMutations = mutations.slice(); - newMutations.sort(function(a, b) { - var procCodeA = a.getAttribute('proccode'); - var procCodeB = b.getAttribute('proccode'); + newMutations.sort(function (a, b) { + var procCodeA = a.getAttribute("proccode"); + var procCodeB = b.getAttribute("proccode"); return scratchBlocksUtils.compareStrings(procCodeA, procCodeB); }); @@ -85,9 +85,9 @@ function getProceduresCategory(workspace) { // // // - var block = document.createElement('block'); - block.setAttribute('type', 'procedures_call'); - block.setAttribute('gap', 16); + var block = document.createElement("block"); + block.setAttribute("type", "procedures_call"); + block.setAttribute("gap", 16); block.appendChild(mutation); xmlList.push(block); } @@ -101,14 +101,14 @@ function getProceduresCategory(workspace) { * @private */ function addCreateButton_(workspace, xmlList) { - var button = document.createElement('button'); + var button = document.createElement("button"); var msg = Blockly.Msg.NEW_PROCEDURE; - var callbackKey = 'CREATE_PROCEDURE'; - var callback = function() { + var callbackKey = "CREATE_PROCEDURE"; + var callback = function () { createProcedureDefCallback(workspace); }; - button.setAttribute('text', msg); - button.setAttribute('callbackKey', callbackKey); + button.setAttribute("text", msg); + button.setAttribute("callbackKey", callbackKey); workspace.registerButtonCallback(callbackKey, callback); xmlList.push(button); } @@ -125,8 +125,7 @@ function addCreateButton_(workspace, xmlList) { * @return {!Array.} Array of caller blocks. * @package */ -function getCallers(name, ws, definitionRoot, - allowRecursive) { +function getCallers(name, ws, definitionRoot, allowRecursive) { var allBlocks = []; var topBlocks = ws.getTopBlocks(); @@ -142,7 +141,7 @@ function getCallers(name, ws, definitionRoot, var callers = []; for (var i = 0; i < allBlocks.length; i++) { var block = allBlocks[i]; - if (block.type == Constants.PROCEDURES_CALL_BLOCK_TYPE ) { + if (block.type == Constants.PROCEDURES_CALL_BLOCK_TYPE) { var procCode = block.getProcCode(); if (procCode && procCode == name) { callers.push(block); @@ -163,24 +162,35 @@ function mutateCallersAndPrototype(name, ws, mutation) { var defineBlock = getDefineBlock(name, ws); var prototypeBlock = getPrototypeBlock(name, ws); if (defineBlock && prototypeBlock) { - var callers = getCallers(name, - defineBlock.workspace, defineBlock, true /* allowRecursive */); + var callers = getCallers( + name, + defineBlock.workspace, + defineBlock, + true /* allowRecursive */ + ); callers.push(prototypeBlock); Blockly.Events.setGroup(true); - for (var i = 0, caller; caller = callers[i]; i++) { + for (var i = 0, caller; (caller = callers[i]); i++) { var oldMutationDom = caller.mutationToDom(); var oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom); caller.domToMutation(mutation); var newMutationDom = caller.mutationToDom(); var newMutation = newMutationDom && Blockly.Xml.domToText(newMutationDom); if (oldMutation != newMutation) { - Blockly.Events.fire(new Blockly.Events.BlockChange( - caller, 'mutation', null, oldMutation, newMutation)); + Blockly.Events.fire( + new Blockly.Events.BlockChange( + caller, + "mutation", + null, + oldMutation, + newMutation + ) + ); } } Blockly.Events.setGroup(false); } else { - alert('No define block on workspace'); // TODO decide what to do about this. + alert("No define block on workspace"); // TODO decide what to do about this. } } @@ -196,8 +206,13 @@ function getDefineBlock(procCode, workspace) { var blocks = workspace.getTopBlocks(false); for (var i = 0; i < blocks.length; i++) { if (blocks[i].type == Constants.PROCEDURES_DEFINITION_BLOCK_TYPE) { - var prototypeBlock = blocks[i].getInput('custom_block').connection.targetBlock(); - if (prototypeBlock.getProcCode && prototypeBlock.getProcCode() == procCode) { + var prototypeBlock = blocks[i] + .getInput("custom_block") + .connection.targetBlock(); + if ( + prototypeBlock.getProcCode && + prototypeBlock.getProcCode() == procCode + ) { return blocks[i]; } } @@ -215,7 +230,7 @@ function getDefineBlock(procCode, workspace) { function getPrototypeBlock(procCode, workspace) { var defineBlock = getDefineBlock(procCode, workspace); if (defineBlock) { - return defineBlock.getInput('custom_block').connection.targetBlock(); + return defineBlock.getInput("custom_block").connection.targetBlock(); } return null; } @@ -226,15 +241,18 @@ function getPrototypeBlock(procCode, workspace) { * @package */ function newProcedureMutation() { - var mutationText = '' + - '' + - '' + - ''; + var mutationText = + "" + + "' + + "" + + ""; return Blockly.utils.xml.textToDom(mutationText).firstChild; } @@ -245,8 +263,8 @@ function newProcedureMutation() { */ function createProcedureDefCallback(workspace) { ScratchProcedures.externalProcedureDefCallback( - newProcedureMutation(), - createProcedureCallbackFactory_(workspace) + newProcedureMutation(), + createProcedureCallbackFactory_(workspace) ); } @@ -257,17 +275,18 @@ function createProcedureDefCallback(workspace) { * @private */ function createProcedureCallbackFactory_(workspace) { - return function(mutation) { + return function (mutation) { if (mutation) { - var blockText = '' + - '' + - '' + - '' + - Blockly.Xml.domToText(mutation) + - '' + - '' + - '' + - ''; + var blockText = + "" + + '' + + '' + + '' + + Blockly.Xml.domToText(mutation) + + "" + + "" + + "" + + ""; var blockDom = Blockly.utils.xml.textToDom(blockText).firstChild; Blockly.Events.setGroup(true); var block = Blockly.Xml.domToBlock(blockDom, workspace); @@ -296,35 +315,37 @@ function editProcedureCallback_(block) { // Edit can come from one of three block types (call, define, prototype) // Normalize by setting the block to the prototype block for the procedure. if (block.type == Constants.PROCEDURES_DEFINITION_BLOCK_TYPE) { - var input = block.getInput('custom_block'); + var input = block.getInput("custom_block"); if (!input) { - alert('Bad input'); // TODO: Decide what to do about this. + alert("Bad input"); // TODO: Decide what to do about this. return; } var conn = input.connection; if (!conn) { - alert('Bad connection'); // TODO: Decide what to do about this. + alert("Bad connection"); // TODO: Decide what to do about this. return; } var innerBlock = conn.targetBlock(); - if (!innerBlock || - !innerBlock.type == Constants.PROCEDURES_PROTOTYPE_BLOCK_TYPE) { - alert('Bad inner block'); // TODO: Decide what to do about this. + if ( + !innerBlock || + !innerBlock.type == Constants.PROCEDURES_PROTOTYPE_BLOCK_TYPE + ) { + alert("Bad inner block"); // TODO: Decide what to do about this. return; } block = innerBlock; } else if (block.type == Constants.PROCEDURES_CALL_BLOCK_TYPE) { // This is a call block, find the prototype corresponding to the procCode. // Make sure to search the correct workspace, call block can be in flyout. - var workspaceToSearch = block.workspace.isFlyout ? - block.workspace.targetWorkspace : block.workspace; - block = getPrototypeBlock( - block.getProcCode(), workspaceToSearch); + var workspaceToSearch = block.workspace.isFlyout + ? block.workspace.targetWorkspace + : block.workspace; + block = getPrototypeBlock(block.getProcCode(), workspaceToSearch); } // Block now refers to the procedure prototype block, it is safe to proceed. ScratchProcedures.externalProcedureDefCallback( - block.mutationToDom(), - editProcedureCallbackFactory_(block) + block.mutationToDom(), + editProcedureCallbackFactory_(block) ); } @@ -335,10 +356,9 @@ function editProcedureCallback_(block) { * @private */ function editProcedureCallbackFactory_(block) { - return function(mutation) { + return function (mutation) { if (mutation) { - mutateCallersAndPrototype(block.getProcCode(), - block.workspace, mutation); + mutateCallersAndPrototype(block.getProcCode(), block.workspace, mutation); } }; } @@ -355,9 +375,9 @@ function makeEditOption(block) { var editOption = { enabled: true, text: Blockly.Msg.EDIT_PROCEDURE, - callback: function() { + callback: function () { editProcedureCallback_(block); - } + }, }; return editOption; } @@ -370,10 +390,13 @@ function makeEditOption(block) { * @return {boolean} True if the custom procedure was deleted, false otherwise. * @package */ -function deleteProcedureDefCallback(procCode, - definitionRoot) { - var callers = getCallers(procCode, - definitionRoot.workspace, definitionRoot, false /* allowRecursive */); +function deleteProcedureDefCallback(procCode, definitionRoot) { + var callers = getCallers( + procCode, + definitionRoot.workspace, + definitionRoot, + false /* allowRecursive */ + ); if (callers.length > 0) { return false; } @@ -399,4 +422,4 @@ const ScratchProcedures = { getProceduresCategory, makeEditOption, }; -export {ScratchProcedures}; +export { ScratchProcedures }; From 87b9ec65c099bc029d6a2dc9fddfd1434c63f98c Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Mon, 5 Aug 2024 15:42:05 -0700 Subject: [PATCH 3/3] refactor: enforce procedure deletion validation --- blocks_vertical/vertical_extensions.js | 48 ++++++++++++-------------- src/procedures.js | 15 ++------ 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/blocks_vertical/vertical_extensions.js b/blocks_vertical/vertical_extensions.js index 866747d47e..992623f5aa 100644 --- a/blocks_vertical/vertical_extensions.js +++ b/blocks_vertical/vertical_extensions.js @@ -157,48 +157,44 @@ VerticalExtensions.OUTPUT_BOOLEAN = function () { * @package * @readonly */ -VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU = { +VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU = function () { /** * Add the "edit" option and removes the "duplicate" option from the context * menu. * @param {!Array.} menuOptions List of menu options to edit. * @this Blockly.Block */ - customContextMenu: function (menuOptions) { - // Add the edit option at the end. - menuOptions.push(ScratchProcedures.makeEditOption(this)); + this.mixin( + { + customContextMenu: function (menuOptions) { + // Add the edit option at the end. + menuOptions.push(ScratchProcedures.makeEditOption(this)); - // Find the delete option and update its callback to be specific to - // functions. - for (var i = 0, option; (option = menuOptions[i]); i++) { - if (option.text == Blockly.Msg.DELETE_BLOCK) { + // Find and remove the duplicate option + for (var i = 0, option; (option = menuOptions[i]); i++) { + if (option.text == Blockly.Msg.DUPLICATE) { + menuOptions.splice(i, 1); + break; + } + } + }, + checkAndDelete: function () { var input = this.getInput("custom_block"); // this is the root block, not the shadow block. if (input && input.connection && input.connection.targetBlock()) { var procCode = input.connection.targetBlock().getProcCode(); - } else { - return; - } - var rootBlock = this; - option.callback = function () { var didDelete = ScratchProcedures.deleteProcedureDefCallback( procCode, - rootBlock + this ); if (!didDelete) { alert(Blockly.Msg.PROCEDURE_USED); } - }; - } - } - // Find and remove the duplicate option - for (var i = 0, option; (option = menuOptions[i]); i++) { - if (option.text == Blockly.Msg.DUPLICATE) { - menuOptions.splice(i, 1); - break; - } - } - }, + } + }, + }, + true + ); }; /** @@ -280,7 +276,7 @@ VerticalExtensions.registerAll = function () { ); // Custom procedures have interesting context menus. - Blockly.Extensions.registerMixin( + Blockly.Extensions.register( "procedure_def_contextmenu", VerticalExtensions.PROCEDURE_DEF_CONTEXTMENU ); diff --git a/src/procedures.js b/src/procedures.js index f826dc3f2b..09f1381f2c 100644 --- a/src/procedures.js +++ b/src/procedures.js @@ -391,7 +391,7 @@ function makeEditOption(block) { * @package */ function deleteProcedureDefCallback(procCode, definitionRoot) { - var callers = getCallers( + const callers = getCallers( procCode, definitionRoot.workspace, definitionRoot, @@ -401,17 +401,8 @@ function deleteProcedureDefCallback(procCode, definitionRoot) { return false; } - var workspace = definitionRoot.workspace; - - // Delete the whole stack. - Blockly.Events.setGroup(true); - definitionRoot.dispose(); - Blockly.Events.setGroup(false); - - // TODO (#1354) Update this function when '_' is removed - // Refresh toolbox, so caller doesn't appear there anymore - workspace.refreshToolboxSelection_(); - + const workspace = definitionRoot.workspace; + Blockly.BlockSvg.prototype.checkAndDelete.call(definitionRoot); return true; }