scratch-blocks 2.0.0 → 2.0.2
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/AGENTS.md +140 -0
- package/dist/main.mjs +1 -1
- package/dist/types/src/blocks/procedures.d.ts +1 -1
- package/dist/types/src/blocks/procedures.d.ts.map +1 -1
- package/dist/types/src/events/events_block_comment_base.d.ts.map +1 -1
- package/dist/types/src/events/events_block_drag_end.d.ts.map +1 -1
- package/dist/types/src/events/events_block_drag_outside.d.ts.map +1 -1
- package/dist/types/src/fields/field_colour_slider.d.ts +4 -4
- package/dist/types/src/fields/field_colour_slider.d.ts.map +1 -1
- package/dist/types/src/fields/field_matrix.d.ts.map +1 -1
- package/dist/types/src/fields/field_note.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_number.d.ts.map +1 -1
- package/dist/types/src/fields/scratch_field_variable.d.ts +1 -1
- package/dist/types/src/fields/scratch_field_variable.d.ts.map +1 -1
- package/dist/types/src/flyout_checkbox_icon.d.ts.map +1 -1
- package/dist/types/src/procedures.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/cat_face.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/drawer.d.ts +1 -1
- package/dist/types/src/renderer/cat/drawer.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/render_info.d.ts.map +1 -1
- package/dist/types/src/renderer/cat/renderer.d.ts +1 -1
- package/dist/types/src/renderer/cat/renderer.d.ts.map +1 -1
- package/dist/types/src/renderer/constants.d.ts +41 -0
- package/dist/types/src/renderer/constants.d.ts.map +1 -0
- package/dist/types/src/renderer/drawer.d.ts +2 -2
- package/dist/types/src/renderer/drawer.d.ts.map +1 -1
- package/dist/types/src/renderer/render_info.d.ts.map +1 -1
- package/dist/types/src/renderer/renderer.d.ts +1 -1
- package/dist/types/src/renderer/renderer.d.ts.map +1 -1
- package/dist/types/src/scratch_comment_bubble.d.ts +2 -2
- package/dist/types/src/scratch_comment_bubble.d.ts.map +1 -1
- package/dist/types/src/scratch_comment_icon.d.ts +1 -1
- package/dist/types/src/scratch_comment_icon.d.ts.map +1 -1
- package/dist/types/src/scratch_dragger.d.ts +1 -1
- package/dist/types/src/scratch_variable_model.d.ts +1 -1
- package/dist/types/src/scratch_variable_model.d.ts.map +1 -1
- package/dist/types/tests/jsunit/connection_db_test.d.ts +3 -3
- package/package.json +9 -9
- package/src/block_reporting.ts +2 -2
- package/src/blocks/control.ts +9 -2
- package/src/blocks/data.ts +34 -6
- package/src/blocks/procedures.ts +49 -31
- package/src/context_menu_items.ts +7 -7
- package/src/data_category.ts +4 -4
- package/src/events/events_block_comment_base.ts +8 -5
- package/src/events/events_block_comment_change.ts +4 -4
- package/src/events/events_block_comment_collapse.ts +14 -2
- package/src/events/events_block_comment_create.ts +4 -1
- package/src/events/events_block_comment_delete.ts +4 -2
- package/src/events/events_block_comment_move.ts +4 -4
- package/src/events/events_block_comment_resize.ts +4 -4
- package/src/events/events_block_drag_end.ts +4 -4
- package/src/events/events_block_drag_outside.ts +2 -2
- package/src/events/events_scratch_variable_create.ts +20 -2
- package/src/fields/field_colour_slider.ts +53 -28
- package/src/fields/field_matrix.ts +9 -8
- package/src/fields/field_note.ts +34 -27
- package/src/fields/field_textinput_removable.ts +2 -2
- package/src/fields/field_variable_getter.ts +5 -5
- package/src/fields/field_vertical_separator.ts +1 -1
- package/src/fields/scratch_field_angle.ts +14 -14
- package/src/fields/scratch_field_dropdown.ts +2 -2
- package/src/fields/scratch_field_number.ts +13 -12
- package/src/fields/scratch_field_variable.ts +8 -5
- package/src/flyout_checkbox_icon.ts +1 -1
- package/src/glows.ts +2 -2
- package/src/procedures.ts +25 -17
- package/src/renderer/cat/cat_face.ts +1 -1
- package/src/renderer/cat/drawer.ts +3 -3
- package/src/renderer/cat/render_info.ts +2 -2
- package/src/renderer/cat/renderer.ts +2 -2
- package/src/renderer/constants.ts +8 -8
- package/src/renderer/drawer.ts +2 -2
- package/src/renderer/render_info.ts +7 -4
- package/src/renderer/renderer.ts +2 -2
- package/src/scratch_block_paster.ts +1 -1
- package/src/scratch_comment_bubble.ts +16 -14
- package/src/scratch_comment_icon.ts +1 -1
- package/src/scratch_dragger.ts +2 -2
- package/src/scratch_variable_model.ts +2 -2
- package/src/status_indicator_label.ts +3 -3
- package/src/status_indicator_label_flyout_inflater.ts +1 -1
- package/src/variables.ts +7 -7
- package/src/xml.ts +3 -3
- package/tsconfig.json +1 -1
|
@@ -39,7 +39,7 @@ enum LEDState {
|
|
|
39
39
|
* Class for a matrix field.
|
|
40
40
|
*/
|
|
41
41
|
class FieldMatrix extends Blockly.Field<string> {
|
|
42
|
-
private originalStyle
|
|
42
|
+
private originalStyle = "";
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* Array of SVGElement<rect> for matrix thumbnail image on block field.
|
|
@@ -215,7 +215,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
215
215
|
this.arrow_.setAttributeNS(
|
|
216
216
|
"http://www.w3.org/1999/xlink",
|
|
217
217
|
"xlink:href",
|
|
218
|
-
this.getConstants()
|
|
218
|
+
this.getConstants()!.FIELD_DROPDOWN_SVG_ARROW_DATAURI
|
|
219
219
|
);
|
|
220
220
|
this.arrow_.style.cursor = "default";
|
|
221
221
|
}
|
|
@@ -348,7 +348,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
dropdownDispose_() {
|
|
351
|
-
const sourceBlock = this.getSourceBlock()
|
|
351
|
+
const sourceBlock = this.getSourceBlock()!;
|
|
352
352
|
if (sourceBlock.isShadow()) {
|
|
353
353
|
sourceBlock.setStyle(this.originalStyle);
|
|
354
354
|
}
|
|
@@ -396,8 +396,8 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
396
396
|
* Redraw the matrix with the current value.
|
|
397
397
|
*/
|
|
398
398
|
private updateMatrix_() {
|
|
399
|
-
const matrix = this.getValue()
|
|
400
|
-
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
|
|
399
|
+
const matrix = this.getValue()!;
|
|
400
|
+
const sourceBlock = this.getSourceBlock()! as Blockly.BlockSvg;
|
|
401
401
|
for (let i = 0; i < matrix.length; i++) {
|
|
402
402
|
if (matrix[i] === LEDState.OFF) {
|
|
403
403
|
this.fillMatrixNode_(
|
|
@@ -451,7 +451,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
451
451
|
|
|
452
452
|
setLEDNode_(led: number, state: LEDState) {
|
|
453
453
|
if (led < 0 || led > 24) return;
|
|
454
|
-
const oldMatrix = this.getValue()
|
|
454
|
+
const oldMatrix = this.getValue()!;
|
|
455
455
|
const newMatrix =
|
|
456
456
|
oldMatrix.substr(0, led) + state + oldMatrix.substr(led + 1);
|
|
457
457
|
this.setValue(newMatrix);
|
|
@@ -469,7 +469,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
469
469
|
|
|
470
470
|
toggleLEDNode_(led: number) {
|
|
471
471
|
if (led < 0 || led > 24) return;
|
|
472
|
-
if (this.getValue()
|
|
472
|
+
if (this.getValue()!.charAt(led) === LEDState.OFF) {
|
|
473
473
|
this.setLEDNode_(led, LEDState.ON);
|
|
474
474
|
} else {
|
|
475
475
|
this.setLEDNode_(led, LEDState.OFF);
|
|
@@ -496,7 +496,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
496
496
|
);
|
|
497
497
|
const ledHit = this.checkForLED_(e);
|
|
498
498
|
if (ledHit > -1) {
|
|
499
|
-
if (this.getValue()
|
|
499
|
+
if (this.getValue()!.charAt(ledHit) === LEDState.OFF) {
|
|
500
500
|
this.paintStyle_ = PaintStyle.FILL;
|
|
501
501
|
} else {
|
|
502
502
|
this.paintStyle_ = PaintStyle.CLEAR;
|
|
@@ -548,6 +548,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
548
548
|
* @returns The matching matrix node or -1 for none.
|
|
549
549
|
*/
|
|
550
550
|
checkForLED_(e: PointerEvent): number {
|
|
551
|
+
if (!this.matrixStage_) return -1;
|
|
551
552
|
const bBox = this.matrixStage_.getBoundingClientRect();
|
|
552
553
|
const nodeSize = FieldMatrix.MATRIX_NODE_SIZE;
|
|
553
554
|
const nodePad = FieldMatrix.MATRIX_NODE_PAD;
|
package/src/fields/field_note.ts
CHANGED
|
@@ -369,7 +369,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
369
369
|
"line",
|
|
370
370
|
{
|
|
371
371
|
stroke: (
|
|
372
|
-
this.sourceBlock_
|
|
372
|
+
this.sourceBlock_!.getParent() as Blockly.BlockSvg
|
|
373
373
|
).getColourTertiary(),
|
|
374
374
|
x1: 0,
|
|
375
375
|
y1: FieldNote.TOP_MENU_HEIGHT,
|
|
@@ -407,7 +407,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
407
407
|
octaveDownButton,
|
|
408
408
|
"mousedown",
|
|
409
409
|
this,
|
|
410
|
-
|
|
410
|
+
() => {
|
|
411
411
|
this.changeOctaveBy_(-1);
|
|
412
412
|
}
|
|
413
413
|
);
|
|
@@ -415,14 +415,14 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
415
415
|
octaveUpButton,
|
|
416
416
|
"mousedown",
|
|
417
417
|
this,
|
|
418
|
-
|
|
418
|
+
() => {
|
|
419
419
|
this.changeOctaveBy_(1);
|
|
420
420
|
}
|
|
421
421
|
);
|
|
422
422
|
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
|
|
423
423
|
Blockly.DropDownDiv.setColour(
|
|
424
|
-
sourceBlock.getParent().getColour(),
|
|
425
|
-
sourceBlock.getParent().getColourTertiary()
|
|
424
|
+
(sourceBlock.getParent() as Blockly.BlockSvg).getColour(),
|
|
425
|
+
(sourceBlock.getParent() as Blockly.BlockSvg).getColourTertiary()
|
|
426
426
|
);
|
|
427
427
|
Blockly.DropDownDiv.showPositionedByBlock(this, sourceBlock);
|
|
428
428
|
|
|
@@ -441,7 +441,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
441
441
|
x: number,
|
|
442
442
|
whiteKeyGroup: SVGElement,
|
|
443
443
|
blackKeyGroup: SVGElement,
|
|
444
|
-
keySVGarray: SVGElement[]
|
|
444
|
+
keySVGarray: SVGElement[] | null
|
|
445
445
|
) {
|
|
446
446
|
let xIncrement, width, height, fill, stroke, group;
|
|
447
447
|
x += FieldNote.EDGE_PADDING / 2;
|
|
@@ -463,7 +463,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
463
463
|
height = FieldNote.WHITE_KEY_HEIGHT;
|
|
464
464
|
fill = FieldNote.WHITE_KEY_COLOR;
|
|
465
465
|
stroke = (
|
|
466
|
-
this.sourceBlock_
|
|
466
|
+
this.sourceBlock_!.getParent() as Blockly.BlockSvg
|
|
467
467
|
).getColourTertiary();
|
|
468
468
|
group = whiteKeyGroup;
|
|
469
469
|
}
|
|
@@ -594,7 +594,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
594
594
|
"line",
|
|
595
595
|
{
|
|
596
596
|
stroke: (
|
|
597
|
-
this.sourceBlock_
|
|
597
|
+
this.sourceBlock_!.getParent() as Blockly.BlockSvg
|
|
598
598
|
).getColourTertiary(),
|
|
599
599
|
x1: x - FieldNote.INSET,
|
|
600
600
|
y1: 0,
|
|
@@ -643,13 +643,15 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
643
643
|
* @param visible If true, set labels to be visible.
|
|
644
644
|
*/
|
|
645
645
|
private setCKeyLabelsVisible_(visible: boolean) {
|
|
646
|
-
if (
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
this.fadeSvgToOpacity_(this.highCText_, 0);
|
|
646
|
+
if (!this.lowCText_ || !this.highCText_) {
|
|
647
|
+
console.warn(
|
|
648
|
+
"FieldNote.setCKeyLabelsVisible_: C-key label DOM is not fully initialized"
|
|
649
|
+
);
|
|
650
|
+
return;
|
|
652
651
|
}
|
|
652
|
+
const opacity = visible ? 1 : 0;
|
|
653
|
+
this.fadeSvgToOpacity_(this.lowCText_, opacity);
|
|
654
|
+
this.fadeSvgToOpacity_(this.highCText_, opacity);
|
|
653
655
|
}
|
|
654
656
|
|
|
655
657
|
/**
|
|
@@ -686,8 +688,10 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
686
688
|
*/
|
|
687
689
|
private onMouseUp_() {
|
|
688
690
|
this.mouseIsDown_ = false;
|
|
689
|
-
|
|
690
|
-
|
|
691
|
+
if (this.mouseUpWrapper_) {
|
|
692
|
+
Blockly.browserEvents.unbind(this.mouseUpWrapper_);
|
|
693
|
+
this.mouseUpWrapper_ = null;
|
|
694
|
+
}
|
|
691
695
|
}
|
|
692
696
|
|
|
693
697
|
/**
|
|
@@ -709,7 +713,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
709
713
|
private selectNoteWithMouseEvent_(e: PointerEvent) {
|
|
710
714
|
const newNoteNum =
|
|
711
715
|
Number((e.target as HTMLElement).getAttribute("data-pitch")) +
|
|
712
|
-
this.displayedOctave_ * 12;
|
|
716
|
+
(this.displayedOctave_ ?? 0) * 12;
|
|
713
717
|
this.setEditorValue_(newNoteNum);
|
|
714
718
|
this.playNoteInternal_();
|
|
715
719
|
}
|
|
@@ -719,7 +723,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
719
723
|
*/
|
|
720
724
|
private playNoteInternal_() {
|
|
721
725
|
if (FieldNote.playNote_) {
|
|
722
|
-
FieldNote.playNote_(Number(this.getValue()), "Music");
|
|
726
|
+
FieldNote.playNote_(Number(this.getValue()!), "Music");
|
|
723
727
|
}
|
|
724
728
|
}
|
|
725
729
|
|
|
@@ -740,7 +744,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
740
744
|
* @param octaves The number of octaves to change by.
|
|
741
745
|
*/
|
|
742
746
|
private changeOctaveBy_(octaves: number) {
|
|
743
|
-
this.displayedOctave_
|
|
747
|
+
this.displayedOctave_ = (this.displayedOctave_ ?? 0) + octaves;
|
|
744
748
|
if (this.displayedOctave_ < 0) {
|
|
745
749
|
this.displayedOctave_ = 0;
|
|
746
750
|
return;
|
|
@@ -766,7 +770,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
766
770
|
private stepOctaveAnimation_() {
|
|
767
771
|
const absDiff = Math.abs(this.animationPos_ - this.animationTarget_);
|
|
768
772
|
if (absDiff < 1) {
|
|
769
|
-
this.pianoSVG_
|
|
773
|
+
this.pianoSVG_?.setAttribute("transform", "translate(0, 0)");
|
|
770
774
|
this.setCKeyLabelsVisible_(true);
|
|
771
775
|
this.playNoteInternal_();
|
|
772
776
|
return;
|
|
@@ -774,7 +778,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
774
778
|
this.animationPos_ +=
|
|
775
779
|
(this.animationTarget_ - this.animationPos_) *
|
|
776
780
|
FieldNote.ANIMATION_FRACTION;
|
|
777
|
-
this.pianoSVG_
|
|
781
|
+
this.pianoSVG_?.setAttribute(
|
|
778
782
|
"transform",
|
|
779
783
|
"translate(" + this.animationPos_ + ",0)"
|
|
780
784
|
);
|
|
@@ -799,7 +803,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
799
803
|
* @returns The index of the piano key.
|
|
800
804
|
*/
|
|
801
805
|
private noteNumToKeyIndex_(noteNum: number): number {
|
|
802
|
-
return Math.floor(noteNum) - this.displayedOctave_ * 12;
|
|
806
|
+
return Math.floor(noteNum) - (this.displayedOctave_ ?? 0) * 12;
|
|
803
807
|
}
|
|
804
808
|
|
|
805
809
|
/**
|
|
@@ -833,12 +837,15 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
833
837
|
this.keySVGs_[index].setAttribute("fill", FieldNote.KEY_SELECTED_COLOR);
|
|
834
838
|
// Update the note name text
|
|
835
839
|
const noteName = FieldNote.KEY_INFO[index].name;
|
|
836
|
-
this.noteNameText_
|
|
837
|
-
|
|
840
|
+
if (this.noteNameText_) {
|
|
841
|
+
this.noteNameText_.textContent =
|
|
842
|
+
noteName + " (" + Math.floor(noteNum) + ")";
|
|
843
|
+
}
|
|
838
844
|
// Update the low and high C note names
|
|
839
|
-
const lowCNum = this.displayedOctave_ * 12;
|
|
840
|
-
this.lowCText_.textContent = "C(" + lowCNum + ")";
|
|
841
|
-
this.highCText_
|
|
845
|
+
const lowCNum = (this.displayedOctave_ ?? 0) * 12;
|
|
846
|
+
if (this.lowCText_) this.lowCText_.textContent = "C(" + lowCNum + ")";
|
|
847
|
+
if (this.highCText_)
|
|
848
|
+
this.highCText_.textContent = "C(" + (lowCNum + 12) + ")";
|
|
842
849
|
}
|
|
843
850
|
}
|
|
844
851
|
|
|
@@ -40,13 +40,13 @@ export class FieldTextInputRemovable extends Blockly.FieldTextInput {
|
|
|
40
40
|
Blockly.renderManagement.finishQueuedRenders().then(() => {
|
|
41
41
|
super.showEditor_();
|
|
42
42
|
|
|
43
|
-
const div = Blockly.WidgetDiv.getDiv()
|
|
43
|
+
const div = Blockly.WidgetDiv.getDiv()!;
|
|
44
44
|
div.className += " removableTextInput";
|
|
45
45
|
const removeButton = document.createElement("img");
|
|
46
46
|
removeButton.className = "blocklyTextRemoveIcon";
|
|
47
47
|
removeButton.setAttribute(
|
|
48
48
|
"src",
|
|
49
|
-
this.sourceBlock_
|
|
49
|
+
this.sourceBlock_!.workspace.options.pathToMedia + "icons/remove.svg"
|
|
50
50
|
);
|
|
51
51
|
this.removeButtonMouseWrapper_ = Blockly.browserEvents.bind(
|
|
52
52
|
removeButton,
|
|
@@ -78,7 +78,7 @@ class FieldVariableGetter extends Blockly.FieldLabel {
|
|
|
78
78
|
*/
|
|
79
79
|
doValueUpdate_(newVariableId: string) {
|
|
80
80
|
super.doValueUpdate_(newVariableId);
|
|
81
|
-
const workspace = this.getSourceBlock()
|
|
81
|
+
const workspace = this.getSourceBlock()!.workspace;
|
|
82
82
|
this.variable = Blockly.Variables.getVariable(workspace, newVariableId);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -97,13 +97,13 @@ class FieldVariableGetter extends Blockly.FieldLabel {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
fromXml(element: Element) {
|
|
100
|
-
this.setValue(element.getAttribute("id"));
|
|
100
|
+
this.setValue(element.getAttribute("id")!);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
toXml(element: Element): Element {
|
|
104
|
-
element.setAttribute("id", this.variable
|
|
105
|
-
element.setAttribute("variabletype", this.variable
|
|
106
|
-
element.textContent = this.variable
|
|
104
|
+
element.setAttribute("id", this.variable!.getId());
|
|
105
|
+
element.setAttribute("variabletype", this.variable!.getType());
|
|
106
|
+
element.textContent = this.variable!.getName();
|
|
107
107
|
return element;
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -51,17 +51,17 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
51
51
|
/**
|
|
52
52
|
* Opaque identifier used to unbind event listener in dispose().
|
|
53
53
|
*/
|
|
54
|
-
private mouseDownWrapper_
|
|
54
|
+
private mouseDownWrapper_!: Blockly.browserEvents.Data;
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Opaque identifier used to unbind event listener in dispose().
|
|
58
58
|
*/
|
|
59
|
-
private mouseMoveWrapper
|
|
59
|
+
private mouseMoveWrapper!: Blockly.browserEvents.Data;
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
62
|
* Opaque identifier used to unbind event listener in dispose().
|
|
63
63
|
*/
|
|
64
|
-
private mouseUpWrapper
|
|
64
|
+
private mouseUpWrapper!: Blockly.browserEvents.Data;
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
67
|
* Round angles to the nearest 15 degrees when using mouse.
|
|
@@ -141,7 +141,7 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
141
141
|
*/
|
|
142
142
|
dispose() {
|
|
143
143
|
super.dispose();
|
|
144
|
-
this.gauge =
|
|
144
|
+
this.gauge = undefined;
|
|
145
145
|
if (this.mouseDownWrapper_) {
|
|
146
146
|
Blockly.browserEvents.unbind(this.mouseDownWrapper_);
|
|
147
147
|
}
|
|
@@ -190,10 +190,10 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
190
190
|
cy: this.HALF,
|
|
191
191
|
r: this.RADIUS,
|
|
192
192
|
fill: (
|
|
193
|
-
this.getSourceBlock()
|
|
193
|
+
this.getSourceBlock()!.getParent() as Blockly.BlockSvg
|
|
194
194
|
).getColourSecondary(),
|
|
195
195
|
stroke: (
|
|
196
|
-
this.getSourceBlock()
|
|
196
|
+
this.getSourceBlock()!.getParent() as Blockly.BlockSvg
|
|
197
197
|
).getColourTertiary(),
|
|
198
198
|
class: "blocklyAngleCircle",
|
|
199
199
|
},
|
|
@@ -284,9 +284,9 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
284
284
|
);
|
|
285
285
|
|
|
286
286
|
Blockly.DropDownDiv.setColour(
|
|
287
|
-
this.getSourceBlock()
|
|
287
|
+
(this.getSourceBlock()!.getParent() as Blockly.BlockSvg).getColour(),
|
|
288
288
|
(
|
|
289
|
-
this.getSourceBlock()
|
|
289
|
+
this.getSourceBlock()!.getParent() as Blockly.BlockSvg
|
|
290
290
|
).getColourTertiary()
|
|
291
291
|
);
|
|
292
292
|
Blockly.DropDownDiv.showPositionedByBlock(
|
|
@@ -336,7 +336,7 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
336
336
|
*/
|
|
337
337
|
onMouseMove(e: PointerEvent) {
|
|
338
338
|
e.preventDefault();
|
|
339
|
-
const bBox = this.gauge
|
|
339
|
+
const bBox = this.gauge!.ownerSVGElement!.getBoundingClientRect();
|
|
340
340
|
const dx = e.clientX - bBox.left - this.HALF;
|
|
341
341
|
const dy = e.clientY - bBox.top - this.HALF;
|
|
342
342
|
let angle = Math.atan(-dy / dx);
|
|
@@ -418,12 +418,12 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
418
418
|
} else {
|
|
419
419
|
imageRotation = -angleDegrees;
|
|
420
420
|
}
|
|
421
|
-
this.arrow
|
|
421
|
+
this.arrow!.setAttribute("transform", "rotate(" + imageRotation + ")");
|
|
422
422
|
}
|
|
423
|
-
this.gauge
|
|
424
|
-
this.line
|
|
425
|
-
this.line
|
|
426
|
-
this.handle
|
|
423
|
+
this.gauge!.setAttribute("d", path.join(""));
|
|
424
|
+
this.line!.setAttribute("x2", `${x2}`);
|
|
425
|
+
this.line!.setAttribute("y2", `${y2}`);
|
|
426
|
+
this.handle!.setAttribute("transform", "translate(" + x2 + "," + y2 + ")");
|
|
427
427
|
}
|
|
428
428
|
|
|
429
429
|
/**
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import * as Blockly from "blockly/core";
|
|
8
8
|
|
|
9
9
|
class ScratchFieldDropdown extends Blockly.FieldDropdown {
|
|
10
|
-
private originalStyle
|
|
10
|
+
private originalStyle!: string;
|
|
11
11
|
|
|
12
12
|
showEditor_(event: PointerEvent) {
|
|
13
13
|
super.showEditor_(event);
|
|
@@ -28,7 +28,7 @@ class ScratchFieldDropdown extends Blockly.FieldDropdown {
|
|
|
28
28
|
|
|
29
29
|
dropdownDispose_() {
|
|
30
30
|
super.dropdownDispose_();
|
|
31
|
-
const sourceBlock = this.getSourceBlock()
|
|
31
|
+
const sourceBlock = this.getSourceBlock()!;
|
|
32
32
|
if (sourceBlock.isShadow()) {
|
|
33
33
|
sourceBlock.setStyle(this.originalStyle);
|
|
34
34
|
}
|
|
@@ -141,7 +141,7 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
141
141
|
|
|
142
142
|
// Show a numeric keypad in the drop-down on touch
|
|
143
143
|
if (showNumPad) {
|
|
144
|
-
this.htmlInput_
|
|
144
|
+
this.htmlInput_!.select();
|
|
145
145
|
this.showNumPad_();
|
|
146
146
|
}
|
|
147
147
|
}
|
|
@@ -173,7 +173,7 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
173
173
|
// Set colour and size of drop-down
|
|
174
174
|
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
|
|
175
175
|
Blockly.DropDownDiv.setColour(
|
|
176
|
-
sourceBlock.getParent().getColour(),
|
|
176
|
+
(sourceBlock.getParent() as Blockly.BlockSvg).getColour(),
|
|
177
177
|
sourceBlock.getColourTertiary()
|
|
178
178
|
);
|
|
179
179
|
contentDiv.style.width = ScratchFieldNumber.DROPDOWN_WIDTH + "px";
|
|
@@ -205,11 +205,12 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
205
205
|
);
|
|
206
206
|
Blockly.DropDownDiv.show(
|
|
207
207
|
this,
|
|
208
|
-
this.getSourceBlock()
|
|
208
|
+
this.getSourceBlock()!.RTL,
|
|
209
209
|
primaryX,
|
|
210
210
|
primaryY,
|
|
211
211
|
secondaryX,
|
|
212
212
|
secondaryY,
|
|
213
|
+
false,
|
|
213
214
|
this.onHide_.bind(this)
|
|
214
215
|
);
|
|
215
216
|
}
|
|
@@ -222,8 +223,8 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
222
223
|
*/
|
|
223
224
|
private addButtons_(contentDiv: Element) {
|
|
224
225
|
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
|
|
225
|
-
const buttonColour = sourceBlock.getParent().getColour();
|
|
226
|
-
const buttonBorderColour = sourceBlock.getParent().getColourTertiary();
|
|
226
|
+
const buttonColour = (sourceBlock.getParent() as Blockly.BlockSvg).getColour();
|
|
227
|
+
const buttonBorderColour = (sourceBlock.getParent() as Blockly.BlockSvg).getColourTertiary();
|
|
227
228
|
|
|
228
229
|
// Add numeric keypad buttons
|
|
229
230
|
const buttons = ScratchFieldNumber.NUMPAD_BUTTONS;
|
|
@@ -298,10 +299,10 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
298
299
|
// String of the button (e.g., '7')
|
|
299
300
|
const spliceValue = (e.target as HTMLElement).innerText;
|
|
300
301
|
// Old value of the text field
|
|
301
|
-
const oldValue = this.htmlInput_
|
|
302
|
+
const oldValue = this.htmlInput_!.value;
|
|
302
303
|
// Determine the selected portion of the text field
|
|
303
|
-
const selectionStart = this.htmlInput_
|
|
304
|
-
const selectionEnd = this.htmlInput_
|
|
304
|
+
const selectionStart = this.htmlInput_!.selectionStart ?? 0;
|
|
305
|
+
const selectionEnd = this.htmlInput_!.selectionEnd ?? 0;
|
|
305
306
|
|
|
306
307
|
// Splice in the new value
|
|
307
308
|
const newValue =
|
|
@@ -327,10 +328,10 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
327
328
|
*/
|
|
328
329
|
numPadEraseButtonTouch(e: PointerEvent) {
|
|
329
330
|
// Old value of the text field
|
|
330
|
-
const oldValue = this.htmlInput_
|
|
331
|
+
const oldValue = this.htmlInput_!.value;
|
|
331
332
|
// Determine what is selected to erase (if anything)
|
|
332
|
-
let selectionStart = this.htmlInput_
|
|
333
|
-
const selectionEnd = this.htmlInput_
|
|
333
|
+
let selectionStart = this.htmlInput_!.selectionStart ?? 0;
|
|
334
|
+
const selectionEnd = this.htmlInput_!.selectionEnd ?? 0;
|
|
334
335
|
|
|
335
336
|
// If selection is zero-length, shift start to the left 1 character
|
|
336
337
|
if (selectionStart == selectionEnd) {
|
|
@@ -359,7 +360,7 @@ class ScratchFieldNumber extends Blockly.FieldTextInput {
|
|
|
359
360
|
private updateDisplay_(newValue: string, newSelection: number) {
|
|
360
361
|
this.setEditorValue_(newValue);
|
|
361
362
|
// Resize and scroll the text field appropriately
|
|
362
|
-
const htmlInput = this.htmlInput_
|
|
363
|
+
const htmlInput = this.htmlInput_!;
|
|
363
364
|
htmlInput.setSelectionRange(newSelection, newSelection);
|
|
364
365
|
htmlInput.scrollLeft = htmlInput.scrollWidth;
|
|
365
366
|
}
|
|
@@ -29,7 +29,7 @@ import { createVariable, renameVariable } from "../variables";
|
|
|
29
29
|
import type { ScratchVariableModel } from "../scratch_variable_model";
|
|
30
30
|
|
|
31
31
|
export class ScratchFieldVariable extends Blockly.FieldVariable {
|
|
32
|
-
private originalStyle
|
|
32
|
+
private originalStyle!: string;
|
|
33
33
|
|
|
34
34
|
constructor(
|
|
35
35
|
varName: string | null | typeof Blockly.Field.SKIP_SETUP,
|
|
@@ -39,7 +39,10 @@ export class ScratchFieldVariable extends Blockly.FieldVariable {
|
|
|
39
39
|
config?: Blockly.FieldVariableConfig
|
|
40
40
|
) {
|
|
41
41
|
super(varName, validator, variableTypes, defaultType, config);
|
|
42
|
-
|
|
42
|
+
// dropdownCreate returns MenuOption[] rather than Blockly.MenuGenerator's
|
|
43
|
+
// MenuOption[][] variant; the cast is needed to satisfy FieldVariable's
|
|
44
|
+
// menuGenerator_ type while the actual runtime shape is compatible.
|
|
45
|
+
this.menuGenerator_ = ScratchFieldVariable.dropdownCreate as unknown as Blockly.MenuGenerator;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
initModel() {
|
|
@@ -73,7 +76,7 @@ export class ScratchFieldVariable extends Blockly.FieldVariable {
|
|
|
73
76
|
*/
|
|
74
77
|
initFlyoutBroadcast(
|
|
75
78
|
workspace: Blockly.WorkspaceSvg
|
|
76
|
-
): Blockly.IVariableModel<Blockly.IVariableState> {
|
|
79
|
+
): Blockly.IVariableModel<Blockly.IVariableState> | undefined {
|
|
77
80
|
const broadcastVars = workspace.getVariablesOfType(
|
|
78
81
|
Constants.BROADCAST_MESSAGE_VARIABLE_TYPE
|
|
79
82
|
);
|
|
@@ -154,7 +157,7 @@ export class ScratchFieldVariable extends Blockly.FieldVariable {
|
|
|
154
157
|
|
|
155
158
|
showEditor_(event: PointerEvent) {
|
|
156
159
|
super.showEditor_(event);
|
|
157
|
-
const sourceBlock = this.getSourceBlock()
|
|
160
|
+
const sourceBlock = this.getSourceBlock()!;
|
|
158
161
|
const styleName = sourceBlock.getStyleName();
|
|
159
162
|
const style = (sourceBlock.workspace as Blockly.WorkspaceSvg)
|
|
160
163
|
.getRenderer()
|
|
@@ -175,7 +178,7 @@ export class ScratchFieldVariable extends Blockly.FieldVariable {
|
|
|
175
178
|
|
|
176
179
|
dropdownDispose_() {
|
|
177
180
|
super.dropdownDispose_();
|
|
178
|
-
const sourceBlock = this.getSourceBlock()
|
|
181
|
+
const sourceBlock = this.getSourceBlock()!;
|
|
179
182
|
if (sourceBlock.isShadow()) {
|
|
180
183
|
sourceBlock.setStyle(this.originalStyle);
|
|
181
184
|
}
|
|
@@ -14,7 +14,7 @@ export class FlyoutCheckboxIcon
|
|
|
14
14
|
extends Blockly.icons.Icon
|
|
15
15
|
implements Blockly.IHasBubble
|
|
16
16
|
{
|
|
17
|
-
private checkboxBubble
|
|
17
|
+
private checkboxBubble!: CheckboxBubble;
|
|
18
18
|
private type = new Blockly.icons.IconType("checkbox");
|
|
19
19
|
|
|
20
20
|
constructor(protected override sourceBlock: Blockly.BlockSvg) {
|
package/src/glows.ts
CHANGED
|
@@ -17,8 +17,8 @@ export function glowStack(id: string, isGlowingStack: boolean) {
|
|
|
17
17
|
const block = (Blockly.getMainWorkspace().getBlockById(id) ||
|
|
18
18
|
(Blockly.getMainWorkspace() as Blockly.WorkspaceSvg)
|
|
19
19
|
.getFlyout()
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
?.getWorkspace()
|
|
21
|
+
?.getBlockById(id)) as Blockly.BlockSvg;
|
|
22
22
|
if (!block) {
|
|
23
23
|
throw "Tried to glow block that does not exist.";
|
|
24
24
|
}
|
package/src/procedures.ts
CHANGED
|
@@ -36,7 +36,7 @@ function allProcedureMutations(root: Blockly.WorkspaceSvg): Element[] {
|
|
|
36
36
|
const blocks = root.getAllBlocks();
|
|
37
37
|
return blocks
|
|
38
38
|
.filter((b) => b.type === Constants.PROCEDURES_PROTOTYPE_BLOCK_TYPE)
|
|
39
|
-
.map((b) => b.mutationToDom(/* opt_generateShadows */ true));
|
|
39
|
+
.map((b) => b.mutationToDom!(/* opt_generateShadows */ true) as Element);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
@@ -47,8 +47,8 @@ function allProcedureMutations(root: Blockly.WorkspaceSvg): Element[] {
|
|
|
47
47
|
*/
|
|
48
48
|
function sortProcedureMutations(mutations: Element[]): Element[] {
|
|
49
49
|
return mutations.slice().sort(function (a, b) {
|
|
50
|
-
const procCodeA = a.getAttribute("proccode")
|
|
51
|
-
const procCodeB = b.getAttribute("proccode")
|
|
50
|
+
const procCodeA = a.getAttribute("proccode")!;
|
|
51
|
+
const procCodeB = b.getAttribute("proccode")!;
|
|
52
52
|
|
|
53
53
|
return scratchBlocksUtils.compareStrings(procCodeA, procCodeB);
|
|
54
54
|
});
|
|
@@ -163,10 +163,10 @@ function mutateCallersAndPrototype(
|
|
|
163
163
|
callers.push(prototypeBlock);
|
|
164
164
|
Blockly.Events.setGroup(true);
|
|
165
165
|
callers.forEach((caller) => {
|
|
166
|
-
const oldMutationDom = caller.mutationToDom();
|
|
166
|
+
const oldMutationDom = caller.mutationToDom!();
|
|
167
167
|
const oldMutation = oldMutationDom && Blockly.Xml.domToText(oldMutationDom);
|
|
168
|
-
caller.domToMutation(mutation);
|
|
169
|
-
const newMutationDom = caller.mutationToDom();
|
|
168
|
+
caller.domToMutation!(mutation);
|
|
169
|
+
const newMutationDom = caller.mutationToDom!();
|
|
170
170
|
const newMutation = newMutationDom && Blockly.Xml.domToText(newMutationDom);
|
|
171
171
|
if (oldMutation !== newMutation) {
|
|
172
172
|
Blockly.Events.fire(
|
|
@@ -197,8 +197,8 @@ function getDefineBlock(
|
|
|
197
197
|
return workspace.getTopBlocks(false).find((block) => {
|
|
198
198
|
if (block.type === Constants.PROCEDURES_DEFINITION_BLOCK_TYPE) {
|
|
199
199
|
const prototypeBlock = block
|
|
200
|
-
.getInput("custom_block")
|
|
201
|
-
.connection
|
|
200
|
+
.getInput("custom_block")!
|
|
201
|
+
.connection!.targetBlock() as Blockly.BlockSvg;
|
|
202
202
|
return (
|
|
203
203
|
isProcedureBlock(prototypeBlock) &&
|
|
204
204
|
prototypeBlock.getProcCode() === procCode
|
|
@@ -222,8 +222,8 @@ function getPrototypeBlock(
|
|
|
222
222
|
const defineBlock = getDefineBlock(procCode, workspace);
|
|
223
223
|
if (defineBlock) {
|
|
224
224
|
return defineBlock
|
|
225
|
-
.getInput("custom_block")
|
|
226
|
-
.connection
|
|
225
|
+
.getInput("custom_block")!
|
|
226
|
+
.connection!.targetBlock() as Blockly.BlockSvg;
|
|
227
227
|
}
|
|
228
228
|
return undefined;
|
|
229
229
|
}
|
|
@@ -243,7 +243,7 @@ function newProcedureMutation(): Element {
|
|
|
243
243
|
warp="false">
|
|
244
244
|
</mutation>
|
|
245
245
|
</xml>`;
|
|
246
|
-
return Blockly.utils.xml.textToDom(mutationText).firstElementChild
|
|
246
|
+
return Blockly.utils.xml.textToDom(mutationText).firstElementChild!;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
/**
|
|
@@ -251,7 +251,7 @@ function newProcedureMutation(): Element {
|
|
|
251
251
|
* @param workspace The workspace to create the new procedure on.
|
|
252
252
|
*/
|
|
253
253
|
function createProcedureDefCallback(workspace: Blockly.WorkspaceSvg) {
|
|
254
|
-
ScratchProcedures.externalProcedureDefCallback(
|
|
254
|
+
ScratchProcedures.externalProcedureDefCallback!(
|
|
255
255
|
newProcedureMutation(),
|
|
256
256
|
createProcedureCallbackFactory(workspace)
|
|
257
257
|
);
|
|
@@ -278,7 +278,7 @@ function createProcedureCallbackFactory(
|
|
|
278
278
|
</statement>
|
|
279
279
|
</block>
|
|
280
280
|
</xml>`;
|
|
281
|
-
const blockDom = Blockly.utils.xml.textToDom(blockText).firstElementChild
|
|
281
|
+
const blockDom = Blockly.utils.xml.textToDom(blockText).firstElementChild!;
|
|
282
282
|
Blockly.Events.setGroup(true);
|
|
283
283
|
const block = Blockly.Xml.domToBlock(
|
|
284
284
|
blockDom,
|
|
@@ -338,15 +338,23 @@ function editProcedureCallback(block: Blockly.BlockSvg) {
|
|
|
338
338
|
// This is a call block, find the prototype corresponding to the procCode.
|
|
339
339
|
// Make sure to search the correct workspace, call block can be in flyout.
|
|
340
340
|
const workspaceToSearch = block.workspace.isFlyout
|
|
341
|
-
? block.workspace.targetWorkspace
|
|
341
|
+
? block.workspace.targetWorkspace!
|
|
342
342
|
: block.workspace;
|
|
343
|
-
|
|
343
|
+
const foundBlock = getPrototypeBlock(block.getProcCode(), workspaceToSearch);
|
|
344
|
+
if (!foundBlock) {
|
|
345
|
+
console.warn(
|
|
346
|
+
"editProcedureCallback: could not find prototype for",
|
|
347
|
+
block.getProcCode()
|
|
348
|
+
);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
prototypeBlock = foundBlock;
|
|
344
352
|
} else {
|
|
345
353
|
prototypeBlock = block;
|
|
346
354
|
}
|
|
347
355
|
// Block now refers to the procedure prototype block, it is safe to proceed.
|
|
348
|
-
ScratchProcedures.externalProcedureDefCallback(
|
|
349
|
-
prototypeBlock.mutationToDom(),
|
|
356
|
+
ScratchProcedures.externalProcedureDefCallback!(
|
|
357
|
+
prototypeBlock.mutationToDom!(),
|
|
350
358
|
editProcedureCallbackFactory(prototypeBlock)
|
|
351
359
|
);
|
|
352
360
|
}
|
|
@@ -36,7 +36,7 @@ const setVisibility = (element: SVGElement, visible: boolean) => {
|
|
|
36
36
|
* Owned by the PathObject with similar lifetime.
|
|
37
37
|
*/
|
|
38
38
|
export class CatFace {
|
|
39
|
-
faceGroup_
|
|
39
|
+
faceGroup_!: SVGElement;
|
|
40
40
|
parts_ = {} as Record<FacePart, SVGElement>;
|
|
41
41
|
pathEarState: CatPathState;
|
|
42
42
|
constants_: ConstantProvider;
|