scratch-blocks 2.0.2 → 2.0.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.
Files changed (275) hide show
  1. package/.nvmrc +1 -1
  2. package/commitlint.config.js +2 -2
  3. package/dist/main.mjs +1 -2
  4. package/dist/types/msg/scratch_msgs.d.ts.map +1 -1
  5. package/dist/types/src/block_reporting.d.ts.map +1 -1
  6. package/dist/types/src/blocks/colour.d.ts +0 -19
  7. package/dist/types/src/blocks/colour.d.ts.map +1 -1
  8. package/dist/types/src/blocks/control.d.ts +0 -19
  9. package/dist/types/src/blocks/control.d.ts.map +1 -1
  10. package/dist/types/src/blocks/data.d.ts +0 -19
  11. package/dist/types/src/blocks/data.d.ts.map +1 -1
  12. package/dist/types/src/blocks/event.d.ts +0 -19
  13. package/dist/types/src/blocks/event.d.ts.map +1 -1
  14. package/dist/types/src/blocks/looks.d.ts +0 -19
  15. package/dist/types/src/blocks/looks.d.ts.map +1 -1
  16. package/dist/types/src/blocks/math.d.ts +0 -19
  17. package/dist/types/src/blocks/math.d.ts.map +1 -1
  18. package/dist/types/src/blocks/matrix.d.ts +0 -19
  19. package/dist/types/src/blocks/matrix.d.ts.map +1 -1
  20. package/dist/types/src/blocks/motion.d.ts +0 -19
  21. package/dist/types/src/blocks/motion.d.ts.map +1 -1
  22. package/dist/types/src/blocks/note.d.ts +0 -19
  23. package/dist/types/src/blocks/note.d.ts.map +1 -1
  24. package/dist/types/src/blocks/operators.d.ts +0 -19
  25. package/dist/types/src/blocks/operators.d.ts.map +1 -1
  26. package/dist/types/src/blocks/procedures.d.ts +7 -10
  27. package/dist/types/src/blocks/procedures.d.ts.map +1 -1
  28. package/dist/types/src/blocks/sensing.d.ts +0 -19
  29. package/dist/types/src/blocks/sensing.d.ts.map +1 -1
  30. package/dist/types/src/blocks/sound.d.ts +0 -19
  31. package/dist/types/src/blocks/sound.d.ts.map +1 -1
  32. package/dist/types/src/blocks/text.d.ts +0 -19
  33. package/dist/types/src/blocks/text.d.ts.map +1 -1
  34. package/dist/types/src/blocks/vertical_extensions.d.ts +0 -19
  35. package/dist/types/src/blocks/vertical_extensions.d.ts.map +1 -1
  36. package/dist/types/src/checkable_continuous_flyout.d.ts +2 -7
  37. package/dist/types/src/checkable_continuous_flyout.d.ts.map +1 -1
  38. package/dist/types/src/checkbox_bubble.d.ts +13 -12
  39. package/dist/types/src/checkbox_bubble.d.ts.map +1 -1
  40. package/dist/types/src/colours.d.ts.map +1 -1
  41. package/dist/types/src/constants.d.ts +0 -7
  42. package/dist/types/src/constants.d.ts.map +1 -1
  43. package/dist/types/src/context_menu_items.d.ts +0 -5
  44. package/dist/types/src/context_menu_items.d.ts.map +1 -1
  45. package/dist/types/src/data_category.d.ts +2 -4
  46. package/dist/types/src/data_category.d.ts.map +1 -1
  47. package/dist/types/src/events/events_block_comment_base.d.ts +2 -3
  48. package/dist/types/src/events/events_block_comment_base.d.ts.map +1 -1
  49. package/dist/types/src/events/events_block_comment_change.d.ts +0 -5
  50. package/dist/types/src/events/events_block_comment_change.d.ts.map +1 -1
  51. package/dist/types/src/events/events_block_comment_collapse.d.ts +0 -5
  52. package/dist/types/src/events/events_block_comment_collapse.d.ts.map +1 -1
  53. package/dist/types/src/events/events_block_comment_create.d.ts +0 -5
  54. package/dist/types/src/events/events_block_comment_create.d.ts.map +1 -1
  55. package/dist/types/src/events/events_block_comment_delete.d.ts +0 -5
  56. package/dist/types/src/events/events_block_comment_delete.d.ts.map +1 -1
  57. package/dist/types/src/events/events_block_comment_move.d.ts +0 -5
  58. package/dist/types/src/events/events_block_comment_move.d.ts.map +1 -1
  59. package/dist/types/src/events/events_block_comment_resize.d.ts +0 -5
  60. package/dist/types/src/events/events_block_comment_resize.d.ts.map +1 -1
  61. package/dist/types/src/events/events_block_drag_end.d.ts +1 -2
  62. package/dist/types/src/events/events_block_drag_end.d.ts.map +1 -1
  63. package/dist/types/src/events/events_block_drag_outside.d.ts +1 -2
  64. package/dist/types/src/events/events_block_drag_outside.d.ts.map +1 -1
  65. package/dist/types/src/events/events_scratch_variable_create.d.ts +0 -5
  66. package/dist/types/src/events/events_scratch_variable_create.d.ts.map +1 -1
  67. package/dist/types/src/fields/field_colour_slider.d.ts +7 -9
  68. package/dist/types/src/fields/field_colour_slider.d.ts.map +1 -1
  69. package/dist/types/src/fields/field_matrix.d.ts +0 -19
  70. package/dist/types/src/fields/field_matrix.d.ts.map +1 -1
  71. package/dist/types/src/fields/field_note.d.ts +8 -23
  72. package/dist/types/src/fields/field_note.d.ts.map +1 -1
  73. package/dist/types/src/fields/field_textinput_removable.d.ts +2 -4
  74. package/dist/types/src/fields/field_textinput_removable.d.ts.map +1 -1
  75. package/dist/types/src/fields/field_variable_getter.d.ts +0 -19
  76. package/dist/types/src/fields/field_variable_getter.d.ts.map +1 -1
  77. package/dist/types/src/fields/field_vertical_separator.d.ts +0 -19
  78. package/dist/types/src/fields/field_vertical_separator.d.ts.map +1 -1
  79. package/dist/types/src/fields/scratch_field_angle.d.ts +0 -19
  80. package/dist/types/src/fields/scratch_field_angle.d.ts.map +1 -1
  81. package/dist/types/src/fields/scratch_field_dropdown.d.ts +0 -5
  82. package/dist/types/src/fields/scratch_field_dropdown.d.ts.map +1 -1
  83. package/dist/types/src/fields/scratch_field_number.d.ts +0 -19
  84. package/dist/types/src/fields/scratch_field_number.d.ts.map +1 -1
  85. package/dist/types/src/fields/scratch_field_variable.d.ts +4 -7
  86. package/dist/types/src/fields/scratch_field_variable.d.ts.map +1 -1
  87. package/dist/types/src/flyout_checkbox_icon.d.ts +2 -3
  88. package/dist/types/src/flyout_checkbox_icon.d.ts.map +1 -1
  89. package/dist/types/src/glows.d.ts +1 -3
  90. package/dist/types/src/glows.d.ts.map +1 -1
  91. package/dist/types/src/index.d.ts +50 -55
  92. package/dist/types/src/index.d.ts.map +1 -1
  93. package/dist/types/src/procedures.d.ts +6 -8
  94. package/dist/types/src/procedures.d.ts.map +1 -1
  95. package/dist/types/src/recyclable_block_flyout_inflater.d.ts +3 -5
  96. package/dist/types/src/recyclable_block_flyout_inflater.d.ts.map +1 -1
  97. package/dist/types/src/renderer/bowler_hat.d.ts +2 -3
  98. package/dist/types/src/renderer/bowler_hat.d.ts.map +1 -1
  99. package/dist/types/src/renderer/cat/cat_face.d.ts +6 -5
  100. package/dist/types/src/renderer/cat/cat_face.d.ts.map +1 -1
  101. package/dist/types/src/renderer/cat/constants.d.ts +2 -2
  102. package/dist/types/src/renderer/cat/constants.d.ts.map +1 -1
  103. package/dist/types/src/renderer/cat/drawer.d.ts +3 -4
  104. package/dist/types/src/renderer/cat/drawer.d.ts.map +1 -1
  105. package/dist/types/src/renderer/cat/path_object.d.ts +2 -3
  106. package/dist/types/src/renderer/cat/path_object.d.ts.map +1 -1
  107. package/dist/types/src/renderer/cat/render_info.d.ts +3 -4
  108. package/dist/types/src/renderer/cat/render_info.d.ts.map +1 -1
  109. package/dist/types/src/renderer/cat/renderer.d.ts +6 -7
  110. package/dist/types/src/renderer/cat/renderer.d.ts.map +1 -1
  111. package/dist/types/src/renderer/constants.d.ts +4 -4
  112. package/dist/types/src/renderer/constants.d.ts.map +1 -1
  113. package/dist/types/src/renderer/drawer.d.ts +5 -4
  114. package/dist/types/src/renderer/drawer.d.ts.map +1 -1
  115. package/dist/types/src/renderer/path_object.d.ts +1 -3
  116. package/dist/types/src/renderer/path_object.d.ts.map +1 -1
  117. package/dist/types/src/renderer/render_info.d.ts +3 -4
  118. package/dist/types/src/renderer/render_info.d.ts.map +1 -1
  119. package/dist/types/src/renderer/renderer.d.ts +8 -15
  120. package/dist/types/src/renderer/renderer.d.ts.map +1 -1
  121. package/dist/types/src/scratch_block_paster.d.ts +0 -5
  122. package/dist/types/src/scratch_block_paster.d.ts.map +1 -1
  123. package/dist/types/src/scratch_blocks_utils.d.ts +0 -20
  124. package/dist/types/src/scratch_blocks_utils.d.ts.map +1 -1
  125. package/dist/types/src/scratch_comment_bubble.d.ts +1 -4
  126. package/dist/types/src/scratch_comment_bubble.d.ts.map +1 -1
  127. package/dist/types/src/scratch_comment_icon.d.ts +2 -3
  128. package/dist/types/src/scratch_comment_icon.d.ts.map +1 -1
  129. package/dist/types/src/scratch_connection_checker.d.ts +0 -5
  130. package/dist/types/src/scratch_connection_checker.d.ts.map +1 -1
  131. package/dist/types/src/scratch_continuous_category.d.ts +5 -5
  132. package/dist/types/src/scratch_continuous_category.d.ts.map +1 -1
  133. package/dist/types/src/scratch_continuous_toolbox.d.ts +3 -6
  134. package/dist/types/src/scratch_continuous_toolbox.d.ts.map +1 -1
  135. package/dist/types/src/scratch_dragger.d.ts +3 -12
  136. package/dist/types/src/scratch_dragger.d.ts.map +1 -1
  137. package/dist/types/src/scratch_insertion_marker_previewer.d.ts +0 -5
  138. package/dist/types/src/scratch_insertion_marker_previewer.d.ts.map +1 -1
  139. package/dist/types/src/scratch_variable_map.d.ts +0 -5
  140. package/dist/types/src/scratch_variable_map.d.ts.map +1 -1
  141. package/dist/types/src/scratch_variable_model.d.ts +1 -2
  142. package/dist/types/src/scratch_variable_model.d.ts.map +1 -1
  143. package/dist/types/src/scratch_zoom_controls.d.ts +4 -6
  144. package/dist/types/src/scratch_zoom_controls.d.ts.map +1 -1
  145. package/dist/types/src/shadows.d.ts +2 -2
  146. package/dist/types/src/shadows.d.ts.map +1 -1
  147. package/dist/types/src/status_indicator_label.d.ts +4 -6
  148. package/dist/types/src/status_indicator_label.d.ts.map +1 -1
  149. package/dist/types/src/status_indicator_label_flyout_inflater.d.ts +1 -6
  150. package/dist/types/src/status_indicator_label_flyout_inflater.d.ts.map +1 -1
  151. package/dist/types/src/variables.d.ts +4 -8
  152. package/dist/types/src/variables.d.ts.map +1 -1
  153. package/dist/types/src/xml.d.ts +2 -3
  154. package/dist/types/src/xml.d.ts.map +1 -1
  155. package/dist/types/tests/jsunit/block_test.d.ts.map +1 -1
  156. package/dist/types/tests/jsunit/connection_db_test.d.ts.map +1 -1
  157. package/dist/types/tests/jsunit/connection_test.d.ts.map +1 -1
  158. package/dist/types/tests/jsunit/event_test.d.ts.map +1 -1
  159. package/dist/types/tests/jsunit/extensions_test.d.ts.map +1 -1
  160. package/dist/types/tests/jsunit/field_number_test.d.ts.map +1 -1
  161. package/dist/types/tests/jsunit/field_test.d.ts.map +1 -1
  162. package/dist/types/tests/jsunit/field_variable_getter_test.d.ts.map +1 -1
  163. package/dist/types/tests/jsunit/field_variable_test.d.ts.map +1 -1
  164. package/dist/types/tests/jsunit/gesture_test.d.ts.map +1 -1
  165. package/dist/types/tests/jsunit/input_test.d.ts +1 -0
  166. package/dist/types/tests/jsunit/input_test.d.ts.map +1 -1
  167. package/dist/types/tests/jsunit/json_test.d.ts.map +1 -1
  168. package/dist/types/tests/jsunit/names_test.d.ts.map +1 -1
  169. package/dist/types/tests/jsunit/procedure_test.d.ts.map +1 -1
  170. package/dist/types/tests/jsunit/scratch_block_comment_test.d.ts.map +1 -1
  171. package/dist/types/tests/jsunit/svg_test.d.ts.map +1 -1
  172. package/dist/types/tests/jsunit/test_utilities.d.ts.map +1 -1
  173. package/dist/types/tests/jsunit/utils_test.d.ts.map +1 -1
  174. package/dist/types/tests/jsunit/variable_map_test.d.ts.map +1 -1
  175. package/dist/types/tests/jsunit/variable_model_test.d.ts.map +1 -1
  176. package/dist/types/tests/jsunit/widget_div_test.d.ts.map +1 -1
  177. package/dist/types/tests/jsunit/workspace_comment_test.d.ts.map +1 -1
  178. package/dist/types/tests/jsunit/workspace_test.d.ts.map +1 -1
  179. package/dist/types/tests/jsunit/workspace_undo_redo_test.d.ts.map +1 -1
  180. package/dist/types/tests/jsunit/xml_test.d.ts.map +1 -1
  181. package/dist/types/tests/workspace_svg/workspace_svg_test.d.ts.map +1 -1
  182. package/eslint.config.mjs +69 -0
  183. package/i18n/create_scratch_msgs.js +44 -45
  184. package/i18n/js_to_json.js +40 -32
  185. package/i18n/json_to_js.js +37 -37
  186. package/i18n/sync_tx_translations.js +64 -65
  187. package/i18n/test_scratch_msgs.js +66 -63
  188. package/msg/js/en.js +289 -287
  189. package/msg/json/en.json +284 -284
  190. package/msg/messages.js +289 -287
  191. package/msg/scratch_msgs.js +22959 -22970
  192. package/package.json +13 -10
  193. package/prettier.config.mjs +3 -0
  194. package/release.config.js +7 -7
  195. package/renovate.json5 +7 -9
  196. package/src/block_reporting.ts +15 -18
  197. package/src/blocks/colour.ts +12 -15
  198. package/src/blocks/control.ts +167 -177
  199. package/src/blocks/data.ts +225 -292
  200. package/src/blocks/event.ts +121 -123
  201. package/src/blocks/looks.ts +165 -167
  202. package/src/blocks/math.ts +44 -46
  203. package/src/blocks/matrix.ts +11 -13
  204. package/src/blocks/motion.ts +151 -153
  205. package/src/blocks/note.ts +11 -13
  206. package/src/blocks/operators.ts +158 -160
  207. package/src/blocks/procedures.ts +488 -536
  208. package/src/blocks/sensing.ts +163 -165
  209. package/src/blocks/sound.ts +58 -60
  210. package/src/blocks/text.ts +10 -12
  211. package/src/blocks/vertical_extensions.ts +86 -102
  212. package/src/checkable_continuous_flyout.ts +25 -42
  213. package/src/checkbox_bubble.ts +83 -100
  214. package/src/colours.ts +35 -37
  215. package/src/constants.ts +22 -29
  216. package/src/context_menu_items.ts +56 -81
  217. package/src/css.ts +3 -4
  218. package/src/data_category.ts +136 -250
  219. package/src/events/events_block_comment_base.ts +21 -31
  220. package/src/events/events_block_comment_change.ts +21 -42
  221. package/src/events/events_block_comment_collapse.ts +22 -43
  222. package/src/events/events_block_comment_create.ts +29 -46
  223. package/src/events/events_block_comment_delete.ts +10 -19
  224. package/src/events/events_block_comment_move.ts +27 -52
  225. package/src/events/events_block_comment_resize.ts +28 -55
  226. package/src/events/events_block_drag_end.ts +16 -26
  227. package/src/events/events_block_drag_outside.ts +12 -22
  228. package/src/events/events_scratch_variable_create.ts +33 -56
  229. package/src/fields/field_colour_slider.ts +173 -228
  230. package/src/fields/field_matrix.ts +200 -269
  231. package/src/fields/field_note.ts +272 -377
  232. package/src/fields/field_textinput_removable.ts +25 -40
  233. package/src/fields/field_variable_getter.ts +26 -31
  234. package/src/fields/field_vertical_separator.ts +19 -24
  235. package/src/fields/scratch_field_angle.ts +150 -186
  236. package/src/fields/scratch_field_dropdown.ts +15 -19
  237. package/src/fields/scratch_field_number.ts +123 -180
  238. package/src/fields/scratch_field_variable.ts +52 -73
  239. package/src/flyout_checkbox_icon.ts +18 -28
  240. package/src/glows.ts +51 -58
  241. package/src/index.ts +119 -133
  242. package/src/procedures.ts +144 -211
  243. package/src/recyclable_block_flyout_inflater.ts +14 -25
  244. package/src/renderer/bowler_hat.ts +6 -8
  245. package/src/renderer/cat/cat_face.ts +98 -99
  246. package/src/renderer/cat/constants.ts +67 -87
  247. package/src/renderer/cat/drawer.ts +21 -27
  248. package/src/renderer/cat/path_object.ts +3 -5
  249. package/src/renderer/cat/render_info.ts +5 -8
  250. package/src/renderer/cat/renderer.ts +11 -15
  251. package/src/renderer/constants.ts +34 -49
  252. package/src/renderer/drawer.ts +35 -51
  253. package/src/renderer/path_object.ts +13 -15
  254. package/src/renderer/render_info.ts +36 -56
  255. package/src/renderer/renderer.ts +16 -29
  256. package/src/scratch_block_paster.ts +12 -20
  257. package/src/scratch_blocks_utils.ts +4 -7
  258. package/src/scratch_comment_bubble.ts +70 -101
  259. package/src/scratch_comment_icon.ts +74 -123
  260. package/src/scratch_connection_checker.ts +22 -17
  261. package/src/scratch_continuous_category.ts +24 -28
  262. package/src/scratch_continuous_toolbox.ts +20 -27
  263. package/src/scratch_dragger.ts +54 -86
  264. package/src/scratch_insertion_marker_previewer.ts +6 -11
  265. package/src/scratch_variable_map.ts +5 -12
  266. package/src/scratch_variable_model.ts +4 -11
  267. package/src/scratch_zoom_controls.ts +101 -156
  268. package/src/shadows.ts +32 -37
  269. package/src/status_indicator_label.ts +54 -67
  270. package/src/status_indicator_label_flyout_inflater.ts +11 -21
  271. package/src/variables.ts +89 -138
  272. package/src/xml.ts +21 -35
  273. package/tsconfig.json +2 -6
  274. package/types/continuous-toolbox.d.ts +1 -1
  275. package/dist/main.mjs.LICENSE.txt +0 -163
