Adding a Category
Adding the category to scratch-blocks
Let's move the alert block to a Dialogs category.
src/blocks
First, create a file called dialogs.ts in src/blocks.
At the top of the file put:
import * as Blockly from "blockly/core";
Move your block from looks.ts to dialogs.ts (leaving looks.ts like it was originally).
Blockly.Blocks['dialogs_alert'] = {
init: function(this: Blockly.Block){
this.jsonInit({
message0: Blockly.Msg.DIALOGS_ALERT,
args0: [
{
type: "input_value",
name: "MESSAGE",
},
],
extensions: ["colours_dialogs", "shape_statement"],
});
},
};
The block messages
First, move your block's message to a new section (to keep the file organised) and update the message to match the one in the block definition.
Second, under the "Category labels" section, add one for your new category.
// Category labels
Blockly.Msg.CATEGORY_DIALOGS = 'Dialogs';
Blockly.Msg.CATEGORY_MOTION = 'Motion';
Blockly.Msg.CATEGORY_LOOKS = 'Looks';
Blockly.Msg.CATEGORY_SOUND = 'Sound';
Blockly.Msg.CATEGORY_EVENTS = 'Events';
Blockly.Msg.CATEGORY_CONTROL = 'Control';
Blockly.Msg.CATEGORY_SENSING = 'Sensing';
Blockly.Msg.CATEGORY_OPERATORS = 'Operators';
Blockly.Msg.CATEGORY_VARIABLES = 'Variables';
Blockly.Msg.CATEGORY_MYBLOCKS = 'My Blocks';
The block category
In src/blocks/vertical_extensions.ts, find categoryNames inside the registerAll() function and add your category to it.
const categoryNames = [
"dialogs",
"control",
"data",
"data_lists",
"sounds",
"motion",
"looks",
"event",
"sensing",
"pen",
"operators",
"more",
];
Additionally, add an import for your category in index.ts with the other imports.
import * as Blockly from "blockly/core";
import "./blocks/colour";
import "./blocks/math";
import "./blocks/matrix";
import "./blocks/note";
import "./blocks/text";
import "./blocks/vertical_extensions";
import "./blocks/dialogs";
import "./blocks/control";
import "./blocks/data";
import "./blocks/event";
import "./blocks/looks";
import "./blocks/motion";
import "./blocks/operators";
import "./blocks/procedures";
import "./blocks/sensing";
import "./blocks/sound";
import * as scratchBlocksUtils from "./scratch_blocks_utils";
// ...
Adding the category to scratch-gui
The block colour
In scratch-gui at src/lib/settings/color-mode/default/index.js, add your colour to the blockColors object.
// This object is passed directly to Blockly, hence the colour* fields need to
// be named exactly as they are, including the UK spelling of "colour".
const blockColors = {
dialogs: {
colourPrimary: '#60a05c',
colourSecondary: '#4c8249',
colourTertiary: '#31542f',
colourQuaternary: '#31542f'
},
motion: {
colourPrimary: '#4C97FF',
colourSecondary: '#4280D7',
colourTertiary: '#3373CC',
colourQuaternary: '#3373CC'
},
The colours are these:
| Colour | Hex Code | Example |
|---|---|---|
| Primary | #60a05c | |
| Secondary | #4c8249 | |
| Tertiary | #31542f | |
| Quaternary | #31542f |
If you want, you can also add the category to the dark, high-constrast or your own custom themes themes.
Adding the category to the toolbox
In src/lib/make-toolbox-xml.js, remove your changes from the looks category and add the following:
const dialogs = function (isInitialSetup, isStage, targetId, colors) {
const hello = ScratchBlocks.ScratchMsgs.translate('LOOKS_HELLO', 'Hello!');
// Note: the category's secondaryColour matches up with the blocks' tertiary color, both used for border color.
return `
<category name="${ScratchBlocks.ScratchMsgs.translate(
'CATEGORY_DIALOGS',
'Dialogs'
)}" toolboxitemid="dialogs" colour="${
colors.colourPrimary
}" secondaryColour="${colors.colourTertiary}">
<block type="dialogs_alert">
<value name="MESSAGE">
<shadow type="text">
<field name="TEXT">${hello}</field>
</shadow>
</value>
</block>
${categorySeparator}
</category>
`;
};
At the bottom of the file, there is a function called makeToolboxXml, make the highlighted changes to it:
const makeToolboxXML = function (isInitialSetup, isStage = true, targetId, categoriesXML = [],
costumeName = '', backdropName = '', soundName = '', colors = defaultColors) {
// ...
categoriesXML = categoriesXML.slice();
const moveCategory = categoryId => {
// ...
};
const dialogsXML = moveCategory('dialogs') || dialogs(isInitialSetup, isStage, targetId, colors.dialogs);
const motionXML = moveCategory('motion') || motion(isInitialSetup, isStage, targetId, colors.motion);
const looksXML = moveCategory('looks') ||
looks(isInitialSetup, isStage, targetId, costumeName, backdropName, colors.looks);
// ...
const everything = [
xmlOpen,
dialogsXML, gap,
motionXML, gap,
looksXML, gap,
// ...
myBlocksXML
];
for (const extensionCategory of categoriesXML) {
everything.push(gap, extensionCategory.xml);
}
everything.push(xmlClose);
return everything.join('\n');
};
Adding the category to scratch-vm.
First, remove the changes from scratch3_looks.js.
In the src/blocks folder, add a tutorialmod_dialogs.js file.
class TutorialModDialogsBlocks {
constructor (runtime){
/**
* The runtime instantiating this block package.
* @type {Runtime}
*/
this.runtime = runtime;
}
/**
* Retrieve the block primitives implemented by this package.
* @return {object.<string, Function>} Mapping of opcode to Function.
*/
getPrimitives () {
return {
dialogs_alert: this.alertBlock
};
}
alertBlock (args, util) {
// eslint-disable-next-line
alert(args.MESSAGE);
}
}
module.exports = TutorialModDialogsBlocks;
And finally, in src/engine/runtime.js, add your category's file to defaultBlockPackages
const defaultBlockPackages = {
tutorialmod_dialogs: require('../blocks/tutorialmod_dialogs'),
scratch3_control: require('../blocks/scratch3_control'),
scratch3_event: require('../blocks/scratch3_event'),
scratch3_looks: require('../blocks/scratch3_looks'),
scratch3_motion: require('../blocks/scratch3_motion'),
scratch3_operators: require('../blocks/scratch3_operators'),
scratch3_sound: require('../blocks/scratch3_sound'),
scratch3_sensing: require('../blocks/scratch3_sensing'),
scratch3_data: require('../blocks/scratch3_data'),
scratch3_procedures: require('../blocks/scratch3_procedures')
};
Make scratch-vm understand how to load the category from save
In scratch-vm's src/serialization/sb3.js file, find the CORE_CATEGORIES array and add your category to it.
const CORE_EXTENSIONS = [
'argument',
'colour',
'control',
'data',
'event',
'looks',
'math',
'motion',
'operator',
'procedures',
'sensing',
'sound',
'dialogs'
];
Completed Files
| Component | File | Download |
|---|---|---|
scratch-blocks | src/blocks/dialogs.ts | dialogs.ts |
scratch-blocks | src/blocks/vertical_extensions.ts | vertical_extensions.ts |
scratch-blocks | src/index.ts | index.ts |
scratch-blocks | msg/messages.js | messages.js |
scratch-gui | src/lib/make-toolbox-xml.js | make-toolbox-xml.js |
scratch-gui | src/lib/themes/default/index.js | index.js |
scratch-vm | src/blocks/tutorialmod_dialogs.js | tutorialmod_dialogs.js |
scratch-vm | src/engine/runtime.js | runtime.js |
scratch-vm | src/serialization/sb3.js | sb3.js |
Scratch commit hashes at the time of this tutorial
scratch-editor: 810ac12eaa1a1eb19d05fcb37f486ad1c4c56314
scratch-blocks: bb2f7ce297e2552767b531c212b18ee4f046e92d