From 4a8e22bab1196e2c8b50608dc292b1e05c83cf68 Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Mon, 23 Feb 2026 18:14:56 +0000 Subject: [PATCH 1/6] Add scratch-style add-item block to Lists category --- toolbox.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/toolbox.js b/toolbox.js index 4664f474..5ba1631b 100644 --- a/toolbox.js +++ b/toolbox.js @@ -3275,6 +3275,15 @@ const toolboxLists = { categorystyle: "variables_category", custom: "LIST", contents: [ + { + kind: "block", + type: "lists_setIndex", + fields: { + MODE: "INSERT", + WHERE: "LAST", + }, + keyword: "add", + }, { kind: "block", type: "lists_create_empty", From 44becf202b2e698d644d0fb71ca9c8e9070a11c7 Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Mon, 23 Feb 2026 18:33:26 +0000 Subject: [PATCH 2/6] Show add-item list block in dynamic LIST category --- main/blocklyinit.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/main/blocklyinit.js b/main/blocklyinit.js index 0fea5240..5846b4f2 100644 --- a/main/blocklyinit.js +++ b/main/blocklyinit.js @@ -530,6 +530,21 @@ export function initializeWorkspace() { ), ); + const addItemBlock = document.createElement("block"); + addItemBlock.setAttribute("type", "lists_setIndex"); + + const modeField = document.createElement("field"); + modeField.setAttribute("name", "MODE"); + modeField.textContent = "INSERT"; + addItemBlock.appendChild(modeField); + + const whereField = document.createElement("field"); + whereField.setAttribute("name", "WHERE"); + whereField.textContent = "LAST"; + addItemBlock.appendChild(whereField); + + xmlList.push(addItemBlock); + [ "lists_create_empty", "lists_create_with", From b537be5bc86f98342cafd23b5ff18fdbec5f139e Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Mon, 23 Feb 2026 18:47:58 +0000 Subject: [PATCH 3/6] Make list add-item block prefilled with item and list inputs --- main/blocklyinit.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/main/blocklyinit.js b/main/blocklyinit.js index 5846b4f2..c3055986 100644 --- a/main/blocklyinit.js +++ b/main/blocklyinit.js @@ -530,6 +530,14 @@ export function initializeWorkspace() { ), ); + const getDefaultListName = () => { + const vars = variableMap.getAllVariables(); + if (vars.length > 0) { + return vars[0].name; + } + return "list1"; + }; + const addItemBlock = document.createElement("block"); addItemBlock.setAttribute("type", "lists_setIndex"); @@ -543,6 +551,29 @@ export function initializeWorkspace() { whereField.textContent = "LAST"; addItemBlock.appendChild(whereField); + const toValue = document.createElement("value"); + toValue.setAttribute("name", "TO"); + const toShadow = document.createElement("shadow"); + toShadow.setAttribute("type", "text"); + const toField = document.createElement("field"); + toField.setAttribute("name", "TEXT"); + toField.textContent = ""; + toShadow.appendChild(toField); + toValue.appendChild(toShadow); + addItemBlock.appendChild(toValue); + + const listValue = document.createElement("value"); + listValue.setAttribute("name", "LIST"); + const listShadow = document.createElement("shadow"); + listShadow.setAttribute("type", "variables_get"); + const listField = document.createElement("field"); + listField.setAttribute("name", "VAR"); + listField.setAttribute("variabletype", ""); + listField.textContent = getDefaultListName(); + listShadow.appendChild(listField); + listValue.appendChild(listShadow); + addItemBlock.appendChild(listValue); + xmlList.push(addItemBlock); [ From f6dcb0e65dd013bb20d4a375d107e5471c614367 Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Mon, 23 Feb 2026 19:04:30 +0000 Subject: [PATCH 4/6] Replace list insert clone with simple add text-to-list block --- blocks/blocks.js | 25 +++++++++++++++++++++++++ generators/generators.js | 15 +++++++++++++++ main/blocklyinit.js | 32 +------------------------------- toolbox.js | 6 +----- 4 files changed, 42 insertions(+), 36 deletions(-) diff --git a/blocks/blocks.js b/blocks/blocks.js index a5e0c7fc..c70a4a61 100644 --- a/blocks/blocks.js +++ b/blocks/blocks.js @@ -1322,6 +1322,31 @@ export function defineBlocks() { }, }; + Blockly.Blocks["lists_add_item"] = { + init: function () { + this.jsonInit({ + type: "lists_add_item", + message0: "add %1 to %2", + args0: [ + { + type: "input_value", + name: "TO", + }, + { + type: "field_variable", + name: "LIST", + variable: "list1", + }, + ], + previousStatement: null, + nextStatement: null, + tooltip: "Add an item to the end of a list.", + }); + this.setStyle("list_blocks"); + this.setHelpUrl(getHelpUrlFor(this.type)); + }, + }; + Blockly.Blocks["to_number"] = { init: function () { this.jsonInit({ diff --git a/generators/generators.js b/generators/generators.js index 526cd501..f82e2cc5 100644 --- a/generators/generators.js +++ b/generators/generators.js @@ -4087,6 +4087,21 @@ javascriptGenerator.forBlock["lists_setIndex"] = function (block) { throw Error("Unhandled combination (lists_setIndex)."); }; +javascriptGenerator.forBlock["lists_add_item"] = function (block) { + const listName = javascriptGenerator.nameDB_.getName( + block.getFieldValue("LIST"), + Blockly.Names.NameType.VARIABLE, + ); + const value = + javascriptGenerator.valueToCode( + block, + "TO", + javascriptGenerator.ORDER_ASSIGNMENT, + ) || '""'; + + return `${listName}.push(${value});\n`; +}; + javascriptGenerator.forBlock["keyword"] = function (block) { return ""; }; diff --git a/main/blocklyinit.js b/main/blocklyinit.js index c3055986..9c5a5566 100644 --- a/main/blocklyinit.js +++ b/main/blocklyinit.js @@ -530,26 +530,8 @@ export function initializeWorkspace() { ), ); - const getDefaultListName = () => { - const vars = variableMap.getAllVariables(); - if (vars.length > 0) { - return vars[0].name; - } - return "list1"; - }; - const addItemBlock = document.createElement("block"); - addItemBlock.setAttribute("type", "lists_setIndex"); - - const modeField = document.createElement("field"); - modeField.setAttribute("name", "MODE"); - modeField.textContent = "INSERT"; - addItemBlock.appendChild(modeField); - - const whereField = document.createElement("field"); - whereField.setAttribute("name", "WHERE"); - whereField.textContent = "LAST"; - addItemBlock.appendChild(whereField); + addItemBlock.setAttribute("type", "lists_add_item"); const toValue = document.createElement("value"); toValue.setAttribute("name", "TO"); @@ -562,18 +544,6 @@ export function initializeWorkspace() { toValue.appendChild(toShadow); addItemBlock.appendChild(toValue); - const listValue = document.createElement("value"); - listValue.setAttribute("name", "LIST"); - const listShadow = document.createElement("shadow"); - listShadow.setAttribute("type", "variables_get"); - const listField = document.createElement("field"); - listField.setAttribute("name", "VAR"); - listField.setAttribute("variabletype", ""); - listField.textContent = getDefaultListName(); - listShadow.appendChild(listField); - listValue.appendChild(listShadow); - addItemBlock.appendChild(listValue); - xmlList.push(addItemBlock); [ diff --git a/toolbox.js b/toolbox.js index 5ba1631b..1c5166b0 100644 --- a/toolbox.js +++ b/toolbox.js @@ -3277,11 +3277,7 @@ const toolboxLists = { contents: [ { kind: "block", - type: "lists_setIndex", - fields: { - MODE: "INSERT", - WHERE: "LAST", - }, + type: "lists_add_item", keyword: "add", }, { From ef7a8aeadbd2d71a14d9679b9a2b3a4302232d4c Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Mon, 23 Feb 2026 19:21:26 +0000 Subject: [PATCH 5/6] Guard add-to-list block against non-array list values --- generators/generators.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generators/generators.js b/generators/generators.js index f82e2cc5..a4a674aa 100644 --- a/generators/generators.js +++ b/generators/generators.js @@ -4099,7 +4099,7 @@ javascriptGenerator.forBlock["lists_add_item"] = function (block) { javascriptGenerator.ORDER_ASSIGNMENT, ) || '""'; - return `${listName}.push(${value});\n`; + return `if (!Array.isArray(${listName})) {\n ${listName} = [];\n}\n${listName}.push(${value});\n`; }; javascriptGenerator.forBlock["keyword"] = function (block) { From 96bd0d902016686f76ca48a7e7fff3ddb908db3e Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Mon, 23 Feb 2026 19:28:31 +0000 Subject: [PATCH 6/6] Add simple delete-nth-from-list block to Lists category --- blocks/blocks.js | 26 ++++++++++++++++++++++++++ generators/generators.js | 18 ++++++++++++++++++ main/blocklyinit.js | 16 ++++++++++++++++ toolbox.js | 5 +++++ 4 files changed, 65 insertions(+) diff --git a/blocks/blocks.js b/blocks/blocks.js index c70a4a61..f92b2120 100644 --- a/blocks/blocks.js +++ b/blocks/blocks.js @@ -1347,6 +1347,32 @@ export function defineBlocks() { }, }; + Blockly.Blocks["lists_delete_nth"] = { + init: function () { + this.jsonInit({ + type: "lists_delete_nth", + message0: "delete %1 from %2", + args0: [ + { + type: "input_value", + name: "INDEX", + check: "Number", + }, + { + type: "field_variable", + name: "LIST", + variable: "list1", + }, + ], + previousStatement: null, + nextStatement: null, + tooltip: "Delete item at index n from a list (0-based).", + }); + this.setStyle("list_blocks"); + this.setHelpUrl(getHelpUrlFor(this.type)); + }, + }; + Blockly.Blocks["to_number"] = { init: function () { this.jsonInit({ diff --git a/generators/generators.js b/generators/generators.js index a4a674aa..c0e0311b 100644 --- a/generators/generators.js +++ b/generators/generators.js @@ -4102,6 +4102,24 @@ javascriptGenerator.forBlock["lists_add_item"] = function (block) { return `if (!Array.isArray(${listName})) {\n ${listName} = [];\n}\n${listName}.push(${value});\n`; }; +javascriptGenerator.forBlock["lists_delete_nth"] = function (block) { + const listName = javascriptGenerator.nameDB_.getName( + block.getFieldValue("LIST"), + Blockly.Names.NameType.VARIABLE, + ); + const index = + javascriptGenerator.valueToCode( + block, + "INDEX", + javascriptGenerator.ORDER_NONE, + ) || "0"; + + return `if (Array.isArray(${listName})) { + ${listName}.splice(${index}, 1); +} +`; +}; + javascriptGenerator.forBlock["keyword"] = function (block) { return ""; }; diff --git a/main/blocklyinit.js b/main/blocklyinit.js index 9c5a5566..612c065c 100644 --- a/main/blocklyinit.js +++ b/main/blocklyinit.js @@ -546,6 +546,22 @@ export function initializeWorkspace() { xmlList.push(addItemBlock); + const deleteItemBlock = document.createElement("block"); + deleteItemBlock.setAttribute("type", "lists_delete_nth"); + + const indexValue = document.createElement("value"); + indexValue.setAttribute("name", "INDEX"); + const indexShadow = document.createElement("shadow"); + indexShadow.setAttribute("type", "math_number"); + const indexField = document.createElement("field"); + indexField.setAttribute("name", "NUM"); + indexField.textContent = "1"; + indexShadow.appendChild(indexField); + indexValue.appendChild(indexShadow); + deleteItemBlock.appendChild(indexValue); + + xmlList.push(deleteItemBlock); + [ "lists_create_empty", "lists_create_with", diff --git a/toolbox.js b/toolbox.js index 1c5166b0..a633218d 100644 --- a/toolbox.js +++ b/toolbox.js @@ -3280,6 +3280,11 @@ const toolboxLists = { type: "lists_add_item", keyword: "add", }, + { + kind: "block", + type: "lists_delete_nth", + keyword: "delete", + }, { kind: "block", type: "lists_create_empty",