@@ -1,5 +1,4 @@
1
1
  /**
2
- * @license
3
2
  * Visual Blocks Editor
4
3
  *
5
4
  * Copyright 2012 Google Inc.
@@ -17,32 +16,66 @@
17
16
  * See the License for the specific language governing permissions and
18
17
  * limitations under the License.
19
18
  */
20
-
21
19
  /**
22
- * @fileoverview Procedure blocks for Scratch.
20
+ * @file Procedure blocks for Scratch.
23
21
  */
24
-
25
- import * as Blockly from "blockly/core";
26
- import { FieldTextInputRemovable } from "../fields/field_textinput_removable";
27
- import type { ScratchDragger } from "../scratch_dragger";
22
+ import * as Blockly from 'blockly/core'
23
+ import { FieldTextInputRemovable } from '../fields/field_textinput_removable'
24
+ import type { ScratchDragger } from '../scratch_dragger'
28
25
 
29
26
  /**
30
27
  * An object mapping argument IDs to blocks and shadow DOMs.
31
28
  */
32
- type ConnectionMap = {
33
- [key: string]: {
34
- shadow: Element;
35
- block: Blockly.BlockSvg;
36
- } | null;
37
- };
29
+ type ConnectionMap = Record<
30
+ string,
31
+ {
32
+ shadow: Element
33
+ block: Blockly.BlockSvg
34
+ } | null
35
+ >
38
36
 
39
37
  /**
40
38
  * Possible types for procedure arguments.
41
39
  */
42
40
  enum ArgumentType {
43
- STRING = "s",
44
- NUMBER = "n",
45
- BOOLEAN = "b",
41
+ STRING = 's',
42
+ NUMBER = 'n',
43
+ BOOLEAN = 'b',
44
+ }
45
+
46
+ /**
47
+ * A drag strategy for the procedures_prototype block that delegates all drag
48
+ * operations to its parent (the procedures_definition block). This lets the
49
+ * prototype act as a non-shadow block (so its argument-reporter children can
50
+ * also be non-shadow and therefore clickable/draggable) while still causing
51
+ * the entire definition to move when the prototype area is dragged.
52
+ */
53
+ class DelegateToParentDraggable implements Blockly.IDraggable {
54
+ constructor(private block: Blockly.BlockSvg) {}
55
+
56
+ isMovable(): boolean {
57
+ return this.block.getParent()?.isMovable() ?? false
58
+ }
59
+
60
+ startDrag(e: PointerEvent) {
61
+ this.block.getParent()?.startDrag(e)
62
+ }
63
+
64
+ drag(newLoc: Blockly.utils.Coordinate, e?: PointerEvent) {
65
+ this.block.getParent()?.drag(newLoc, e)
66
+ }
67
+
68
+ endDrag(e: PointerEvent) {
69
+ this.block.getParent()?.endDrag(e)
70
+ }
71
+
72
+ revertDrag() {
73
+ this.block.getParent()?.revertDrag()
74
+ }
75
+
76
+ getRelativeToSurfaceXY() {
77
+ return (this.block.getParent() ?? this.block).getRelativeToSurfaceXY()
78
+ }
46
79
  }
