blockly 7.20211209.4 → 8.0.1

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 (231) hide show
  1. package/blockly.d.ts +18963 -18432
  2. package/blockly.min.js +5 -4
  3. package/blockly_compressed.js +4 -3
  4. package/blockly_compressed.js.map +1 -1
  5. package/blocks/blocks.js +47 -0
  6. package/blocks/colour.js +13 -3
  7. package/blocks/lists.js +22 -13
  8. package/blocks/logic.js +13 -3
  9. package/blocks/loops.js +24 -11
  10. package/blocks/math.js +12 -3
  11. package/blocks/procedures.js +45 -32
  12. package/blocks/text.js +22 -13
  13. package/blocks/variables.js +14 -3
  14. package/blocks/variables_dynamic.js +13 -3
  15. package/blocks_compressed.js +1 -1
  16. package/blocks_compressed.js.map +1 -1
  17. package/core/block.js +1869 -1814
  18. package/core/block_drag_surface.js +201 -200
  19. package/core/block_dragger.js +377 -373
  20. package/core/block_svg.js +1593 -1479
  21. package/core/blockly.js +8 -22
  22. package/core/blocks.js +9 -2
  23. package/core/browser_events.js +22 -5
  24. package/core/bubble.js +841 -797
  25. package/core/bubble_dragger.js +213 -206
  26. package/core/bump_objects.js +2 -2
  27. package/core/clipboard.js +9 -9
  28. package/core/comment.js +353 -332
  29. package/core/common.js +46 -17
  30. package/core/component_manager.js +181 -174
  31. package/core/config.js +87 -0
  32. package/core/connection.js +595 -584
  33. package/core/connection_checker.js +242 -244
  34. package/core/connection_db.js +235 -230
  35. package/core/contextmenu.js +9 -6
  36. package/core/contextmenu_items.js +1 -2
  37. package/core/contextmenu_registry.js +93 -89
  38. package/core/css.js +474 -474
  39. package/core/delete_area.js +45 -42
  40. package/core/drag_target.js +57 -56
  41. package/core/dropdowndiv.js +153 -163
  42. package/core/events/events.js +2 -2
  43. package/core/events/events_abstract.js +89 -77
  44. package/core/events/events_block_base.js +37 -36
  45. package/core/events/events_block_change.js +130 -124
  46. package/core/events/events_block_create.js +73 -71
  47. package/core/events/events_block_delete.js +84 -82
  48. package/core/events/events_block_drag.js +50 -49
  49. package/core/events/events_block_move.js +147 -140
  50. package/core/events/events_bubble_open.js +51 -50
  51. package/core/events/events_click.js +48 -44
  52. package/core/events/events_comment_base.js +72 -69
  53. package/core/events/events_comment_change.js +63 -61
  54. package/core/events/events_comment_create.js +44 -42
  55. package/core/events/events_comment_delete.js +42 -40
  56. package/core/events/events_comment_move.js +106 -104
  57. package/core/events/events_marker_move.js +65 -64
  58. package/core/events/events_selected.js +46 -45
  59. package/core/events/events_theme_change.js +36 -35
  60. package/core/events/events_toolbox_item_select.js +46 -45
  61. package/core/events/events_trashcan_open.js +37 -36
  62. package/core/events/events_ui.js +47 -46
  63. package/core/events/events_ui_base.js +30 -29
  64. package/core/events/events_var_base.js +37 -36
  65. package/core/events/events_var_create.js +50 -48
  66. package/core/events/events_var_delete.js +50 -48
  67. package/core/events/events_var_rename.js +51 -49
  68. package/core/events/events_viewport.js +66 -65
  69. package/core/events/utils.js +29 -14
  70. package/core/events/workspace_events.js +49 -55
  71. package/core/extensions.js +4 -3
  72. package/core/field.js +1061 -997
  73. package/core/field_angle.js +462 -442
  74. package/core/field_checkbox.js +194 -182
  75. package/core/field_colour.js +519 -505
  76. package/core/field_dropdown.js +617 -598
  77. package/core/field_image.js +229 -220
  78. package/core/field_label.js +102 -91
  79. package/core/field_label_serializable.js +42 -41
  80. package/core/field_multilineinput.js +372 -358
  81. package/core/field_number.js +272 -253
  82. package/core/field_textinput.js +499 -467
  83. package/core/field_variable.js +458 -420
  84. package/core/flyout_base.js +1005 -952
  85. package/core/flyout_button.js +277 -260
  86. package/core/flyout_horizontal.js +304 -302
  87. package/core/flyout_metrics_manager.js +64 -64
  88. package/core/flyout_vertical.js +306 -300
  89. package/core/generator.js +459 -446
  90. package/core/gesture.js +829 -813
  91. package/core/grid.js +166 -163
  92. package/core/icon.js +168 -159
  93. package/core/inject.js +7 -5
  94. package/core/input.js +257 -248
  95. package/core/insertion_marker_manager.js +655 -624
  96. package/core/internal_constants.js +0 -129
  97. package/core/keyboard_nav/ast_node.js +605 -596
  98. package/core/keyboard_nav/basic_cursor.js +166 -165
  99. package/core/keyboard_nav/cursor.js +99 -97
  100. package/core/keyboard_nav/marker.js +83 -79
  101. package/core/keyboard_nav/tab_navigate_cursor.js +18 -23
  102. package/core/marker_manager.js +153 -141
  103. package/core/menu.js +377 -372
  104. package/core/menuitem.js +223 -217
  105. package/core/metrics_manager.js +403 -390
  106. package/core/mutator.js +468 -437
  107. package/core/names.js +229 -188
  108. package/core/options.js +290 -284
  109. package/core/procedures.js +29 -17
  110. package/core/registry.js +19 -16
  111. package/core/rendered_connection.js +482 -463
  112. package/core/renderers/common/block_rendering.js +9 -3
  113. package/core/renderers/common/constants.js +1119 -1112
  114. package/core/renderers/common/debug.js +14 -0
  115. package/core/renderers/common/debugger.js +338 -316
  116. package/core/renderers/common/drawer.js +380 -370
  117. package/core/renderers/common/i_path_object.js +2 -2
  118. package/core/renderers/common/info.js +626 -618
  119. package/core/renderers/common/marker_svg.js +579 -541
  120. package/core/renderers/common/path_object.js +203 -200
  121. package/core/renderers/common/renderer.js +220 -218
  122. package/core/renderers/geras/constants.js +36 -36
  123. package/core/renderers/geras/drawer.js +155 -147
  124. package/core/renderers/geras/highlight_constants.js +244 -238
  125. package/core/renderers/geras/highlighter.js +231 -179
  126. package/core/renderers/geras/info.js +392 -369
  127. package/core/renderers/geras/measurables/inline_input.js +25 -19
  128. package/core/renderers/geras/measurables/statement_input.js +23 -17
  129. package/core/renderers/geras/path_object.js +106 -121
  130. package/core/renderers/geras/renderer.js +96 -98
  131. package/core/renderers/measurables/base.js +30 -18
  132. package/core/renderers/measurables/bottom_row.js +83 -80
  133. package/core/renderers/measurables/connection.js +22 -15
  134. package/core/renderers/measurables/external_value_input.js +35 -22
  135. package/core/renderers/measurables/field.js +35 -20
  136. package/core/renderers/measurables/hat.js +18 -13
  137. package/core/renderers/measurables/icon.js +24 -17
  138. package/core/renderers/measurables/in_row_spacer.js +15 -13
  139. package/core/renderers/measurables/inline_input.js +43 -33
  140. package/core/renderers/measurables/input_connection.js +41 -28
  141. package/core/renderers/measurables/input_row.js +50 -44
  142. package/core/renderers/measurables/jagged_edge.js +14 -12
  143. package/core/renderers/measurables/next_connection.js +16 -14
  144. package/core/renderers/measurables/output_connection.js +26 -20
  145. package/core/renderers/measurables/previous_connection.js +16 -15
  146. package/core/renderers/measurables/round_corner.js +20 -18
  147. package/core/renderers/measurables/row.js +184 -168
  148. package/core/renderers/measurables/spacer_row.js +38 -23
  149. package/core/renderers/measurables/square_corner.js +18 -16
  150. package/core/renderers/measurables/statement_input.js +23 -20
  151. package/core/renderers/measurables/top_row.js +88 -85
  152. package/core/renderers/minimalist/constants.js +8 -7
  153. package/core/renderers/minimalist/drawer.js +11 -10
  154. package/core/renderers/minimalist/info.js +18 -18
  155. package/core/renderers/minimalist/renderer.js +40 -39
  156. package/core/renderers/thrasos/info.js +258 -248
  157. package/core/renderers/thrasos/renderer.js +20 -20
  158. package/core/renderers/zelos/constants.js +898 -873
  159. package/core/renderers/zelos/drawer.js +186 -169
  160. package/core/renderers/zelos/info.js +502 -479
  161. package/core/renderers/zelos/marker_svg.js +129 -115
  162. package/core/renderers/zelos/measurables/bottom_row.js +31 -30
  163. package/core/renderers/zelos/measurables/inputs.js +22 -21
  164. package/core/renderers/zelos/measurables/row_elements.js +14 -13
  165. package/core/renderers/zelos/measurables/top_row.js +34 -33
  166. package/core/renderers/zelos/path_object.js +181 -180
  167. package/core/renderers/zelos/renderer.js +91 -92
  168. package/core/scrollbar.js +759 -713
  169. package/core/scrollbar_pair.js +250 -245
  170. package/core/serialization/blocks.js +26 -10
  171. package/core/serialization/workspaces.js +3 -2
  172. package/core/shortcut_registry.js +286 -277
  173. package/core/sprites.js +31 -0
  174. package/core/theme.js +135 -141
  175. package/core/theme_manager.js +147 -143
  176. package/core/toolbox/category.js +602 -576
  177. package/core/toolbox/collapsible_category.js +226 -227
  178. package/core/toolbox/separator.js +70 -61
  179. package/core/toolbox/toolbox.js +934 -927
  180. package/core/toolbox/toolbox_item.js +115 -99
  181. package/core/tooltip.js +108 -35
  182. package/core/touch.js +8 -3
  183. package/core/touch_gesture.js +254 -251
  184. package/core/trashcan.js +606 -595
  185. package/core/utils/coordinate.js +97 -95
  186. package/core/utils/dom.js +2 -2
  187. package/core/utils/global.js +2 -0
  188. package/core/utils/rect.js +41 -37
  189. package/core/utils/sentinel.js +25 -0
  190. package/core/utils/size.js +30 -27
  191. package/core/utils/svg.js +18 -16
  192. package/core/variable_map.js +325 -341
  193. package/core/variable_model.js +55 -54
  194. package/core/variables.js +9 -2
  195. package/core/variables_dynamic.js +3 -1
  196. package/core/warning.js +126 -120
  197. package/core/widgetdiv.js +4 -4
  198. package/core/workspace.js +685 -664
  199. package/core/workspace_audio.js +124 -118
  200. package/core/workspace_comment.js +308 -298
  201. package/core/workspace_comment_svg.js +1029 -951
  202. package/core/workspace_drag_surface_svg.js +147 -140
  203. package/core/workspace_dragger.js +70 -71
  204. package/core/workspace_svg.js +2322 -2297
  205. package/core/xml.js +30 -20
  206. package/core/zoom_controls.js +431 -439
  207. package/generators/dart/colour.js +56 -64
  208. package/generators/dart/lists.js +61 -50
  209. package/generators/dart/math.js +160 -148
  210. package/generators/dart/text.js +83 -61
  211. package/generators/javascript/colour.js +37 -34
  212. package/generators/javascript/lists.js +50 -43
  213. package/generators/javascript/math.js +123 -139
  214. package/generators/javascript/text.js +67 -81
  215. package/generators/lua/colour.js +25 -23
  216. package/generators/lua/lists.js +97 -69
  217. package/generators/lua/logic.js +1 -2
  218. package/generators/lua/math.js +182 -144
  219. package/generators/lua/text.js +116 -99
  220. package/generators/php/colour.js +38 -32
  221. package/generators/php/lists.js +109 -89
  222. package/generators/php/math.js +90 -81
  223. package/generators/php/text.js +63 -61
  224. package/generators/python/colour.js +18 -18
  225. package/generators/python/lists.js +38 -30
  226. package/generators/python/loops.js +12 -8
  227. package/generators/python/math.js +104 -106
  228. package/generators/python/text.js +34 -30
  229. package/msg/smn.js +436 -0
  230. package/package.json +7 -6
  231. package/blocks/all.js +0 -23
