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.
Files changed (81) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/main.js +1 -1
  3. package/package.json +1 -1
  4. package/src/{block_reporting.js → block_reporting.ts} +7 -5
  5. package/src/blocks/{colour.js → colour.ts} +6 -6
  6. package/src/blocks/{control.js → control.ts} +21 -54
  7. package/src/blocks/{data.js → data.ts} +134 -142
  8. package/src/blocks/{event.js → event.ts} +12 -33
  9. package/src/blocks/{looks.js → looks.ts} +24 -73
  10. package/src/blocks/{math.js → math.ts} +6 -11
  11. package/src/blocks/{matrix.js → matrix.ts} +2 -3
  12. package/src/blocks/{motion.js → motion.ts} +23 -70
  13. package/src/blocks/{note.js → note.ts} +2 -3
  14. package/src/blocks/{operators.js → operators.ts} +18 -55
  15. package/src/blocks/{procedures.js → procedures.ts} +418 -269
  16. package/src/blocks/{sensing.js → sensing.ts} +21 -61
  17. package/src/blocks/{sound.js → sound.ts} +9 -28
  18. package/src/blocks/{text.js → text.ts} +1 -2
  19. package/src/blocks/{vertical_extensions.js → vertical_extensions.ts} +63 -100
  20. package/src/checkable_continuous_flyout.js +2 -2
  21. package/src/{checkbox_bubble.js → checkbox_bubble.ts} +36 -53
  22. package/src/{colours.js → colours.ts} +11 -4
  23. package/src/{constants.js → constants.ts} +13 -0
  24. package/src/{context_menu_items.js → context_menu_items.ts} +18 -12
  25. package/src/{data_category.js → data_category.ts} +216 -150
  26. package/src/events/{events_block_comment_base.js → events_block_comment_base.ts} +23 -4
  27. package/src/events/{events_block_comment_change.js → events_block_comment_change.ts} +29 -5
  28. package/src/events/{events_block_comment_collapse.js → events_block_comment_collapse.ts} +24 -6
  29. package/src/events/{events_block_comment_create.js → events_block_comment_create.ts} +36 -10
  30. package/src/events/{events_block_comment_delete.js → events_block_comment_delete.ts} +6 -2
  31. package/src/events/{events_block_comment_move.js → events_block_comment_move.ts} +36 -6
  32. package/src/events/events_block_comment_resize.ts +88 -0
  33. package/src/events/events_block_drag_end.ts +49 -0
  34. package/src/events/events_block_drag_outside.ts +44 -0
  35. package/src/events/{events_scratch_variable_create.js → events_scratch_variable_create.ts} +28 -15
  36. package/src/fields/{field_colour_slider.js → field_colour_slider.ts} +117 -106
  37. package/src/fields/{field_matrix.js → field_matrix.ts} +189 -215
  38. package/src/fields/{field_note.js → field_note.ts} +227 -286
  39. package/src/fields/{field_textinput_removable.js → field_textinput_removable.ts} +17 -20
  40. package/src/fields/{field_variable_getter.js → field_variable_getter.ts} +28 -17
  41. package/src/fields/{field_vertical_separator.js → field_vertical_separator.ts} +14 -30
  42. package/src/fields/{field_angle.js → scratch_field_angle.ts} +124 -80
  43. package/src/fields/{field_dropdown.js → scratch_field_dropdown.ts} +9 -7
  44. package/src/fields/{field_number.js → scratch_field_number.ts} +60 -55
  45. package/src/fields/{field_variable.js → scratch_field_variable.ts} +46 -27
  46. package/src/{flyout_checkbox_icon.js → flyout_checkbox_icon.ts} +15 -19
  47. package/src/{glows.js → glows.ts} +29 -18
  48. package/src/index.ts +59 -60
  49. package/src/procedures.ts +462 -0
  50. package/src/{recyclable_block_flyout_inflater.js → recyclable_block_flyout_inflater.ts} +35 -35
  51. package/src/renderer/{bowler_hat.js → bowler_hat.ts} +1 -1
  52. package/src/renderer/{constants.js → constants.ts} +26 -12
  53. package/src/renderer/{drawer.js → drawer.ts} +8 -3
  54. package/src/renderer/{path_object.js → path_object.ts} +2 -2
  55. package/src/renderer/{render_info.js → render_info.ts} +19 -7
  56. package/src/renderer/renderer.ts +76 -0
  57. package/src/{scratch_block_paster.js → scratch_block_paster.ts} +9 -7
  58. package/src/scratch_blocks_utils.ts +39 -0
  59. package/src/{scratch_comment_icon.js → scratch_comment_icon.ts} +43 -26
  60. package/src/scratch_connection_checker.ts +44 -0
  61. package/src/{scratch_continuous_category.js → scratch_continuous_category.ts} +20 -13
  62. package/src/{scratch_continuous_toolbox.js → scratch_continuous_toolbox.ts} +20 -18
  63. package/src/{scratch_dragger.js → scratch_dragger.ts} +97 -28
  64. package/src/{scratch_variable_map.js → scratch_variable_map.ts} +4 -1
  65. package/src/scratch_variable_model.ts +30 -0
  66. package/src/{shadows.js → shadows.ts} +8 -4
  67. package/src/{status_indicator_label.js → status_indicator_label.ts} +24 -36
  68. package/src/{status_indicator_label_flyout_inflater.js → status_indicator_label_flyout_inflater.ts} +9 -7
  69. package/src/{variables.js → variables.ts} +153 -123
  70. package/tsconfig.json +5 -0
  71. package/src/categories.js +0 -15
  72. package/src/events/events_block_comment_resize.js +0 -52
  73. package/src/events/events_block_drag_end.js +0 -33
  74. package/src/events/events_block_drag_outside.js +0 -30
  75. package/src/procedures.js +0 -425
  76. package/src/renderer/renderer.js +0 -74
  77. package/src/scratch_blocks_utils.js +0 -148
  78. package/src/scratch_connection_checker.js +0 -29
  79. package/src/scratch_variable_model.js +0 -24
  80. /package/src/{css.js → css.ts} +0 -0
  81. /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.js";
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 {!Object} state A JSON representation of a block to load.
30
- * @param {!Blockly.WorkspaceSvg} flyoutWorkspace The flyout's workspace.
31
- * @returns {!Blockly.BlockSvg} The newly created block.
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(state, flyoutWorkspace) {
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 {boolean} enabled True if recycling should be enabled.
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 {!Object} blockDefinition The definition to create a block from.
58
- * @returns {!Blockly.BlockSvg} The newly created block.
58
+ * @param blockDefinition The definition to create a block from.
59
+ * @returns The newly created block.
59
60
  */
60
- createBlock(blockDefinition) {
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 {!Object} The block definition to parse.
72
- * @returns {string} The block type.
74
+ * @param blockDefinition The block definition to parse.
75
+ * @returns The block type.
73
76
  */
74
- getTypeFromDefinition(blockDefinition) {
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 {!Blockly.BlockSvg} block The block to recycle.
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 {string} blockType The type of the block to try to recycle.
104
- * @returns {?Blockly.BlockSvg} The recycled block, or undefined if
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 {!Blockly.BlockSvg} block The block to check for recyclability.
117
- * @returns {boolean} True if the block can be recycled. False otherwise.
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 {!Blockly.BlockSvg} element The block to dispose of.
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
- * @param {!Blockly.Theme} The new theme to apply.
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 === "string") {
26
+ if (typeof colour !== "object") {
27
27
  const varKey = `--colour-${key}`;
28
28
  root.style.setProperty(varKey, colour);
29
29
  } else {
30
- theme.setBlockStyle(`${key}_selected`, {
31
- colourPrimary: colour.colourQuaternary ?? colour.colourTertiary,
32
- colourSecondary: colour.colourQuaternary ?? colour.colourTertiary,
33
- colourTertiary: colour.colourQuaternary ?? colour.colourTertiary,
34
- colourQuaternary: colour.colourQuaternary ?? colour.colourTertiary,
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
- drawStatementInput_(row) {
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.blockRendering.Drawer.prototype.drawRightSideRow_.call(this, row);
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 {!Blockly.BlockSvg} block The source block.
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.js";
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(true);
54
+ this.topRow.measure();
55
55
  }
56
56
  }
57
57
 
58
- getInRowSpacing_(prev, next) {
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_(prev, next) {
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_(row, elem) {
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.field instanceof Blockly.FieldImage &&
86
- elem.field === this.block_.inputList[0].fieldRow[0] &&
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 {!Blockly.clipboard.BlockCopyData} copyData The serialized block
17
- * state to create a copy of on the workspace.
18
- * @param {!Blockly.WorkspaceSvg} workspace The workspace to paste the block
19
- * onto.
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(copyData, workspace, coordinate) {
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 extends Blockly.icons.Icon {
16
- constructor(sourceBlock) {
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?.dispose();
184
- this.commentBubble = null;
185
- this.sourceBlock = null;
202
+ this.commentBubble.dispose();
186
203
  super.dispose();
187
204
  }
188
205
  }