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
|
@@ -5,7 +5,7 @@
|
|
|
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
|
* A block inflater that caches and reuses blocks to improve performance.
|
|
@@ -13,26 +13,27 @@ import { CheckboxBubble } from "./checkbox_bubble.js";
|
|
|
13
13
|
export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater {
|
|
14
14
|
/**
|
|
15
15
|
* Whether or not block recycling is enabled.
|
|
16
|
-
* @type {boolean}
|
|
17
16
|
*/
|
|
18
17
|
recyclingEnabled = true;
|
|
19
18
|
|
|
20
19
|
/**
|
|
21
20
|
* Map from block type to block instance.
|
|
22
|
-
* @type {Map<string, !Blockly.BlockSvg>}
|
|
23
21
|
*/
|
|
24
|
-
recycledBlocks = new Map();
|
|
22
|
+
recycledBlocks = new Map<string, Blockly.BlockSvg>();
|
|
25
23
|
|
|
26
24
|
/**
|
|
27
25
|
* Creates a block on the flyout workspace from the given block definition.
|
|
28
26
|
*
|
|
29
|
-
* @param
|
|
30
|
-
* @param
|
|
31
|
-
* @returns
|
|
27
|
+
* @param state A JSON representation of a block to load.
|
|
28
|
+
* @param flyoutWorkspace The flyout's workspace.
|
|
29
|
+
* @returns The newly created block.
|
|
32
30
|
*/
|
|
33
|
-
load(
|
|
31
|
+
load(
|
|
32
|
+
state: Blockly.utils.toolbox.BlockInfo,
|
|
33
|
+
flyoutWorkspace: Blockly.WorkspaceSvg
|
|
34
|
+
): Blockly.IBoundedElement {
|
|
34
35
|
const block = super.load(state, flyoutWorkspace);
|
|
35
|
-
if (block.checkboxInFlyout) {
|
|
36
|
+
if ("checkboxInFlyout" in block && block.checkboxInFlyout) {
|
|
36
37
|
block.moveBy(
|
|
37
38
|
CheckboxBubble.CHECKBOX_SIZE + CheckboxBubble.CHECKBOX_MARGIN,
|
|
38
39
|
0
|
|
@@ -45,19 +46,21 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater {
|
|
|
45
46
|
/**
|
|
46
47
|
* Toggles whether or not recycling is enabled.
|
|
47
48
|
*
|
|
48
|
-
* @param
|
|
49
|
+
* @param enabled True if recycling should be enabled.
|
|
49
50
|
*/
|
|
50
|
-
setRecyclingEnabled(enabled) {
|
|
51
|
+
setRecyclingEnabled(enabled: boolean) {
|
|
51
52
|
this.recyclingEnabled = enabled;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
56
|
* Creates a new block from the given block definition.
|
|
56
57
|
*
|
|
57
|
-
* @param
|
|
58
|
-
* @returns
|
|
58
|
+
* @param blockDefinition The definition to create a block from.
|
|
59
|
+
* @returns The newly created block.
|
|
59
60
|
*/
|
|
60
|
-
createBlock(
|
|
61
|
+
createBlock(
|
|
62
|
+
blockDefinition: Blockly.utils.toolbox.BlockInfo
|
|
63
|
+
): Blockly.BlockSvg {
|
|
61
64
|
const blockType = this.getTypeFromDefinition(blockDefinition);
|
|
62
65
|
return (
|
|
63
66
|
this.getRecycledBlock(blockType) ??
|
|
@@ -68,15 +71,17 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater {
|
|
|
68
71
|
/**
|
|
69
72
|
* Returns the type of a block from an XML or JSON block definition.
|
|
70
73
|
*
|
|
71
|
-
* @param blockDefinition
|
|
72
|
-
* @returns
|
|
74
|
+
* @param blockDefinition The block definition to parse.
|
|
75
|
+
* @returns The block type.
|
|
73
76
|
*/
|
|
74
|
-
getTypeFromDefinition(
|
|
77
|
+
getTypeFromDefinition(
|
|
78
|
+
blockDefinition: Blockly.utils.toolbox.BlockInfo
|
|
79
|
+
): string {
|
|
75
80
|
if (blockDefinition["blockxml"]) {
|
|
76
81
|
const xml =
|
|
77
82
|
typeof blockDefinition["blockxml"] === "string"
|
|
78
83
|
? Blockly.utils.xml.textToDom(blockDefinition["blockxml"])
|
|
79
|
-
: blockDefinition["blockxml"];
|
|
84
|
+
: (blockDefinition["blockxml"] as Element);
|
|
80
85
|
return xml.getAttribute("type");
|
|
81
86
|
} else {
|
|
82
87
|
return blockDefinition["type"];
|
|
@@ -88,9 +93,9 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater {
|
|
|
88
93
|
* top of the workspace. Used during large workspace swaps to limit the number
|
|
89
94
|
* of new DOM elements we need to create.
|
|
90
95
|
*
|
|
91
|
-
* @param
|
|
96
|
+
* @param block The block to recycle.
|
|
92
97
|
*/
|
|
93
|
-
recycleBlock(block) {
|
|
98
|
+
recycleBlock(block: Blockly.BlockSvg) {
|
|
94
99
|
const xy = block.getRelativeToSurfaceXY();
|
|
95
100
|
block.moveBy(-xy.x, -xy.y);
|
|
96
101
|
this.recycledBlocks.set(block.type, block);
|
|
@@ -100,11 +105,10 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater {
|
|
|
100
105
|
* Returns a block from the cache of recycled blocks with the given type, or
|
|
101
106
|
* undefined if one cannot be found.
|
|
102
107
|
*
|
|
103
|
-
* @param
|
|
104
|
-
* @returns
|
|
105
|
-
* one could not be recycled.
|
|
108
|
+
* @param blockType The type of the block to try to recycle.
|
|
109
|
+
* @returns The recycled block, or undefined if one could not be recycled.
|
|
106
110
|
*/
|
|
107
|
-
getRecycledBlock(blockType) {
|
|
111
|
+
getRecycledBlock(blockType: string): Blockly.BlockSvg | undefined {
|
|
108
112
|
const block = this.recycledBlocks.get(blockType);
|
|
109
113
|
this.recycledBlocks.delete(blockType);
|
|
110
114
|
return block;
|
|
@@ -113,10 +117,10 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater {
|
|
|
113
117
|
/**
|
|
114
118
|
* Returns whether the given block can be recycled or not.
|
|
115
119
|
*
|
|
116
|
-
* @param
|
|
117
|
-
* @returns
|
|
120
|
+
* @param block The block to check for recyclability.
|
|
121
|
+
* @returns True if the block can be recycled. False otherwise.
|
|
118
122
|
*/
|
|
119
|
-
blockIsRecyclable(block) {
|
|
123
|
+
blockIsRecyclable(block: Blockly.Block): boolean {
|
|
120
124
|
if (!this.recyclingEnabled) {
|
|
121
125
|
return false;
|
|
122
126
|
}
|
|
@@ -144,9 +148,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater {
|
|
|
144
148
|
}
|
|
145
149
|
// Check children.
|
|
146
150
|
if (input.connection) {
|
|
147
|
-
const targetBlock =
|
|
148
|
-
/** @type {Blockly.BlockSvg} */
|
|
149
|
-
(input.connection.targetBlock());
|
|
151
|
+
const targetBlock = input.connection.targetBlock();
|
|
150
152
|
if (targetBlock && !this.blockIsRecyclable(targetBlock)) {
|
|
151
153
|
return false;
|
|
152
154
|
}
|
|
@@ -158,9 +160,9 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater {
|
|
|
158
160
|
/**
|
|
159
161
|
* Disposes of the provided block.
|
|
160
162
|
*
|
|
161
|
-
* @param
|
|
163
|
+
* @param element The block to dispose of.
|
|
162
164
|
*/
|
|
163
|
-
disposeElement(element) {
|
|
165
|
+
disposeElement(element: Blockly.BlockSvg) {
|
|
164
166
|
if (this.blockIsRecyclable(element)) {
|
|
165
167
|
this.removeListeners(element.id);
|
|
166
168
|
this.recycleBlock(element);
|
|
@@ -173,9 +175,7 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater {
|
|
|
173
175
|
* Clears the cache of recycled blocks.
|
|
174
176
|
*/
|
|
175
177
|
emptyRecycledBlocks() {
|
|
176
|
-
this.recycledBlocks
|
|
177
|
-
.values()
|
|
178
|
-
.forEach((block) => block.dispose(false, false));
|
|
178
|
+
this.recycledBlocks.forEach((block) => block.dispose(false, false));
|
|
179
179
|
this.recycledBlocks.clear();
|
|
180
180
|
}
|
|
181
181
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import * as Blockly from "blockly/core";
|
|
8
8
|
|
|
9
9
|
export class BowlerHat extends Blockly.blockRendering.Hat {
|
|
10
|
-
constructor(constants) {
|
|
10
|
+
constructor(constants: Blockly.blockRendering.ConstantProvider) {
|
|
11
11
|
super(constants);
|
|
12
12
|
// Calculated dynamically by computeBounds_().
|
|
13
13
|
this.width = 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
|
}
|