package/core/mutator.js CHANGED
@@ -17,14 +17,12 @@
17
17
  */
18
18
  goog.module('Blockly.Mutator');
19
19
 
20
- /* eslint-disable-next-line no-unused-vars */
21
- const Abstract = goog.requireType('Blockly.Events.Abstract');
22
20
  const dom = goog.require('Blockly.utils.dom');
23
21
  const eventUtils = goog.require('Blockly.Events.utils');
24
- const internalConstants = goog.require('Blockly.internalConstants');
25
- const object = goog.require('Blockly.utils.object');
26
22
  const toolbox = goog.require('Blockly.utils.toolbox');
27
23
  const xml = goog.require('Blockly.utils.xml');
24
+ /* eslint-disable-next-line no-unused-vars */
25
+ const {Abstract} = goog.requireType('Blockly.Events.Abstract');
28
26
  const {BlockChange} = goog.require('Blockly.Events.BlockChange');
29
27
  /* eslint-disable-next-line no-unused-vars */
30
28
  const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
@@ -33,6 +31,7 @@ const {BlocklyOptions} = goog.requireType('Blockly.BlocklyOptions');
33
31
  /* eslint-disable-next-line no-unused-vars */
34
32
  const {Block} = goog.requireType('Blockly.Block');
35
33
  const {Bubble} = goog.require('Blockly.Bubble');