47
80
 
48
81
  /**
@@ -52,66 +85,61 @@ class DuplicateOnDragDraggable implements Blockly.IDraggable {
52
85
  /**
53
86
  * The newly-created duplicate block.
54
87
  */
55
- private copy?: Blockly.BlockSvg;
88
+ private copy?: Blockly.BlockSvg
56
89
  constructor(private block: Blockly.BlockSvg) {}
57
90
 
58
91
  /**
59
- * Returns whether or not this draggable is movable. */
92
+ * Returns whether or not this draggable is movable.
93
+ * @returns Always true.
94
+ */
60
95
  isMovable(): boolean {
61
- return true;
96
+ return true
62
97
  }
63
98
 
64
99
  /**
65
100
  * Handles the start of a drag.
66
- *
67
101
  * @param e The event that triggered the drag.
68
102
  */
69
103
  startDrag(e: PointerEvent) {
70
- const data = this.block.toCopyData();
104
+ const data = this.block.toCopyData()
71
105
  if (!data) {
72
106
  console.warn(
73
- "DuplicateOnDragDraggable.startDrag: failed to serialize block for copy",
107
+ 'DuplicateOnDragDraggable.startDrag: failed to serialize block for copy',
74
108
  this.block.type,
75
- this.block.id
76
- );
77
- return;
109
+ this.block.id,
110
+ )
111
+ return
78
112
  }
79
- this.copy = Blockly.clipboard.paste(
80
- data,
81
- this.block.workspace
82
- ) as Blockly.BlockSvg;
83
- this.copy.startDrag(e);
113
+ this.copy = Blockly.clipboard.paste(data, this.block.workspace) as Blockly.BlockSvg
114
+ this.copy.setDeletable(true)
115
+ this.copy.setDragStrategy(new Blockly.dragging.BlockDragStrategy(this.copy))
116
+ this.copy.startDrag(e)
84
117
  }
85
118
 
86
119
  drag(newLoc: Blockly.utils.Coordinate, e?: PointerEvent) {
87
- const gesture = this.block.workspace.getGesture(e);
120
+ const gesture = this.block.workspace.getGesture(e)
88
121
  if (!gesture || !this.copy) {
89
- console.warn(
90
- "DuplicateOnDragDraggable.drag: missing gesture or copied block",
91
- {
92
- hasGesture: Boolean(gesture),
93
- hasCopy: Boolean(this.copy),
94
- blockId: this.block.id,
95
- }
96
- );
97
- return;
122
+ console.warn('DuplicateOnDragDraggable.drag: missing gesture or copied block', {
123
+ hasGesture: Boolean(gesture),
124
+ hasCopy: Boolean(this.copy),
125
+ blockId: this.block.id,
126
+ })
127
+ return
98
128
  }
99
- (gesture.getCurrentDragger() as ScratchDragger).setDraggable(this.copy);
100
- this.copy.drag(newLoc, e);
129
+ ;(gesture.getCurrentDragger() as ScratchDragger).setDraggable(this.copy)
130
+ this.copy.drag(newLoc, e)
101
131
  }
102
132
 
103
133
  endDrag(e: PointerEvent) {
104
- this.copy?.endDrag(e);
134
+ this.copy?.endDrag(e)
105
135
  }
106
136
 
107
137
  revertDrag() {
108
- this.copy?.dispose();
138
+ this.copy?.dispose()
109
139
  }
110
140
 
111
141
  getRelativeToSurfaceXY() {
112
- return this.copy
113
- ? this.copy.getRelativeToSurfaceXY()
114
- : this.block.getRelativeToSurfaceXY();
142
+ return this.copy ? this.copy.getRelativeToSurfaceXY() : this.block.getRelativeToSurfaceXY()
115
143
  }
116
144
  }
117
145
 
