scratch-blocks 2.0.0-spork.3 → 2.0.0-spork.5
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 +24 -0
- package/dist/main.js +1 -1
- package/dist/main.js.LICENSE.txt +3 -9
- package/package.json +4 -4
- package/src/blocks/procedures.ts +1 -1
- package/src/checkable_continuous_flyout.ts +116 -0
- package/src/checkbox_bubble.ts +25 -5
- package/src/colours.ts +1 -0
- package/src/context_menu_items.ts +24 -0
- package/src/css.ts +30 -21
- package/src/fields/field_matrix.ts +38 -27
- package/src/fields/field_note.ts +1 -1
- package/src/fields/scratch_field_angle.ts +9 -1
- package/src/fields/scratch_field_variable.ts +9 -8
- package/src/flyout_checkbox_icon.ts +15 -21
- package/src/index.ts +6 -3
- package/src/recyclable_block_flyout_inflater.ts +8 -151
- package/src/scratch_block_paster.ts +10 -0
- package/src/{scratch_comment_bubble.js → scratch_comment_bubble.ts} +52 -19
- package/src/scratch_comment_icon.ts +20 -5
- package/src/scratch_continuous_toolbox.ts +36 -30
- package/src/scratch_insertion_marker_previewer.ts +45 -0
- package/src/status_indicator_label_flyout_inflater.ts +8 -6
- package/src/variables.ts +1 -1
- package/src/xml.ts +57 -0
- package/src/checkable_continuous_flyout.js +0 -138
package/dist/main.js.LICENSE.txt
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @license
|
|
3
|
-
* Copyright
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @license
|
|
9
|
-
* Copyright 2021 Google LLC
|
|
3
|
+
* Copyright 2023 Google LLC
|
|
10
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
11
5
|
*/
|
|
12
6
|
|
|
13
7
|
/**
|
|
14
8
|
* @license
|
|
15
|
-
* Copyright
|
|
9
|
+
* Copyright 2024 Google LLC
|
|
16
10
|
* SPDX-License-Identifier: Apache-2.0
|
|
17
11
|
*/
|
|
18
12
|
|
|
19
13
|
/**
|
|
20
14
|
* @license
|
|
21
|
-
* Copyright
|
|
15
|
+
* Copyright 2025 Google LLC
|
|
22
16
|
* SPDX-License-Identifier: Apache-2.0
|
|
23
17
|
*/
|
|
24
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scratch-blocks",
|
|
3
|
-
"version": "2.0.0-spork.
|
|
3
|
+
"version": "2.0.0-spork.5",
|
|
4
4
|
"description": "Scratch Blocks is a library for building creative computing interfaces.",
|
|
5
5
|
"author": "Massachusetts Institute of Technology",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"webpack-dev-server": "^4.11.1"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@blockly/continuous-toolbox": "^
|
|
36
|
-
"@blockly/field-colour": "^
|
|
37
|
-
"blockly": "
|
|
35
|
+
"@blockly/continuous-toolbox": "^7.0.1",
|
|
36
|
+
"@blockly/field-colour": "^6.0.3",
|
|
37
|
+
"blockly": "12.3.0-beta.0"
|
|
38
38
|
},
|
|
39
39
|
"config": {
|
|
40
40
|
"commitizen": {
|
package/src/blocks/procedures.ts
CHANGED
|
@@ -224,7 +224,7 @@ function disconnectOldBlocks_(this: ProcedureBlock): ConnectionMap {
|
|
|
224
224
|
if (input.connection) {
|
|
225
225
|
const target = input.connection.targetBlock() as Blockly.BlockSvg;
|
|
226
226
|
const saveInfo = {
|
|
227
|
-
shadow: input.connection.getShadowDom(),
|
|
227
|
+
shadow: input.connection.getShadowDom(true),
|
|
228
228
|
block: target,
|
|
229
229
|
};
|
|
230
230
|
connectionMap[input.name] = saveInfo;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as Blockly from "blockly/core";
|
|
8
|
+
import { ContinuousFlyout } from "@blockly/continuous-toolbox";
|
|
9
|
+
import { CheckboxBubble } from "./checkbox_bubble";
|
|
10
|
+
import { StatusIndicatorLabel } from "./status_indicator_label";
|
|
11
|
+
import { STATUS_INDICATOR_LABEL_TYPE } from "./status_indicator_label_flyout_inflater";
|
|
12
|
+
|
|
13
|
+
export class CheckableContinuousFlyout extends ContinuousFlyout {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new CheckableContinuousFlyout.
|
|
16
|
+
*
|
|
17
|
+
* @param workspaceOptions Configuration options for the flyout workspace.
|
|
18
|
+
*/
|
|
19
|
+
constructor(workspaceOptions: Blockly.Options) {
|
|
20
|
+
workspaceOptions.modalInputs = false;
|
|
21
|
+
super(workspaceOptions);
|
|
22
|
+
this.tabWidth_ = 0;
|
|
23
|
+
this.MARGIN = 12;
|
|
24
|
+
this.GAP_Y = 12;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Serializes a block to JSON in order to copy it to the main workspace.
|
|
29
|
+
*
|
|
30
|
+
* @param block The block to serialize.
|
|
31
|
+
* @returns A JSON representation of the block.
|
|
32
|
+
*/
|
|
33
|
+
protected serializeBlock(block: Blockly.BlockSvg) {
|
|
34
|
+
const json = super.serializeBlock(block);
|
|
35
|
+
// Delete the serialized block's ID so that a new one is generated when it is
|
|
36
|
+
// placed on the workspace. Otherwise, the block on the workspace may be
|
|
37
|
+
// indistinguishable from the one in the flyout, which can cause reporter blocks
|
|
38
|
+
// to have their value dropdown shown in the wrong place.
|
|
39
|
+
delete json.id;
|
|
40
|
+
return json;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Set the state of a checkbox by block ID.
|
|
45
|
+
*
|
|
46
|
+
* @param blockId ID of the block whose checkbox should be set
|
|
47
|
+
* @param value Value to set the checkbox to.
|
|
48
|
+
*/
|
|
49
|
+
setCheckboxState(blockId: string, value: boolean) {
|
|
50
|
+
this.getWorkspace()
|
|
51
|
+
.getBlockById(blockId)
|
|
52
|
+
?.getIcon("checkbox")
|
|
53
|
+
?.setChecked(value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
getFlyoutScale() {
|
|
57
|
+
return 0.675;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
getWidth() {
|
|
61
|
+
return 250;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected reflowInternal_() {
|
|
65
|
+
super.reflowInternal_();
|
|
66
|
+
|
|
67
|
+
if (this.RTL) {
|
|
68
|
+
// The parent implementation assumes that the flyout grows to fit its
|
|
69
|
+
// contents, and adjusts blocks in RTL mode accordingly. In Scratch, the
|
|
70
|
+
// flyout width is fixed (and blocks may exceed it), so re-adjust blocks
|
|
71
|
+
// accordingly based on the actual fixed width.
|
|
72
|
+
for (const item of this.getContents()) {
|
|
73
|
+
const oldX = item.getElement().getBoundingRectangle().left;
|
|
74
|
+
let newX =
|
|
75
|
+
this.getWidth() / this.workspace_.scale -
|
|
76
|
+
item.getElement().getBoundingRectangle().getWidth() -
|
|
77
|
+
this.MARGIN;
|
|
78
|
+
if (
|
|
79
|
+
"checkboxInFlyout" in item.getElement() &&
|
|
80
|
+
item.getElement().checkboxInFlyout
|
|
81
|
+
) {
|
|
82
|
+
newX -= CheckboxBubble.CHECKBOX_SIZE + CheckboxBubble.CHECKBOX_MARGIN;
|
|
83
|
+
}
|
|
84
|
+
item.getElement().moveBy(newX - oldX, 0);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Validates that the given toolbox item represents a label.
|
|
91
|
+
*
|
|
92
|
+
* @param item The toolbox item to check.
|
|
93
|
+
* @returns True if the item represents a label in the flyout.
|
|
94
|
+
*/
|
|
95
|
+
protected toolboxItemIsLabel(item: Blockly.FlyoutItem) {
|
|
96
|
+
return (
|
|
97
|
+
item.getType() === STATUS_INDICATOR_LABEL_TYPE ||
|
|
98
|
+
super.toolboxItemIsLabel(item)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Updates the state of status indicators for hardware-based extensions.
|
|
104
|
+
*/
|
|
105
|
+
refreshStatusButtons() {
|
|
106
|
+
for (const item of this.contents) {
|
|
107
|
+
if (item.element instanceof StatusIndicatorLabel) {
|
|
108
|
+
item.element.refreshStatus();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
scrollTo(position: number) {
|
|
114
|
+
super.scrollTo(Math.ceil(position));
|
|
115
|
+
}
|
|
116
|
+
}
|
package/src/checkbox_bubble.ts
CHANGED
|
@@ -203,15 +203,14 @@ export class CheckboxBubble
|
|
|
203
203
|
* Recalculates this bubble's location, keeping it adjacent to its block.
|
|
204
204
|
*/
|
|
205
205
|
updateLocation() {
|
|
206
|
-
const
|
|
207
|
-
const blockBounds = this.sourceBlock.getHeightWidth();
|
|
206
|
+
const bounds = this.sourceBlock.getBoundingRectangle();
|
|
208
207
|
const x = this.sourceBlock.workspace.RTL
|
|
209
|
-
?
|
|
210
|
-
:
|
|
208
|
+
? bounds.right + CheckboxBubble.CHECKBOX_MARGIN
|
|
209
|
+
: bounds.left -
|
|
211
210
|
CheckboxBubble.CHECKBOX_MARGIN -
|
|
212
211
|
CheckboxBubble.CHECKBOX_SIZE;
|
|
213
212
|
const y =
|
|
214
|
-
|
|
213
|
+
bounds.top + (bounds.getHeight() - CheckboxBubble.CHECKBOX_SIZE) / 2;
|
|
215
214
|
this.moveTo(x, y);
|
|
216
215
|
}
|
|
217
216
|
|
|
@@ -244,6 +243,27 @@ export class CheckboxBubble
|
|
|
244
243
|
Blockly.browserEvents.unbind(this.clickListener);
|
|
245
244
|
}
|
|
246
245
|
|
|
246
|
+
/** See IFocusableNode.getFocusableElement. */
|
|
247
|
+
getFocusableElement(): HTMLElement | SVGElement {
|
|
248
|
+
return this.svgRoot;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** See IFocusableNode.getFocusableTree. */
|
|
252
|
+
getFocusableTree(): Blockly.IFocusableTree {
|
|
253
|
+
return this.sourceBlock.workspace;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** See IFocusableNode.onNodeFocus. */
|
|
257
|
+
onNodeFocus(): void {}
|
|
258
|
+
|
|
259
|
+
/** See IFocusableNode.onNodeBlur. */
|
|
260
|
+
onNodeBlur(): void {}
|
|
261
|
+
|
|
262
|
+
/** See IFocusableNode.canBeFocused. */
|
|
263
|
+
canBeFocused(): boolean {
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
|
|
247
267
|
// These methods are required by the interfaces, but intentionally have no
|
|
248
268
|
// implementation, largely because this bubble's location is fixed relative
|
|
249
269
|
// to its block and is not draggable by the user.
|
package/src/colours.ts
CHANGED
|
@@ -154,3 +154,27 @@ function deleteNext(deleteList: Blockly.BlockSvg[], eventGroup?: string) {
|
|
|
154
154
|
}
|
|
155
155
|
Blockly.Events.setGroup(false);
|
|
156
156
|
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Registers a block duplicate option that duplicates the selected block and
|
|
160
|
+
* all subsequent blocks in the stack.
|
|
161
|
+
*/
|
|
162
|
+
export function registerDuplicateBlock() {
|
|
163
|
+
const original =
|
|
164
|
+
Blockly.ContextMenuRegistry.registry.getItem("blockDuplicate");
|
|
165
|
+
const duplicateOption = {
|
|
166
|
+
displayText: original.displayText,
|
|
167
|
+
preconditionFn: original.preconditionFn,
|
|
168
|
+
callback(scope: Blockly.ContextMenuRegistry.Scope) {
|
|
169
|
+
if (!scope.block) return;
|
|
170
|
+
const data = scope.block.toCopyData(true);
|
|
171
|
+
if (!data) return;
|
|
172
|
+
Blockly.clipboard.paste(data, scope.block.workspace);
|
|
173
|
+
},
|
|
174
|
+
scopeType: original.scopeType,
|
|
175
|
+
id: original.id,
|
|
176
|
+
weight: original.weight,
|
|
177
|
+
};
|
|
178
|
+
Blockly.ContextMenuRegistry.registry.unregister(duplicateOption.id);
|
|
179
|
+
Blockly.ContextMenuRegistry.registry.register(duplicateOption);
|
|
180
|
+
}
|
package/src/css.ts
CHANGED
|
@@ -702,16 +702,16 @@ const styles = `
|
|
|
702
702
|
}
|
|
703
703
|
|
|
704
704
|
.blocklyAngleCenterPoint {
|
|
705
|
-
stroke:
|
|
705
|
+
stroke: var(--colour-text);
|
|
706
706
|
stroke-width: 1;
|
|
707
|
-
fill:
|
|
707
|
+
fill: var(--colour-text);
|
|
708
708
|
}
|
|
709
709
|
|
|
710
710
|
.blocklyAngleDragHandle {
|
|
711
|
-
stroke:
|
|
711
|
+
stroke: var(--colour-text);
|
|
712
712
|
stroke-width: 5;
|
|
713
713
|
stroke-opacity: 0.25;
|
|
714
|
-
fill:
|
|
714
|
+
fill: var(--colour-text);
|
|
715
715
|
cursor: pointer;
|
|
716
716
|
}
|
|
717
717
|
|
|
@@ -720,18 +720,18 @@ const styles = `
|
|
|
720
720
|
}
|
|
721
721
|
|
|
722
722
|
.blocklyAngleMarks {
|
|
723
|
-
stroke:
|
|
723
|
+
stroke: var(--colour-text);
|
|
724
724
|
stroke-width: 1;
|
|
725
725
|
stroke-opacity: 0.5;
|
|
726
726
|
}
|
|
727
727
|
|
|
728
728
|
.blocklyAngleGauge {
|
|
729
|
-
fill:
|
|
729
|
+
fill: var(--colour-text);
|
|
730
730
|
fill-opacity: 0.20;
|
|
731
731
|
}
|
|
732
732
|
|
|
733
733
|
.blocklyAngleLine {
|
|
734
|
-
stroke:
|
|
734
|
+
stroke: var(--colour-text);
|
|
735
735
|
stroke-width: 1;
|
|
736
736
|
stroke-linecap: round;
|
|
737
737
|
pointer-events: none;
|
|
@@ -751,8 +751,9 @@ const styles = `
|
|
|
751
751
|
}
|
|
752
752
|
|
|
753
753
|
/* Category tree in Toolbox. */
|
|
754
|
-
.
|
|
754
|
+
.blocklyToolbox {
|
|
755
755
|
background-color: var(--colour-toolbox);
|
|
756
|
+
border-right: 1px solid #ddd;
|
|
756
757
|
color: var(--colour-toolboxText);
|
|
757
758
|
overflow-x: visible;
|
|
758
759
|
overflow-y: auto;
|
|
@@ -763,6 +764,11 @@ const styles = `
|
|
|
763
764
|
padding: 0;
|
|
764
765
|
}
|
|
765
766
|
|
|
767
|
+
.blocklyToolbox[dir="RTL"] {
|
|
768
|
+
border-right: none;
|
|
769
|
+
border-left: 1px solid #ddd;
|
|
770
|
+
}
|
|
771
|
+
|
|
766
772
|
.blocklyTreeRoot {
|
|
767
773
|
padding: 4px 0;
|
|
768
774
|
}
|
|
@@ -771,7 +777,7 @@ const styles = `
|
|
|
771
777
|
outline: none;
|
|
772
778
|
}
|
|
773
779
|
|
|
774
|
-
.
|
|
780
|
+
.blocklyToolbox .blocklyToolboxCategory {
|
|
775
781
|
line-height: 22px;
|
|
776
782
|
margin: 0;
|
|
777
783
|
padding: 0.375rem 0px;
|
|
@@ -789,11 +795,11 @@ const styles = `
|
|
|
789
795
|
margin: 1px 0 8px 5px;
|
|
790
796
|
}
|
|
791
797
|
|
|
792
|
-
.
|
|
793
|
-
margin-left:
|
|
798
|
+
.blocklyToolbox[dir="RTL"] .blocklyToolboxCategory {
|
|
799
|
+
margin-left: 0px;
|
|
794
800
|
}
|
|
795
801
|
|
|
796
|
-
.
|
|
802
|
+
.blocklyToolboxCategory:hover {
|
|
797
803
|
color: var(--colour-toolboxHover);
|
|
798
804
|
}
|
|
799
805
|
|
|
@@ -844,7 +850,7 @@ const styles = `
|
|
|
844
850
|
background-position: -48px -1px;
|
|
845
851
|
}
|
|
846
852
|
|
|
847
|
-
.
|
|
853
|
+
.blocklyToolboxCategoryLabel {
|
|
848
854
|
cursor: default;
|
|
849
855
|
font-family: "Helvetica Neue", Helvetica, sans-serif;
|
|
850
856
|
font-size: .65rem;
|
|
@@ -855,7 +861,7 @@ const styles = `
|
|
|
855
861
|
text-wrap: wrap;
|
|
856
862
|
}
|
|
857
863
|
|
|
858
|
-
.
|
|
864
|
+
.blocklyToolboxSelected .blocklyToolboxCategoryLabel {
|
|
859
865
|
color: inherit;
|
|
860
866
|
}
|
|
861
867
|
|
|
@@ -1005,12 +1011,12 @@ const styles = `
|
|
|
1005
1011
|
z-index: 20000; /* Arbitrary, but some apps depend on it... */
|
|
1006
1012
|
}
|
|
1007
1013
|
|
|
1008
|
-
.blocklyDropDownDiv .blocklyMenu .blocklyMenuItem
|
|
1009
|
-
background: var(--colour-menuHover);
|
|
1014
|
+
.blocklyDropDownDiv .blocklyMenu .blocklyMenuItem.blocklyMenuItemHighlight {
|
|
1015
|
+
background-color: var(--colour-menuHover);
|
|
1010
1016
|
}
|
|
1011
1017
|
|
|
1012
|
-
.blocklyWidgetDiv .blocklyMenu .blocklyMenuItem
|
|
1013
|
-
background: var(--colour-contextualMenuHover);
|
|
1018
|
+
.blocklyWidgetDiv .blocklyMenu .blocklyMenuItem.blocklyMenuItemHighlight {
|
|
1019
|
+
background-color: var(--colour-contextualMenuHover);
|
|
1014
1020
|
}
|
|
1015
1021
|
|
|
1016
1022
|
.blocklyWidgetDiv .blocklyMenu .blocklyMenuItemDisabled.blocklyMenuItem:hover {
|
|
@@ -1162,13 +1168,12 @@ const styles = `
|
|
|
1162
1168
|
color: #4c97ff;
|
|
1163
1169
|
}
|
|
1164
1170
|
.blocklyDropDownDiv .blocklyMenuItem {
|
|
1165
|
-
color: #fff;
|
|
1166
1171
|
font-weight: bold;
|
|
1167
1172
|
min-height: 32px;
|
|
1168
1173
|
padding: 4px 7em 4px 28px;
|
|
1169
1174
|
}
|
|
1170
|
-
.
|
|
1171
|
-
color:
|
|
1175
|
+
.scratch-renderer.blocklyDropDownDiv .blocklyMenuItem .blocklyMenuItemContent {
|
|
1176
|
+
color: var(--colour-text);
|
|
1172
1177
|
}
|
|
1173
1178
|
.blocklyToolboxSelected .blocklyTreeLabel {
|
|
1174
1179
|
color: var(--colour-toolboxText);
|
|
@@ -1192,6 +1197,10 @@ const styles = `
|
|
|
1192
1197
|
stroke: revert-layer;
|
|
1193
1198
|
stroke-width: 1;
|
|
1194
1199
|
}
|
|
1200
|
+
|
|
1201
|
+
.blocklyInsertionMarker > g:not(:last-child) {
|
|
1202
|
+
visibility: hidden;
|
|
1203
|
+
}
|
|
1195
1204
|
`;
|
|
1196
1205
|
|
|
1197
1206
|
Blockly.Css.register(styles);
|
|
@@ -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
|
-
|
|
218
|
+
this.getConstants().FIELD_DROPDOWN_SVG_ARROW_DATAURI
|
|
219
219
|
);
|
|
220
220
|
this.arrow_.style.cursor = "default";
|
|
221
221
|
}
|
|
@@ -238,6 +238,25 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
238
238
|
* Show the drop-down menu for editing this field.
|
|
239
239
|
*/
|
|
240
240
|
showEditor_() {
|
|
241
|
+
const sourceBlock = this.getSourceBlock() as Blockly.BlockSvg;
|
|
242
|
+
Blockly.DropDownDiv.setColour(
|
|
243
|
+
sourceBlock.getColour(),
|
|
244
|
+
sourceBlock.getColourTertiary()
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
const style = sourceBlock.style;
|
|
248
|
+
if (sourceBlock.isShadow()) {
|
|
249
|
+
this.originalStyle = sourceBlock.getStyleName();
|
|
250
|
+
sourceBlock.setStyle(`${this.originalStyle}_selected`);
|
|
251
|
+
} else if (this.borderRect_) {
|
|
252
|
+
this.borderRect_.setAttribute(
|
|
253
|
+
"fill",
|
|
254
|
+
"colourQuaternary" in style
|
|
255
|
+
? `${style.colourQuaternary}`
|
|
256
|
+
: style.colourTertiary
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
241
260
|
const div = Blockly.DropDownDiv.getContentDiv();
|
|
242
261
|
// Build the SVG DOM.
|
|
243
262
|
const matrixSize =
|
|
@@ -286,23 +305,19 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
286
305
|
// Button to clear matrix
|
|
287
306
|
const clearButtonDiv = document.createElement("div");
|
|
288
307
|
clearButtonDiv.className = "scratchMatrixButtonDiv";
|
|
289
|
-
|
|
308
|
+
|
|
290
309
|
const clearButton = this.createButton_(sourceBlock.getColourSecondary());
|
|
291
310
|
clearButtonDiv.appendChild(clearButton);
|
|
292
311
|
// Button to fill matrix
|
|
293
312
|
const fillButtonDiv = document.createElement("div");
|
|
294
313
|
fillButtonDiv.className = "scratchMatrixButtonDiv";
|
|
295
|
-
const fillButton = this.createButton_("
|
|
314
|
+
const fillButton = this.createButton_("var(--colour-text)");
|
|
296
315
|
fillButtonDiv.appendChild(fillButton);
|
|
297
316
|
|
|
298
317
|
buttonDiv.appendChild(clearButtonDiv);
|
|
299
318
|
buttonDiv.appendChild(fillButtonDiv);
|
|
300
319
|
div.appendChild(buttonDiv);
|
|
301
320
|
|
|
302
|
-
Blockly.DropDownDiv.setColour(
|
|
303
|
-
sourceBlock.getColour(),
|
|
304
|
-
sourceBlock.getColourTertiary()
|
|
305
|
-
);
|
|
306
321
|
Blockly.DropDownDiv.showPositionedByBlock(
|
|
307
322
|
this,
|
|
308
323
|
sourceBlock,
|
|
@@ -328,19 +343,6 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
328
343
|
this.fillMatrix_
|
|
329
344
|
);
|
|
330
345
|
|
|
331
|
-
const style = sourceBlock.style;
|
|
332
|
-
if (sourceBlock.isShadow()) {
|
|
333
|
-
this.originalStyle = sourceBlock.getStyleName();
|
|
334
|
-
sourceBlock.setStyle(`${this.originalStyle}_selected`);
|
|
335
|
-
} else if (this.borderRect_) {
|
|
336
|
-
this.borderRect_.setAttribute(
|
|
337
|
-
"fill",
|
|
338
|
-
"colourQuaternary" in style
|
|
339
|
-
? `${style.colourQuaternary}`
|
|
340
|
-
: style.colourTertiary
|
|
341
|
-
);
|
|
342
|
-
}
|
|
343
|
-
|
|
344
346
|
// Update the matrix for the current value
|
|
345
347
|
this.updateMatrix_();
|
|
346
348
|
}
|
|
@@ -350,6 +352,7 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
350
352
|
if (sourceBlock.isShadow()) {
|
|
351
353
|
sourceBlock.setStyle(this.originalStyle);
|
|
352
354
|
}
|
|
355
|
+
this.updateMatrix_();
|
|
353
356
|
}
|
|
354
357
|
|
|
355
358
|
/**
|
|
@@ -400,12 +403,16 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
400
403
|
this.fillMatrixNode_(
|
|
401
404
|
this.ledButtons_,
|
|
402
405
|
i,
|
|
406
|
+
sourceBlock.getColourTertiary()
|
|
407
|
+
);
|
|
408
|
+
this.fillMatrixNode_(
|
|
409
|
+
this.ledThumbNodes_,
|
|
410
|
+
i,
|
|
403
411
|
sourceBlock.getColourSecondary()
|
|
404
412
|
);
|
|
405
|
-
this.fillMatrixNode_(this.ledThumbNodes_, i, sourceBlock.getColour());
|
|
406
413
|
} else {
|
|
407
|
-
this.fillMatrixNode_(this.ledButtons_, i, "
|
|
408
|
-
this.fillMatrixNode_(this.ledThumbNodes_, i, "
|
|
414
|
+
this.fillMatrixNode_(this.ledButtons_, i, "var(--colour-text)");
|
|
415
|
+
this.fillMatrixNode_(this.ledThumbNodes_, i, "var(--colour-text)");
|
|
409
416
|
}
|
|
410
417
|
}
|
|
411
418
|
}
|
|
@@ -505,10 +512,14 @@ class FieldMatrix extends Blockly.Field<string> {
|
|
|
505
512
|
* Unbind mouse move event and clear the paint style.
|
|
506
513
|
*/
|
|
507
514
|
onMouseUp() {
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
515
|
+
if (this.matrixMoveWrapper_) {
|
|
516
|
+
Blockly.browserEvents.unbind(this.matrixMoveWrapper_);
|
|
517
|
+
this.matrixMoveWrapper_ = null;
|
|
518
|
+
}
|
|
519
|
+
if (this.matrixReleaseWrapper_) {
|
|
520
|
+
Blockly.browserEvents.unbind(this.matrixReleaseWrapper_);
|
|
521
|
+
this.matrixReleaseWrapper_ = null;
|
|
522
|
+
}
|
|
512
523
|
this.paintStyle_ = null;
|
|
513
524
|
}
|
|
514
525
|
|
package/src/fields/field_note.ts
CHANGED
|
@@ -286,7 +286,7 @@ export class FieldNote extends Blockly.FieldTextInput {
|
|
|
286
286
|
* Show a field with piano keys.
|
|
287
287
|
*/
|
|
288
288
|
showEditor_(event: PointerEvent, quietInput = false) {
|
|
289
|
-
super.showEditor_(event, quietInput);
|
|
289
|
+
super.showEditor_(event, quietInput, false);
|
|
290
290
|
|
|
291
291
|
// Build the SVG DOM.
|
|
292
292
|
const div = Blockly.DropDownDiv.getContentDiv();
|
|
@@ -157,7 +157,15 @@ class ScratchFieldAngle extends Blockly.FieldNumber {
|
|
|
157
157
|
* Show the inline free-text editor on top of the text.
|
|
158
158
|
*/
|
|
159
159
|
showEditor_(event: PointerEvent) {
|
|
160
|
-
|
|
160
|
+
// Mobile browsers have issues with in-line textareas (focus & keyboards).
|
|
161
|
+
// Also, don't let the parent take ephemeral focus since the drop-down div
|
|
162
|
+
// below will handle it, instead.
|
|
163
|
+
const noFocus =
|
|
164
|
+
Blockly.utils.userAgent.MOBILE ||
|
|
165
|
+
Blockly.utils.userAgent.ANDROID ||
|
|
166
|
+
Blockly.utils.userAgent.IPAD;
|
|
167
|
+
super.showEditor_(event, noFocus, false);
|
|
168
|
+
|
|
161
169
|
// If there is an existing drop-down someone else owns, hide it immediately and clear it.
|
|
162
170
|
Blockly.DropDownDiv.hideWithoutAnimation();
|
|
163
171
|
Blockly.DropDownDiv.clearContent();
|
|
@@ -94,7 +94,7 @@ export class ScratchFieldVariable extends Blockly.FieldVariable {
|
|
|
94
94
|
* @returns Array of variable names.
|
|
95
95
|
*/
|
|
96
96
|
static dropdownCreate(this: ScratchFieldVariable): Blockly.MenuOption[] {
|
|
97
|
-
|
|
97
|
+
let options = super.dropdownCreate();
|
|
98
98
|
const type = this.getDefaultType();
|
|
99
99
|
if (type === Constants.BROADCAST_MESSAGE_VARIABLE_TYPE) {
|
|
100
100
|
options.splice(-2, 2, [
|
|
@@ -102,16 +102,17 @@ export class ScratchFieldVariable extends Blockly.FieldVariable {
|
|
|
102
102
|
Constants.NEW_BROADCAST_MESSAGE_ID,
|
|
103
103
|
]);
|
|
104
104
|
} else if (type === Constants.LIST_VARIABLE_TYPE) {
|
|
105
|
-
|
|
105
|
+
options = options.map((option) => {
|
|
106
106
|
if (option[1] === Blockly.RENAME_VARIABLE_ID) {
|
|
107
|
-
|
|
107
|
+
return [ScratchMsgs.translate("RENAME_LIST"), option[1]];
|
|
108
108
|
} else if (option[1] === Blockly.DELETE_VARIABLE_ID) {
|
|
109
|
-
|
|
110
|
-
"%1",
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
return [
|
|
110
|
+
ScratchMsgs.translate("DELETE_LIST").replace("%1", this.getText()),
|
|
111
|
+
option[1],
|
|
112
|
+
];
|
|
113
113
|
}
|
|
114
|
-
|
|
114
|
+
return option;
|
|
115
|
+
});
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
return options;
|
|
@@ -10,11 +10,15 @@ import { CheckboxBubble } from "./checkbox_bubble";
|
|
|
10
10
|
/**
|
|
11
11
|
* Invisible icon that exists solely to host the corresponding checkbox bubble.
|
|
12
12
|
*/
|
|
13
|
-
export class FlyoutCheckboxIcon
|
|
13
|
+
export class FlyoutCheckboxIcon
|
|
14
|
+
extends Blockly.icons.Icon
|
|
15
|
+
implements Blockly.IHasBubble
|
|
16
|
+
{
|
|
14
17
|
private checkboxBubble: CheckboxBubble;
|
|
15
18
|
private type = new Blockly.icons.IconType("checkbox");
|
|
16
19
|
|
|
17
|
-
constructor(
|
|
20
|
+
constructor(protected override sourceBlock: Blockly.BlockSvg) {
|
|
21
|
+
super(sourceBlock);
|
|
18
22
|
if (this.sourceBlock.workspace.isFlyout) {
|
|
19
23
|
this.checkboxBubble = new CheckboxBubble(this.sourceBlock);
|
|
20
24
|
}
|
|
@@ -24,19 +28,11 @@ export class FlyoutCheckboxIcon implements Blockly.IIcon, Blockly.IHasBubble {
|
|
|
24
28
|
return this.type;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
getWeight(): number {
|
|
28
|
-
return -1;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
31
|
getSize(): Blockly.utils.Size {
|
|
32
32
|
// Awful hack to cancel out the default padding added to icons.
|
|
33
33
|
return new Blockly.utils.Size(-8, 0);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
isShownWhenCollapsed(): boolean {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
36
|
isClickableInFlyout(): boolean {
|
|
41
37
|
return false;
|
|
42
38
|
}
|
|
@@ -55,25 +51,23 @@ export class FlyoutCheckboxIcon implements Blockly.IIcon, Blockly.IHasBubble {
|
|
|
55
51
|
|
|
56
52
|
dispose() {
|
|
57
53
|
this.checkboxBubble?.dispose();
|
|
54
|
+
super.dispose();
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
// These methods are required by the interfaces, but intentionally have no
|
|
61
58
|
// implementation, largely because this icon has no visual representation.
|
|
62
|
-
applyColour() {}
|
|
63
|
-
|
|
64
|
-
hideForInsertionMarker() {}
|
|
65
|
-
|
|
66
|
-
updateEditable() {}
|
|
67
|
-
|
|
68
|
-
updateCollapsed() {}
|
|
69
|
-
|
|
70
|
-
setOffsetInBlock() {}
|
|
71
|
-
|
|
72
|
-
onClick() {}
|
|
73
59
|
|
|
74
60
|
async setBubbleVisible(visible: boolean) {}
|
|
75
61
|
|
|
76
62
|
initView(pointerDownListener: (e: PointerEvent) => void) {}
|
|
63
|
+
|
|
64
|
+
canBeFocused() {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getBubble() {
|
|
69
|
+
return this.checkboxBubble;
|
|
70
|
+
}
|
|
77
71
|
}
|
|
78
72
|
|
|
79
73
|
Blockly.registry.register(
|