34
+ const {config} = goog.require('Blockly.config');
36
35
  /* eslint-disable-next-line no-unused-vars */
37
36
  const {Connection} = goog.requireType('Blockly.Connection');
38
37
  /* eslint-disable-next-line no-unused-vars */
@@ -41,504 +40,536 @@ const {Icon} = goog.require('Blockly.Icon');
41
40
  const {Options} = goog.require('Blockly.Options');
42
41
  const {Svg} = goog.require('Blockly.utils.Svg');
43
42
  const {WorkspaceSvg} = goog.require('Blockly.WorkspaceSvg');
44
- /* eslint-disable-next-line no-unused-vars */
45
- const {Workspace} = goog.requireType('Blockly.Workspace');
46
43
  /** @suppress {extraRequire} */
47
44
  goog.require('Blockly.Events.BubbleOpen');
48
45
 
49
46
 
50
47
  /**
51
48
  * Class for a mutator dialog.
52
- * @param {!Array<string>} quarkNames List of names of sub-blocks for flyout.
53
49
  * @extends {Icon}
54
- * @constructor
55
50
  * @alias Blockly.Mutator
56
51
  */
57
- const Mutator = function(quarkNames) {
58
- Mutator.superClass_.constructor.call(this, null);
59
- this.quarkNames_ = quarkNames;
60
- };
61
- object.inherits(Mutator, Icon);
62
-
63
- /**
64
- * Workspace in the mutator's bubble.
65
- * @type {?WorkspaceSvg}
66
- * @private
67
- */
68
- Mutator.prototype.workspace_ = null;
69
-
70
- /**
71
- * Width of workspace.
72
- * @private
73
- */
74
- Mutator.prototype.workspaceWidth_ = 0;
52
+ class Mutator extends Icon {
53
+ /**
54
+ * @param {!Array<string>} quarkNames List of names of sub-blocks for flyout.
55
+ */
56
+ constructor(quarkNames) {
57
+ super(null);
58
+ this.quarkNames_ = quarkNames;
59
+
60
+ /**
61
+ * Workspace in the mutator's bubble.
62
+ * @type {?WorkspaceSvg}
63
+ * @private
64
+ */
65
+ this.workspace_ = null;
75
66
 
76
- /**
77
- * Height of workspace.
78
- * @private
79
- */
80
- Mutator.prototype.workspaceHeight_ = 0;
67
+ /**
68
+ * Width of workspace.
69
+ * @type {number}
70
+ * @private
71
+ */
72
+ this.workspaceWidth_ = 0;
81
73
 
82
- /**
83
- * Set the block this mutator is associated with.
84
- * @param {!BlockSvg} block The block associated with this mutator.
85
- * @package
86
- */
87
- Mutator.prototype.setBlock = function(block) {
88
- this.block_ = block;
89
- };
74
+ /**
75
+ * Height of workspace.
76
+ * @type {number}
77
+ * @private
78
+ */
79
+ this.workspaceHeight_ = 0;
90
80
 
91
- /**
92
- * Returns the workspace inside this mutator icon's bubble.
93
- * @return {?WorkspaceSvg} The workspace inside this mutator icon's
94
- * bubble or null if the mutator isn't open.
95
- * @package
96
- */
97
- Mutator.prototype.getWorkspace = function() {
98
- return this.workspace_;
99
- };
81
+ /**
82
+ * The SVG element that is the parent of the mutator workspace, or null if
83
+ * not created.
84
+ * @type {?SVGSVGElement}
85
+ * @private
86
+ */
87
+ this.svgDialog_ = null;
100
88
 
101
- /**
102
- * Draw the mutator icon.
103
- * @param {!Element} group The icon group.
104
- * @protected
105
- */
106
- Mutator.prototype.drawIcon_ = function(group) {
107
- // Square with rounded corners.
108
- dom.createSvgElement(
109
- Svg.RECT, {
110
- 'class': 'blocklyIconShape',
111
- 'rx': '4',
112
- 'ry': '4',
113
- 'height': '16',
114
- 'width': '16',
115
- },
116
- group);
117
- // Gear teeth.
118
- dom.createSvgElement(
119
- Svg.PATH, {
120
- 'class': 'blocklyIconSymbol',
121
- 'd': 'm4.203,7.296 0,1.368 -0.92,0.677 -0.11,0.41 0.9,1.559 0.41,' +
122
- '0.11 1.043,-0.457 1.187,0.683 0.127,1.134 0.3,0.3 1.8,0 0.3,' +
123
- '-0.299 0.127,-1.138 1.185,-0.682 1.046,0.458 0.409,-0.11 0.9,' +
124
- '-1.559 -0.11,-0.41 -0.92,-0.677 0,-1.366 0.92,-0.677 0.11,' +
125
- '-0.41 -0.9,-1.559 -0.409,-0.109 -1.046,0.458 -1.185,-0.682 ' +
126
- '-0.127,-1.138 -0.3,-0.299 -1.8,0 -0.3,0.3 -0.126,1.135 -1.187,' +
127
- '0.682 -1.043,-0.457 -0.41,0.11 -0.899,1.559 0.108,0.409z',
128
- },
129
- group);
130
- // Axle hole.
131
- dom.createSvgElement(
132
- Svg.CIRCLE,
133
- {'class': 'blocklyIconShape', 'r': '2.7', 'cx': '8', 'cy': '8'}, group);
134
- };
89
+ /**
90
+ * The root block of the mutator workspace, created by decomposing the
91
+ * source block.
92
+ * @type {?BlockSvg}
93
+ * @private
94
+ */
95
+ this.rootBlock_ = null;
135
96
 
136
- /**
137
- * Clicking on the icon toggles if the mutator bubble is visible.
138
- * Disable if block is uneditable.
139
- * @param {!Event} e Mouse click event.
140
- * @protected
141
- * @override
142
- */
143
- Mutator.prototype.iconClick_ = function(e) {
144
- if (this.block_.isEditable()) {
145
- Icon.prototype.iconClick_.call(this, e);
97
+ /**
98
+ * Function registered on the main workspace to update the mutator contents
99
+ * when the main workspace changes.
100
+ * @type {?Function}
101
+ * @private
102
+ */
103
+ this.sourceListener_ = null;
146
104
  }
147
- };
148
105
 
149
- /**
150
- * Create the editor for the mutator's bubble.
151
- * @return {!SVGElement} The top-level node of the editor.
152
- * @private
153
- */
154
- Mutator.prototype.createEditor_ = function() {
155
- /* Create the editor. Here's the markup that will be generated:
156
- <svg>
157
- [Workspace]
158
- </svg>
159
- */
160
- this.svgDialog_ = dom.createSvgElement(
161
- Svg.SVG, {'x': Bubble.BORDER_WIDTH, 'y': Bubble.BORDER_WIDTH}, null);
162
- // Convert the list of names into a list of XML objects for the flyout.
163
- let quarkXml;
164
- if (this.quarkNames_.length) {
165
- quarkXml = xml.createElement('xml');
166
- for (let i = 0, quarkName; (quarkName = this.quarkNames_[i]); i++) {
167
- const element = xml.createElement('block');
168
- element.setAttribute('type', quarkName);
169
- quarkXml.appendChild(element);
170
- }
171
- } else {
172
- quarkXml = null;
173
- }
174
- const workspaceOptions = new Options(
175
- /** @type {!BlocklyOptions} */
176
- ({
177
- // If you want to enable disabling, also remove the
178
- // event filter from workspaceChanged_ .
179
- 'disable': false,
180
- 'parentWorkspace': this.block_.workspace,
181
- 'media': this.block_.workspace.options.pathToMedia,
182
- 'rtl': this.block_.RTL,
183
- 'horizontalLayout': false,
184
- 'renderer': this.block_.workspace.options.renderer,
185
- 'rendererOverrides': this.block_.workspace.options.rendererOverrides,
186
- }));
187
- workspaceOptions.toolboxPosition =
188
- this.block_.RTL ? toolbox.Position.RIGHT : toolbox.Position.LEFT;
189
- const hasFlyout = !!quarkXml;
190
- if (hasFlyout) {
191
- workspaceOptions.languageTree = toolbox.convertToolboxDefToJson(quarkXml);
106
+ /**
107
+ * Set the block this mutator is associated with.
108
+ * @param {!BlockSvg} block The block associated with this mutator.
109
+ * @package
110
+ */
111
+ setBlock(block) {
112
+ this.block_ = block;
192
113
  }
193
- this.workspace_ = new WorkspaceSvg(workspaceOptions);
194
- this.workspace_.isMutator = true;
195
- this.workspace_.addChangeListener(eventUtils.disableOrphans);
196
-
197
- // Mutator flyouts go inside the mutator workspace's <g> rather than in
198
- // a top level SVG. Instead of handling scale themselves, mutators
199
- // inherit scale from the parent workspace.
200
- // To fix this, scale needs to be applied at a different level in the DOM.
201
- const flyoutSvg = hasFlyout ? this.workspace_.addFlyout(Svg.G) : null;
202
- const background = this.workspace_.createDom('blocklyMutatorBackground');
203
-
204
- if (flyoutSvg) {
205
- // Insert the flyout after the <rect> but before the block canvas so that
206
- // the flyout is underneath in z-order. This makes blocks layering during
207
- // dragging work properly.
208
- background.insertBefore(flyoutSvg, this.workspace_.svgBlockCanvas_);
114
+
115
+ /**
116
+ * Returns the workspace inside this mutator icon's bubble.
117
+ * @return {?WorkspaceSvg} The workspace inside this mutator icon's
118
+ * bubble or null if the mutator isn't open.
119
+ * @package
120
+ */
121
+ getWorkspace() {
122
+ return this.workspace_;
209
123
  }
210
- this.svgDialog_.appendChild(background);
211
124
 
212
- return this.svgDialog_;
213
- };
125
+ /**
126
+ * Draw the mutator icon.
127
+ * @param {!Element} group The icon group.
128
+ * @protected
129
+ */
130
+ drawIcon_(group) {
131
+ // Square with rounded corners.
132
+ dom.createSvgElement(
133
+ Svg.RECT, {
134
+ 'class': 'blocklyIconShape',
135
+ 'rx': '4',
136
+ 'ry': '4',
137
+ 'height': '16',
138
+ 'width': '16',
139
+ },
140
+ group);
141
+ // Gear teeth.
142
+ dom.createSvgElement(
143
+ Svg.PATH, {
144
+ 'class': 'blocklyIconSymbol',
145
+ 'd': 'm4.203,7.296 0,1.368 -0.92,0.677 -0.11,0.41 0.9,1.559 0.41,' +
146
+ '0.11 1.043,-0.457 1.187,0.683 0.127,1.134 0.3,0.3 1.8,0 0.3,' +
147
+ '-0.299 0.127,-1.138 1.185,-0.682 1.046,0.458 0.409,-0.11 0.9,' +
148
+ '-1.559 -0.11,-0.41 -0.92,-0.677 0,-1.366 0.92,-0.677 0.11,' +
149
+ '-0.41 -0.9,-1.559 -0.409,-0.109 -1.046,0.458 -1.185,-0.682 ' +
150
+ '-0.127,-1.138 -0.3,-0.299 -1.8,0 -0.3,0.3 -0.126,1.135 -1.187,' +
151
+ '0.682 -1.043,-0.457 -0.41,0.11 -0.899,1.559 0.108,0.409z',
152
+ },
153
+ group);
154
+ // Axle hole.
155
+ dom.createSvgElement(
156
+ Svg.CIRCLE,
157
+ {'class': 'blocklyIconShape', 'r': '2.7', 'cx': '8', 'cy': '8'}, group);
158
+ }
214
159
 
215
- /**
216
- * Add or remove the UI indicating if this icon may be clicked or not.
217
- */
218
- Mutator.prototype.updateEditable = function() {
219
- Mutator.superClass_.updateEditable.call(this);
220
- if (!this.block_.isInFlyout) {
160
+ /**
161
+ * Clicking on the icon toggles if the mutator bubble is visible.
162
+ * Disable if block is uneditable.
163
+ * @param {!Event} e Mouse click event.
164
+ * @protected
165
+ * @override
166
+ */
167
+ iconClick_(e) {
221
168
  if (this.block_.isEditable()) {
222
- if (this.iconGroup_) {
223
- dom.removeClass(
224
- /** @type {!Element} */ (this.iconGroup_),
225
- 'blocklyIconGroupReadonly');
226
- }
227
- } else {
228
- // Close any mutator bubble. Icon is not clickable.
229
- this.setVisible(false);
230
- if (this.iconGroup_) {
231
- dom.addClass(
232
- /** @type {!Element} */ (this.iconGroup_),
233
- 'blocklyIconGroupReadonly');
234
- }
169
+ Icon.prototype.iconClick_.call(this, e);
235
170
  }
236
171
  }
237
- };
238
172
 
239
- /**
240
- * Resize the bubble to match the size of the workspace.
241
- * @private
242
- */
243
- Mutator.prototype.resizeBubble_ = function() {
244
- const doubleBorderWidth = 2 * Bubble.BORDER_WIDTH;
245
- const workspaceSize = this.workspace_.getCanvas().getBBox();
246
- let width = workspaceSize.width + workspaceSize.x;
247
- let height = workspaceSize.height + doubleBorderWidth * 3;
248
- const flyout = this.workspace_.getFlyout();
249
- if (flyout) {
250
- const flyoutScrollMetrics =
251
- flyout.getWorkspace().getMetricsManager().getScrollMetrics();
252
- height = Math.max(height, flyoutScrollMetrics.height + 20);
253
- width += flyout.getWidth();
254
- }
255
- if (this.block_.RTL) {
256
- width = -workspaceSize.x;
257
- }
258
- width += doubleBorderWidth * 3;
259
- // Only resize if the size difference is significant. Eliminates shuddering.
260
- if (Math.abs(this.workspaceWidth_ - width) > doubleBorderWidth ||
261
- Math.abs(this.workspaceHeight_ - height) > doubleBorderWidth) {
262
- // Record some layout information for workspace metrics.
263
- this.workspaceWidth_ = width;
264
- this.workspaceHeight_ = height;
265
- // Resize the bubble.
266
- this.bubble_.setBubbleSize(
267
- width + doubleBorderWidth, height + doubleBorderWidth);
268
- this.svgDialog_.setAttribute('width', this.workspaceWidth_);
269
- this.svgDialog_.setAttribute('height', this.workspaceHeight_);
270
- this.workspace_.setCachedParentSvgSize(
271
- this.workspaceWidth_, this.workspaceHeight_);
272
- }
173
+ /**
174
+ * Create the editor for the mutator's bubble.
175
+ * @return {!SVGElement} The top-level node of the editor.
176
+ * @private
177
+ */
178
+ createEditor_() {
179
+ /* Create the editor. Here's the markup that will be generated:
180
+ <svg>
181
+ [Workspace]
182
+ </svg>
183
+ */
184
+ this.svgDialog_ = dom.createSvgElement(
185
+ Svg.SVG, {'x': Bubble.BORDER_WIDTH, 'y': Bubble.BORDER_WIDTH}, null);
186
+ // Convert the list of names into a list of XML objects for the flyout.
187
+ let quarkXml;
188
+ if (this.quarkNames_.length) {
189
+ quarkXml = xml.createElement('xml');
190
+ for (let i = 0, quarkName; (quarkName = this.quarkNames_[i]); i++) {
191
+ const element = xml.createElement('block');
192
+ element.setAttribute('type', quarkName);
193
+ quarkXml.appendChild(element);
194
+ }
195
+ } else {
196
+ quarkXml = null;
197
+ }
198
+ const workspaceOptions = new Options(
199
+ /** @type {!BlocklyOptions} */
200
+ ({
201
+ // If you want to enable disabling, also remove the
202
+ // event filter from workspaceChanged_ .
203
+ 'disable': false,
204
+ 'parentWorkspace': this.block_.workspace,
205
+ 'media': this.block_.workspace.options.pathToMedia,
206
+ 'rtl': this.block_.RTL,
207
+ 'horizontalLayout': false,
208
+ 'renderer': this.block_.workspace.options.renderer,
209
+ 'rendererOverrides': this.block_.workspace.options.rendererOverrides,
210
+ }));
211
+ workspaceOptions.toolboxPosition =
212
+ this.block_.RTL ? toolbox.Position.RIGHT : toolbox.Position.LEFT;
213
+ const hasFlyout = !!quarkXml;
214
+ if (hasFlyout) {
215
+ workspaceOptions.languageTree = toolbox.convertToolboxDefToJson(quarkXml);
216
+ }
217
+ this.workspace_ = new WorkspaceSvg(workspaceOptions);
218
+ this.workspace_.isMutator = true;
219
+ this.workspace_.addChangeListener(eventUtils.disableOrphans);
220
+
221
+ // Mutator flyouts go inside the mutator workspace's <g> rather than in
222
+ // a top level SVG. Instead of handling scale themselves, mutators
223
+ // inherit scale from the parent workspace.
224
+ // To fix this, scale needs to be applied at a different level in the DOM.
225
+ const flyoutSvg = hasFlyout ? this.workspace_.addFlyout(Svg.G) : null;
226
+ const background = this.workspace_.createDom('blocklyMutatorBackground');
227
+
228
+ if (flyoutSvg) {
229
+ // Insert the flyout after the <rect> but before the block canvas so that
230
+ // the flyout is underneath in z-order. This makes blocks layering during
231
+ // dragging work properly.
232
+ background.insertBefore(flyoutSvg, this.workspace_.svgBlockCanvas_);
233
+ }
234
+ this.svgDialog_.appendChild(background);
273
235
 
274
- if (this.block_.RTL) {
275
- // Scroll the workspace to always left-align.
276
- const translation = 'translate(' + this.workspaceWidth_ + ',0)';
277
- this.workspace_.getCanvas().setAttribute('transform', translation);
236
+ return this.svgDialog_;
278
237
  }
279
- this.workspace_.resize();
280
- };
281
238
 
282
- /**
283
- * A method handler for when the bubble is moved.
284
- * @private
285
- */
286
- Mutator.prototype.onBubbleMove_ = function() {
287
- if (this.workspace_) {
288
- this.workspace_.recordDragTargets();
239
+ /**
240
+ * Add or remove the UI indicating if this icon may be clicked or not.
241
+ */
242
+ updateEditable() {
243
+ super.updateEditable();
244
+ if (!this.block_.isInFlyout) {
245
+ if (this.block_.isEditable()) {
246
+ if (this.iconGroup_) {
247
+ dom.removeClass(
248
+ /** @type {!Element} */ (this.iconGroup_),
249
+ 'blocklyIconGroupReadonly');
250
+ }
251
+ } else {
252
+ // Close any mutator bubble. Icon is not clickable.
253
+ this.setVisible(false);
254
+ if (this.iconGroup_) {
255
+ dom.addClass(
256
+ /** @type {!Element} */ (this.iconGroup_),
257
+ 'blocklyIconGroupReadonly');
258
+ }
259
+ }
260
+ }
289
261
  }
290
- };
291
262
 
292
- /**
293
- * Show or hide the mutator bubble.
294
- * @param {boolean} visible True if the bubble should be visible.
295
- */
296
- Mutator.prototype.setVisible = function(visible) {
297
- if (visible === this.isVisible()) {
298
- // No change.
299
- return;
300
- }
301
- eventUtils.fire(new (eventUtils.get(eventUtils.BUBBLE_OPEN))(
302
- this.block_, visible, 'mutator'));
303
- if (visible) {
304
- // Create the bubble.
305
- this.bubble_ = new Bubble(
306
- /** @type {!WorkspaceSvg} */ (this.block_.workspace),
307
- this.createEditor_(), this.block_.pathObject.svgPath,
308
- /** @type {!Coordinate} */ (this.iconXY_), null, null);
309
- // Expose this mutator's block's ID on its top-level SVG group.
310
- this.bubble_.setSvgId(this.block_.id);
311
- this.bubble_.registerMoveEvent(this.onBubbleMove_.bind(this));
312
- const tree = this.workspace_.options.languageTree;
263
+ /**
264
+ * Resize the bubble to match the size of the workspace.
265
+ * @private
266
+ */
267
+ resizeBubble_() {
268
+ const doubleBorderWidth = 2 * Bubble.BORDER_WIDTH;
269
+ const workspaceSize = this.workspace_.getCanvas().getBBox();
270
+ let width = workspaceSize.width + workspaceSize.x;
271
+ let height = workspaceSize.height + doubleBorderWidth * 3;
313
272
  const flyout = this.workspace_.getFlyout();
314
- if (tree) {
315
- flyout.init(this.workspace_);
316
- flyout.show(tree);
317
- }
318
-
319
- this.rootBlock_ = this.block_.decompose(this.workspace_);
320
- const blocks = this.rootBlock_.getDescendants(false);
321
- for (let i = 0, child; (child = blocks[i]); i++) {
322
- child.render();
323
- }
324
- // The root block should not be draggable or deletable.
325
- this.rootBlock_.setMovable(false);
326
- this.rootBlock_.setDeletable(false);
327
- let margin;
328
- let x;
329
273
  if (flyout) {
330
- margin = flyout.CORNER_RADIUS * 2;
331
- x = this.rootBlock_.RTL ? flyout.getWidth() + margin : margin;
332
- } else {
333
- margin = 16;
334
- x = margin;
274
+ const flyoutScrollMetrics =
275
+ flyout.getWorkspace().getMetricsManager().getScrollMetrics();
276
+ height = Math.max(height, flyoutScrollMetrics.height + 20);
277
+ width += flyout.getWidth();
335
278
  }
336
279
  if (this.block_.RTL) {
337
- x = -x;
280
+ width = -workspaceSize.x;
338
281
  }
339
- this.rootBlock_.moveBy(x, margin);
340
- // Save the initial connections, then listen for further changes.
341
- if (this.block_.saveConnections) {
342
- const thisMutator = this;
343
- const mutatorBlock =
344
- /** @type {{saveConnections: function(!Block)}} */ (this.block_);
345
- mutatorBlock.saveConnections(this.rootBlock_);
346
- this.sourceListener_ = function() {
347
- mutatorBlock.saveConnections(thisMutator.rootBlock_);
348
- };
349
- this.block_.workspace.addChangeListener(this.sourceListener_);
282
+ width += doubleBorderWidth * 3;
283
+ // Only resize if the size difference is significant. Eliminates
284
+ // shuddering.
285
+ if (Math.abs(this.workspaceWidth_ - width) > doubleBorderWidth ||
286
+ Math.abs(this.workspaceHeight_ - height) > doubleBorderWidth) {
287
+ // Record some layout information for workspace metrics.
288
+ this.workspaceWidth_ = width;
289
+ this.workspaceHeight_ = height;
290
+ // Resize the bubble.
291
+ this.bubble_.setBubbleSize(
292
+ width + doubleBorderWidth, height + doubleBorderWidth);
293
+ this.svgDialog_.setAttribute('width', this.workspaceWidth_);
294
+ this.svgDialog_.setAttribute('height', this.workspaceHeight_);
295
+ this.workspace_.setCachedParentSvgSize(
296
+ this.workspaceWidth_, this.workspaceHeight_);
350
297
  }
351
- this.resizeBubble_();
352
- // When the mutator's workspace changes, update the source block.
353
- this.workspace_.addChangeListener(this.workspaceChanged_.bind(this));
354
- // Update the source block immediately after the bubble becomes visible.
355
- this.updateWorkspace_();
356
- this.applyColour();
357
- } else {
358
- // Dispose of the bubble.
359
- this.svgDialog_ = null;
360
- this.workspace_.dispose();
361
- this.workspace_ = null;
362
- this.rootBlock_ = null;
363
- this.bubble_.dispose();
364
- this.bubble_ = null;
365
- this.workspaceWidth_ = 0;
366
- this.workspaceHeight_ = 0;
367
- if (this.sourceListener_) {
368
- this.block_.workspace.removeChangeListener(this.sourceListener_);
369
- this.sourceListener_ = null;
298
+
299
+ if (this.block_.RTL) {
300
+ // Scroll the workspace to always left-align.
301
+ const translation = 'translate(' + this.workspaceWidth_ + ',0)';
302
+ this.workspace_.getCanvas().setAttribute('transform', translation);
370
303
  }
304
+ this.workspace_.resize();
371
305
  }
372
- };
373
306
 
374
- /**
375
- * Fired whenever a change is made to the mutator's workspace.
376
- * @param {!Abstract} e Custom data for event.
377
- * @private
378
- */
379
- Mutator.prototype.workspaceChanged_ = function(e) {
380
- if (!(e.isUiEvent ||
381
- (e.type === eventUtils.CHANGE && e.element === 'disabled') ||
382
- e.type === eventUtils.CREATE)) {
383
- this.updateWorkspace_();
307
+ /**
308
+ * A method handler for when the bubble is moved.
309
+ * @private
310
+ */
311
+ onBubbleMove_() {
312
+ if (this.workspace_) {
313
+ this.workspace_.recordDragTargets();
314
+ }
384
315
  }
385
- };
386
316
 
387
- /**
388
- * Updates the source block when the mutator's blocks are changed.
389
- * Bump down any block that's too high.
390
- * @private
391
- */
392
- Mutator.prototype.updateWorkspace_ = function() {
393
- if (!this.workspace_.isDragging()) {
394
- const blocks = this.workspace_.getTopBlocks(false);
395
- const MARGIN = 20;
396
-
397
- for (let b = 0, block; (block = blocks[b]); b++) {
398
- const blockXY = block.getRelativeToSurfaceXY();
317
+ /**
318
+ * Show or hide the mutator bubble.
319
+ * @param {boolean} visible True if the bubble should be visible.
320
+ */
321
+ setVisible(visible) {
322
+ if (visible === this.isVisible()) {
323
+ // No change.
324
+ return;
325
+ }
326
+ eventUtils.fire(new (eventUtils.get(eventUtils.BUBBLE_OPEN))(
327
+ this.block_, visible, 'mutator'));
328
+ if (visible) {
329
+ // Create the bubble.
330
+ this.bubble_ = new Bubble(
331
+ /** @type {!WorkspaceSvg} */ (this.block_.workspace),
332
+ this.createEditor_(), this.block_.pathObject.svgPath,
333
+ /** @type {!Coordinate} */ (this.iconXY_), null, null);
334
+ // Expose this mutator's block's ID on its top-level SVG group.
335
+ this.bubble_.setSvgId(this.block_.id);
336
+ this.bubble_.registerMoveEvent(this.onBubbleMove_.bind(this));
337
+ const tree = this.workspace_.options.languageTree;
338
+ const flyout = this.workspace_.getFlyout();
339
+ if (tree) {
340
+ flyout.init(this.workspace_);
341
+ flyout.show(tree);
342
+ }
399
343
 
400
- // Bump any block that's above the top back inside.
401
- if (blockXY.y < MARGIN) {
402
- block.moveBy(0, MARGIN - blockXY.y);
344
+ this.rootBlock_ = this.block_.decompose(this.workspace_);
345
+ const blocks = this.rootBlock_.getDescendants(false);
346
+ for (let i = 0, child; (child = blocks[i]); i++) {
347
+ child.render();
403
348
  }
404
- // Bump any block overlapping the flyout back inside.
405
- if (block.RTL) {
406
- let right = -MARGIN;
407
- const flyout = this.workspace_.getFlyout();
408
- if (flyout) {
409
- right -= flyout.getWidth();
410
- }
411
- if (blockXY.x > right) {
412
- block.moveBy(right - blockXY.x, 0);
413
- }
414
- } else if (blockXY.x < MARGIN) {
415
- block.moveBy(MARGIN - blockXY.x, 0);
349
+ // The root block should not be draggable or deletable.
350
+ this.rootBlock_.setMovable(false);
351
+ this.rootBlock_.setDeletable(false);
352
+ let margin;
353
+ let x;
354
+ if (flyout) {
355
+ margin = flyout.CORNER_RADIUS * 2;
356
+ x = this.rootBlock_.RTL ? flyout.getWidth() + margin : margin;
357
+ } else {
358
+ margin = 16;
359
+ x = margin;
360
+ }
361
+ if (this.block_.RTL) {
362
+ x = -x;
363
+ }
364
+ this.rootBlock_.moveBy(x, margin);
365
+ // Save the initial connections, then listen for further changes.
366
+ if (this.block_.saveConnections) {
367
+ const thisRootBlock = this.rootBlock_;
368
+ this.block_.saveConnections(thisRootBlock);
369
+ this.sourceListener_ = () => {
370
+ if (this.block_) {
371
+ this.block_.saveConnections(thisRootBlock);
372
+ }
373
+ };
374
+ this.block_.workspace.addChangeListener(this.sourceListener_);
375
+ }
376
+ this.resizeBubble_();
377
+ // When the mutator's workspace changes, update the source block.
378
+ this.workspace_.addChangeListener(this.workspaceChanged_.bind(this));
379
+ // Update the source block immediately after the bubble becomes visible.
380
+ this.updateWorkspace_();
381
+ this.applyColour();
382
+ } else {
383
+ // Dispose of the bubble.
384
+ this.svgDialog_ = null;
385
+ this.workspace_.dispose();
386
+ this.workspace_ = null;
387
+ this.rootBlock_ = null;
388
+ this.bubble_.dispose();
389
+ this.bubble_ = null;
390
+ this.workspaceWidth_ = 0;
391
+ this.workspaceHeight_ = 0;
392
+ if (this.sourceListener_) {
393
+ this.block_.workspace.removeChangeListener(this.sourceListener_);
394
+ this.sourceListener_ = null;
416
395
  }
417
396
  }
418
397
  }
419
398
 
420
- // When the mutator's workspace changes, update the source block.
421
- if (this.rootBlock_.workspace === this.workspace_) {
422
- eventUtils.setGroup(true);
423
- const block = /** @type {!BlockSvg} */ (this.block_);
424
- const oldExtraState = BlockChange.getExtraBlockState_(block);
425
-
426
- // Switch off rendering while the source block is rebuilt.
427
- const savedRendered = block.rendered;
428
- // TODO(#4288): We should not be setting the rendered property to false.
429
- block.rendered = false;
430
-
431
- // Allow the source block to rebuild itself.
432
- block.compose(this.rootBlock_);
433
- // Restore rendering and show the changes.
434
- block.rendered = savedRendered;
435
- // Mutation may have added some elements that need initializing.
436
- block.initSvg();
437
-
438
- if (block.rendered) {
439
- block.render();
440
- }
441
-
442
- const newExtraState = BlockChange.getExtraBlockState_(block);
443
- if (oldExtraState !== newExtraState) {
444
- eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
445
- block, 'mutation', null, oldExtraState, newExtraState));
446
- // Ensure that any bump is part of this mutation's event group.
447
- const group = eventUtils.getGroup();
448
- setTimeout(function() {
449
- eventUtils.setGroup(group);
450
- block.bumpNeighbours();
451
- eventUtils.setGroup(false);
452
- }, internalConstants.BUMP_DELAY);
399
+ /**
400
+ * Fired whenever a change is made to the mutator's workspace.
401
+ * @param {!Abstract} e Custom data for event.
402
+ * @private
403
+ */
404
+ workspaceChanged_(e) {
405
+ if (!(e.isUiEvent ||
406
+ (e.type === eventUtils.CHANGE &&
407
+ /** @type {!BlockChange} */ (e).element === 'disabled') ||
408
+ e.type === eventUtils.CREATE)) {
409
+ this.updateWorkspace_();
453
410
  }
411
+ }
454
412
 
455
- // Don't update the bubble until the drag has ended, to avoid moving blocks
456
- // under the cursor.
413
+ /**
414
+ * Updates the source block when the mutator's blocks are changed.
415
+ * Bump down any block that's too high.
416
+ * @private
417
+ */
418
+ updateWorkspace_() {
457
419
  if (!this.workspace_.isDragging()) {
458
- this.resizeBubble_();
420
+ const blocks = this.workspace_.getTopBlocks(false);
421
+ const MARGIN = 20;
422
+
423
+ for (let b = 0, block; (block = blocks[b]); b++) {
424
+ const blockXY = block.getRelativeToSurfaceXY();
425
+
426
+ // Bump any block that's above the top back inside.
427
+ if (blockXY.y < MARGIN) {
428
+ block.moveBy(0, MARGIN - blockXY.y);
429
+ }
430
+ // Bump any block overlapping the flyout back inside.
431
+ if (block.RTL) {
432
+ let right = -MARGIN;
433
+ const flyout = this.workspace_.getFlyout();
434
+ if (flyout) {
435
+ right -= flyout.getWidth();
436
+ }
437
+ if (blockXY.x > right) {
438
+ block.moveBy(right - blockXY.x, 0);
439
+ }
440
+ } else if (blockXY.x < MARGIN) {
441
+ block.moveBy(MARGIN - blockXY.x, 0);
442
+ }
443
+ }
459
444
  }
460
- eventUtils.setGroup(false);
461
- }
462
- };
463
445
 
464
- /**
465
- * Dispose of this mutator.
466
- */
467
- Mutator.prototype.dispose = function() {
468
- this.block_.mutator = null;
469
- Icon.prototype.dispose.call(this);
470
- };
446
+ // When the mutator's workspace changes, update the source block.
447
+ if (this.rootBlock_.workspace === this.workspace_) {
448
+ const existingGroup = eventUtils.getGroup();
449
+ if (!existingGroup) {
450
+ eventUtils.setGroup(true);
451
+ }
452
+ const block = /** @type {!BlockSvg} */ (this.block_);
453
+ const oldExtraState = BlockChange.getExtraBlockState_(block);
454
+
455
+ // Switch off rendering while the source block is rebuilt.
456
+ const savedRendered = block.rendered;
457
+ // TODO(#4288): We should not be setting the rendered property to false.
458
+ block.rendered = false;
459
+
460
+ // Allow the source block to rebuild itself.
461
+ block.compose(this.rootBlock_);
462
+ // Restore rendering and show the changes.
463
+ block.rendered = savedRendered;
464
+ // Mutation may have added some elements that need initializing.
465
+ block.initSvg();
466
+
467
+ if (block.rendered) {
468
+ block.render();
469
+ }
471
470
 
472
- /**
473
- * Update the styles on all blocks in the mutator.
474
- * @public
475
- */
476
- Mutator.prototype.updateBlockStyle = function() {
477
- const ws = this.workspace_;
471
+ const newExtraState = BlockChange.getExtraBlockState_(block);
472
+ if (oldExtraState !== newExtraState) {
473
+ eventUtils.fire(new (eventUtils.get(eventUtils.BLOCK_CHANGE))(
474
+ block, 'mutation', null, oldExtraState, newExtraState));
475
+ // Ensure that any bump is part of this mutation's event group.
476
+ const mutationGroup = eventUtils.getGroup();
477
+ setTimeout(function() {
478
+ const oldGroup = eventUtils.getGroup();
479
+ eventUtils.setGroup(mutationGroup);
480
+ block.bumpNeighbours();
481
+ eventUtils.setGroup(oldGroup);
482
+ }, config.bumpDelay);
483
+ }
478
484
 
479
- if (ws && ws.getAllBlocks(false)) {
480
- const workspaceBlocks = ws.getAllBlocks(false);
481
- for (let i = 0, block; (block = workspaceBlocks[i]); i++) {
482
- block.setStyle(block.getStyleName());
485
+ // Don't update the bubble until the drag has ended, to avoid moving
486
+ // blocks under the cursor.
487
+ if (!this.workspace_.isDragging()) {
488
+ this.resizeBubble_();
489
+ }
490
+ eventUtils.setGroup(existingGroup);
483
491
  }
492
+ }
484
493
 
485
- const flyout = ws.getFlyout();
486
- if (flyout) {
487
- const flyoutBlocks = flyout.workspace_.getAllBlocks(false);
488
- for (let i = 0, block; (block = flyoutBlocks[i]); i++) {
494
+ /**
495
+ * Dispose of this mutator.
496
+ */
497
+ dispose() {
498
+ this.block_.mutator = null;
499
+ Icon.prototype.dispose.call(this);
500
+ }
501
+
502
+ /**
503
+ * Update the styles on all blocks in the mutator.
504
+ * @public
505
+ */
506
+ updateBlockStyle() {
507
+ const ws = this.workspace_;
508
+
509
+ if (ws && ws.getAllBlocks(false)) {
510
+ const workspaceBlocks = ws.getAllBlocks(false);
511
+ for (let i = 0, block; (block = workspaceBlocks[i]); i++) {
489
512
  block.setStyle(block.getStyleName());
490
513
  }
514
+
515
+ const flyout = ws.getFlyout();
516
+ if (flyout) {
517
+ const flyoutBlocks = flyout.workspace_.getAllBlocks(false);
518
+ for (let i = 0, block; (block = flyoutBlocks[i]); i++) {
519
+ block.setStyle(block.getStyleName());
520
+ }
521
+ }
491
522
  }
492
523
  }
493
- };
494
524
 
495
- /**
496
- * Reconnect an block to a mutated input.
497
- * @param {Connection} connectionChild Connection on child block.
498
- * @param {!Block} block Parent block.
499
- * @param {string} inputName Name of input on parent block.
500
- * @return {boolean} True iff a reconnection was made, false otherwise.
501
- */
502
- Mutator.reconnect = function(connectionChild, block, inputName) {
503
- if (!connectionChild || !connectionChild.getSourceBlock().workspace) {
504
- return false; // No connection or block has been deleted.
505
- }
506
- const connectionParent = block.getInput(inputName).connection;
507
- const currentParent = connectionChild.targetBlock();
508
- if ((!currentParent || currentParent === block) &&
509
- connectionParent.targetConnection !== connectionChild) {
510
- if (connectionParent.isConnected()) {
511
- // There's already something connected here. Get rid of it.
512
- connectionParent.disconnect();
525
+ /**
526
+ * Reconnect an block to a mutated input.
527
+ * @param {Connection} connectionChild Connection on child block.
528
+ * @param {!Block} block Parent block.
529
+ * @param {string} inputName Name of input on parent block.
530
+ * @return {boolean} True iff a reconnection was made, false otherwise.
531
+ */
532
+ static reconnect(connectionChild, block, inputName) {
533
+ if (!connectionChild || !connectionChild.getSourceBlock().workspace) {
534
+ return false; // No connection or block has been deleted.
535
+ }
536
+ const connectionParent = block.getInput(inputName).connection;
537
+ const currentParent = connectionChild.targetBlock();
538
+ if ((!currentParent || currentParent === block) &&
539
+ connectionParent.targetConnection !== connectionChild) {
540
+ if (connectionParent.isConnected()) {
541
+ // There's already something connected here. Get rid of it.
542
+ connectionParent.disconnect();
543
+ }
544
+ connectionParent.connect(connectionChild);
545
+ return true;
513
546
  }
514
- connectionParent.connect(connectionChild);
515
- return true;
547
+ return false;
516
548
  }
517
- return false;
518
- };
519
549
 
520
- /**
521
- * Get the parent workspace of a workspace that is inside a mutator, taking into
522
- * account whether it is a flyout.
523
- * @param {Workspace} workspace The workspace that is inside a mutator.
524
- * @return {?Workspace} The mutator's parent workspace or null.
525
- * @public
526
- */
527
- Mutator.findParentWs = function(workspace) {
528
- let outerWs = null;
529
- if (workspace && workspace.options) {
530
- const parent = workspace.options.parentWorkspace;
531
- // If we were in a flyout in a mutator, need to go up two levels to find
532
- // the actual parent.
533
- if (workspace.isFlyout) {
534
- if (parent && parent.options) {
535
- outerWs = parent.options.parentWorkspace;
550
+ /**
551
+ * Get the parent workspace of a workspace that is inside a mutator, taking
552
+ * into account whether it is a flyout.
553
+ * @param {WorkspaceSvg} workspace The workspace that is inside a mutator.
554
+ * @return {?WorkspaceSvg} The mutator's parent workspace or null.
555
+ * @public
556
+ */
557
+ static findParentWs(workspace) {
558
+ let outerWs = null;
559
+ if (workspace && workspace.options) {
560
+ const parent = workspace.options.parentWorkspace;
561
+ // If we were in a flyout in a mutator, need to go up two levels to find
562
+ // the actual parent.
563
+ if (workspace.isFlyout) {
564
+ if (parent && parent.options) {
565
+ outerWs = parent.options.parentWorkspace;
566
+ }
567
+ } else if (parent) {
568
+ outerWs = parent;
536
569
  }
537
- } else if (parent) {
538
- outerWs = parent;
539
570
  }
571
+ return outerWs;
540
572
  }
541
- return outerWs;
542
- };
573
+ }
543
574
 
544
575
  exports.Mutator = Mutator;