@@ -120,85 +148,71 @@ class DuplicateOnDragDraggable implements Blockly.IDraggable {
120
148
  /**
121
149
  * Create XML to represent the (non-editable) name and arguments of a procedure
122
150
  * call block.
123
- *
124
151
  * @returns XML storage element.
125
152
  */
126
153
  function callerMutationToDom(this: ProcedureCallBlock): Element {
127
- const container = document.createElement("mutation");
128
- container.setAttribute("proccode", this.procCode_);
129
- container.setAttribute("argumentids", JSON.stringify(this.argumentIds_));
130
- container.setAttribute("warp", JSON.stringify(this.warp_));
131
- return container;
154
+ const container = document.createElement('mutation')
155
+ container.setAttribute('proccode', this.procCode_)
156
+ container.setAttribute('argumentids', JSON.stringify(this.argumentIds_))
157
+ container.setAttribute('warp', JSON.stringify(this.warp_))
158
+ return container
132
159
  }
133
160
 
134
161
  /**
135
162
  * Parse XML to restore the (non-editable) name and arguments of a procedure
136
163
  * call block.
137
- *
138
164
  * @param xmlElement XML storage element.
139
165
  */
140
166
  function callerDomToMutation(this: ProcedureCallBlock, xmlElement: Element) {
141
- this.procCode_ = xmlElement.getAttribute("proccode")!;
142
- this.generateShadows_ = JSON.parse(
143
- xmlElement.getAttribute("generateshadows")!
144
- );
145
- this.argumentIds_ = JSON.parse(xmlElement.getAttribute("argumentids")!);
146
- this.warp_ = JSON.parse(xmlElement.getAttribute("warp")!);
147
- this.updateDisplay_();
167
+ this.procCode_ = xmlElement.getAttribute('proccode')!
168
+ this.generateShadows_ = JSON.parse(xmlElement.getAttribute('generateshadows')!)
169
+ this.argumentIds_ = JSON.parse(xmlElement.getAttribute('argumentids')!)
170
+ this.warp_ = JSON.parse(xmlElement.getAttribute('warp')!)
171
+ this.updateDisplay_()
148
172
  }
149
173
 
150
174
  /**
151
175
  * Create XML to represent the (non-editable) name and arguments of a
152
176
  * procedures_prototype block or a procedures_declaration block.
153
- *
154
177
  * @param opt_generateShadows Whether to include the generateshadows flag in the
155
178
  * generated XML. False if not provided.
156
179
  * @returns XML storage element.
157
180
  */
158
181
  function definitionMutationToDom(
159
182
  this: ProcedurePrototypeBlock | ProcedureDeclarationBlock,
160
- opt_generateShadows?: boolean
183
+ opt_generateShadows?: boolean,
161
184
  ): Element {
162
- const container = document.createElement("mutation");
185
+ const container = document.createElement('mutation')
163
186
 
164
187
  if (opt_generateShadows) {
165
- container.setAttribute("generateshadows", "true");
188
+ container.setAttribute('generateshadows', 'true')
166
189
  }
167
- container.setAttribute("proccode", this.procCode_);
168
- container.setAttribute("argumentids", JSON.stringify(this.argumentIds_));
169
- container.setAttribute("argumentnames", JSON.stringify(this.displayNames_));
170
- container.setAttribute(
171
- "argumentdefaults",
172
- JSON.stringify(this.argumentDefaults_)
173
- );
174
- container.setAttribute("warp", JSON.stringify(this.warp_));
175
- return container;
190
+ container.setAttribute('proccode', this.procCode_)
191
+ container.setAttribute('argumentids', JSON.stringify(this.argumentIds_))
192
+ container.setAttribute('argumentnames', JSON.stringify(this.displayNames_))
193
+ container.setAttribute('argumentdefaults', JSON.stringify(this.argumentDefaults_))
194
+ container.setAttribute('warp', JSON.stringify(this.warp_))
195
+ return container
176
196
  }
177
197
 
178
198
  /**
179
199
  * Parse XML to restore the (non-editable) name and arguments of a
180
200
  * procedures_prototype block or a procedures_declaration block.
181
- *
182
201
  * @param xmlElement XML storage element.
183
202
  */
184
- function definitionDomToMutation(
185
- this: ProcedurePrototypeBlock | ProcedureDeclarationBlock,
186
- xmlElement: Element
187
- ) {
188
- this.procCode_ = xmlElement.getAttribute("proccode")!;
189
- this.warp_ = JSON.parse(xmlElement.getAttribute("warp")!);
190
-
191
- const prevArgIds = this.argumentIds_;
192
- const prevDisplayNames = this.displayNames_;
193
-
194
- this.argumentIds_ = JSON.parse(xmlElement.getAttribute("argumentids")!);
195
- this.displayNames_ = JSON.parse(xmlElement.getAttribute("argumentnames")!);
196
- this.argumentDefaults_ = JSON.parse(
197
- xmlElement.getAttribute("argumentdefaults")!
198
- );
199
- this.updateDisplay_();
200
- if ("updateArgumentReporterNames_" in this) {
201
- this.updateArgumentReporterNames_(prevArgIds, prevDisplayNames);
203
+ function definitionDomToMutation(this: ProcedurePrototypeBlock | ProcedureDeclarationBlock, xmlElement: Element) {
204
+ this.procCode_ = xmlElement.getAttribute('proccode')!
205
+ this.warp_ = JSON.parse(xmlElement.getAttribute('warp')!)
206
+
207
+ const prevArgIds = this.argumentIds_
208
+ const prevDisplayNames = this.displayNames_
209
+
210
+ this.argumentIds_ = JSON.parse(xmlElement.getAttribute('argumentids')!)
211
+ this.displayNames_ = JSON.parse(xmlElement.getAttribute('argumentnames')!)
212
+ this.argumentDefaults_ = JSON.parse(xmlElement.getAttribute('argumentdefaults')!)
213
+ this.updateDisplay_()
214
+ if ('updateArgumentReporterNames_' in this) {
215
+ this.updateArgumentReporterNames_(prevArgIds, prevDisplayNames)
202
216
  }
203
217
  }
204
218
 
@@ -209,11 +223,10 @@ function definitionDomToMutation(
209
223
  /**
210
224
  * Returns the name of the procedure this block calls, or the empty string if
211
225
  * it has not yet been set.
212
- *
213
226
  * @returns Procedure name.
214
227
  */
215
228
  function getProcCode(this: ProcedureBlock): string {
216
- return this.procCode_;
229
+ return this.procCode_
217
230
  }
218
231
 
219
232
  /**
@@ -221,10 +234,10 @@ function getProcCode(this: ProcedureBlock): string {
221
234
  * mutation.
222
235
  */
223
236
  function updateDisplay_(this: ProcedureBlock) {
224
- const connectionMap = this.disconnectOldBlocks_();
225
- this.removeAllInputs_();
226
- this.createAllInputs_(connectionMap);
227
- this.deleteShadows_(connectionMap);
237
+ const connectionMap = this.disconnectOldBlocks_()
238
+ this.removeAllInputs_()
239
+ this.createAllInputs_(connectionMap)
240
+ this.disposeObsoleteBlocks_(connectionMap)
228
241
  }
229
242
 
230
243
  /**
@@ -232,27 +245,26 @@ function updateDisplay_(this: ProcedureBlock) {
232
245
  * in case they can be reattached later. Also save the shadow DOM if it exists.
233
246
  * The result is a map from argument ID to information that was associated with
234
247
  * that argument at the beginning of the mutation.
235
- *
236
248
  * @returns An object mapping argument IDs to blocks and shadow DOMs.
237
249
  */
238
250
  function disconnectOldBlocks_(this: ProcedureBlock): ConnectionMap {
239
251
  // Remove old stuff
240
- const connectionMap: ConnectionMap = {};
252
+ const connectionMap: ConnectionMap = {}
241
253
  for (const input of this.inputList) {
242
254
  if (input.connection) {
243
- const target = input.connection.targetBlock() as Blockly.BlockSvg;
255
+ const target = input.connection.targetBlock() as Blockly.BlockSvg
244
256
  const saveInfo = {
245
- shadow: input.connection.getShadowDom(true) as Element,
257
+ shadow: input.connection.getShadowDom(true)!,
246
258
  block: target,
247
- };
248
- connectionMap[input.name] = saveInfo;
259
+ }
260
+ connectionMap[input.name] = saveInfo
249
261
 
250
262
  if (target) {
251
- input.connection.disconnect();
263
+ input.connection.disconnect()
252
264
  }
253
265
  }
254
266
  }
255
- return connectionMap;
267
+ return connectionMap
256
268
  }
257
269
 
258
270
  /**
@@ -262,29 +274,26 @@ function disconnectOldBlocks_(this: ProcedureBlock): ConnectionMap {
262
274
  function removeAllInputs_(this: ProcedureBlock) {
263
275
  // Delete inputs directly instead of with block.removeInput to avoid splicing
264
276
  // out of the input list at every index.
265
- this.inputList.forEach((input: Blockly.Input) => input.dispose());
266
- this.inputList = [];
277
+ this.inputList.forEach((input: Blockly.Input) => input.dispose())
278
+ this.inputList = []
267
279
  }
268
280
 
269
281
  /**
270
282
  * Create all inputs specified by the new procCode, and populate them with
271
283
  * shadow blocks or reconnected old blocks as appropriate.
272
- *
273
284
  * @param connectionMap An object mapping argument IDs to blocks and shadow DOMs.
274
285
  */
275
286
  function createAllInputs_(this: ProcedureBlock, connectionMap: ConnectionMap) {
276
287
  // Split the proc into components, by %n, %b, and %s (ignoring escaped).
277
- const procComponents = this.procCode_
278
- .split(/(?=[^\\]%[nbs])/)
279
- .map(function (c: string) {
280
- return c.trim(); // Strip whitespace.
281
- });
288
+ const procComponents = this.procCode_.split(/(?=[^\\]%[nbs])/).map(
289
+ (c: string) => c.trim(), // Strip whitespace.
290
+ )
282
291
  // Create arguments and labels as appropriate.
283
- let argumentCount = 0;
292
+ let argumentCount = 0
284
293
  for (const component of procComponents) {
285
- let labelText;
286
- if (component.substring(0, 1) === "%") {
287
- const argumentType = component.substring(1, 2);
294
+ let labelText
295
+ if (component.startsWith('%')) {
296
+ const argumentType = component.substring(1, 2)
288
297
  if (
289
298
  !(
290
299
  argumentType === ArgumentType.NUMBER ||
@@ -292,52 +301,47 @@ function createAllInputs_(this: ProcedureBlock, connectionMap: ConnectionMap) {
292
301
  argumentType === ArgumentType.STRING
293
302
  )
294
303
  ) {
295
- throw new Error(
296
- "Found an custom procedure with an invalid type: " + argumentType
297
- );
304
+ throw new Error('Found an custom procedure with an invalid type: ' + argumentType)
298
305
  }
299
- labelText = component.substring(2).trim();
306
+ labelText = component.substring(2).trim()
300
307
 
301
- const id = this.argumentIds_[argumentCount];
308
+ const id = this.argumentIds_[argumentCount]
302
309
 
303
- const input = this.appendValueInput(id);
310
+ const input = this.appendValueInput(id)
304
311
  if (argumentType === ArgumentType.BOOLEAN) {
305
- input.setCheck("Boolean");
312
+ input.setCheck('Boolean')
306
313
  }
307
- this.populateArgument_(
308
- argumentType,
309
- argumentCount,
310
- connectionMap,
311
- id,
312
- input
313
- );
314
- argumentCount++;
314
+ this.populateArgument_(argumentType, argumentCount, connectionMap, id, input)
315
+ argumentCount++
315
316
  } else {
316
- labelText = component.trim();
317
+ labelText = component.trim()
317
318
  }
318
- this.addProcedureLabel_(labelText.replace(/\\%/, "%"));
319
+ this.addProcedureLabel_(labelText.replace(/\\%/, '%'))
319
320
  }
320
321
  }
321
322
 
322
323
  /**
323
- * Delete all shadow blocks in the given map.
324
- *
324
+ * Dispose of blocks that were disconnected from the block (and not reconnected) during mutation.
325
+ * This includes:
326
+ * - shadow blocks for default argument values (on call blocks)
327
+ * - shadow argument editor blocks (on declaration blocks in the procedure editor)
328
+ * - non-shadow argument reporter blocks (on the prototype)
325
329
  * @param connectionMap An object mapping argument IDs to the blocks that were
326
330
  * connected to those IDs at the beginning of the mutation.
327
331
  */
328
- function deleteShadows_(this: ProcedureBlock, connectionMap: ConnectionMap) {
329
- // Get rid of all of the old shadow blocks if they aren't connected.
330
- if (connectionMap) {
331
- for (const id in connectionMap) {
332
- const saveInfo = connectionMap[id];
333
- if (saveInfo) {
334
- const block = saveInfo["block"];
335
- if (block && block.isShadow()) {
336
- block.dispose();
337
- connectionMap[id] = null;
338
- // At this point we know which shadow DOMs are about to be orphaned in
339
- // the VM. What do we do with that information?
340
- }
332
+ function disposeObsoleteBlocks_(this: ProcedureBlock, connectionMap: ConnectionMap) {
333
+ for (const id in connectionMap) {
334
+ const saveInfo = connectionMap[id]
335
+ if (saveInfo) {
336
+ const block = saveInfo.block
337
+ const isOrphanedArgumentReporter =
338
+ this.type === 'procedures_prototype' &&
339
+ (block.type === 'argument_reporter_string_number' || block.type === 'argument_reporter_boolean')
340
+ if (block.isShadow() || isOrphanedArgumentReporter) {
341
+ block.dispose()
342
+ connectionMap[id] = null
343
+ // At this point we know which shadow DOMs are about to be orphaned in
344
+ // the VM. What do we do with that information?
341
345
  }
342
346
  }
343
347
  }
@@ -347,104 +351,84 @@ function deleteShadows_(this: ProcedureBlock, connectionMap: ConnectionMap) {
347
351
  /**
348
352
  * Add a label field with the given text to a procedures_call or
349
353
  * procedures_prototype block.
350
- *
351
- * @param text The label text.
354
+ * @param text The string to display in the block's label field.
352
355
  */
353
- function addLabelField_(
354
- this: ProcedureCallBlock | ProcedurePrototypeBlock,
355
- text: string
356
- ) {
357
- this.appendDummyInput().appendField(text);
356
+ function addLabelField_(this: ProcedureCallBlock | ProcedurePrototypeBlock, text: string) {
357
+ this.appendDummyInput().appendField(text)
358
358
  }
359
359
 
360
360
  /**
361
361
  * Add a label editor with the given text to a procedures_declaration
362
362
  * block. Editing the text in the label editor updates the text of the
363
363
  * corresponding label fields on function calls.
364
- *
365
- * @param text The label text.
364
+ * @param text The initial string to show in the label editor.
366
365
  */
367
366
  function addLabelEditor_(this: ProcedureDeclarationBlock, text: string) {
368
367
  if (text) {
369
- this.appendDummyInput(Blockly.utils.idGenerator.genUid()).appendField(
370
- new FieldTextInputRemovable(text)
371
- );
368
+ this.appendDummyInput(Blockly.utils.idGenerator.genUid()).appendField(new FieldTextInputRemovable(text))
372
369
  }
373
370
  }
374
371
 
375
372
  /**
376
373
  * Build a DOM node representing a shadow block of the given type.
377
- *
378
374
  * @param type One of 's' (string) or 'n' (number).
379
375
  * @returns The DOM node representing the new shadow block.
380
376
  */
381
377
  function buildShadowDom_(type: ArgumentType): Element {
382
- const shadowDom = document.createElement("shadow");
383
- let shadowType, fieldName, fieldValue;
378
+ const shadowDom = document.createElement('shadow')
379
+ let shadowType, fieldName, fieldValue
384
380
  if (type === ArgumentType.NUMBER) {
385
- shadowType = "math_number";
386
- fieldName = "NUM";
387
- fieldValue = "1";
381
+ shadowType = 'math_number'
382
+ fieldName = 'NUM'
383
+ fieldValue = '1'
388
384
  } else {
389
- shadowType = "text";
390
- fieldName = "TEXT";
391
- fieldValue = "";
385
+ shadowType = 'text'
386
+ fieldName = 'TEXT'
387
+ fieldValue = ''
392
388
  }
393
- shadowDom.setAttribute("type", shadowType);
394
- const fieldDom = document.createElement("field");
395
- fieldDom.textContent = fieldValue;
396
- fieldDom.setAttribute("name", fieldName);
397
- shadowDom.appendChild(fieldDom);
398
- return shadowDom;
389
+ shadowDom.setAttribute('type', shadowType)
390
+ const fieldDom = document.createElement('field')
391
+ fieldDom.textContent = fieldValue
392
+ fieldDom.setAttribute('name', fieldName)
393
+ shadowDom.appendChild(fieldDom)
394
+ return shadowDom
399
395
  }
400
396
 
401
397
  /**
402
398
  * Create a new shadow block and attach it to the given input.
403
- *
404
399
  * @param input The value input to attach a block to.
405
400
  * @param argumentType One of 'b' (boolean), 's' (string) or
406
401
  * 'n' (number).
407
402
  */
408
- function attachShadow_(
409
- this: ProcedureCallBlock,
410
- input: Blockly.Input,
411
- argumentType: ArgumentType
412
- ) {
413
- if (
414
- argumentType === ArgumentType.NUMBER ||
415
- argumentType === ArgumentType.STRING
416
- ) {
417
- const blockType =
418
- argumentType === ArgumentType.NUMBER ? "math_number" : "text";
419
- Blockly.Events.disable();
420
- let newBlock;
403
+ function attachShadow_(this: ProcedureCallBlock, input: Blockly.Input, argumentType: ArgumentType) {
404
+ if (argumentType === ArgumentType.NUMBER || argumentType === ArgumentType.STRING) {
405
+ const blockType = argumentType === ArgumentType.NUMBER ? 'math_number' : 'text'
406
+ Blockly.Events.disable()
407
+ let newBlock
421
408
  try {
422
- newBlock = this.workspace.newBlock(blockType);
409
+ newBlock = this.workspace.newBlock(blockType)
423
410
  if (argumentType === ArgumentType.NUMBER) {
424
- newBlock.setFieldValue("1", "NUM");
411
+ newBlock.setFieldValue('1', 'NUM')
425
412
  } else {
426
- newBlock.setFieldValue("", "TEXT");
413
+ newBlock.setFieldValue('', 'TEXT')
427
414
  }
428
- newBlock.setShadow(true);
415
+ newBlock.setShadow(true)
429
416
  if (!this.isInsertionMarker()) {
430
- newBlock.initSvg();
431
- newBlock.render();
417
+ newBlock.initSvg()
418
+ newBlock.render()
432
419
  }
433
420
  } finally {
434
- Blockly.Events.enable();
421
+ Blockly.Events.enable()
435
422
  }
436
423
  if (Blockly.Events.isEnabled()) {
437
- Blockly.Events.fire(
438
- new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock)
439
- );
424
+ Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock))
440
425
  }
441
- newBlock.outputConnection!.connect(input.connection!);
426
+ newBlock.outputConnection.connect(input.connection!)
442
427
  }
443
428
  }
444
429
 
445
430
  /**
446
431
  * Create a new argument reporter block.
447
- *
448
432
  * @param argumentType One of 'b' (boolean), 's' (string) or
449
433
  * 'n' (number).
450
434
  * @param displayName The name of the argument as provided by the
@@ -454,42 +438,36 @@ function attachShadow_(
454
438
  function createArgumentReporter_(
455
439
  this: ProcedurePrototypeBlock,
456
440
  argumentType: ArgumentType,
457
- displayName: string
441
+ displayName: string,
458
442
  ): Blockly.BlockSvg {
459
- let blockType;
460
- if (
461
- argumentType === ArgumentType.NUMBER ||
462
- argumentType === ArgumentType.STRING
463
- ) {
464
- blockType = "argument_reporter_string_number";
443
+ let blockType
444
+ if (argumentType === ArgumentType.NUMBER || argumentType === ArgumentType.STRING) {
445
+ blockType = 'argument_reporter_string_number'
465
446
  } else {
466
- blockType = "argument_reporter_boolean";
447
+ blockType = 'argument_reporter_boolean'
467
448
  }
468
- Blockly.Events.disable();
469
- let newBlock;
449
+ Blockly.Events.disable()
450
+ let newBlock
470
451
  try {
471
- newBlock = this.workspace.newBlock(blockType);
472
- newBlock.setShadow(true);
473
- newBlock.setFieldValue(displayName, "VALUE");
452
+ newBlock = this.workspace.newBlock(blockType)
453
+ newBlock.setDeletable(false)
454
+ newBlock.setFieldValue(displayName, 'VALUE')
474
455
  if (!this.isInsertionMarker()) {
475
- newBlock.initSvg();
476
- newBlock.render();
456
+ newBlock.initSvg()
457
+ newBlock.render()
477
458
  }
478
459
  } finally {
479
- Blockly.Events.enable();
460
+ Blockly.Events.enable()
480
461
  }
481
462
  if (Blockly.Events.isEnabled()) {
482
- Blockly.Events.fire(
483
- new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock)
484
- );
463
+ Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock))
485
464
  }
486
- return newBlock;
465
+ return newBlock
487
466
  }
488
467
 
489
468
  /**
490
469
  * Populate the argument by attaching the correct child block or shadow to the
491
470
  * given input.
492
- *
493
471
  * @param type One of 'b' (boolean), 's' (string) or 'n' (number).
494
472
  * @param index The index of this argument into the argument id array.
495
473
  * @param connectionMap An object mapping argument IDs to blocks and shadow DOMs.
@@ -502,33 +480,32 @@ function populateArgumentOnCaller_(
502
480
  index: number,
503
481
  connectionMap: ConnectionMap,
504
482
  id: string,
505
- input: Blockly.Input
483
+ input: Blockly.Input,
506
484
  ) {
507
- let oldBlock: Blockly.BlockSvg | undefined;
508
- let oldShadow: Element | undefined;
485
+ let oldBlock: Blockly.BlockSvg | undefined
486
+ let oldShadow: Element | undefined
509
487
  if (connectionMap && id in connectionMap) {
510
- const saveInfo = connectionMap[id];
511
- oldBlock = saveInfo?.["block"];
512
- oldShadow = saveInfo?.["shadow"];
488
+ const saveInfo = connectionMap[id]
489
+ oldBlock = saveInfo?.block
490
+ oldShadow = saveInfo?.shadow
513
491
  }
514
492
 
515
493
  if (connectionMap && oldBlock) {
516
494
  // Reattach the old block and shadow DOM.
517
- connectionMap[input.name] = null;
518
- oldBlock.outputConnection!.connect(input.connection!);
495
+ connectionMap[input.name] = null
496
+ oldBlock.outputConnection.connect(input.connection!)
519
497
  if (type !== ArgumentType.BOOLEAN && this.generateShadows_) {
520
- const shadowDom = oldShadow || this.buildShadowDom_(type);
521
- input.connection!.setShadowDom(shadowDom);
498
+ const shadowDom = oldShadow || this.buildShadowDom_(type)
499
+ input.connection!.setShadowDom(shadowDom)
522
500
  }
523
501
  } else if (this.generateShadows_) {
524
- this.attachShadow_(input, type);
502
+ this.attachShadow_(input, type)
525
503
  }
526
504
  }
527
505
 
528
506
  /**
529
507
  * Populate the argument by attaching the correct argument reporter to the given
530
508
  * input.
531
- *
532
509
  * @param type One of 'b' (boolean), 's' (string) or 'n' (number).
533
510
  * @param index The index of this argument into the argument ID and
534
511
  * argument display name arrays.
@@ -542,37 +519,36 @@ function populateArgumentOnPrototype_(
542
519
  index: number,
543
520
  connectionMap: ConnectionMap,
544
521
  id: string,
545
- input: Blockly.Input
522
+ input: Blockly.Input,
546
523
  ) {
547
- let oldBlock: Blockly.BlockSvg | null = null;
524
+ let oldBlock: Blockly.BlockSvg | null = null
548
525
  if (connectionMap && id in connectionMap) {
549
- const saveInfo = connectionMap[id];
550
- oldBlock = saveInfo?.["block"] ?? null;
526
+ const saveInfo = connectionMap[id]
527
+ oldBlock = saveInfo?.block ?? null
551
528
  }
552
529
 
553
- const oldTypeMatches = checkOldTypeMatches_(oldBlock, type);
554
- const displayName = this.displayNames_[index];
530
+ const oldTypeMatches = checkOldTypeMatches_(oldBlock, type)
531
+ const displayName = this.displayNames_[index]
555
532
 
556
533
  // Decide which block to attach.
557
- let argumentReporter: Blockly.BlockSvg;
534
+ let argumentReporter: Blockly.BlockSvg
558
535
  if (connectionMap && oldBlock && oldTypeMatches) {
559
536
  // Update the text if needed. The old argument reporter is the same type,
560
537
  // and on the same input, but the argument's display name may have changed.
561
- argumentReporter = oldBlock;
562
- argumentReporter.setFieldValue(displayName, "VALUE");
563
- connectionMap[input.name] = null;
538
+ argumentReporter = oldBlock
539
+ argumentReporter.setFieldValue(displayName, 'VALUE')
540
+ connectionMap[input.name] = null
564
541
  } else {
565
- argumentReporter = this.createArgumentReporter_(type, displayName);
542
+ argumentReporter = this.createArgumentReporter_(type, displayName)
566
543
  }
567
544
 
568
545
  // Attach the block.
569
- input.connection!.connect(argumentReporter.outputConnection!);
546
+ input.connection!.connect(argumentReporter.outputConnection)
570
547
  }
571
548
 
572
549
  /**
573
550
  * Populate the argument by attaching the correct argument editor to the given
574
551
  * input.
575
- *
576
552
  * @param type One of 'b' (boolean), 's' (string) or 'n' (number).
577
553
  * @param index The index of this argument into the argument id and argument
578
554
  * display name arrays.
@@ -586,69 +562,61 @@ function populateArgumentOnDeclaration_(
586
562
  index: number,
587
563
  connectionMap: ConnectionMap,
588
564
  id: string,
589
- input: Blockly.Input
565
+ input: Blockly.Input,
590
566
  ) {
591
- let oldBlock: Blockly.BlockSvg | null = null;
567
+ let oldBlock: Blockly.BlockSvg | null = null
592
568
  if (connectionMap && id in connectionMap) {
593
- const saveInfo = connectionMap[id];
594
- oldBlock = saveInfo?.["block"] ?? null;
569
+ const saveInfo = connectionMap[id]
570
+ oldBlock = saveInfo?.block ?? null
595
571
  }
596
572
 
597
573
  // TODO: This always returns false, because it checks for argument reporter
598
574
  // blocks instead of argument editor blocks. Create a new version for argument
599
575
  // editors.
600
- const oldTypeMatches = checkOldTypeMatches_(oldBlock, type);
601
- const displayName = this.displayNames_[index];
576
+ const oldTypeMatches = checkOldTypeMatches_(oldBlock, type)
577
+ const displayName = this.displayNames_[index]
602
578
 
603
579
  // Decide which block to attach.
604
- let argumentEditor: Blockly.BlockSvg;
580
+ let argumentEditor: Blockly.BlockSvg
605
581
  if (oldBlock && oldTypeMatches) {
606
- argumentEditor = oldBlock;
607
- oldBlock.setFieldValue(displayName, "TEXT");
608
- connectionMap[input.name] = null;
582
+ argumentEditor = oldBlock
583
+ oldBlock.setFieldValue(displayName, 'TEXT')
584
+ connectionMap[input.name] = null
609
585
  } else {
610
- argumentEditor = this.createArgumentEditor_(type, displayName);
586
+ argumentEditor = this.createArgumentEditor_(type, displayName)
611
587
  }
612
588
 
613
589
  // Attach the block.
614
- input.connection!.connect(argumentEditor.outputConnection!);
590
+ input.connection!.connect(argumentEditor.outputConnection)
615
591
  }
616
592
 
617
593
  /**
618
594
  * Check whether the type of the old block corresponds to the given argument
619
595
  * type.
620
- *
621
596
  * @param oldBlock The old block to check.
622
597
  * @param type The argument type. One of 'n', 'n', or 's'.
623
598
  * @returns True if the type matches, false otherwise.
624
599
  */
625
- function checkOldTypeMatches_(
626
- oldBlock: Blockly.BlockSvg | null,
627
- type: string
628
- ): boolean {
600
+ function checkOldTypeMatches_(oldBlock: Blockly.BlockSvg | null, type: string): boolean {
629
601
  if (!oldBlock) {
630
- return false;
602
+ return false
631
603
  }
632
604
  if (
633
605
  (type === ArgumentType.NUMBER || type === ArgumentType.STRING) &&
634
- oldBlock.type === "argument_reporter_string_number"
606
+ oldBlock.type === 'argument_reporter_string_number'
635
607
  ) {
636
- return true;
608
+ return true
637
609
  }
638
- if (
639
- type === ArgumentType.BOOLEAN &&
640
- oldBlock.type === "argument_reporter_boolean"
641
- ) {
642
- return true;
610
+ if (type === ArgumentType.BOOLEAN && oldBlock.type === 'argument_reporter_boolean') {
611
+ return true
643
612
  }
644
- return false;
613
+ return false
645
614
  }
646
615
 
647
616
  /**
648
617
  * Create an argument editor.
649
618
  * An argument editor is a shadow block with a single text field, which is used
650
619
  * to set the display name of the argument.
651
- *
652
620
  * @param argumentType One of 'b' (boolean), 's' (string) or 'n' (number).
653
621
  * @param displayName The display name of this argument, which is the text of
654
622
  * the field on the shadow block.
@@ -657,34 +625,29 @@ function checkOldTypeMatches_(
657
625
  function createArgumentEditor_(
658
626
  this: ProcedureDeclarationBlock,
659
627
  argumentType: ArgumentType,
660
- displayName: string
628
+ displayName: string,
661
629
  ): Blockly.BlockSvg {
662
- Blockly.Events.disable();
663
- let newBlock;
630
+ Blockly.Events.disable()
631
+ let newBlock
664
632
  try {
665
- if (
666
- argumentType === ArgumentType.NUMBER ||
667
- argumentType === ArgumentType.STRING
668
- ) {
669
- newBlock = this.workspace.newBlock("argument_editor_string_number");
633
+ if (argumentType === ArgumentType.NUMBER || argumentType === ArgumentType.STRING) {
634
+ newBlock = this.workspace.newBlock('argument_editor_string_number')
670
635
  } else {
671
- newBlock = this.workspace.newBlock("argument_editor_boolean");
636
+ newBlock = this.workspace.newBlock('argument_editor_boolean')
672
637
  }
673
- newBlock.setFieldValue(displayName, "TEXT");
674
- newBlock.setShadow(true);
638
+ newBlock.setFieldValue(displayName, 'TEXT')
639
+ newBlock.setShadow(true)
675
640
  if (!this.isInsertionMarker()) {
676
- newBlock.initSvg();
677
- newBlock.queueRender();
641
+ newBlock.initSvg()
642
+ newBlock.queueRender()
678
643
  }
679
644
  } finally {
680
- Blockly.Events.enable();
645
+ Blockly.Events.enable()
681
646
  }
682
647
  if (Blockly.Events.isEnabled()) {
683
- Blockly.Events.fire(
684
- new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock)
685
- );
648
+ Blockly.Events.fire(new (Blockly.Events.get(Blockly.Events.BLOCK_CREATE))(newBlock))
686
649
  }
687
- return newBlock;
650
+ return newBlock
688
651
  }
689
652
 
690
653
  /**
@@ -692,30 +655,28 @@ function createArgumentEditor_(
692
655
  * and their text.
693
656
  */
694
657
  function updateDeclarationProcCode_(this: ProcedureDeclarationBlock) {
695
- this.procCode_ = "";
696
- this.displayNames_ = [];
697
- this.argumentIds_ = [];
658
+ this.procCode_ = ''
659
+ this.displayNames_ = []
660
+ this.argumentIds_ = []
698
661
  for (let i = 0; i < this.inputList.length; i++) {
699
662
  if (i !== 0) {
700
- this.procCode_ += " ";
663
+ this.procCode_ += ' '
701
664
  }
702
- const input = this.inputList[i];
665
+ const input = this.inputList[i]
703
666
  if (input.type === Blockly.inputs.inputTypes.DUMMY) {
704
- this.procCode_ += input.fieldRow[0].getValue();
667
+ this.procCode_ += input.fieldRow[0].getValue()
705
668
  } else if (input.type === Blockly.inputs.inputTypes.VALUE) {
706
669
  // Inspect the argument editor.
707
- const target = input.connection!.targetBlock()!;
708
- this.displayNames_.push(target.getFieldValue("TEXT"));
709
- this.argumentIds_.push(input.name);
710
- if (target.type === "argument_editor_boolean") {
711
- this.procCode_ += "%b";
670
+ const target = input.connection!.targetBlock()!
671
+ this.displayNames_.push(target.getFieldValue('TEXT'))
672
+ this.argumentIds_.push(input.name)
673
+ if (target.type === 'argument_editor_boolean') {
674
+ this.procCode_ += '%b'
712
675
  } else {
713
- this.procCode_ += "%s";
676
+ this.procCode_ += '%s'
714
677
  }
715
678
  } else {
716
- throw new Error(
717
- "Unexpected input type on a procedure mutator root: " + input.type
718
- );
679
+ throw new Error('Unexpected input type on a procedure mutator root: ' + input.type)
719
680
  }
720
681
  }
721
682
  }
@@ -725,13 +686,13 @@ function updateDeclarationProcCode_(this: ProcedureDeclarationBlock) {
725
686
  */
726
687
  function focusLastEditor_(this: ProcedureDeclarationBlock) {
727
688
  if (this.inputList.length > 0) {
728
- const newInput = this.inputList[this.inputList.length - 1];
689
+ const newInput = this.inputList[this.inputList.length - 1]
729
690
  if (newInput.type === Blockly.inputs.inputTypes.DUMMY) {
730
- newInput.fieldRow[0].showEditor();
691
+ newInput.fieldRow[0].showEditor()
731
692
  } else if (newInput.type === Blockly.inputs.inputTypes.VALUE) {
732
693
  // Inspect the argument editor.
733
- const target = newInput.connection!.targetBlock()!;
734
- target.getField("TEXT")!.showEditor();
694
+ const target = newInput.connection!.targetBlock()!
695
+ target.getField('TEXT')!.showEditor()
735
696
  }
736
697
  }
737
698
  }
@@ -740,10 +701,10 @@ function focusLastEditor_(this: ProcedureDeclarationBlock) {
740
701
  * Externally-visible function to add a label to the procedure declaration.
741
702
  */
742
703
  function addLabelExternal(this: ProcedureDeclarationBlock) {
743
- Blockly.WidgetDiv.hide();
744
- this.procCode_ = this.procCode_ + " label text";
745
- this.updateDisplay_();
746
- this.focusLastEditor_();
704
+ Blockly.WidgetDiv.hide()
705
+ this.procCode_ = this.procCode_ + ' label text'
706
+ this.updateDisplay_()
707
+ this.focusLastEditor_()
747
708
  }
748
709
 
749
710
  /**
@@ -751,13 +712,13 @@ function addLabelExternal(this: ProcedureDeclarationBlock) {
751
712
  * declaration.
752
713
  */
753
714
  function addBooleanExternal(this: ProcedureDeclarationBlock) {
754
- Blockly.WidgetDiv.hide();
755
- this.procCode_ = this.procCode_ + " %b";
756
- this.displayNames_.push("boolean");
757
- this.argumentIds_.push(Blockly.utils.idGenerator.genUid());
758
- this.argumentDefaults_.push("false");
759
- this.updateDisplay_();
760
- this.focusLastEditor_();
715
+ Blockly.WidgetDiv.hide()
716
+ this.procCode_ = this.procCode_ + ' %b'
717
+ this.displayNames_.push('boolean')
718
+ this.argumentIds_.push(Blockly.utils.idGenerator.genUid())
719
+ this.argumentDefaults_.push('false')
720
+ this.updateDisplay_()
721
+ this.focusLastEditor_()
761
722
  }
762
723
 
763
724
  /**
@@ -765,82 +726,75 @@ function addBooleanExternal(this: ProcedureDeclarationBlock) {
765
726
  * declaration.
766
727
  */
767
728
  function addStringNumberExternal(this: ProcedureDeclarationBlock) {
768
- Blockly.WidgetDiv.hide();
769
- this.procCode_ = this.procCode_ + " %s";
770
- this.displayNames_.push("number or text");
771
- this.argumentIds_.push(Blockly.utils.idGenerator.genUid());
772
- this.argumentDefaults_.push("");
773
- this.updateDisplay_();
774
- this.focusLastEditor_();
729
+ Blockly.WidgetDiv.hide()
730
+ this.procCode_ = this.procCode_ + ' %s'
731
+ this.displayNames_.push('number or text')
732
+ this.argumentIds_.push(Blockly.utils.idGenerator.genUid())
733
+ this.argumentDefaults_.push('')
734
+ this.updateDisplay_()
735
+ this.focusLastEditor_()
775
736
  }
776
737
 
777
738
  /**
778
739
  * Externally-visible function to get the warp on procedure declaration.
779
- *
780
740
  * @returns The value of the warp_ property.
781
741
  */
782
742
  function getWarp(this: ProcedureDeclarationBlock): boolean {
783
- return this.warp_;
743
+ return this.warp_
784
744
  }
785
745
 
786
746
  /**
787
747
  * Externally-visible function to set the warp on procedure declaration.
788
- *
789
748
  * @param warp The value of the warp_ property.
790
749
  */
791
750
  function setWarp(this: ProcedureDeclarationBlock, warp: boolean) {
792
- this.warp_ = warp;
751
+ this.warp_ = warp
793
752
  }
794
753
 
795
754
  /**
796
755
  * Callback to remove a field, only for the declaration block.
797
- *
798
756
  * @param field The field being removed.
799
757
  */
800
- function removeFieldCallback(
801
- this: ProcedureDeclarationBlock,
802
- field: Blockly.Field
803
- ) {
758
+ function removeFieldCallback(this: ProcedureDeclarationBlock, field: Blockly.Field) {
804
759
  // Do not delete if there is only one input
805
760
  if (this.inputList.length === 1) {
806
- return;
761
+ return
807
762
  }
808
- var inputNameToRemove = null;
809
- for (var n = 0; n < this.inputList.length; n++) {
810
- var input = this.inputList[n];
763
+ let inputNameToRemove = null
764
+ for (let n = 0; n < this.inputList.length; n++) {
765
+ const input = this.inputList[n]
811
766
  if (input.connection) {
812
- var target = input.connection!.targetBlock()!;
767
+ const target = input.connection.targetBlock()!
813
768
  if (field.name && target.getField(field.name) === field) {
814
- inputNameToRemove = input.name;
769
+ inputNameToRemove = input.name
815
770
  }
816
771
  } else {
817
- for (var j = 0; j < input.fieldRow.length; j++) {
772
+ for (let j = 0; j < input.fieldRow.length; j++) {
818
773
  if (input.fieldRow[j] === field) {
819
- inputNameToRemove = input.name;
774
+ inputNameToRemove = input.name
820
775
  }
821
776
  }
822
777
  }
823
778
  }
824
779
  if (inputNameToRemove) {
825
- Blockly.WidgetDiv.hide();
826
- this.removeInput(inputNameToRemove);
827
- this.onChangeFn();
828
- this.updateDisplay_();
780
+ Blockly.WidgetDiv.hide()
781
+ this.removeInput(inputNameToRemove)
782
+ this.onChangeFn()
783
+ this.updateDisplay_()
829
784
  }
830
785
  }
831
786
 
832
787
  /**
833
788
  * Callback to pass removeField up to the declaration block from arguments.
834
- *
835
789
  * @param field The field being removed.
836
790
  */
837
791
  function removeArgumentCallback_(
838
792
  this: ProcedureDeclarationBlock | ProcedureArgumentEditorBlock,
839
- field: Blockly.Field
793
+ field: Blockly.Field,
840
794
  ) {
841
- const parent = this.getParent();
795
+ const parent = this.getParent()
842
796
  if (parent && parent.removeFieldCallback) {
843
- parent.removeFieldCallback(field);
797
+ parent.removeFieldCallback(field)
844
798
  }
845
799
  }
846
800
 
@@ -853,46 +807,43 @@ function removeArgumentCallback_(
853
807
  * Until there is a more explicit way of identifying argument reporter blocks using ids,
854
808
  * be conservative and only update argument reporters that are used in the
855
809
  * stack below the prototype, ie the definition.
856
- *
857
810
  * @param prevArgIds The previous ordering of argument ids.
858
811
  * @param prevDisplayNames The previous argument names.
859
812
  */
860
813
  function updateArgumentReporterNames_(
861
814
  this: ProcedurePrototypeBlock,
862
815
  prevArgIds: string[],
863
- prevDisplayNames: string[]
816
+ prevDisplayNames: string[],
864
817
  ) {
865
- const nameChanges: { newName: string; blocks: Blockly.BlockSvg[] }[] = [];
866
- const argReporters: Blockly.BlockSvg[] = [];
867
- const definitionBlock = this.getParent();
868
- if (!definitionBlock) return;
818
+ const nameChanges: { newName: string; blocks: Blockly.BlockSvg[] }[] = []
819
+ const argReporters: Blockly.BlockSvg[] = []
820
+ const definitionBlock = this.getParent()
821
+ if (!definitionBlock) return
869
822
 
870
823
  // Create a list of argument reporters that are descendants of the definition stack (see above comment)
871
- definitionBlock.getDescendants(false).forEach((block: Blockly.BlockSvg) => {
824
+ // Exclude arg reporters in the prototype block itself (they're owned by the prototype, not the user).
825
+ const protoDescendants = new Set(this.getDescendants(false))
826
+ definitionBlock.getDescendants(false).forEach((block) => {
872
827
  if (
873
- (block.type === "argument_reporter_string_number" ||
874
- block.type === "argument_reporter_boolean") &&
875
- !block.isShadow()
828
+ (block.type === 'argument_reporter_string_number' || block.type === 'argument_reporter_boolean') &&
829
+ !protoDescendants.has(block)
876
830
  ) {
877
- // Exclude arg reporters in the prototype block, which are shadows.
878
- argReporters.push(block);
831
+ argReporters.push(block)
879
832
  }
880
- });
833
+ })
881
834
 
882
835
  // Create a list of "name changes", including the new name and blocks matching the old name
883
836
  // Only search over the current set of argument ids, ignore args that have been removed
884
837
  for (let i = 0, id; (id = this.argumentIds_[i]); i++) {
885
838
  // Find the previous index of this argument id. Could be -1 if it is newly added.
886
- const prevIndex = prevArgIds.indexOf(id);
887
- if (prevIndex === -1) continue; // Newly added argument, no corresponding previous argument to update.
888
- const prevName = prevDisplayNames[prevIndex];
839
+ const prevIndex = prevArgIds.indexOf(id)
840
+ if (prevIndex === -1) continue // Newly added argument, no corresponding previous argument to update.
841
+ const prevName = prevDisplayNames[prevIndex]
889
842
  if (prevName !== this.displayNames_[i]) {
890
843
  nameChanges.push({
891
844
  newName: this.displayNames_[i],
892
- blocks: argReporters.filter((block) => {
893
- return block.getFieldValue("VALUE") === prevName;
894
- }),
895
- });
845
+ blocks: argReporters.filter((block) => block.getFieldValue('VALUE') === prevName),
846
+ })
896
847
  }
897
848
  }
898
849
 
@@ -900,12 +851,12 @@ function updateArgumentReporterNames_(
900
851
  // Do this after creating the lists to avoid cycles of renaming.
901
852
  for (const nameChange of nameChanges) {
902
853
  for (const block of nameChange.blocks) {
903
- block.setFieldValue(nameChange.newName, "VALUE");
854
+ block.setFieldValue(nameChange.newName, 'VALUE')
904
855
  }
905
856
  }
906
857
  }
907
858
 
908
- Blockly.Blocks["procedures_definition"] = {
859
+ Blockly.Blocks.procedures_definition = {
909
860
  /**
910
861
  * Block for defining a procedure with no return value.
911
862
  */
@@ -914,263 +865,264 @@ Blockly.Blocks["procedures_definition"] = {
914
865
  message0: Blockly.Msg.PROCEDURES_DEFINITION,
915
866
  args0: [
916
867
  {
917
- type: "input_statement",
918
- name: "custom_block",
868
+ type: 'input_statement',
869
+ name: 'custom_block',
919
870
  },
920
871
  ],
921
- extensions: [
922
- "colours_more",
923
- "shape_bowler_hat",
924
- "procedure_def_contextmenu",
925
- ],
926
- });
872
+ extensions: ['colours_more', 'shape_bowler_hat', 'procedure_def_contextmenu'],
873
+ })
927
874
  },
928
- };
875
+ }
929
876
 
930
- Blockly.Blocks["procedures_call"] = {
877
+ Blockly.Blocks.procedures_call = {
931
878
  /**
932
879
  * Block for calling a procedure with no return value.
933
880
  */
934
881
  init: function (this: ProcedureCallBlock) {
935
882
  this.jsonInit({
936
- extensions: [
937
- "colours_more",
938
- "shape_statement",
939
- "procedure_call_contextmenu",
940
- ],
941
- });
942
- this.procCode_ = "";
943
- this.argumentIds_ = [];
944
- this.warp_ = false;
883
+ extensions: ['colours_more', 'shape_statement', 'procedure_call_contextmenu'],
884
+ })
885
+ this.procCode_ = ''
886
+ this.argumentIds_ = []
887
+ this.warp_ = false
945
888
 
946
889
  // Shared.
947
- this.getProcCode = getProcCode.bind(this);
948
- this.removeAllInputs_ = removeAllInputs_.bind(this);
949
- this.disconnectOldBlocks_ = disconnectOldBlocks_.bind(this);
950
- this.deleteShadows_ = deleteShadows_.bind(this);
951
- this.createAllInputs_ = createAllInputs_.bind(this);
952
- this.updateDisplay_ = updateDisplay_.bind(this);
890
+ this.getProcCode = getProcCode.bind(this)
891
+ this.removeAllInputs_ = removeAllInputs_.bind(this)
892
+ this.disconnectOldBlocks_ = disconnectOldBlocks_.bind(this)
893
+ this.disposeObsoleteBlocks_ = disposeObsoleteBlocks_.bind(this)
894
+ this.createAllInputs_ = createAllInputs_.bind(this)
895
+ this.updateDisplay_ = updateDisplay_.bind(this)
953
896
 
954
897
  // Exist on all three blocks, but have different implementations.
955
- this.mutationToDom = callerMutationToDom.bind(this);
956
- this.domToMutation = callerDomToMutation.bind(this);
957
- this.populateArgument_ = populateArgumentOnCaller_.bind(this);
958
- this.addProcedureLabel_ = addLabelField_.bind(this);
898
+ this.mutationToDom = callerMutationToDom.bind(this)
899
+ this.domToMutation = callerDomToMutation.bind(this)
900
+ this.populateArgument_ = populateArgumentOnCaller_.bind(this)
901
+ this.addProcedureLabel_ = addLabelField_.bind(this)
959
902
 
960
903
  // Only exists on the external caller.
961
- this.attachShadow_ = attachShadow_.bind(this);
962
- this.buildShadowDom_ = buildShadowDom_.bind(this);
904
+ this.attachShadow_ = attachShadow_.bind(this)
905
+ this.buildShadowDom_ = buildShadowDom_.bind(this)
963
906
  },
964
- };
907
+ }
965
908
 
966
- Blockly.Blocks["procedures_prototype"] = {
909
+ Blockly.Blocks.procedures_prototype = {
967
910
  /**
968
911
  * Block for calling a procedure with no return value, for rendering inside
969
912
  * define block.
970
913
  */
971
914
  init: function (this: ProcedurePrototypeBlock) {
972
915
  this.jsonInit({
973
- extensions: ["colours_more", "shape_statement"],
974
- });
916
+ extensions: ['colours_more', 'shape_statement'],
917
+ })
918
+
919
+ // Previously this block was a shadow, which is non-deletable and
920
+ // non-movable by default. Now that it's a regular block, explicitly
921
+ // replicate those properties and add a drag strategy that delegates all
922
+ // drag operations to the parent (procedures_definition) block.
923
+ this.setDeletable(false)
924
+ this.setDragStrategy(new DelegateToParentDraggable(this))
975
925
 
976
926
  /* Data known about the procedure. */
977
- this.procCode_ = "";
978
- this.displayNames_ = [];
979
- this.argumentIds_ = [];
980
- this.argumentDefaults_ = [];
981
- this.warp_ = false;
927
+ this.procCode_ = ''
928
+ this.displayNames_ = []
929
+ this.argumentIds_ = []
930
+ this.argumentDefaults_ = []
931
+ this.warp_ = false
982
932
 
983
933
  // Shared.
984
- this.getProcCode = getProcCode.bind(this);
985
- this.removeAllInputs_ = removeAllInputs_.bind(this);
986
- this.disconnectOldBlocks_ = disconnectOldBlocks_.bind(this);
987
- this.deleteShadows_ = deleteShadows_.bind(this);
988
- this.createAllInputs_ = createAllInputs_.bind(this);
989
- this.updateDisplay_ = updateDisplay_.bind(this);
934
+ this.getProcCode = getProcCode.bind(this)
935
+ this.removeAllInputs_ = removeAllInputs_.bind(this)
936
+ this.disconnectOldBlocks_ = disconnectOldBlocks_.bind(this)
937
+ this.disposeObsoleteBlocks_ = disposeObsoleteBlocks_.bind(this)
938
+ this.createAllInputs_ = createAllInputs_.bind(this)
939
+ this.updateDisplay_ = updateDisplay_.bind(this)
990
940
  // Exist on all three blocks, but have different implementations.
991
- this.mutationToDom = definitionMutationToDom.bind(this);
992
- this.domToMutation = definitionDomToMutation.bind(this);
993
- this.populateArgument_ = populateArgumentOnPrototype_.bind(this);
994
- this.addProcedureLabel_ = addLabelField_.bind(this);
941
+ this.mutationToDom = definitionMutationToDom.bind(this)
942
+ this.domToMutation = definitionDomToMutation.bind(this)
943
+ this.populateArgument_ = populateArgumentOnPrototype_.bind(this)
944
+ this.addProcedureLabel_ = addLabelField_.bind(this)
995
945
 
996
946
  // Only exists on procedures_prototype.
997
- this.createArgumentReporter_ = createArgumentReporter_.bind(this);
998
- this.updateArgumentReporterNames_ = updateArgumentReporterNames_.bind(this);
947
+ this.createArgumentReporter_ = createArgumentReporter_.bind(this)
948
+ this.updateArgumentReporterNames_ = updateArgumentReporterNames_.bind(this)
999
949
  },
1000
- };
950
+ }
1001
951
 
1002
- Blockly.Blocks["procedures_declaration"] = {
952
+ Blockly.Blocks.procedures_declaration = {
1003
953
  /**
1004
954
  * The root block in the procedure declaration editor.
1005
955
  */
1006
956
  init: function (this: ProcedureDeclarationBlock) {
1007
957
  this.jsonInit({
1008
- extensions: ["colours_more", "shape_statement"],
1009
- });
958
+ extensions: ['colours_more', 'shape_statement'],
959
+ })
1010
960
  /* Data known about the procedure. */
1011
- this.procCode_ = "";
1012
- this.displayNames_ = [];
1013
- this.argumentIds_ = [];
1014
- this.argumentDefaults_ = [];
1015
- this.warp_ = false;
961
+ this.procCode_ = ''
962
+ this.displayNames_ = []
963
+ this.argumentIds_ = []
964
+ this.argumentDefaults_ = []
965
+ this.warp_ = false
1016
966
 
1017
967
  // Shared.
1018
- this.getProcCode = getProcCode.bind(this);
1019
- this.removeAllInputs_ = removeAllInputs_.bind(this);
1020
- this.disconnectOldBlocks_ = disconnectOldBlocks_.bind(this);
1021
- this.deleteShadows_ = deleteShadows_.bind(this);
1022
- this.createAllInputs_ = createAllInputs_.bind(this);
1023
- this.updateDisplay_ = updateDisplay_.bind(this);
968
+ this.getProcCode = getProcCode.bind(this)
969
+ this.removeAllInputs_ = removeAllInputs_.bind(this)
970
+ this.disconnectOldBlocks_ = disconnectOldBlocks_.bind(this)
971
+ this.disposeObsoleteBlocks_ = disposeObsoleteBlocks_.bind(this)
972
+ this.createAllInputs_ = createAllInputs_.bind(this)
973
+ this.updateDisplay_ = updateDisplay_.bind(this)
1024
974
 
1025
975
  // Exist on all three blocks, but have different implementations.
1026
- this.mutationToDom = definitionMutationToDom.bind(this);
1027
- this.domToMutation = definitionDomToMutation.bind(this);
1028
- this.populateArgument_ = populateArgumentOnDeclaration_.bind(this);
1029
- this.addProcedureLabel_ = addLabelEditor_.bind(this);
976
+ this.mutationToDom = definitionMutationToDom.bind(this)
977
+ this.domToMutation = definitionDomToMutation.bind(this)
978
+ this.populateArgument_ = populateArgumentOnDeclaration_.bind(this)
979
+ this.addProcedureLabel_ = addLabelEditor_.bind(this)
1030
980
 
1031
981
  // Exist on declaration and arguments editors, with different implementations.
1032
- this.removeFieldCallback = removeFieldCallback.bind(this);
982
+ this.removeFieldCallback = removeFieldCallback.bind(this)
1033
983
 
1034
984
  // Only exist on procedures_declaration.
1035
- this.createArgumentEditor_ = createArgumentEditor_.bind(this);
1036
- this.focusLastEditor_ = focusLastEditor_.bind(this);
1037
- this.getWarp = getWarp.bind(this);
1038
- this.setWarp = setWarp.bind(this);
1039
- this.addLabelExternal = addLabelExternal.bind(this);
1040
- this.addBooleanExternal = addBooleanExternal.bind(this);
1041
- this.addStringNumberExternal = addStringNumberExternal.bind(this);
1042
- this.onChangeFn = updateDeclarationProcCode_.bind(this);
985
+ this.createArgumentEditor_ = createArgumentEditor_.bind(this)
986
+ this.focusLastEditor_ = focusLastEditor_.bind(this)
987
+ this.getWarp = getWarp.bind(this)
988
+ this.setWarp = setWarp.bind(this)
989
+ this.addLabelExternal = addLabelExternal.bind(this)
990
+ this.addBooleanExternal = addBooleanExternal.bind(this)
991
+ this.addStringNumberExternal = addStringNumberExternal.bind(this)
992
+ this.onChangeFn = updateDeclarationProcCode_.bind(this)
993
+ },
994
+ // The procedures_declaration block lives in the ephemeral Custom Procedures
995
+ // dialog workspace, which is disposed (and unregistered from FocusManager)
996
+ // when the dialog closes. If FocusManager tracks this block as the focused
997
+ // node while the WidgetDiv is open, the `returnEphemeralFocus` callback
998
+ // schedules a setTimeout that tries to re-focus it after the dialog workspace
999
+ // has been disposed — throwing "Attempted to focus unregistered node". Making
1000
+ // this block non-focusable prevents FocusManager from ever storing it as the
1001
+ // focused node, so the setTimeout is never scheduled.
1002
+ canBeFocused: function () {
1003
+ return false
1043
1004
  },
1044
- };
1005
+ }
1045
1006
 
1046
- Blockly.Blocks["argument_reporter_boolean"] = {
1007
+ Blockly.Blocks.argument_reporter_boolean = {
1047
1008
  init: function (this: Blockly.BlockSvg) {
1048
1009
  this.jsonInit({
1049
- message0: " %1",
1010
+ message0: ' %1',
1050
1011
  args0: [
1051
1012
  {
1052
- type: "field_label_serializable",
1053
- name: "VALUE",
1054
- text: "",
1013
+ type: 'field_label_serializable',
1014
+ name: 'VALUE',
1015
+ text: '',
1055
1016
  },
1056
1017
  ],
1057
- extensions: ["colours_more", "output_boolean"],
1058
- });
1059
- this.setDragStrategy(new DuplicateOnDragDraggable(this));
1018
+ extensions: ['colours_more', 'output_boolean'],
1019
+ })
1020
+ this.setDragStrategy(new DuplicateOnDragDraggable(this))
1060
1021
  },
1061
- };
1022
+ }
1062
1023
 
1063
- Blockly.Blocks["argument_reporter_string_number"] = {
1024
+ Blockly.Blocks.argument_reporter_string_number = {
1064
1025
  init: function (this: Blockly.BlockSvg) {
1065
1026
  this.jsonInit({
1066
- message0: " %1",
1027
+ message0: ' %1',
1067
1028
  args0: [
1068
1029
  {
1069
- type: "field_label_serializable",
1070
- name: "VALUE",
1071
- text: "",
1030
+ type: 'field_label_serializable',
1031
+ name: 'VALUE',
1032
+ text: '',
1072
1033
  },
1073
1034
  ],
1074
- extensions: ["colours_more", "output_number", "output_string"],
1075
- });
1076
- this.setDragStrategy(new DuplicateOnDragDraggable(this));
1035
+ extensions: ['colours_more', 'output_number', 'output_string'],
1036
+ })
1037
+ this.setDragStrategy(new DuplicateOnDragDraggable(this))
1077
1038
  },
1078
- };
1039
+ }
1079
1040
 
1080
- Blockly.Blocks["argument_editor_boolean"] = {
1041
+ Blockly.Blocks.argument_editor_boolean = {
1081
1042
  init: function (this: ProcedureArgumentEditorBlock) {
1082
1043
  this.jsonInit({
1083
- message0: " %1",
1044
+ message0: ' %1',
1084
1045
  args0: [
1085
1046
  {
1086
- type: "field_input_removable",
1087
- name: "TEXT",
1088
- text: "foo",
1047
+ type: 'field_input_removable',
1048
+ name: 'TEXT',
1049
+ text: 'foo',
1089
1050
  },
1090
1051
  ],
1091
- extensions: ["colours_textfield", "output_boolean"],
1092
- });
1052
+ extensions: ['colours_textfield', 'output_boolean'],
1053
+ })
1093
1054
 
1094
1055
  // Exist on declaration and arguments editors, with different implementations.
1095
- this.removeFieldCallback = removeArgumentCallback_.bind(this);
1056
+ this.removeFieldCallback = removeArgumentCallback_.bind(this)
1096
1057
  },
1097
- };
1058
+ }
1098
1059
 
1099
- Blockly.Blocks["argument_editor_string_number"] = {
1060
+ Blockly.Blocks.argument_editor_string_number = {
1100
1061
  init: function (this: ProcedureArgumentEditorBlock) {
1101
1062
  this.jsonInit({
1102
- message0: " %1",
1063
+ message0: ' %1',
1103
1064
  args0: [
1104
1065
  {
1105
- type: "field_input_removable",
1106
- name: "TEXT",
1107
- text: "foo",
1066
+ type: 'field_input_removable',
1067
+ name: 'TEXT',
1068
+ text: 'foo',
1108
1069
  },
1109
1070
  ],
1110
- extensions: ["colours_textfield", "output_number", "output_string"],
1111
- });
1071
+ extensions: ['colours_textfield', 'output_number', 'output_string'],
1072
+ })
1112
1073
 
1113
1074
  // Exist on declaration and arguments editors, with different implementations.
1114
- this.removeFieldCallback = removeArgumentCallback_.bind(this);
1075
+ this.removeFieldCallback = removeArgumentCallback_.bind(this)
1115
1076
  },
1116
- };
1077
+ }
1117
1078
 
1118
1079
  interface ProcedureBlock extends Blockly.BlockSvg {
1119
- procCode_: string;
1120
- argumentIds_: string[];
1121
- warp_: boolean;
1122
- getProcCode: () => string;
1123
- removeAllInputs_: () => void;
1124
- disconnectOldBlocks_: () => ConnectionMap;
1125
- deleteShadows_: (connectionMap: ConnectionMap) => void;
1126
- createAllInputs_: (connectionMap: ConnectionMap) => void;
1127
- updateDisplay_: () => void;
1080
+ procCode_: string
1081
+ argumentIds_: string[]
1082
+ warp_: boolean
1083
+ getProcCode: () => string
1084
+ removeAllInputs_: () => void
1085
+ disconnectOldBlocks_: () => ConnectionMap
1086
+ disposeObsoleteBlocks_: (connectionMap: ConnectionMap) => void
1087
+ createAllInputs_: (connectionMap: ConnectionMap) => void
1088
+ updateDisplay_: () => void
1128
1089
  populateArgument_: (
1129
1090
  type: ArgumentType,
1130
1091
  index: number,
1131
1092
  connectionMap: ConnectionMap,
1132
1093
  id: string,
1133
- input: Blockly.Input
1134
- ) => void;
1135
- addProcedureLabel_: (text: string) => void;
1094
+ input: Blockly.Input,
1095
+ ) => void
1096
+ addProcedureLabel_: (text: string) => void
1136
1097
  }
