scratch-blocks 2.0.0-spork.2 → 2.0.0-spork.4
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 +14 -0
- package/dist/main.js +1 -1
- package/dist/main.js.LICENSE.txt +0 -12
- package/package.json +4 -4
- 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.ts +112 -0
- package/src/{checkbox_bubble.js → checkbox_bubble.ts} +40 -58
- 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/{css.js → css.ts} +13 -7
- 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 +62 -63
- package/src/procedures.ts +462 -0
- package/src/recyclable_block_flyout_inflater.ts +51 -0
- 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.ts +70 -0
- 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} +13 -9
- package/src/{variables.js → variables.ts} +153 -123
- package/tsconfig.json +5 -0
- package/src/categories.js +0 -15
- package/src/checkable_continuous_flyout.js +0 -138
- 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/recyclable_block_flyout_inflater.js +0 -194
- 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_continuous_toolbox.js +0 -78
- package/src/scratch_variable_model.js +0 -24
- /package/{continuous-toolbox.d.ts → types/continuous-toolbox.d.ts} +0 -0
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as Blockly from "blockly/core";
|
|
8
|
-
import { cssVarify } from "../colours.js";
|
|
9
8
|
|
|
10
9
|
export class ConstantProvider extends Blockly.zelos.ConstantProvider {
|
|
11
10
|
REPLACEMENT_GLOW_COLOUR = "#ffffff";
|
|
@@ -18,27 +17,42 @@ export class ConstantProvider extends Blockly.zelos.ConstantProvider {
|
|
|
18
17
|
* styles contain any raw color values, corresponding CSS variables will be
|
|
19
18
|
* created/overridden so that those colors can be dynamically referenced in
|
|
20
19
|
* stylesheets.
|
|
21
|
-
*
|
|
20
|
+
*
|
|
21
|
+
* @param theme The new theme to apply.
|
|
22
22
|
*/
|
|
23
|
-
setTheme(theme) {
|
|
24
|
-
const root = document.querySelector(":root");
|
|
23
|
+
setTheme(theme: Blockly.Theme) {
|
|
24
|
+
const root = document.querySelector(":root") as HTMLElement;
|
|
25
25
|
for (const [key, colour] of Object.entries(theme.blockStyles)) {
|
|
26
|
-
if (typeof colour
|
|
26
|
+
if (typeof colour !== "object") {
|
|
27
27
|
const varKey = `--colour-${key}`;
|
|
28
28
|
root.style.setProperty(varKey, colour);
|
|
29
29
|
} else {
|
|
30
|
-
|
|
31
|
-
colourPrimary:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
const style = {
|
|
31
|
+
colourPrimary:
|
|
32
|
+
"colourQuaternary" in colour
|
|
33
|
+
? `${colour.colourQuaternary}`
|
|
34
|
+
: colour.colourTertiary,
|
|
35
|
+
colourSecondary:
|
|
36
|
+
"colourQuaternary" in colour
|
|
37
|
+
? `${colour.colourQuaternary}`
|
|
38
|
+
: colour.colourTertiary,
|
|
39
|
+
colourTertiary:
|
|
40
|
+
"colourQuaternary" in colour
|
|
41
|
+
? `${colour.colourQuaternary}`
|
|
42
|
+
: colour.colourTertiary,
|
|
43
|
+
colourQuaternary:
|
|
44
|
+
"colourQuaternary" in colour
|
|
45
|
+
? `${colour.colourQuaternary}`
|
|
46
|
+
: colour.colourTertiary,
|
|
47
|
+
hat: "",
|
|
48
|
+
};
|
|
49
|
+
theme.setBlockStyle(`${key}_selected`, style);
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
52
|
super.setTheme(theme);
|
|
39
53
|
}
|
|
40
54
|
|
|
41
|
-
createDom(svg, tagName, selector) {
|
|
55
|
+
createDom(svg: SVGElement, tagName: string, selector: string) {
|
|
42
56
|
super.createDom(svg, tagName, selector);
|
|
43
57
|
this.selectedGlowFilterId = "";
|
|
44
58
|
}
|
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as Blockly from "blockly/core";
|
|
8
|
+
import type { RenderInfo } from "./render_info";
|
|
8
9
|
|
|
9
10
|
export class Drawer extends Blockly.zelos.Drawer {
|
|
10
|
-
|
|
11
|
+
info_: RenderInfo;
|
|
12
|
+
drawStatementInput_(row: Blockly.blockRendering.Row) {
|
|
11
13
|
if (this.info_.isBowlerHatBlock()) {
|
|
12
14
|
// Bowler hat blocks have straight sides with no C-shape/indentation for
|
|
13
15
|
// statement blocks.
|
|
@@ -18,14 +20,17 @@ export class Drawer extends Blockly.zelos.Drawer {
|
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
drawRightSideRow_(row) {
|
|
23
|
+
drawRightSideRow_(row: Blockly.blockRendering.Row) {
|
|
22
24
|
if (
|
|
23
25
|
this.info_.isBowlerHatBlock() &&
|
|
24
26
|
Blockly.blockRendering.Types.isSpacer(row)
|
|
25
27
|
) {
|
|
26
28
|
// Multi-row bowler hat blocks are not supported, this may need
|
|
27
29
|
// adjustment to do so.
|
|
28
|
-
Blockly.
|
|
30
|
+
this.outlinePath_ += Blockly.utils.svgPaths.lineOnAxis(
|
|
31
|
+
"V",
|
|
32
|
+
row.yPos + row.height
|
|
33
|
+
);
|
|
29
34
|
} else {
|
|
30
35
|
super.drawRightSideRow_(row);
|
|
31
36
|
}
|
|
@@ -15,9 +15,9 @@ export class PathObject extends Blockly.zelos.PathObject {
|
|
|
15
15
|
* Apply the stored colours to the block's path, taking into account whether
|
|
16
16
|
* the paths belong to a shadow block.
|
|
17
17
|
*
|
|
18
|
-
* @param
|
|
18
|
+
* @param block The source block.
|
|
19
19
|
*/
|
|
20
|
-
applyColour(block) {
|
|
20
|
+
applyColour(block: Blockly.BlockSvg) {
|
|
21
21
|
super.applyColour(block);
|
|
22
22
|
|
|
23
23
|
// These blocks are special in that, while they are technically shadow
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as Blockly from "blockly/core";
|
|
8
|
-
import { BowlerHat } from "./bowler_hat
|
|
8
|
+
import { BowlerHat } from "./bowler_hat";
|
|
9
9
|
|
|
10
10
|
export class RenderInfo extends Blockly.zelos.RenderInfo {
|
|
11
11
|
populateTopRow_() {
|
|
@@ -51,11 +51,14 @@ export class RenderInfo extends Blockly.zelos.RenderInfo {
|
|
|
51
51
|
Blockly.blockRendering.Types.isHat(e)
|
|
52
52
|
);
|
|
53
53
|
hat.width = this.width;
|
|
54
|
-
this.topRow.measure(
|
|
54
|
+
this.topRow.measure();
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
getInRowSpacing_(
|
|
58
|
+
getInRowSpacing_(
|
|
59
|
+
prev: Blockly.blockRendering.Measurable,
|
|
60
|
+
next: Blockly.blockRendering.Measurable
|
|
61
|
+
): number {
|
|
59
62
|
if (
|
|
60
63
|
this.isBowlerHatBlock() &&
|
|
61
64
|
((prev && Blockly.blockRendering.Types.isHat(prev)) ||
|
|
@@ -68,7 +71,10 @@ export class RenderInfo extends Blockly.zelos.RenderInfo {
|
|
|
68
71
|
return super.getInRowSpacing_(prev, next);
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
getSpacerRowHeight_(
|
|
74
|
+
getSpacerRowHeight_(
|
|
75
|
+
prev: Blockly.blockRendering.Row,
|
|
76
|
+
next: Blockly.blockRendering.Row
|
|
77
|
+
): number {
|
|
72
78
|
if (this.isBowlerHatBlock() && prev === this.topRow) {
|
|
73
79
|
return 0;
|
|
74
80
|
}
|
|
@@ -76,14 +82,20 @@ export class RenderInfo extends Blockly.zelos.RenderInfo {
|
|
|
76
82
|
return super.getSpacerRowHeight_(prev, next);
|
|
77
83
|
}
|
|
78
84
|
|
|
79
|
-
getElemCenterline_(
|
|
85
|
+
getElemCenterline_(
|
|
86
|
+
row: Blockly.blockRendering.Row,
|
|
87
|
+
elem: Blockly.blockRendering.Measurable
|
|
88
|
+
): number {
|
|
80
89
|
if (this.isBowlerHatBlock() && Blockly.blockRendering.Types.isField(elem)) {
|
|
81
90
|
return row.yPos + row.height / 2;
|
|
82
91
|
} else if (
|
|
92
|
+
"isScratchExtension" in this.block_ &&
|
|
83
93
|
this.block_.isScratchExtension &&
|
|
84
94
|
Blockly.blockRendering.Types.isField(elem) &&
|
|
85
|
-
elem
|
|
86
|
-
|
|
95
|
+
(elem as Blockly.blockRendering.Field).field instanceof
|
|
96
|
+
Blockly.FieldImage &&
|
|
97
|
+
(elem as Blockly.blockRendering.Field).field ===
|
|
98
|
+
this.block_.inputList[0].fieldRow[0] &&
|
|
87
99
|
this.block_.previousConnection
|
|
88
100
|
) {
|
|
89
101
|
// Vertically center the icon on extension blocks.
|
|
@@ -0,0 +1,76 @@
|
|
|
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 { Drawer } from "./drawer";
|
|
9
|
+
import { RenderInfo } from "./render_info";
|
|
10
|
+
import { ConstantProvider } from "./constants";
|
|
11
|
+
import { PathObject } from "./path_object";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Custom renderer for Scratch-style blocks.
|
|
15
|
+
*/
|
|
16
|
+
export class ScratchRenderer extends Blockly.zelos.Renderer {
|
|
17
|
+
/**
|
|
18
|
+
* Create a new instance of the renderer's drawer.
|
|
19
|
+
*
|
|
20
|
+
* @param block The block to render.
|
|
21
|
+
* @param infoAn object containing all the information needed to render this
|
|
22
|
+
* block.
|
|
23
|
+
* @returns The drawer.
|
|
24
|
+
*/
|
|
25
|
+
makeDrawer_(block: Blockly.BlockSvg, info: RenderInfo): Drawer {
|
|
26
|
+
return new Drawer(block, info);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Create a new instance of the renderer's render info object.
|
|
31
|
+
*
|
|
32
|
+
* @param block The block to measure.
|
|
33
|
+
* @returns The render info object.
|
|
34
|
+
*/
|
|
35
|
+
makeRenderInfo_(block: Blockly.BlockSvg): RenderInfo {
|
|
36
|
+
return new RenderInfo(this, block);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Create a new instance of the renderer's constant provider.
|
|
41
|
+
*
|
|
42
|
+
* @returns The constant provider.
|
|
43
|
+
*/
|
|
44
|
+
makeConstants_(): ConstantProvider {
|
|
45
|
+
return new ConstantProvider();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a new instance of a renderer path object.
|
|
50
|
+
*
|
|
51
|
+
* @param root The root SVG element.
|
|
52
|
+
* @param style The style object to use for colouring.
|
|
53
|
+
* @returns The renderer path object.
|
|
54
|
+
*/
|
|
55
|
+
makePathObject(
|
|
56
|
+
root: SVGElement,
|
|
57
|
+
style: Blockly.Theme.BlockStyle
|
|
58
|
+
): PathObject {
|
|
59
|
+
return new PathObject(root, style, this.getConstants());
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Determine whether or not to highlight a connection.
|
|
64
|
+
*
|
|
65
|
+
* @param connection The connection to determine whether or not to highlight.
|
|
66
|
+
* @returns True if we should highlight the connection.
|
|
67
|
+
*/
|
|
68
|
+
shouldHighlightConnection(connection: Blockly.RenderedConnection): boolean {
|
|
69
|
+
return (
|
|
70
|
+
connection.type === Blockly.ConnectionType.INPUT_VALUE &&
|
|
71
|
+
connection.getCheck()?.includes("Boolean")
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Blockly.blockRendering.register("scratch", ScratchRenderer);
|
|
@@ -13,14 +13,16 @@ class ScratchBlockPaster extends Blockly.clipboard.BlockPaster {
|
|
|
13
13
|
/**
|
|
14
14
|
* Deserializes the given block data onto the workspace.
|
|
15
15
|
*
|
|
16
|
-
* @param
|
|
17
|
-
*
|
|
18
|
-
* @param
|
|
19
|
-
*
|
|
20
|
-
* @param {?Blockly.utils.Coordinate} coordinate The location to paste the
|
|
21
|
-
* block.
|
|
16
|
+
* @param copyData The serialized block state to create a copy of on the
|
|
17
|
+
* workspace.
|
|
18
|
+
* @param workspace The workspace to paste the block onto.
|
|
19
|
+
* @param coordinate The location to paste the block.
|
|
22
20
|
*/
|
|
23
|
-
paste(
|
|
21
|
+
paste(
|
|
22
|
+
copyData: Blockly.clipboard.BlockCopyData,
|
|
23
|
+
workspace: Blockly.WorkspaceSvg,
|
|
24
|
+
coordinate: Blockly.utils.Coordinate
|
|
25
|
+
) {
|
|
24
26
|
const block = super.paste(copyData, workspace, coordinate);
|
|
25
27
|
if (
|
|
26
28
|
block?.type === "argument_reporter_boolean" ||
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Visual Blocks Editor
|
|
4
|
+
*
|
|
5
|
+
* Copyright 2018 Google Inc.
|
|
6
|
+
* https://developers.google.com/blockly/
|
|
7
|
+
*
|
|
8
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
9
|
+
* you may not use this file except in compliance with the License.
|
|
10
|
+
* You may obtain a copy of the License at
|
|
11
|
+
*
|
|
12
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
13
|
+
*
|
|
14
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
15
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
16
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
17
|
+
* See the License for the specific language governing permissions and
|
|
18
|
+
* limitations under the License.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @fileoverview Utility methods for Scratch Blocks but not Blockly.
|
|
23
|
+
* @author fenichel@google.com (Rachel Fenichel)
|
|
24
|
+
*/
|
|
25
|
+
import * as Blockly from "blockly/core";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Compare strings with natural number sorting.
|
|
29
|
+
*
|
|
30
|
+
* @param str1 First input.
|
|
31
|
+
* @param str2 Second input.
|
|
32
|
+
* @returns -1, 0, or 1 to signify greater than, equality, or less than.
|
|
33
|
+
*/
|
|
34
|
+
export function compareStrings(str1: string, str2: string): number {
|
|
35
|
+
return str1.localeCompare(str2, [], {
|
|
36
|
+
sensitivity: "base",
|
|
37
|
+
numeric: true,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -7,15 +7,32 @@
|
|
|
7
7
|
import * as Blockly from "blockly/core";
|
|
8
8
|
import { ScratchCommentBubble } from "./scratch_comment_bubble.js";
|
|
9
9
|
|
|
10
|
+
interface CommentState {
|
|
11
|
+
text: string;
|
|
12
|
+
height: number;
|
|
13
|
+
width: number;
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
collapsed: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
/**
|
|
11
20
|
* Custom comment icon that draws no icon indicator, used for block comments.
|
|
12
|
-
* @implements {IHasBubble}
|
|
13
|
-
* @implements {ISerializable}
|
|
14
21
|
*/
|
|
15
|
-
class ScratchCommentIcon
|
|
16
|
-
|
|
22
|
+
class ScratchCommentIcon
|
|
23
|
+
extends Blockly.icons.Icon
|
|
24
|
+
implements Blockly.ISerializable, Blockly.IHasBubble
|
|
25
|
+
{
|
|
26
|
+
private commentBubble: ScratchCommentBubble;
|
|
27
|
+
private onTextChangedListener: (oldText: string, newText: string) => void;
|
|
28
|
+
private onSizeChangedListener: (
|
|
29
|
+
oldSize: Blockly.utils.Size,
|
|
30
|
+
newSize: Blockly.utils.Size
|
|
31
|
+
) => void;
|
|
32
|
+
private onCollapseListener: (collapsed: boolean) => void;
|
|
33
|
+
|
|
34
|
+
constructor(protected sourceBlock: Blockly.BlockSvg) {
|
|
17
35
|
super(sourceBlock);
|
|
18
|
-
this.sourceBlock = sourceBlock;
|
|
19
36
|
this.commentBubble = new ScratchCommentBubble(this.sourceBlock);
|
|
20
37
|
Blockly.Events.fire(
|
|
21
38
|
new (Blockly.Events.get("block_comment_create"))(this.commentBubble)
|
|
@@ -28,28 +45,28 @@ class ScratchCommentIcon extends Blockly.icons.Icon {
|
|
|
28
45
|
this.commentBubble.addOnCollapseListener(this.onCollapseListener);
|
|
29
46
|
}
|
|
30
47
|
|
|
31
|
-
getType() {
|
|
48
|
+
getType(): Blockly.icons.IconType<ScratchCommentIcon> {
|
|
32
49
|
return Blockly.icons.IconType.COMMENT;
|
|
33
50
|
}
|
|
34
51
|
|
|
35
|
-
initView(pointerDownListener) {
|
|
52
|
+
initView(pointerDownListener: (e: PointerEvent) => void) {
|
|
36
53
|
// Scratch comments have no indicator icon on the block.
|
|
37
54
|
return;
|
|
38
55
|
}
|
|
39
56
|
|
|
40
|
-
getSize() {
|
|
57
|
+
getSize(): Blockly.utils.Size {
|
|
41
58
|
// Awful hack to cancel out the default padding added to icons.
|
|
42
59
|
return new Blockly.utils.Size(-8, 0);
|
|
43
60
|
}
|
|
44
61
|
|
|
45
|
-
getAnchorPoint() {
|
|
62
|
+
getAnchorPoint(): Blockly.utils.Coordinate {
|
|
46
63
|
const blockRect = this.sourceBlock.getBoundingRectangleWithoutChildren();
|
|
47
64
|
const y = blockRect.top + this.offsetInBlock.y;
|
|
48
65
|
const x = this.sourceBlock.workspace.RTL ? blockRect.left : blockRect.right;
|
|
49
66
|
return new Blockly.utils.Coordinate(x, y);
|
|
50
67
|
}
|
|
51
68
|
|
|
52
|
-
onLocationChange(blockOrigin) {
|
|
69
|
+
onLocationChange(blockOrigin: Blockly.utils.Coordinate) {
|
|
53
70
|
if (!this.sourceBlock || !this.commentBubble) return;
|
|
54
71
|
|
|
55
72
|
if (this.sourceBlock.isInsertionMarker()) {
|
|
@@ -70,15 +87,15 @@ class ScratchCommentIcon extends Blockly.icons.Icon {
|
|
|
70
87
|
);
|
|
71
88
|
}
|
|
72
89
|
|
|
73
|
-
setText(text) {
|
|
90
|
+
setText(text: string) {
|
|
74
91
|
this.commentBubble?.setText(text);
|
|
75
92
|
}
|
|
76
93
|
|
|
77
|
-
getText() {
|
|
94
|
+
getText(): string {
|
|
78
95
|
return this.commentBubble?.getText() ?? "";
|
|
79
96
|
}
|
|
80
97
|
|
|
81
|
-
onTextChanged(oldText, newText) {
|
|
98
|
+
onTextChanged(oldText: string, newText: string) {
|
|
82
99
|
Blockly.Events.fire(
|
|
83
100
|
new (Blockly.Events.get(Blockly.Events.BLOCK_CHANGE))(
|
|
84
101
|
this.sourceBlock,
|
|
@@ -97,7 +114,7 @@ class ScratchCommentIcon extends Blockly.icons.Icon {
|
|
|
97
114
|
);
|
|
98
115
|
}
|
|
99
116
|
|
|
100
|
-
onCollapsed(collapsed) {
|
|
117
|
+
onCollapsed(collapsed: boolean) {
|
|
101
118
|
Blockly.Events.fire(
|
|
102
119
|
new (Blockly.Events.get("block_comment_collapse"))(
|
|
103
120
|
this.commentBubble,
|
|
@@ -106,7 +123,7 @@ class ScratchCommentIcon extends Blockly.icons.Icon {
|
|
|
106
123
|
);
|
|
107
124
|
}
|
|
108
125
|
|
|
109
|
-
onSizeChanged(oldSize, newSize) {
|
|
126
|
+
onSizeChanged(oldSize: Blockly.utils.Size, newSize: Blockly.utils.Size) {
|
|
110
127
|
Blockly.Events.fire(
|
|
111
128
|
new (Blockly.Events.get("block_comment_resize"))(
|
|
112
129
|
this.commentBubble,
|
|
@@ -116,15 +133,15 @@ class ScratchCommentIcon extends Blockly.icons.Icon {
|
|
|
116
133
|
);
|
|
117
134
|
}
|
|
118
135
|
|
|
119
|
-
setBubbleSize(size) {
|
|
136
|
+
setBubbleSize(size: Blockly.utils.Size) {
|
|
120
137
|
this.commentBubble?.setSize(size);
|
|
121
138
|
}
|
|
122
139
|
|
|
123
|
-
getBubbleSize() {
|
|
140
|
+
getBubbleSize(): Blockly.utils.Size {
|
|
124
141
|
return this.commentBubble?.getSize() ?? new Blockly.utils.Size(0, 0);
|
|
125
142
|
}
|
|
126
143
|
|
|
127
|
-
setBubbleLocation(newLocation) {
|
|
144
|
+
setBubbleLocation(newLocation: Blockly.utils.Coordinate) {
|
|
128
145
|
const oldLocation = this.getBubbleLocation();
|
|
129
146
|
this.commentBubble?.moveTo(newLocation);
|
|
130
147
|
Blockly.Events.fire(
|
|
@@ -136,11 +153,11 @@ class ScratchCommentIcon extends Blockly.icons.Icon {
|
|
|
136
153
|
);
|
|
137
154
|
}
|
|
138
155
|
|
|
139
|
-
getBubbleLocation() {
|
|
156
|
+
getBubbleLocation(): Blockly.utils.Coordinate {
|
|
140
157
|
return this.commentBubble?.getRelativeToSurfaceXY();
|
|
141
158
|
}
|
|
142
159
|
|
|
143
|
-
saveState() {
|
|
160
|
+
saveState(): CommentState | null {
|
|
144
161
|
if (!this.commentBubble) return null;
|
|
145
162
|
|
|
146
163
|
const size = this.getBubbleSize();
|
|
@@ -159,7 +176,8 @@ class ScratchCommentIcon extends Blockly.icons.Icon {
|
|
|
159
176
|
};
|
|
160
177
|
}
|
|
161
178
|
|
|
162
|
-
loadState(state) {
|
|
179
|
+
loadState(state: CommentState) {
|
|
180
|
+
Blockly.Events.setGroup(true);
|
|
163
181
|
this.setText(state["text"]);
|
|
164
182
|
this.setBubbleSize(new Blockly.utils.Size(state["width"], state["height"]));
|
|
165
183
|
const delta = new Blockly.utils.Coordinate(state["x"], state["y"]);
|
|
@@ -169,20 +187,19 @@ class ScratchCommentIcon extends Blockly.icons.Icon {
|
|
|
169
187
|
);
|
|
170
188
|
this.commentBubble.moveTo(newBubbleLocation);
|
|
171
189
|
this.commentBubble.setCollapsed(state["collapsed"]);
|
|
190
|
+
Blockly.Events.setGroup(false);
|
|
172
191
|
}
|
|
173
192
|
|
|
174
|
-
bubbleIsVisible() {
|
|
193
|
+
bubbleIsVisible(): boolean {
|
|
175
194
|
return true;
|
|
176
195
|
}
|
|
177
196
|
|
|
178
|
-
async setBubbleVisible(visible) {
|
|
197
|
+
async setBubbleVisible(visible: boolean) {
|
|
179
198
|
this.commentBubble.setCollapsed(!visible);
|
|
180
199
|
}
|
|
181
200
|
|
|
182
201
|
dispose() {
|
|
183
|
-
this.commentBubble
|
|
184
|
-
this.commentBubble = null;
|
|
185
|
-
this.sourceBlock = null;
|
|
202
|
+
this.commentBubble.dispose();
|
|
186
203
|
super.dispose();
|
|
187
204
|
}
|
|
188
205
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Custom connection checker to restrict which blocks can be connected.
|
|
11
|
+
*/
|
|
12
|
+
class ScratchConnectionChecker extends Blockly.ConnectionChecker {
|
|
13
|
+
/**
|
|
14
|
+
* Returns whether or not the two connections should be allowed to connect.
|
|
15
|
+
*
|
|
16
|
+
* @param a One of the connections to check.
|
|
17
|
+
* @param b The other connection to check.
|
|
18
|
+
* @param distance The maximum allowable distance between connections.
|
|
19
|
+
* @returns True if the connections should be allowed to connect.
|
|
20
|
+
*/
|
|
21
|
+
doDragChecks(
|
|
22
|
+
a: Blockly.RenderedConnection,
|
|
23
|
+
b: Blockly.RenderedConnection,
|
|
24
|
+
distance: number
|
|
25
|
+
): boolean {
|
|
26
|
+
// This check prevents dragging a block into the slot occupied by the
|
|
27
|
+
// procedure caller example block in a procedure definition block.
|
|
28
|
+
if (
|
|
29
|
+
b.getSourceBlock().type === "procedures_definition" &&
|
|
30
|
+
b.getParentInput()?.name === "custom_block"
|
|
31
|
+
) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return super.doDragChecks(a, b, distance);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Blockly.registry.register(
|
|
40
|
+
Blockly.registry.Type.CONNECTION_CHECKER,
|
|
41
|
+
Blockly.registry.DEFAULT,
|
|
42
|
+
ScratchConnectionChecker,
|
|
43
|
+
true
|
|
44
|
+
);
|
|
@@ -7,34 +7,41 @@
|
|
|
7
7
|
import * as Blockly from "blockly/core";
|
|
8
8
|
import { ContinuousCategory } from "@blockly/continuous-toolbox";
|
|
9
9
|
|
|
10
|
+
type StatusIndicatorCategoryInfo = Blockly.utils.toolbox.CategoryInfo & {
|
|
11
|
+
showStatusButton?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Selectable category shown in the Scratch toolbox.
|
|
16
|
+
*/
|
|
10
17
|
export class ScratchContinuousCategory extends ContinuousCategory {
|
|
11
18
|
/**
|
|
12
19
|
* Whether this toolbox category has a status indicator button on its label
|
|
13
20
|
* in the flyout, typically for extensions that interface with hardware
|
|
14
21
|
* devices.
|
|
15
|
-
* @type {boolean}
|
|
16
22
|
*/
|
|
17
|
-
showStatusButton = false;
|
|
23
|
+
private showStatusButton = false;
|
|
18
24
|
|
|
19
25
|
/** Creates a new ScratchContinuousCategory.
|
|
20
26
|
*
|
|
21
|
-
* @param
|
|
22
|
-
*
|
|
23
|
-
* @param
|
|
24
|
-
* added to.
|
|
25
|
-
* @param {?Blockly.ICollapsibleToolboxItem} opt_parent The parent toolbox
|
|
26
|
-
* category, if any.
|
|
27
|
+
* @param toolboxItemDef A toolbox item definition.
|
|
28
|
+
* @param parentToolbox The toolbox this category is being added to.
|
|
29
|
+
* @param opt_parent The parent toolbox category, if any.
|
|
27
30
|
*/
|
|
28
|
-
constructor(
|
|
31
|
+
constructor(
|
|
32
|
+
toolboxItemDef: StatusIndicatorCategoryInfo,
|
|
33
|
+
parentToolbox: Blockly.Toolbox,
|
|
34
|
+
opt_parent?: Blockly.ICollapsibleToolboxItem
|
|
35
|
+
) {
|
|
29
36
|
super(toolboxItemDef, parentToolbox, opt_parent);
|
|
30
37
|
this.showStatusButton = toolboxItemDef["showStatusButton"] === "true";
|
|
31
38
|
}
|
|
32
39
|
|
|
33
40
|
/**
|
|
34
41
|
* Creates a DOM element for this category's icon.
|
|
35
|
-
* @returns
|
|
42
|
+
* @returns A DOM element for this category's icon.
|
|
36
43
|
*/
|
|
37
|
-
createIconDom_() {
|
|
44
|
+
createIconDom_(): HTMLElement {
|
|
38
45
|
if (this.toolboxItemDef_.iconURI) {
|
|
39
46
|
const icon = document.createElement("img");
|
|
40
47
|
icon.src = this.toolboxItemDef_.iconURI;
|
|
@@ -49,9 +56,9 @@ export class ScratchContinuousCategory extends ContinuousCategory {
|
|
|
49
56
|
|
|
50
57
|
/**
|
|
51
58
|
* Sets whether or not this category is selected.
|
|
52
|
-
* @param
|
|
59
|
+
* @param isSelected True if this category is selected.
|
|
53
60
|
*/
|
|
54
|
-
setSelected(isSelected) {
|
|
61
|
+
setSelected(isSelected: boolean) {
|
|
55
62
|
super.setSelected(isSelected);
|
|
56
63
|
// Prevent hardcoding the background color to grey.
|
|
57
64
|
this.rowDiv_.style.backgroundColor = "";
|
|
@@ -0,0 +1,70 @@
|
|
|
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 { ContinuousToolbox } from "@blockly/continuous-toolbox";
|
|
9
|
+
import { ScratchContinuousCategory } from "./scratch_continuous_category";
|
|
10
|
+
import { STATUS_INDICATOR_LABEL_TYPE } from "./status_indicator_label_flyout_inflater";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A toolbox that displays items from all categories in one scrolling list.
|
|
14
|
+
*/
|
|
15
|
+
export class ScratchContinuousToolbox extends ContinuousToolbox {
|
|
16
|
+
/**
|
|
17
|
+
* List of functions to run after the next time the toolbox renders.
|
|
18
|
+
*/
|
|
19
|
+
private postRenderCallbacks: (() => void)[] = [];
|
|
20
|
+
|
|
21
|
+
refreshSelection() {
|
|
22
|
+
// Intentionally a no-op, Scratch manually manages refreshing the toolbox
|
|
23
|
+
// via forceRerender().
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Converts the given toolbox item to a corresponding array of items that
|
|
28
|
+
* should appear in the flyout.
|
|
29
|
+
*
|
|
30
|
+
* @param toolboxItem The toolbox item to convert.
|
|
31
|
+
* @returns An array of flyout item definitions.
|
|
32
|
+
*/
|
|
33
|
+
protected convertToolboxItemToFlyoutItems(
|
|
34
|
+
toolboxItem: Blockly.IToolboxItem
|
|
35
|
+
): Blockly.utils.toolbox.FlyoutItemInfoArray {
|
|
36
|
+
const contents = super.convertToolboxItemToFlyoutItems(toolboxItem);
|
|
37
|
+
if (
|
|
38
|
+
toolboxItem instanceof ScratchContinuousCategory &&
|
|
39
|
+
toolboxItem.shouldShowStatusButton()
|
|
40
|
+
) {
|
|
41
|
+
contents.splice(0, 1, {
|
|
42
|
+
kind: STATUS_INDICATOR_LABEL_TYPE,
|
|
43
|
+
id: toolboxItem.getId(),
|
|
44
|
+
text: toolboxItem.getName(),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return contents;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Forcibly rerenders the toolbox, preserving selection when possible.
|
|
52
|
+
*/
|
|
53
|
+
forceRerender() {
|
|
54
|
+
const selectedCategoryName = this.selectedItem_?.getName();
|
|
55
|
+
this.getFlyout().show(this.getInitialFlyoutContents());
|
|
56
|
+
this.selectCategoryByName(selectedCategoryName);
|
|
57
|
+
let callback;
|
|
58
|
+
while ((callback = this.postRenderCallbacks.shift())) {
|
|
59
|
+
callback();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Runs the specified callback after the next rerender.
|
|
65
|
+
* @param callback A callback to run whenever the toolbox next rerenders.
|
|
66
|
+
*/
|
|
67
|
+
runAfterRerender(callback: () => void) {
|
|
68
|
+
this.postRenderCallbacks.push(callback);
|
|
69
|
+
}
|
|
70
|
+
}
|