scratch-blocks 2.0.0-spork.2 → 2.0.0-spork.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/main.js +1 -1
- package/package.json +1 -1
- package/src/{block_reporting.js → block_reporting.ts} +7 -5
- package/src/blocks/{colour.js → colour.ts} +6 -6
- package/src/blocks/{control.js → control.ts} +21 -54
- package/src/blocks/{data.js → data.ts} +134 -142
- package/src/blocks/{event.js → event.ts} +12 -33
- package/src/blocks/{looks.js → looks.ts} +24 -73
- package/src/blocks/{math.js → math.ts} +6 -11
- package/src/blocks/{matrix.js → matrix.ts} +2 -3
- package/src/blocks/{motion.js → motion.ts} +23 -70
- package/src/blocks/{note.js → note.ts} +2 -3
- package/src/blocks/{operators.js → operators.ts} +18 -55
- package/src/blocks/{procedures.js → procedures.ts} +418 -269
- package/src/blocks/{sensing.js → sensing.ts} +21 -61
- package/src/blocks/{sound.js → sound.ts} +9 -28
- package/src/blocks/{text.js → text.ts} +1 -2
- package/src/blocks/{vertical_extensions.js → vertical_extensions.ts} +63 -100
- package/src/checkable_continuous_flyout.js +2 -2
- package/src/{checkbox_bubble.js → checkbox_bubble.ts} +36 -53
- package/src/{colours.js → colours.ts} +11 -4
- package/src/{constants.js → constants.ts} +13 -0
- package/src/{context_menu_items.js → context_menu_items.ts} +18 -12
- package/src/{data_category.js → data_category.ts} +216 -150
- package/src/events/{events_block_comment_base.js → events_block_comment_base.ts} +23 -4
- package/src/events/{events_block_comment_change.js → events_block_comment_change.ts} +29 -5
- package/src/events/{events_block_comment_collapse.js → events_block_comment_collapse.ts} +24 -6
- package/src/events/{events_block_comment_create.js → events_block_comment_create.ts} +36 -10
- package/src/events/{events_block_comment_delete.js → events_block_comment_delete.ts} +6 -2
- package/src/events/{events_block_comment_move.js → events_block_comment_move.ts} +36 -6
- package/src/events/events_block_comment_resize.ts +88 -0
- package/src/events/events_block_drag_end.ts +49 -0
- package/src/events/events_block_drag_outside.ts +44 -0
- package/src/events/{events_scratch_variable_create.js → events_scratch_variable_create.ts} +28 -15
- package/src/fields/{field_colour_slider.js → field_colour_slider.ts} +117 -106
- package/src/fields/{field_matrix.js → field_matrix.ts} +189 -215
- package/src/fields/{field_note.js → field_note.ts} +227 -286
- package/src/fields/{field_textinput_removable.js → field_textinput_removable.ts} +17 -20
- package/src/fields/{field_variable_getter.js → field_variable_getter.ts} +28 -17
- package/src/fields/{field_vertical_separator.js → field_vertical_separator.ts} +14 -30
- package/src/fields/{field_angle.js → scratch_field_angle.ts} +124 -80
- package/src/fields/{field_dropdown.js → scratch_field_dropdown.ts} +9 -7
- package/src/fields/{field_number.js → scratch_field_number.ts} +60 -55
- package/src/fields/{field_variable.js → scratch_field_variable.ts} +46 -27
- package/src/{flyout_checkbox_icon.js → flyout_checkbox_icon.ts} +15 -19
- package/src/{glows.js → glows.ts} +29 -18
- package/src/index.ts +59 -60
- package/src/procedures.ts +462 -0
- package/src/{recyclable_block_flyout_inflater.js → recyclable_block_flyout_inflater.ts} +35 -35
- package/src/renderer/{bowler_hat.js → bowler_hat.ts} +1 -1
- package/src/renderer/{constants.js → constants.ts} +26 -12
- package/src/renderer/{drawer.js → drawer.ts} +8 -3
- package/src/renderer/{path_object.js → path_object.ts} +2 -2
- package/src/renderer/{render_info.js → render_info.ts} +19 -7
- package/src/renderer/renderer.ts +76 -0
- package/src/{scratch_block_paster.js → scratch_block_paster.ts} +9 -7
- package/src/scratch_blocks_utils.ts +39 -0
- package/src/{scratch_comment_icon.js → scratch_comment_icon.ts} +43 -26
- package/src/scratch_connection_checker.ts +44 -0
- package/src/{scratch_continuous_category.js → scratch_continuous_category.ts} +20 -13
- package/src/{scratch_continuous_toolbox.js → scratch_continuous_toolbox.ts} +20 -18
- package/src/{scratch_dragger.js → scratch_dragger.ts} +97 -28
- package/src/{scratch_variable_map.js → scratch_variable_map.ts} +4 -1
- package/src/scratch_variable_model.ts +30 -0
- package/src/{shadows.js → shadows.ts} +8 -4
- package/src/{status_indicator_label.js → status_indicator_label.ts} +24 -36
- package/src/{status_indicator_label_flyout_inflater.js → status_indicator_label_flyout_inflater.ts} +9 -7
- package/src/{variables.js → variables.ts} +153 -123
- package/tsconfig.json +5 -0
- package/src/categories.js +0 -15
- package/src/events/events_block_comment_resize.js +0 -52
- package/src/events/events_block_drag_end.js +0 -33
- package/src/events/events_block_drag_outside.js +0 -30
- package/src/procedures.js +0 -425
- package/src/renderer/renderer.js +0 -74
- package/src/scratch_blocks_utils.js +0 -148
- package/src/scratch_connection_checker.js +0 -29
- package/src/scratch_variable_model.js +0 -24
- /package/src/{css.js → css.ts} +0 -0
- /package/{continuous-toolbox.d.ts → types/continuous-toolbox.d.ts} +0 -0
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
import * as Blockly from "blockly/core";
|
|
8
8
|
|
|
9
|
-
class
|
|
10
|
-
originalStyle;
|
|
9
|
+
class ScratchFieldDropdown extends Blockly.FieldDropdown {
|
|
10
|
+
private originalStyle: string;
|
|
11
11
|
|
|
12
|
-
showEditor_(event) {
|
|
12
|
+
showEditor_(event: PointerEvent) {
|
|
13
13
|
super.showEditor_(event);
|
|
14
|
-
const sourceBlock = this.getSourceBlock();
|
|
14
|
+
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
|
|
15
15
|
const style = sourceBlock.style;
|
|
16
16
|
if (sourceBlock.isShadow()) {
|
|
17
17
|
this.originalStyle = sourceBlock.getStyleName();
|
|
@@ -19,7 +19,9 @@ class FieldDropdown extends Blockly.FieldDropdown {
|
|
|
19
19
|
} else if (this.borderRect_) {
|
|
20
20
|
this.borderRect_.setAttribute(
|
|
21
21
|
"fill",
|
|
22
|
-
|
|
22
|
+
"colourQuaternary" in style
|
|
23
|
+
? `${style.colourQuaternary}`
|
|
24
|
+
: style.colourTertiary
|
|
23
25
|
);
|
|
24
26
|
}
|
|
25
27
|
}
|
|
@@ -36,7 +38,7 @@ class FieldDropdown extends Blockly.FieldDropdown {
|
|
|
36
38
|
/**
|
|
37
39
|
* Register the field and any dependencies.
|
|
38
40
|
*/
|
|
39
|
-
export function
|
|
41
|
+
export function registerScratchFieldDropdown() {
|
|
40
42
|
Blockly.fieldRegistry.unregister("field_dropdown");
|
|
41
|
-
Blockly.fieldRegistry.register("field_dropdown",
|
|
43
|
+
Blockly.fieldRegistry.register("field_dropdown", ScratchFieldDropdown);
|
|
42
44
|
}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* @author tmickel@mit.edu (Tim Mickel)
|
|
24
24
|
*/
|
|
25
25
|
import * as Blockly from "blockly/core";
|
|
26
|
-
import { Colours } from "../colours
|
|
26
|
+
import { Colours } from "../colours";
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* Class for an editable number field.
|
|
@@ -45,7 +45,10 @@ import { Colours } from "../colours.js";
|
|
|
45
45
|
* @extends {Blockly.FieldTextInput}
|
|
46
46
|
* @constructor
|
|
47
47
|
*/
|
|
48
|
-
class
|
|
48
|
+
class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
49
|
+
private negativeAllowed_ = true;
|
|
50
|
+
private decimalAllowed_ = true;
|
|
51
|
+
private exponentialAllowed_ = true;
|
|
49
52
|
/**
|
|
50
53
|
* Fixed width of the num-pad drop-down, in px.
|
|
51
54
|
* @type {number}
|
|
@@ -96,7 +99,7 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
96
99
|
Colours.numPadText +
|
|
97
100
|
'"/></svg>';
|
|
98
101
|
|
|
99
|
-
configure_(config) {
|
|
102
|
+
configure_(config: Blockly.FieldNumberFromJsonConfig) {
|
|
100
103
|
super.configure_(config);
|
|
101
104
|
this.decimalAllowed_ =
|
|
102
105
|
typeof config.precision == "undefined" ||
|
|
@@ -114,7 +117,7 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
114
117
|
* @return {!RegExp} Regular expression for this FieldNumber's restrictor.
|
|
115
118
|
*/
|
|
116
119
|
getNumRestrictor() {
|
|
117
|
-
|
|
120
|
+
let pattern = "[\\d]"; // Always allow digits.
|
|
118
121
|
if (this.decimalAllowed_) {
|
|
119
122
|
pattern += "|[\\.]";
|
|
120
123
|
}
|
|
@@ -130,11 +133,10 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
130
133
|
/**
|
|
131
134
|
* Show the inline free-text editor on top of the text and the num-pad if
|
|
132
135
|
* appropriate.
|
|
133
|
-
* @private
|
|
134
136
|
*/
|
|
135
|
-
showEditor_(e) {
|
|
137
|
+
showEditor_(e: PointerEvent) {
|
|
136
138
|
// Do not focus on mobile devices so we can show the num-pad
|
|
137
|
-
|
|
139
|
+
const showNumPad = e && e.pointerType === "touch";
|
|
138
140
|
super.showEditor_(e, showNumPad);
|
|
139
141
|
|
|
140
142
|
// Show a numeric keypad in the drop-down on touch
|
|
@@ -144,7 +146,7 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
144
146
|
}
|
|
145
147
|
}
|
|
146
148
|
|
|
147
|
-
onHtmlInputKeyDown_(e) {
|
|
149
|
+
onHtmlInputKeyDown_(e: KeyboardEvent) {
|
|
148
150
|
super.onHtmlInputKeyDown_(e);
|
|
149
151
|
// key can be things like "Backspace", so only validate when it represents a single
|
|
150
152
|
// character so as to allow non-textual input to work as normal.
|
|
@@ -158,10 +160,9 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
158
160
|
|
|
159
161
|
/**
|
|
160
162
|
* Show the number pad.
|
|
161
|
-
* @private
|
|
162
163
|
*/
|
|
163
|
-
showNumPad_() {
|
|
164
|
-
|
|
164
|
+
private showNumPad_() {
|
|
165
|
+
const contentDiv = Blockly.DropDownDiv.getContentDiv();
|
|
165
166
|
|
|
166
167
|
// Accessibility properties
|
|
167
168
|
contentDiv.setAttribute("role", "menu");
|
|
@@ -170,36 +171,37 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
170
171
|
this.addButtons_(contentDiv);
|
|
171
172
|
|
|
172
173
|
// Set colour and size of drop-down
|
|
174
|
+
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
|
|
173
175
|
Blockly.DropDownDiv.setColour(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
+
sourceBlock.getParent().getColour(),
|
|
177
|
+
sourceBlock.getColourTertiary()
|
|
176
178
|
);
|
|
177
|
-
contentDiv.style.width =
|
|
179
|
+
contentDiv.style.width = ScratchFieldNumber.DROPDOWN_WIDTH + "px";
|
|
178
180
|
|
|
179
181
|
this.position_();
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
/**
|
|
183
185
|
* Figure out where to place the drop-down, and move it there.
|
|
184
|
-
* @private
|
|
185
186
|
*/
|
|
186
|
-
position_() {
|
|
187
|
+
private position_() {
|
|
187
188
|
// Calculate positioning for the drop-down
|
|
188
189
|
// sourceBlock_ is the rendered shadow field input box
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
|
|
191
|
+
const scale = sourceBlock.workspace.scale;
|
|
192
|
+
let bBox = sourceBlock.getHeightWidth();
|
|
191
193
|
bBox.width *= scale;
|
|
192
194
|
bBox.height *= scale;
|
|
193
|
-
|
|
195
|
+
const position = this.getAbsoluteXY_();
|
|
194
196
|
// If we can fit it, render below the shadow block
|
|
195
|
-
|
|
196
|
-
|
|
197
|
+
const primaryX = position.x + bBox.width / 2;
|
|
198
|
+
const primaryY = position.y + bBox.height;
|
|
197
199
|
// If we can't fit it, render above the entire parent block
|
|
198
|
-
|
|
199
|
-
|
|
200
|
+
const secondaryX = primaryX;
|
|
201
|
+
const secondaryY = position.y;
|
|
200
202
|
|
|
201
203
|
Blockly.DropDownDiv.setBoundsElement(
|
|
202
|
-
|
|
204
|
+
sourceBlock.workspace.getParentSvg().parentElement
|
|
203
205
|
);
|
|
204
206
|
Blockly.DropDownDiv.show(
|
|
205
207
|
this,
|
|
@@ -215,17 +217,18 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
215
217
|
/**
|
|
216
218
|
* Add number, punctuation, and erase buttons to the numeric keypad's content
|
|
217
219
|
* div.
|
|
218
|
-
*
|
|
219
|
-
* @
|
|
220
|
+
*
|
|
221
|
+
* @param contentDiv The div for the numeric keypad.
|
|
220
222
|
*/
|
|
221
|
-
addButtons_(contentDiv) {
|
|
222
|
-
|
|
223
|
-
|
|
223
|
+
private addButtons_(contentDiv: Element) {
|
|
224
|
+
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
|
|
225
|
+
const buttonColour = sourceBlock.getParent().getColour();
|
|
226
|
+
const buttonBorderColour = sourceBlock.getParent().getColourTertiary();
|
|
224
227
|
|
|
225
228
|
// Add numeric keypad buttons
|
|
226
|
-
|
|
227
|
-
for (
|
|
228
|
-
|
|
229
|
+
const buttons = ScratchFieldNumber.NUMPAD_BUTTONS;
|
|
230
|
+
for (let i = 0, buttonText; (buttonText = buttons[i]); i++) {
|
|
231
|
+
const button = document.createElement("button");
|
|
229
232
|
button.setAttribute("role", "menuitem");
|
|
230
233
|
button.setAttribute("class", "blocklyNumPadButton");
|
|
231
234
|
button.setAttribute(
|
|
@@ -258,7 +261,7 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
258
261
|
contentDiv.appendChild(button);
|
|
259
262
|
}
|
|
260
263
|
// Add erase button to the end
|
|
261
|
-
|
|
264
|
+
const eraseButton = document.createElement("button");
|
|
262
265
|
eraseButton.setAttribute("role", "menuitem");
|
|
263
266
|
eraseButton.setAttribute("class", "blocklyNumPadButton");
|
|
264
267
|
eraseButton.setAttribute(
|
|
@@ -272,8 +275,8 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
272
275
|
);
|
|
273
276
|
eraseButton.title = "Delete";
|
|
274
277
|
|
|
275
|
-
|
|
276
|
-
eraseImage.src =
|
|
278
|
+
const eraseImage = document.createElement("img");
|
|
279
|
+
eraseImage.src = ScratchFieldNumber.NUMPAD_DELETE_ICON;
|
|
277
280
|
eraseButton.appendChild(eraseImage);
|
|
278
281
|
|
|
279
282
|
Blockly.browserEvents.bind(
|
|
@@ -288,19 +291,20 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
288
291
|
/**
|
|
289
292
|
* Call for when a num-pad number or punctuation button is touched.
|
|
290
293
|
* Determine what the user is inputting and update the text field appropriately.
|
|
291
|
-
*
|
|
294
|
+
*
|
|
295
|
+
* @param e DOM event triggering the touch.
|
|
292
296
|
*/
|
|
293
|
-
numPadButtonTouch(e) {
|
|
297
|
+
numPadButtonTouch(e: PointerEvent) {
|
|
294
298
|
// String of the button (e.g., '7')
|
|
295
|
-
|
|
299
|
+
const spliceValue = (e.target as HTMLElement).innerText;
|
|
296
300
|
// Old value of the text field
|
|
297
|
-
|
|
301
|
+
const oldValue = this.htmlInput_.value;
|
|
298
302
|
// Determine the selected portion of the text field
|
|
299
|
-
|
|
300
|
-
|
|
303
|
+
const selectionStart = this.htmlInput_.selectionStart;
|
|
304
|
+
const selectionEnd = this.htmlInput_.selectionEnd;
|
|
301
305
|
|
|
302
306
|
// Splice in the new value
|
|
303
|
-
|
|
307
|
+
const newValue =
|
|
304
308
|
oldValue.slice(0, selectionStart) +
|
|
305
309
|
spliceValue +
|
|
306
310
|
oldValue.slice(selectionEnd);
|
|
@@ -318,14 +322,15 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
318
322
|
/**
|
|
319
323
|
* Call for when the num-pad erase button is touched.
|
|
320
324
|
* Determine what the user is asking to erase, and erase it.
|
|
321
|
-
*
|
|
325
|
+
*
|
|
326
|
+
* @param e DOM event triggering the touch.
|
|
322
327
|
*/
|
|
323
|
-
numPadEraseButtonTouch(e) {
|
|
328
|
+
numPadEraseButtonTouch(e: PointerEvent) {
|
|
324
329
|
// Old value of the text field
|
|
325
|
-
|
|
330
|
+
const oldValue = this.htmlInput_.value;
|
|
326
331
|
// Determine what is selected to erase (if anything)
|
|
327
|
-
|
|
328
|
-
|
|
332
|
+
let selectionStart = this.htmlInput_.selectionStart;
|
|
333
|
+
const selectionEnd = this.htmlInput_.selectionEnd;
|
|
329
334
|
|
|
330
335
|
// If selection is zero-length, shift start to the left 1 character
|
|
331
336
|
if (selectionStart == selectionEnd) {
|
|
@@ -333,7 +338,7 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
333
338
|
}
|
|
334
339
|
|
|
335
340
|
// Cut out selected range
|
|
336
|
-
|
|
341
|
+
const newValue =
|
|
337
342
|
oldValue.slice(0, selectionStart) + oldValue.slice(selectionEnd);
|
|
338
343
|
|
|
339
344
|
this.updateDisplay_(newValue, selectionStart);
|
|
@@ -347,11 +352,11 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
347
352
|
|
|
348
353
|
/**
|
|
349
354
|
* Update the displayed value and resize/scroll the text field as needed.
|
|
350
|
-
*
|
|
351
|
-
* @param
|
|
352
|
-
* @
|
|
355
|
+
*
|
|
356
|
+
* @param newValue The new text to display.
|
|
357
|
+
* @param newSelection The new index to put the cursor
|
|
353
358
|
*/
|
|
354
|
-
updateDisplay_(newValue, newSelection) {
|
|
359
|
+
private updateDisplay_(newValue: string, newSelection: number) {
|
|
355
360
|
this.setEditorValue_(newValue);
|
|
356
361
|
// Resize and scroll the text field appropriately
|
|
357
362
|
const htmlInput = this.htmlInput_;
|
|
@@ -369,12 +374,12 @@ class FieldNumberPicker extends Blockly.FieldTextInput {
|
|
|
369
374
|
}
|
|
370
375
|
}
|
|
371
376
|
|
|
372
|
-
|
|
377
|
+
ScratchFieldNumber.prototype.DEFAULT_VALUE = "";
|
|
373
378
|
|
|
374
379
|
/**
|
|
375
380
|
* Register the field and any dependencies.
|
|
376
381
|
*/
|
|
377
|
-
export function
|
|
382
|
+
export function registerScratchFieldNumber() {
|
|
378
383
|
Blockly.fieldRegistry.unregister("field_number");
|
|
379
|
-
Blockly.fieldRegistry.register("field_number",
|
|
384
|
+
Blockly.fieldRegistry.register("field_number", ScratchFieldNumber);
|
|
380
385
|
}
|
|
@@ -23,24 +23,31 @@
|
|
|
23
23
|
* @author fraser@google.com (Neil Fraser)
|
|
24
24
|
*/
|
|
25
25
|
import * as Blockly from "blockly/core";
|
|
26
|
-
import * as Constants from "../constants
|
|
26
|
+
import * as Constants from "../constants";
|
|
27
27
|
import { ScratchMsgs } from "../../msg/scratch_msgs.js";
|
|
28
|
-
import { createVariable, renameVariable } from "../variables
|
|
28
|
+
import { createVariable, renameVariable } from "../variables";
|
|
29
|
+
import type { ScratchVariableModel } from "../scratch_variable_model";
|
|
29
30
|
|
|
30
|
-
class
|
|
31
|
-
originalStyle;
|
|
31
|
+
export class ScratchFieldVariable extends Blockly.FieldVariable {
|
|
32
|
+
private originalStyle: string;
|
|
32
33
|
|
|
33
|
-
constructor(
|
|
34
|
+
constructor(
|
|
35
|
+
varName: string | null | typeof Blockly.Field.SKIP_SETUP,
|
|
36
|
+
validator?: Blockly.FieldVariableValidator,
|
|
37
|
+
variableTypes?: string[],
|
|
38
|
+
defaultType?: string,
|
|
39
|
+
config?: Blockly.FieldVariableConfig
|
|
40
|
+
) {
|
|
34
41
|
super(varName, validator, variableTypes, defaultType, config);
|
|
35
|
-
this.menuGenerator_ =
|
|
42
|
+
this.menuGenerator_ = ScratchFieldVariable.dropdownCreate;
|
|
36
43
|
}
|
|
37
44
|
|
|
38
45
|
initModel() {
|
|
39
|
-
if (!this.
|
|
46
|
+
if (!this.getVariable()) {
|
|
40
47
|
const sourceBlock = this.getSourceBlock();
|
|
41
48
|
if (sourceBlock) {
|
|
42
49
|
const broadcastVariable = this.initFlyoutBroadcast(
|
|
43
|
-
sourceBlock.workspace
|
|
50
|
+
sourceBlock.workspace as Blockly.WorkspaceSvg
|
|
44
51
|
);
|
|
45
52
|
if (broadcastVariable) {
|
|
46
53
|
this.doValueUpdate_(broadcastVariable.getId());
|
|
@@ -59,12 +66,14 @@ class FieldVariable extends Blockly.FieldVariable {
|
|
|
59
66
|
* selected option when the workspace is refreshed.
|
|
60
67
|
* Re-sort the broadcast messages by name, and set the field value to the id
|
|
61
68
|
* of the variable that comes first in sorted order.
|
|
62
|
-
*
|
|
63
|
-
* broadcast block.
|
|
64
|
-
* @
|
|
65
|
-
*
|
|
69
|
+
*
|
|
70
|
+
* @param workspace The flyout workspace containing the broadcast block.
|
|
71
|
+
* @returns The variable of type 'broadcast_msg' that comes first in sorted
|
|
72
|
+
* order.
|
|
66
73
|
*/
|
|
67
|
-
initFlyoutBroadcast(
|
|
74
|
+
initFlyoutBroadcast(
|
|
75
|
+
workspace: Blockly.WorkspaceSvg
|
|
76
|
+
): Blockly.IVariableModel<Blockly.IVariableState> {
|
|
68
77
|
const broadcastVars = workspace.getVariablesOfType(
|
|
69
78
|
Constants.BROADCAST_MESSAGE_VARIABLE_TYPE
|
|
70
79
|
);
|
|
@@ -81,10 +90,10 @@ class FieldVariable extends Blockly.FieldVariable {
|
|
|
81
90
|
/**
|
|
82
91
|
* Return a sorted list of variable names for variable dropdown menus.
|
|
83
92
|
* Include a special option at the end for creating a new variable name.
|
|
84
|
-
*
|
|
85
|
-
* @
|
|
93
|
+
*
|
|
94
|
+
* @returns Array of variable names.
|
|
86
95
|
*/
|
|
87
|
-
static dropdownCreate() {
|
|
96
|
+
static dropdownCreate(this: ScratchFieldVariable): Blockly.MenuOption[] {
|
|
88
97
|
const options = super.dropdownCreate();
|
|
89
98
|
const type = this.getDefaultType();
|
|
90
99
|
if (type === Constants.BROADCAST_MESSAGE_VARIABLE_TYPE) {
|
|
@@ -112,16 +121,17 @@ class FieldVariable extends Blockly.FieldVariable {
|
|
|
112
121
|
* Special case the 'Rename variable...', 'Delete variable...',
|
|
113
122
|
* and 'New message...' options.
|
|
114
123
|
* In the rename case, prompt the user for a new name.
|
|
115
|
-
*
|
|
116
|
-
* @param
|
|
124
|
+
*
|
|
125
|
+
* @param menu The Menu component clicked.
|
|
126
|
+
* @param menuItem The MenuItem selected within menu.
|
|
117
127
|
*/
|
|
118
|
-
onItemSelected_(menu, menuItem) {
|
|
128
|
+
onItemSelected_(menu: Blockly.Menu, menuItem: Blockly.MenuItem) {
|
|
119
129
|
const sourceBlock = this.getSourceBlock();
|
|
120
130
|
if (sourceBlock && !sourceBlock.isDeadOrDying()) {
|
|
121
131
|
const selectedItem = menuItem.getValue();
|
|
122
132
|
if (selectedItem === Constants.NEW_BROADCAST_MESSAGE_ID) {
|
|
123
133
|
createVariable(
|
|
124
|
-
sourceBlock.workspace,
|
|
134
|
+
sourceBlock.workspace as Blockly.WorkspaceSvg,
|
|
125
135
|
(varId) => {
|
|
126
136
|
if (varId) {
|
|
127
137
|
this.setValue(varId);
|
|
@@ -131,24 +141,33 @@ class FieldVariable extends Blockly.FieldVariable {
|
|
|
131
141
|
);
|
|
132
142
|
return;
|
|
133
143
|
} else if (selectedItem === Blockly.RENAME_VARIABLE_ID) {
|
|
134
|
-
renameVariable(
|
|
144
|
+
renameVariable(
|
|
145
|
+
sourceBlock.workspace as Blockly.WorkspaceSvg,
|
|
146
|
+
this.getVariable() as ScratchVariableModel
|
|
147
|
+
);
|
|
135
148
|
return;
|
|
136
149
|
}
|
|
137
150
|
}
|
|
138
151
|
super.onItemSelected_(menu, menuItem);
|
|
139
152
|
}
|
|
140
153
|
|
|
141
|
-
showEditor_(event) {
|
|
154
|
+
showEditor_(event: PointerEvent) {
|
|
142
155
|
super.showEditor_(event);
|
|
143
156
|
const sourceBlock = this.getSourceBlock();
|
|
144
|
-
const
|
|
157
|
+
const styleName = sourceBlock.getStyleName();
|
|
158
|
+
const style = (sourceBlock.workspace as Blockly.WorkspaceSvg)
|
|
159
|
+
.getRenderer()
|
|
160
|
+
.getConstants()
|
|
161
|
+
.getBlockStyle(styleName);
|
|
145
162
|
if (sourceBlock.isShadow()) {
|
|
146
|
-
this.originalStyle =
|
|
163
|
+
this.originalStyle = styleName;
|
|
147
164
|
sourceBlock.setStyle(`${this.originalStyle}_selected`);
|
|
148
165
|
} else if (this.borderRect_) {
|
|
149
166
|
this.borderRect_.setAttribute(
|
|
150
167
|
"fill",
|
|
151
|
-
|
|
168
|
+
"colourQuaternary" in style
|
|
169
|
+
? `${style.colourQuaternary}`
|
|
170
|
+
: style.colourTertiary
|
|
152
171
|
);
|
|
153
172
|
}
|
|
154
173
|
}
|
|
@@ -165,7 +184,7 @@ class FieldVariable extends Blockly.FieldVariable {
|
|
|
165
184
|
/**
|
|
166
185
|
* Register the field and any dependencies.
|
|
167
186
|
*/
|
|
168
|
-
export function
|
|
187
|
+
export function registerScratchFieldVariable() {
|
|
169
188
|
Blockly.fieldRegistry.unregister("field_variable");
|
|
170
|
-
Blockly.fieldRegistry.register("field_variable",
|
|
189
|
+
Blockly.fieldRegistry.register("field_variable", ScratchFieldVariable);
|
|
171
190
|
}
|
|
@@ -5,55 +5,51 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as Blockly from "blockly/core";
|
|
8
|
-
import { CheckboxBubble } from "./checkbox_bubble
|
|
8
|
+
import { CheckboxBubble } from "./checkbox_bubble";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Invisible icon that exists solely to host the corresponding checkbox bubble.
|
|
12
|
-
* @implements {Blockly.IIcon}
|
|
13
|
-
* @implements {Blockly.IHasBubble}
|
|
14
12
|
*/
|
|
15
|
-
export class FlyoutCheckboxIcon {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type = new Blockly.icons.IconType("checkbox");
|
|
13
|
+
export class FlyoutCheckboxIcon implements Blockly.IIcon, Blockly.IHasBubble {
|
|
14
|
+
private checkboxBubble: CheckboxBubble;
|
|
15
|
+
private type = new Blockly.icons.IconType("checkbox");
|
|
19
16
|
|
|
20
|
-
constructor(sourceBlock) {
|
|
21
|
-
this.sourceBlock = sourceBlock;
|
|
17
|
+
constructor(private sourceBlock: Blockly.BlockSvg) {
|
|
22
18
|
if (this.sourceBlock.workspace.isFlyout) {
|
|
23
19
|
this.checkboxBubble = new CheckboxBubble(this.sourceBlock);
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
|
|
27
|
-
getType() {
|
|
23
|
+
getType(): Blockly.icons.IconType<FlyoutCheckboxIcon> {
|
|
28
24
|
return this.type;
|
|
29
25
|
}
|
|
30
26
|
|
|
31
|
-
getWeight() {
|
|
27
|
+
getWeight(): number {
|
|
32
28
|
return -1;
|
|
33
29
|
}
|
|
34
30
|
|
|
35
|
-
getSize() {
|
|
31
|
+
getSize(): Blockly.utils.Size {
|
|
36
32
|
// Awful hack to cancel out the default padding added to icons.
|
|
37
33
|
return new Blockly.utils.Size(-8, 0);
|
|
38
34
|
}
|
|
39
35
|
|
|
40
|
-
isShownWhenCollapsed() {
|
|
36
|
+
isShownWhenCollapsed(): boolean {
|
|
41
37
|
return false;
|
|
42
38
|
}
|
|
43
39
|
|
|
44
|
-
isClickableInFlyout() {
|
|
40
|
+
isClickableInFlyout(): boolean {
|
|
45
41
|
return false;
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
bubbleIsVisible() {
|
|
44
|
+
bubbleIsVisible(): boolean {
|
|
49
45
|
return this.sourceBlock.workspace.isFlyout;
|
|
50
46
|
}
|
|
51
47
|
|
|
52
|
-
onLocationChange(blockOrigin) {
|
|
48
|
+
onLocationChange(blockOrigin: Blockly.utils.Coordinate) {
|
|
53
49
|
this.checkboxBubble?.updateLocation();
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
setChecked(checked) {
|
|
52
|
+
setChecked(checked: boolean) {
|
|
57
53
|
this.checkboxBubble?.setChecked(checked);
|
|
58
54
|
}
|
|
59
55
|
|
|
@@ -75,9 +71,9 @@ export class FlyoutCheckboxIcon {
|
|
|
75
71
|
|
|
76
72
|
onClick() {}
|
|
77
73
|
|
|
78
|
-
async setBubbleVisible(visible) {}
|
|
74
|
+
async setBubbleVisible(visible: boolean) {}
|
|
79
75
|
|
|
80
|
-
initView(pointerDownListener) {}
|
|
76
|
+
initView(pointerDownListener: (e: PointerEvent) => void) {}
|
|
81
77
|
}
|
|
82
78
|
|
|
83
79
|
Blockly.registry.register(
|
|
@@ -1,30 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
import * as Blockly from "blockly/core";
|
|
2
|
-
import { Colours } from "./colours
|
|
8
|
+
import { Colours } from "./colours";
|
|
3
9
|
|
|
4
10
|
/**
|
|
5
11
|
* Glow/unglow a stack in the workspace.
|
|
6
|
-
*
|
|
7
|
-
* @param
|
|
12
|
+
*
|
|
13
|
+
* @param id ID of block which starts the stack.
|
|
14
|
+
* @param isGlowingStack Whether to glow the stack.
|
|
8
15
|
*/
|
|
9
|
-
export function glowStack(id, isGlowingStack) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
export function glowStack(id: string, isGlowingStack: boolean) {
|
|
17
|
+
const block = (Blockly.getMainWorkspace().getBlockById(id) ||
|
|
18
|
+
(Blockly.getMainWorkspace() as Blockly.WorkspaceSvg)
|
|
19
|
+
.getFlyout()
|
|
20
|
+
.getWorkspace()
|
|
21
|
+
.getBlockById(id)) as Blockly.BlockSvg;
|
|
22
|
+
if (!block) {
|
|
23
|
+
throw "Tried to glow block that does not exist.";
|
|
24
|
+
}
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
26
|
+
const svg = block.getSvgRoot();
|
|
27
|
+
if (isGlowingStack && !svg.hasAttribute("filter")) {
|
|
28
|
+
svg.setAttribute("filter", "url(#blocklyStackGlowFilter)");
|
|
29
|
+
} else if (!isGlowingStack && svg.hasAttribute("filter")) {
|
|
30
|
+
svg.removeAttribute("filter");
|
|
24
31
|
}
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Creates an SVG filter to render block glows and adds it to the DOM.
|
|
36
|
+
* @param workspace The workspace whose DOM the filter will be inserted in.
|
|
37
|
+
*/
|
|
38
|
+
export function buildGlowFilter(workspace: Blockly.WorkspaceSvg) {
|
|
28
39
|
const svg = workspace.getParentSvg();
|
|
29
40
|
const defs = Blockly.utils.dom.createSvgElement(
|
|
30
41
|
Blockly.utils.Svg.DEFS,
|