1137
1098
 
1138
1099
  export interface ProcedureDeclarationBlock extends ProcedureBlock {
1139
- displayNames_: string[];
1140
- argumentDefaults_: string[];
1141
- removeFieldCallback: (field: Blockly.Field) => void;
1142
- createArgumentEditor_: (
1143
- argumentType: ArgumentType,
1144
- displayName: string
1145
- ) => Blockly.BlockSvg;
1146
- focusLastEditor_: () => void;
1147
- getWarp: () => boolean;
1148
- setWarp: (warp: boolean) => void;
1149
- addLabelExternal: () => void;
1150
- addBooleanExternal: () => void;
1151
- addStringNumberExternal: () => void;
1152
- onChangeFn: () => void;
1100
+ displayNames_: string[]
1101
+ argumentDefaults_: string[]
1102
+ removeFieldCallback: (field: Blockly.Field) => void
1103
+ createArgumentEditor_: (argumentType: ArgumentType, displayName: string) => Blockly.BlockSvg
1104
+ focusLastEditor_: () => void
1105
+ getWarp: () => boolean
1106
+ setWarp: (warp: boolean) => void
1107
+ addLabelExternal: () => void
1108
+ addBooleanExternal: () => void
1109
+ addStringNumberExternal: () => void
1110
+ onChangeFn: () => void
1153
1111
  }
