Skip to content

Commit cecf874

Browse files
committed
Add "is in editor?" block
1 parent ff12997 commit cecf874

4 files changed

Lines changed: 97 additions & 21 deletions

File tree

addon-api/content-script/Tab.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,18 @@ export default class Tab extends Listenable {
6262
blocks.init(this);
6363
return blocks.addBlock(proccode, opts);
6464
}
65+
/**
66+
* Adds a custom reporter block definition. Internally this is a special-cased argument reporter block.
67+
* @param {string} proccode the procedure definition code
68+
* @param {boolean} isBoolean - whether the block is hexagonal.
69+
* @param {object} opts - options.
70+
* @param {Tab~blockCallback} opts.callback - the callback, the returned value is the output of the block.
71+
* @param {boolean=} opts.hidden - whether the block is hidden from the palette.
72+
*/
73+
addReporterBlock(proccode, isBoolean, opts) {
74+
blocks.init(this);
75+
return blocks.addReporterBlock(proccode, isBoolean, opts);
76+
}
6577
/**
6678
* Removes a stack block definition. Should not be called in most cases.
6779
* @param {string} proccode the procedure definition code of the block

addon-api/content-script/blocks.js

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export const addBlock = (proccode, { args, callback, hidden, displayName }) => {
103103

104104
const blockData = {
105105
id: proccode,
106+
type: "procedures_call",
106107
args,
107108
handler: callback,
108109
hide: !!hidden,
@@ -113,6 +114,23 @@ export const addBlock = (proccode, { args, callback, hidden, displayName }) => {
113114
queueToolboxUpdate();
114115
};
115116

117+
export const addReporterBlock = (proccode, isBoolean, { callback, hidden }) => {
118+
// The `proccode` parameter is not the proccode but the name of the argument
119+
if (getCustomBlock(proccode)) {
120+
return;
121+
}
122+
123+
const blockData = {
124+
id: proccode,
125+
type: isBoolean ? "argument_reporter_boolean" : "argument_reporter_string_number",
126+
handler: callback,
127+
hide: !!hidden,
128+
proccode,
129+
};
130+
customBlocks[proccode] = blockData;
131+
queueToolboxUpdate();
132+
};
133+
116134
export const removeBlock = (proccode) => {
117135
customBlocks[proccode] = null;
118136
customBlockParamNamesIdsDefaults[proccode] = null;
@@ -123,14 +141,21 @@ const generateBlockXML = () => {
123141
for (const proccode of Object.keys(customBlocks)) {
124142
const blockData = customBlocks[proccode];
125143
if (blockData.hide) continue;
126-
const [names, ids, defaults] = getNamesIdsDefaults(blockData);
127-
xml +=
128-
'<block type="procedures_call" gap="16"><mutation generateshadows="true" warp="false"' +
129-
` proccode="${escapeHTML(proccode)}"` +
130-
` argumentnames="${escapeHTML(JSON.stringify(names))}"` +
131-
` argumentids="${escapeHTML(JSON.stringify(ids))}"` +
132-
` argumentdefaults="${escapeHTML(JSON.stringify(defaults))}"` +
133-
"></mutation></block>";
144+
145+
if (blockData.type === "procedures_call") {
146+
const [names, ids, defaults] = getNamesIdsDefaults(blockData);
147+
xml +=
148+
'<block type="procedures_call" gap="16"><mutation generateshadows="true" warp="false"' +
149+
` proccode="${escapeHTML(proccode)}"` +
150+
` argumentnames="${escapeHTML(JSON.stringify(names))}"` +
151+
` argumentids="${escapeHTML(JSON.stringify(ids))}"` +
152+
` argumentdefaults="${escapeHTML(JSON.stringify(defaults))}"` +
153+
"></mutation></block>";
154+
155+
} else {
156+
xml +=
157+
`<block type="${blockData.type}"><field name="VALUE">${blockData.id}</field></block>`;
158+
}
134159
}
135160
if (xml.length === 0) {
136161
const message = scratchAddons.l10n.get("noAddedBlocks", null, "No addons have added blocks.");
@@ -172,15 +197,20 @@ const injectWorkspace = (ScratchBlocks) => {
172197
const oldUpdateColour = BlockSvg.prototype.updateColour;
173198
BlockSvg.prototype.updateColour = function (...args) {
174199
// procedures_prototype also have a procedure code but we do not want to color them.
175-
if (!this.isInsertionMarker() && this.type === "procedures_call") {
176-
const block = this.procCode_ && getCustomBlock(this.procCode_);
177-
const color = ScratchBlocks.Colours.text === "#000000" ? highContrastColor : defaultColor;
178-
if (block) {
179-
this.colour_ = customColor.color || color.color;
180-
this.colourSecondary_ = customColor.secondaryColor || color.secondaryColor;
181-
this.colourTertiary_ = customColor.tertiaryColor || color.tertiaryColor;
182-
this.customContextMenu = null;
183-
}
200+
if (this.isInsertionMarker()) return;
201+
let block;
202+
if (this.type === "procedures_call") {
203+
block = this.procCode_ && getCustomBlock(this.procCode_);
204+
} else if (this.type === "argument_reporter_string_number" || this.type === "argument_reporter_boolean") {
205+
const name = this.inputList[0].fieldRow[0].text_
206+
block = name && getCustomBlock(name);
207+
}
208+
const color = ScratchBlocks.Colours.text === "#000000" ? highContrastColor : defaultColor;
209+
if (block) {
210+
this.colour_ = customColor.color || color.color;
211+
this.colourSecondary_ = customColor.secondaryColor || color.secondaryColor;
212+
this.colourTertiary_ = customColor.tertiaryColor || color.tertiaryColor;
213+
this.customContextMenu = null;
184214
}
185215
return oldUpdateColour.call(this, ...args);
186216
};
@@ -315,6 +345,24 @@ export async function init(tab) {
315345
return oldStepToProcedure.call(this, thread, proccode);
316346
};
317347

348+
const oldArgumentReporterStringNumber = vm.runtime._primitives.argument_reporter_string_number;
349+
vm.runtime._primitives.argument_reporter_string_number = (args, util) => {
350+
const blockData = getCustomBlock(args.VALUE);
351+
if (blockData) {
352+
return blockData.handler();
353+
}
354+
return oldArgumentReporterStringNumber.call(this, args, util)
355+
}
356+
357+
const oldArgumentReporterBoolean = vm.runtime._primitives.argument_reporter_boolean;
358+
vm.runtime._primitives.argument_reporter_boolean = (args, util) => {
359+
const blockData = getCustomBlock(args.VALUE);
360+
if (blockData) {
361+
return blockData.handler(args, util);
362+
}
363+
return oldArgumentReporterBoolean.call(this, args, util)
364+
}
365+
318366
const ScratchBlocks = await tab.traps.getBlockly();
319367
injectWorkspace(ScratchBlocks);
320368
}

addons/debugger/addon.json

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
{
22
"name": "Debugger",
3-
"description": "Adds a new \"debugger\" window to the editor. Allows for logging into the \"Logs\" tab of the debugger window using the \"log\", \"warn\" and \"error\" blocks. The \"breakpoint\" block will pause the project when executed. All running stacks of blocks can be viewed in the \"Threads\" tab of the debugger window, and when paused the \"Step\" button can be used to execute the next block. A graph of frames per second and number of clones can be viewed in the \"Performance\" tab.",
3+
"description": "Adds a new \"debugger\" window to the editor. Allows for logging into the \"Logs\" tab of the debugger window using the \"log\", \"warn\" and \"error\" blocks. The \"breakpoint\" block will pause the project when executed. All running stacks of blocks can be viewed in the \"Threads\" tab of the debugger window, and when paused the \"Step\" button can be used to execute the next block. A graph of frames per second and number of clones can be viewed in the \"Performance\" tab. The \"is it in editor?\" block allows to check if the project is running in the editor.",
4+
"info": [
5+
{
6+
"type": "notice",
7+
"text": "Debug blocks only work for Scratch Addons users with this enabled. The \"is in editor?\" block cannot therefore it cannot be used as an anti-cheat method.",
8+
"id": "debuggerBlocks"
9+
}
10+
],
411
"credits": [
512
{
613
"name": "Tacodiva",
@@ -17,6 +24,10 @@
1724
},
1825
{
1926
"name": "retronbv"
27+
},
28+
{
29+
"name": "Valmontechno",
30+
"link": "https://github.com/Valmontechno"
2031
}
2132
],
2233
"userscripts": [
@@ -84,9 +95,9 @@
8495
"tags": ["editor", "codeEditor", "featured"],
8596
"versionAdded": "1.16.0",
8697
"latestUpdate": {
87-
"version": "1.33.0",
88-
"temporaryNotice": "Graph animation is now disabled by default to increase performance. You can re-enable it if you want.",
89-
"newSettings": ["fancy_graphs"]
98+
"version": "1.43.0",
99+
"temporaryNotice": "New available block: \"is in editor?\"",
100+
"isMajor": true
90101
},
91102
"libraries": ["chartjs", "scratch-gui", "scratch-vm"]
92103
}

addons/debugger/userscript.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ export default async function ({ addon, console, msg }) {
6868
logMessage(content, thread, "error");
6969
},
7070
});
71+
addon.tab.addReporterBlock("\u200B\u200Bis in editor?\u200B\u200B", true, {
72+
callback: () => {
73+
return document.body.classList.contains("sa-body-editor") ? true : 0;
74+
}
75+
});
7176

7277
const vm = addon.tab.traps.vm;
7378
await new Promise((resolve, reject) => {

0 commit comments

Comments
 (0)