1154
1112
 
1155
1113
  interface ProcedureCallBlock extends ProcedureBlock {
1156
- generateShadows_: boolean;
1157
- attachShadow_: (input: Blockly.Input, argumentType: ArgumentType) => void;
1158
- buildShadowDom_: (type: ArgumentType) => Element;
1114
+ generateShadows_: boolean
1115
+ attachShadow_: (input: Blockly.Input, argumentType: ArgumentType) => void
1116
+ buildShadowDom_: (type: ArgumentType) => Element
1159
1117
  }
1160
1118
 
1161
1119
  interface ProcedurePrototypeBlock extends ProcedureBlock {
1162
- displayNames_: string[];
1163
- argumentDefaults_: string[];
1164
- createArgumentReporter_: (
1165
- argumentType: ArgumentType,
1166
- displayName: string
1167
- ) => Blockly.BlockSvg;
1168
- updateArgumentReporterNames_: (
1169
- prevArgIds: string[],
1170
- prevDisplayNames: string[]
1171
- ) => void;
1120
+ displayNames_: string[]
1121
+ argumentDefaults_: string[]
1122
+ createArgumentReporter_: (argumentType: ArgumentType, displayName: string) => Blockly.BlockSvg
1123
+ updateArgumentReporterNames_: (prevArgIds: string[], prevDisplayNames: string[]) => void
1172
1124
  }
1173
1125
 
1174
1126
  interface ProcedureArgumentEditorBlock extends Blockly.BlockSvg {
1175
- removeFieldCallback: (field: Blockly.Field) => void;
1127
+ removeFieldCallback: (field: Blockly.Field) => void
1176
1128
  }