blockly 7.20211209.2 → 8.0.0

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 (262) hide show
  1. package/blockly.d.ts +18963 -18432
  2. package/blockly.min.js +852 -844
  3. package/blockly_compressed.js +669 -664
  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 +41 -27
  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 +146 -141
  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 +19 -9
  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/dart_compressed.js +40 -43
  208. package/dart_compressed.js.map +1 -1
  209. package/generators/dart/colour.js +56 -64
  210. package/generators/dart/lists.js +61 -50
  211. package/generators/dart/math.js +160 -148
  212. package/generators/dart/text.js +83 -61
  213. package/generators/javascript/colour.js +37 -34
  214. package/generators/javascript/lists.js +50 -43
  215. package/generators/javascript/math.js +123 -139
  216. package/generators/javascript/text.js +67 -81
  217. package/generators/lua/colour.js +25 -23
  218. package/generators/lua/lists.js +97 -69
  219. package/generators/lua/logic.js +1 -2
  220. package/generators/lua/math.js +182 -144
  221. package/generators/lua/text.js +116 -99
  222. package/generators/php/colour.js +38 -32
  223. package/generators/php/lists.js +109 -89
  224. package/generators/php/math.js +90 -81
  225. package/generators/php/text.js +63 -61
  226. package/generators/python/colour.js +18 -18
  227. package/generators/python/lists.js +38 -30
  228. package/generators/python/loops.js +12 -8
  229. package/generators/python/math.js +104 -106
  230. package/generators/python/text.js +34 -30
  231. package/javascript_compressed.js +37 -39
  232. package/javascript_compressed.js.map +1 -1
  233. package/lua_compressed.js +39 -42
  234. package/lua_compressed.js.map +1 -1
  235. package/msg/az.js +2 -2
  236. package/msg/be.js +4 -4
  237. package/msg/cs.js +15 -15
  238. package/msg/de.js +1 -1
  239. package/msg/diq.js +1 -1
  240. package/msg/eo.js +1 -1
  241. package/msg/es.js +1 -1
  242. package/msg/fa.js +1 -1
  243. package/msg/fr.js +4 -4
  244. package/msg/he.js +1 -1
  245. package/msg/hr.js +2 -2
  246. package/msg/hy.js +2 -2
  247. package/msg/id.js +12 -12
  248. package/msg/inh.js +14 -14
  249. package/msg/ja.js +7 -7
  250. package/msg/lv.js +29 -29
  251. package/msg/pa.js +3 -3
  252. package/msg/smn.js +436 -0
  253. package/msg/te.js +1 -1
  254. package/msg/yue.js +1 -1
  255. package/msg/zh-hans.js +3 -3
  256. package/msg/zh-hant.js +3 -3
  257. package/package.json +7 -6
  258. package/php_compressed.js +38 -42
  259. package/php_compressed.js.map +1 -1
  260. package/python_compressed.js +26 -25
  261. package/python_compressed.js.map +1 -1
  262. package/blocks/all.js +0 -23
@@ -22,6 +22,8 @@ const dom = goog.require('Blockly.utils.dom');
22
22
  const eventUtils = goog.require('Blockly.Events.utils');
23
23
  const registry = goog.require('Blockly.registry');
24
24
  /* eslint-disable-next-line no-unused-vars */
25
+ const {BlockMove} = goog.requireType('Blockly.Events.BlockMove');
26
+ /* eslint-disable-next-line no-unused-vars */
25
27
  const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
26
28
  const {Coordinate} = goog.require('Blockly.utils.Coordinate');
27
29
  /* eslint-disable-next-line no-unused-vars */
@@ -40,439 +42,441 @@ goog.require('Blockly.Events.BlockMove');
40
42
  /**
41
43
  * Class for a block dragger. It moves blocks around the workspace when they
42
44
  * are being dragged by a mouse or touch.
43
- * @param {!BlockSvg} block The block to drag.
44
- * @param {!WorkspaceSvg} workspace The workspace to drag on.
45
- * @constructor
46
45
  * @implements {IBlockDragger}
47
46
  * @alias Blockly.BlockDragger
48
47
  */
49
- const BlockDragger = function(block, workspace) {
48
+ const BlockDragger = class {
50
49
  /**
51
- * The top block in the stack that is being dragged.
52
- * @type {!BlockSvg}
53
- * @protected
50
+ * @param {!BlockSvg} block The block to drag.
51
+ * @param {!WorkspaceSvg} workspace The workspace to drag on.
54
52
  */
55
- this.draggingBlock_ = block;
53
+ constructor(block, workspace) {
54
+ /**
55
+ * The top block in the stack that is being dragged.
56
+ * @type {!BlockSvg}
57
+ * @protected
58
+ */
59
+ this.draggingBlock_ = block;
60
+
61
+ /**
62
+ * The workspace on which the block is being dragged.
63
+ * @type {!WorkspaceSvg}
64
+ * @protected
65
+ */
66
+ this.workspace_ = workspace;
67
+
68
+ /**
69
+ * Object that keeps track of connections on dragged blocks.
70
+ * @type {!InsertionMarkerManager}
71
+ * @protected
72
+ */
73
+ this.draggedConnectionManager_ =
74
+ new InsertionMarkerManager(this.draggingBlock_);
75
+
76
+ /**
77
+ * Which drag area the mouse pointer is over, if any.
78
+ * @type {?IDragTarget}
79
+ * @private
80
+ */
81
+ this.dragTarget_ = null;
82
+
83
+ /**
84
+ * Whether the block would be deleted if dropped immediately.
85
+ * @type {boolean}
86
+ * @protected
87
+ */
88
+ this.wouldDeleteBlock_ = false;
89
+
90
+ /**
91
+ * The location of the top left corner of the dragging block at the
92
+ * beginning of the drag in workspace coordinates.
93
+ * @type {!Coordinate}
94
+ * @protected
95
+ */
96
+ this.startXY_ = this.draggingBlock_.getRelativeToSurfaceXY();
97
+
98
+ /**
99
+ * A list of all of the icons (comment, warning, and mutator) that are
100
+ * on this block and its descendants. Moving an icon moves the bubble that
101
+ * extends from it if that bubble is open.
102
+ * @type {Array<!Object>}
103
+ * @protected
104
+ */
105
+ this.dragIconData_ = initIconData(block);
106
+ }
56
107
 
57
108
  /**
58
- * The workspace on which the block is being dragged.
59
- * @type {!WorkspaceSvg}
60
- * @protected
109
+ * Sever all links from this object.
110
+ * @package
61
111
  */
62
- this.workspace_ = workspace;
112
+ dispose() {
113
+ this.dragIconData_.length = 0;
63
114
 
64
- /**
65
- * Object that keeps track of connections on dragged blocks.
66
- * @type {!InsertionMarkerManager}
67
- * @protected
68
- */
69
- this.draggedConnectionManager_ =
70
- new InsertionMarkerManager(this.draggingBlock_);
115
+ if (this.draggedConnectionManager_) {
116
+ this.draggedConnectionManager_.dispose();
117
+ }
118
+ }
71
119
 
72
120
  /**
73
- * Which drag area the mouse pointer is over, if any.
74
- * @type {?IDragTarget}
75
- * @private
121
+ * Start dragging a block. This includes moving it to the drag surface.
122
+ * @param {!Coordinate} currentDragDeltaXY How far the pointer has
123
+ * moved from the position at mouse down, in pixel units.
124
+ * @param {boolean} healStack Whether or not to heal the stack after
125
+ * disconnecting.
126
+ * @public
76
127
  */
77
- this.dragTarget_ = null;
128
+ startDrag(currentDragDeltaXY, healStack) {
129
+ if (!eventUtils.getGroup()) {
130
+ eventUtils.setGroup(true);
131
+ }
132
+ this.fireDragStartEvent_();
133
+
134
+ // Mutators don't have the same type of z-ordering as the normal workspace
135
+ // during a drag. They have to rely on the order of the blocks in the SVG.
136
+ // For performance reasons that usually happens at the end of a drag,
137
+ // but do it at the beginning for mutators.
138
+ if (this.workspace_.isMutator) {
139
+ this.draggingBlock_.bringToFront();
140
+ }
141
+
142
+ // During a drag there may be a lot of rerenders, but not field changes.
143
+ // Turn the cache on so we don't do spurious remeasures during the drag.
144
+ dom.startTextWidthCache();
145
+ this.workspace_.setResizesEnabled(false);
146
+ blockAnimation.disconnectUiStop();
147
+
148
+ if (this.shouldDisconnect_(healStack)) {
149
+ this.disconnectBlock_(healStack, currentDragDeltaXY);
150
+ }
151
+ this.draggingBlock_.setDragging(true);
152
+ // For future consideration: we may be able to put moveToDragSurface inside
153
+ // the block dragger, which would also let the block not track the block
154
+ // drag surface.
155
+ this.draggingBlock_.moveToDragSurface();
156
+ }
78
157
 
79
158
  /**
80
- * Whether the block would be deleted if dropped immediately.
81
- * @type {boolean}
159
+ * Whether or not we should disconnect the block when a drag is started.
160
+ * @param {boolean} healStack Whether or not to heal the stack after
161
+ * disconnecting.
162
+ * @return {boolean} True to disconnect the block, false otherwise.
82
163
  * @protected
83
164
  */
84
- this.wouldDeleteBlock_ = false;
165
+ shouldDisconnect_(healStack) {
166
+ return !!(
167
+ this.draggingBlock_.getParent() ||
168
+ (healStack && this.draggingBlock_.nextConnection &&
169
+ this.draggingBlock_.nextConnection.targetBlock()));
170
+ }
85
171
 
86
172
  /**
87
- * The location of the top left corner of the dragging block at the beginning
88
- * of the drag in workspace coordinates.
89
- * @type {!Coordinate}
173
+ * Disconnects the block and moves it to a new location.
174
+ * @param {boolean} healStack Whether or not to heal the stack after
175
+ * disconnecting.
176
+ * @param {!Coordinate} currentDragDeltaXY How far the pointer has
177
+ * moved from the position at mouse down, in pixel units.
90
178
  * @protected
91
179
  */
92
- this.startXY_ = this.draggingBlock_.getRelativeToSurfaceXY();
180
+ disconnectBlock_(healStack, currentDragDeltaXY) {
181
+ this.draggingBlock_.unplug(healStack);
182
+ const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
183
+ const newLoc = Coordinate.sum(this.startXY_, delta);
184
+
185
+ this.draggingBlock_.translate(newLoc.x, newLoc.y);
186
+ blockAnimation.disconnectUiEffect(this.draggingBlock_);
187
+ this.draggedConnectionManager_.updateAvailableConnections();
188
+ }
93
189
 
94
190
  /**
95
- * A list of all of the icons (comment, warning, and mutator) that are
96
- * on this block and its descendants. Moving an icon moves the bubble that
97
- * extends from it if that bubble is open.
98
- * @type {Array<!Object>}
191
+ * Fire a UI event at the start of a block drag.
99
192
  * @protected
100
193
  */
101
- this.dragIconData_ = initIconData(block);
102
- };
103
-
104
- /**
105
- * Sever all links from this object.
106
- * @package
107
- */
108
- BlockDragger.prototype.dispose = function() {
109
- this.dragIconData_.length = 0;
110
-
111
- if (this.draggedConnectionManager_) {
112
- this.draggedConnectionManager_.dispose();
194
+ fireDragStartEvent_() {
195
+ const event = new (eventUtils.get(eventUtils.BLOCK_DRAG))(
196
+ this.draggingBlock_, true, this.draggingBlock_.getDescendants(false));
197
+ eventUtils.fire(event);
113
198
  }
114
- };
115
199
 
116
- /**
117
- * Make a list of all of the icons (comment, warning, and mutator) that are
118
- * on this block and its descendants. Moving an icon moves the bubble that
119
- * extends from it if that bubble is open.
120
- * @param {!BlockSvg} block The root block that is being dragged.
121
- * @return {!Array<!Object>} The list of all icons and their locations.
122
- */
123
- const initIconData = function(block) {
124
- // Build a list of icons that need to be moved and where they started.
125
- const dragIconData = [];
126
- const descendants = block.getDescendants(false);
127
-
128
- for (let i = 0, descendant; (descendant = descendants[i]); i++) {
129
- const icons = descendant.getIcons();
130
- for (let j = 0; j < icons.length; j++) {
131
- const data = {
132
- // Coordinate with x and y properties (workspace
133
- // coordinates).
134
- location: icons[j].getIconLocation(),
135
- // Blockly.Icon
136
- icon: icons[j],
137
- };
138
- dragIconData.push(data);
200
+ /**
201
+ * Execute a step of block dragging, based on the given event. Update the
202
+ * display accordingly.
203
+ * @param {!Event} e The most recent move event.
204
+ * @param {!Coordinate} currentDragDeltaXY How far the pointer has
205
+ * moved from the position at the start of the drag, in pixel units.
206
+ * @public
207
+ */
208
+ drag(e, currentDragDeltaXY) {
209
+ const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
210
+ const newLoc = Coordinate.sum(this.startXY_, delta);
211
+ this.draggingBlock_.moveDuringDrag(newLoc);
212
+ this.dragIcons_(delta);
213
+
214
+ const oldDragTarget = this.dragTarget_;
215
+ this.dragTarget_ = this.workspace_.getDragTarget(e);
216
+
217
+ this.draggedConnectionManager_.update(delta, this.dragTarget_);
218
+ const oldWouldDeleteBlock = this.wouldDeleteBlock_;
219
+ this.wouldDeleteBlock_ = this.draggedConnectionManager_.wouldDeleteBlock();
220
+ if (oldWouldDeleteBlock !== this.wouldDeleteBlock_) {
221
+ // Prevent unnecessary add/remove class calls.
222
+ this.updateCursorDuringBlockDrag_();
139
223
  }
140
- }
141
- return dragIconData;
142
- };
143
-
144
- /**
145
- * Start dragging a block. This includes moving it to the drag surface.
146
- * @param {!Coordinate} currentDragDeltaXY How far the pointer has
147
- * moved from the position at mouse down, in pixel units.
148
- * @param {boolean} healStack Whether or not to heal the stack after
149
- * disconnecting.
150
- * @public
151
- */
152
- BlockDragger.prototype.startDrag = function(currentDragDeltaXY, healStack) {
153
- if (!eventUtils.getGroup()) {
154
- eventUtils.setGroup(true);
155
- }
156
- this.fireDragStartEvent_();
157
-
158
- // Mutators don't have the same type of z-ordering as the normal workspace
159
- // during a drag. They have to rely on the order of the blocks in the SVG.
160
- // For performance reasons that usually happens at the end of a drag,
161
- // but do it at the beginning for mutators.
162
- if (this.workspace_.isMutator) {
163
- this.draggingBlock_.bringToFront();
164
- }
165
-
166
- // During a drag there may be a lot of rerenders, but not field changes.
167
- // Turn the cache on so we don't do spurious remeasures during the drag.
168
- dom.startTextWidthCache();
169
- this.workspace_.setResizesEnabled(false);
170
- blockAnimation.disconnectUiStop();
171
224
 
172
- if (this.shouldDisconnect_(healStack)) {
173
- this.disconnectBlock_(healStack, currentDragDeltaXY);
225
+ // Call drag enter/exit/over after wouldDeleteBlock is called in
226
+ // InsertionMarkerManager.update.
227
+ if (this.dragTarget_ !== oldDragTarget) {
228
+ oldDragTarget && oldDragTarget.onDragExit(this.draggingBlock_);
229
+ this.dragTarget_ && this.dragTarget_.onDragEnter(this.draggingBlock_);
230
+ }
231
+ this.dragTarget_ && this.dragTarget_.onDragOver(this.draggingBlock_);
174
232
  }
175
- this.draggingBlock_.setDragging(true);
176
- // For future consideration: we may be able to put moveToDragSurface inside
177
- // the block dragger, which would also let the block not track the block drag
178
- // surface.
179
- this.draggingBlock_.moveToDragSurface();
180
- };
181
233
 
182
- /**
183
- * Whether or not we should disconnect the block when a drag is started.
184
- * @param {boolean} healStack Whether or not to heal the stack after
185
- * disconnecting.
186
- * @return {boolean} True to disconnect the block, false otherwise.
187
- * @protected
188
- */
189
- BlockDragger.prototype.shouldDisconnect_ = function(healStack) {
190
- return !!(
191
- this.draggingBlock_.getParent() ||
192
- (healStack && this.draggingBlock_.nextConnection &&
193
- this.draggingBlock_.nextConnection.targetBlock()));
194
- };
195
-
196
- /**
197
- * Disconnects the block and moves it to a new location.
198
- * @param {boolean} healStack Whether or not to heal the stack after
199
- * disconnecting.
200
- * @param {!Coordinate} currentDragDeltaXY How far the pointer has
201
- * moved from the position at mouse down, in pixel units.
202
- * @protected
203
- */
204
- BlockDragger.prototype.disconnectBlock_ = function(
205
- healStack, currentDragDeltaXY) {
206
- this.draggingBlock_.unplug(healStack);
207
- const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
208
- const newLoc = Coordinate.sum(this.startXY_, delta);
209
-
210
- this.draggingBlock_.translate(newLoc.x, newLoc.y);
211
- blockAnimation.disconnectUiEffect(this.draggingBlock_);
212
- this.draggedConnectionManager_.updateAvailableConnections();
213
- };
234
+ /**
235
+ * Finish a block drag and put the block back on the workspace.
236
+ * @param {!Event} e The mouseup/touchend event.
237
+ * @param {!Coordinate} currentDragDeltaXY How far the pointer has
238
+ * moved from the position at the start of the drag, in pixel units.
239
+ * @public
240
+ */
241
+ endDrag(e, currentDragDeltaXY) {
242
+ // Make sure internal state is fresh.
243
+ this.drag(e, currentDragDeltaXY);
244
+ this.dragIconData_ = [];
245
+ this.fireDragEndEvent_();
246
+
247
+ dom.stopTextWidthCache();
248
+
249
+ blockAnimation.disconnectUiStop();
250
+
251
+ const preventMove = !!this.dragTarget_ &&
252
+ this.dragTarget_.shouldPreventMove(this.draggingBlock_);
253
+ /** @type {Coordinate} */
254
+ let newLoc;
255
+ /** @type {Coordinate} */
256
+ let delta;
257
+ if (preventMove) {
258
+ newLoc = this.startXY_;
259
+ } else {
260
+ const newValues = this.getNewLocationAfterDrag_(currentDragDeltaXY);
261
+ delta = newValues.delta;
262
+ newLoc = newValues.newLocation;
263
+ }
264
+ this.draggingBlock_.moveOffDragSurface(newLoc);
214
265
 
215
- /**
216
- * Fire a UI event at the start of a block drag.
217
- * @protected
218
- */
219
- BlockDragger.prototype.fireDragStartEvent_ = function() {
220
- const event = new (eventUtils.get(eventUtils.BLOCK_DRAG))(
221
- this.draggingBlock_, true, this.draggingBlock_.getDescendants(false));
222
- eventUtils.fire(event);
223
- };
266
+ if (this.dragTarget_) {
267
+ this.dragTarget_.onDrop(this.draggingBlock_);
268
+ }
224
269
 
225
- /**
226
- * Execute a step of block dragging, based on the given event. Update the
227
- * display accordingly.
228
- * @param {!Event} e The most recent move event.
229
- * @param {!Coordinate} currentDragDeltaXY How far the pointer has
230
- * moved from the position at the start of the drag, in pixel units.
231
- * @public
232
- */
233
- BlockDragger.prototype.drag = function(e, currentDragDeltaXY) {
234
- const delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
235
- const newLoc = Coordinate.sum(this.startXY_, delta);
236
- this.draggingBlock_.moveDuringDrag(newLoc);
237
- this.dragIcons_(delta);
238
-
239
- const oldDragTarget = this.dragTarget_;
240
- this.dragTarget_ = this.workspace_.getDragTarget(e);
241
-
242
- this.draggedConnectionManager_.update(delta, this.dragTarget_);
243
- const oldWouldDeleteBlock = this.wouldDeleteBlock_;
244
- this.wouldDeleteBlock_ = this.draggedConnectionManager_.wouldDeleteBlock();
245
- if (oldWouldDeleteBlock !== this.wouldDeleteBlock_) {
246
- // Prevent unnecessary add/remove class calls.
247
- this.updateCursorDuringBlockDrag_();
248
- }
270
+ const deleted = this.maybeDeleteBlock_();
271
+ if (!deleted) {
272
+ // These are expensive and don't need to be done if we're deleting.
273
+ this.draggingBlock_.setDragging(false);
274
+ if (delta) { // !preventMove
275
+ this.updateBlockAfterMove_(delta);
276
+ } else {
277
+ // Blocks dragged directly from a flyout may need to be bumped into
278
+ // bounds.
279
+ bumpObjects.bumpIntoBounds(
280
+ this.draggingBlock_.workspace,
281
+ this.workspace_.getMetricsManager().getScrollMetrics(true),
282
+ this.draggingBlock_);
283
+ }
284
+ }
285
+ this.workspace_.setResizesEnabled(true);
249
286
 
250
- // Call drag enter/exit/over after wouldDeleteBlock is called in
251
- // InsertionMarkerManager.update.
252
- if (this.dragTarget_ !== oldDragTarget) {
253
- oldDragTarget && oldDragTarget.onDragExit(this.draggingBlock_);
254
- this.dragTarget_ && this.dragTarget_.onDragEnter(this.draggingBlock_);
287
+ eventUtils.setGroup(false);
255
288
  }
256
- this.dragTarget_ && this.dragTarget_.onDragOver(this.draggingBlock_);
257
- };
258
289
 
259
- /**
260
- * Finish a block drag and put the block back on the workspace.
261
- * @param {!Event} e The mouseup/touchend event.
262
- * @param {!Coordinate} currentDragDeltaXY How far the pointer has
263
- * moved from the position at the start of the drag, in pixel units.
264
- * @public
265
- */
266
- BlockDragger.prototype.endDrag = function(e, currentDragDeltaXY) {
267
- // Make sure internal state is fresh.
268
- this.drag(e, currentDragDeltaXY);
269
- this.dragIconData_ = [];
270
- this.fireDragEndEvent_();
271
-
272
- dom.stopTextWidthCache();
273
-
274
- blockAnimation.disconnectUiStop();
275
-
276
- const preventMove = !!this.dragTarget_ &&
277
- this.dragTarget_.shouldPreventMove(this.draggingBlock_);
278
- /** @type {Coordinate} */
279
- let newLoc;
280
- /** @type {Coordinate} */
281
- let delta;
282
- if (preventMove) {
283
- newLoc = this.startXY_;
284
- } else {
285
- const newValues = this.getNewLocationAfterDrag_(currentDragDeltaXY);
286
- delta = newValues.delta;
287
- newLoc = newValues.newLocation;
290
+ /**
291
+ * Calculates the drag delta and new location values after a block is dragged.
292
+ * @param {!Coordinate} currentDragDeltaXY How far the pointer has
293
+ * moved from the start of the drag, in pixel units.
294
+ * @return {{delta: !Coordinate, newLocation:
295
+ * !Coordinate}} New location after drag. delta is in
296
+ * workspace units. newLocation is the new coordinate where the block
297
+ * should end up.
298
+ * @protected
299
+ */
300
+ getNewLocationAfterDrag_(currentDragDeltaXY) {
301
+ const newValues = {};
302
+ newValues.delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
303
+ newValues.newLocation = Coordinate.sum(this.startXY_, newValues.delta);
304
+ return newValues;
288
305
  }
289
- this.draggingBlock_.moveOffDragSurface(newLoc);
290
306
 
291
- if (this.dragTarget_) {
292
- this.dragTarget_.onDrop(this.draggingBlock_);
307
+ /**
308
+ * May delete the dragging block, if allowed. If `this.wouldDeleteBlock_` is
309
+ * not true, the block will not be deleted. This should be called at the end
310
+ * of a block drag.
311
+ * @return {boolean} True if the block was deleted.
312
+ * @protected
313
+ */
314
+ maybeDeleteBlock_() {
315
+ if (this.wouldDeleteBlock_) {
316
+ // Fire a move event, so we know where to go back to for an undo.
317
+ this.fireMoveEvent_();
318
+ this.draggingBlock_.dispose(false, true);
319
+ common.draggingConnections.length = 0;
320
+ return true;
321
+ }
322
+ return false;
293
323
  }
294
324
 
295
- const deleted = this.maybeDeleteBlock_();
296
- if (!deleted) {
297
- // These are expensive and don't need to be done if we're deleting.
298
- this.draggingBlock_.setDragging(false);
299
- if (delta) { // !preventMove
300
- this.updateBlockAfterMove_(delta);
325
+ /**
326
+ * Updates the necessary information to place a block at a certain location.
327
+ * @param {!Coordinate} delta The change in location from where
328
+ * the block started the drag to where it ended the drag.
329
+ * @protected
330
+ */
331
+ updateBlockAfterMove_(delta) {
332
+ this.draggingBlock_.moveConnections(delta.x, delta.y);
333
+ this.fireMoveEvent_();
334
+ if (this.draggedConnectionManager_.wouldConnectBlock()) {
335
+ // Applying connections also rerenders the relevant blocks.
336
+ this.draggedConnectionManager_.applyConnections();
301
337
  } else {
302
- // Blocks dragged directly from a flyout may need to be bumped into
303
- // bounds.
304
- bumpObjects.bumpIntoBounds(
305
- this.draggingBlock_.workspace,
306
- this.workspace_.getMetricsManager().getScrollMetrics(true),
307
- this.draggingBlock_);
338
+ this.draggingBlock_.render();
308
339
  }
340
+ this.draggingBlock_.scheduleSnapAndBump();
309
341
  }
310
- this.workspace_.setResizesEnabled(true);
311
-
312
- eventUtils.setGroup(false);
313
- };
314
-
315
- /**
316
- * Calculates the drag delta and new location values after a block is dragged.
317
- * @param {!Coordinate} currentDragDeltaXY How far the pointer has
318
- * moved from the start of the drag, in pixel units.
319
- * @return {{delta: !Coordinate, newLocation:
320
- * !Coordinate}} New location after drag. delta is in
321
- * workspace units. newLocation is the new coordinate where the block should
322
- * end up.
323
- * @protected
324
- */
325
- BlockDragger.prototype.getNewLocationAfterDrag_ = function(currentDragDeltaXY) {
326
- const newValues = {};
327
- newValues.delta = this.pixelsToWorkspaceUnits_(currentDragDeltaXY);
328
- newValues.newLocation = Coordinate.sum(this.startXY_, newValues.delta);
329
- return newValues;
330
- };
331
342
 
332
- /**
333
- * May delete the dragging block, if allowed. If `this.wouldDeleteBlock_` is not
334
- * true, the block will not be deleted. This should be called at the end of a
335
- * block drag.
336
- * @return {boolean} True if the block was deleted.
337
- * @protected
338
- */
339
- BlockDragger.prototype.maybeDeleteBlock_ = function() {
340
- if (this.wouldDeleteBlock_) {
341
- // Fire a move event, so we know where to go back to for an undo.
342
- this.fireMoveEvent_();
343
- this.draggingBlock_.dispose(false, true);
344
- common.draggingConnections.length = 0;
345
- return true;
343
+ /**
344
+ * Fire a UI event at the end of a block drag.
345
+ * @protected
346
+ */
347
+ fireDragEndEvent_() {
348
+ const event = new (eventUtils.get(eventUtils.BLOCK_DRAG))(
349
+ this.draggingBlock_, false, this.draggingBlock_.getDescendants(false));
350
+ eventUtils.fire(event);
346
351
  }
347
- return false;
348
- };
349
352
 
350
- /**
351
- * Updates the necessary information to place a block at a certain location.
352
- * @param {!Coordinate} delta The change in location from where
353
- * the block started the drag to where it ended the drag.
354
- * @protected
355
- */
356
- BlockDragger.prototype.updateBlockAfterMove_ = function(delta) {
357
- this.draggingBlock_.moveConnections(delta.x, delta.y);
358
- this.fireMoveEvent_();
359
- if (this.draggedConnectionManager_.wouldConnectBlock()) {
360
- // Applying connections also rerenders the relevant blocks.
361
- this.draggedConnectionManager_.applyConnections();
362
- } else {
363
- this.draggingBlock_.render();
353
+ /**
354
+ * Adds or removes the style of the cursor for the toolbox.
355
+ * This is what changes the cursor to display an x when a deletable block is
356
+ * held over the toolbox.
357
+ * @param {boolean} isEnd True if we are at the end of a drag, false
358
+ * otherwise.
359
+ * @protected
360
+ */
361
+ updateToolboxStyle_(isEnd) {
362
+ const toolbox = this.workspace_.getToolbox();
363
+
364
+ if (toolbox) {
365
+ const style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' :
366
+ 'blocklyToolboxGrab';
367
+
368
+ if (isEnd && typeof toolbox.removeStyle === 'function') {
369
+ toolbox.removeStyle(style);
370
+ } else if (!isEnd && typeof toolbox.addStyle === 'function') {
371
+ toolbox.addStyle(style);
372
+ }
373
+ }
364
374
  }
365
- this.draggingBlock_.scheduleSnapAndBump();
366
- };
367
375
 
368
- /**
369
- * Fire a UI event at the end of a block drag.
370
- * @protected
371
- */
372
- BlockDragger.prototype.fireDragEndEvent_ = function() {
373
- const event = new (eventUtils.get(eventUtils.BLOCK_DRAG))(
374
- this.draggingBlock_, false, this.draggingBlock_.getDescendants(false));
375
- eventUtils.fire(event);
376
- };
377
-
378
- /**
379
- * Adds or removes the style of the cursor for the toolbox.
380
- * This is what changes the cursor to display an x when a deletable block is
381
- * held over the toolbox.
382
- * @param {boolean} isEnd True if we are at the end of a drag, false otherwise.
383
- * @protected
384
- */
385
- BlockDragger.prototype.updateToolboxStyle_ = function(isEnd) {
386
- const toolbox = this.workspace_.getToolbox();
376
+ /**
377
+ * Fire a move event at the end of a block drag.
378
+ * @protected
379
+ */
380
+ fireMoveEvent_() {
381
+ const event = /** @type {!BlockMove} */
382
+ (new (eventUtils.get(eventUtils.BLOCK_MOVE))(this.draggingBlock_));
383
+ event.oldCoordinate = this.startXY_;
384
+ event.recordNew();
385
+ eventUtils.fire(event);
386
+ }
387
387
 
388
- if (toolbox) {
389
- const style = this.draggingBlock_.isDeletable() ? 'blocklyToolboxDelete' :
390
- 'blocklyToolboxGrab';
388
+ /**
389
+ * Update the cursor (and possibly the trash can lid) to reflect whether the
390
+ * dragging block would be deleted if released immediately.
391
+ * @protected
392
+ */
393
+ updateCursorDuringBlockDrag_() {
394
+ this.draggingBlock_.setDeleteStyle(this.wouldDeleteBlock_);
395
+ }
391
396
 
392
- if (isEnd && typeof toolbox.removeStyle === 'function') {
393
- toolbox.removeStyle(style);
394
- } else if (!isEnd && typeof toolbox.addStyle === 'function') {
395
- toolbox.addStyle(style);
397
+ /**
398
+ * Convert a coordinate object from pixels to workspace units, including a
399
+ * correction for mutator workspaces.
400
+ * This function does not consider differing origins. It simply scales the
401
+ * input's x and y values.
402
+ * @param {!Coordinate} pixelCoord A coordinate with x and y
403
+ * values in CSS pixel units.
404
+ * @return {!Coordinate} The input coordinate divided by the
405
+ * workspace scale.
406
+ * @protected
407
+ */
408
+ pixelsToWorkspaceUnits_(pixelCoord) {
409
+ const result = new Coordinate(
410
+ pixelCoord.x / this.workspace_.scale,
411
+ pixelCoord.y / this.workspace_.scale);
412
+ if (this.workspace_.isMutator) {
413
+ // If we're in a mutator, its scale is always 1, purely because of some
414
+ // oddities in our rendering optimizations. The actual scale is the same
415
+ // as the scale on the parent workspace. Fix that for dragging.
416
+ const mainScale = this.workspace_.options.parentWorkspace.scale;
417
+ result.scale(1 / mainScale);
396
418
  }
419
+ return result;
397
420
  }
398
- };
399
421
 
400
-
401
- /**
402
- * Fire a move event at the end of a block drag.
403
- * @protected
404
- */
405
- BlockDragger.prototype.fireMoveEvent_ = function() {
406
- const event =
407
- new (eventUtils.get(eventUtils.BLOCK_MOVE))(this.draggingBlock_);
408
- event.oldCoordinate = this.startXY_;
409
- event.recordNew();
410
- eventUtils.fire(event);
411
- };
412
-
413
- /**
414
- * Update the cursor (and possibly the trash can lid) to reflect whether the
415
- * dragging block would be deleted if released immediately.
416
- * @protected
417
- */
418
- BlockDragger.prototype.updateCursorDuringBlockDrag_ = function() {
419
- this.draggingBlock_.setDeleteStyle(this.wouldDeleteBlock_);
420
- };
421
-
422
- /**
423
- * Convert a coordinate object from pixels to workspace units, including a
424
- * correction for mutator workspaces.
425
- * This function does not consider differing origins. It simply scales the
426
- * input's x and y values.
427
- * @param {!Coordinate} pixelCoord A coordinate with x and y
428
- * values in CSS pixel units.
429
- * @return {!Coordinate} The input coordinate divided by the
430
- * workspace scale.
431
- * @protected
432
- */
433
- BlockDragger.prototype.pixelsToWorkspaceUnits_ = function(pixelCoord) {
434
- const result = new Coordinate(
435
- pixelCoord.x / this.workspace_.scale,
436
- pixelCoord.y / this.workspace_.scale);
437
- if (this.workspace_.isMutator) {
438
- // If we're in a mutator, its scale is always 1, purely because of some
439
- // oddities in our rendering optimizations. The actual scale is the same as
440
- // the scale on the parent workspace.
441
- // Fix that for dragging.
442
- const mainScale = this.workspace_.options.parentWorkspace.scale;
443
- result.scale(1 / mainScale);
422
+ /**
423
+ * Move all of the icons connected to this drag.
424
+ * @param {!Coordinate} dxy How far to move the icons from their
425
+ * original positions, in workspace units.
426
+ * @protected
427
+ */
428
+ dragIcons_(dxy) {
429
+ // Moving icons moves their associated bubbles.
430
+ for (let i = 0; i < this.dragIconData_.length; i++) {
431
+ const data = this.dragIconData_[i];
432
+ data.icon.setIconLocation(Coordinate.sum(data.location, dxy));
433
+ }
444
434
  }
445
- return result;
446
- };
447
435
 
448
- /**
449
- * Move all of the icons connected to this drag.
450
- * @param {!Coordinate} dxy How far to move the icons from their
451
- * original positions, in workspace units.
452
- * @protected
453
- */
454
- BlockDragger.prototype.dragIcons_ = function(dxy) {
455
- // Moving icons moves their associated bubbles.
456
- for (let i = 0; i < this.dragIconData_.length; i++) {
457
- const data = this.dragIconData_[i];
458
- data.icon.setIconLocation(Coordinate.sum(data.location, dxy));
436
+ /**
437
+ * Get a list of the insertion markers that currently exist. Drags have 0, 1,
438
+ * or 2 insertion markers.
439
+ * @return {!Array<!BlockSvg>} A possibly empty list of insertion
440
+ * marker blocks.
441
+ * @public
442
+ */
443
+ getInsertionMarkers() {
444
+ // No insertion markers with the old style of dragged connection managers.
445
+ if (this.draggedConnectionManager_ &&
446
+ this.draggedConnectionManager_.getInsertionMarkers) {
447
+ return this.draggedConnectionManager_.getInsertionMarkers();
448
+ }
449
+ return [];
459
450
  }
460
451
  };
461
452
 
462
453
  /**
463
- * Get a list of the insertion markers that currently exist. Drags have 0, 1,
464
- * or 2 insertion markers.
465
- * @return {!Array<!BlockSvg>} A possibly empty list of insertion
466
- * marker blocks.
467
- * @public
454
+ * Make a list of all of the icons (comment, warning, and mutator) that are
455
+ * on this block and its descendants. Moving an icon moves the bubble that
456
+ * extends from it if that bubble is open.
457
+ * @param {!BlockSvg} block The root block that is being dragged.
458
+ * @return {!Array<!Object>} The list of all icons and their locations.
468
459
  */
469
- BlockDragger.prototype.getInsertionMarkers = function() {
470
- // No insertion markers with the old style of dragged connection managers.
471
- if (this.draggedConnectionManager_ &&
472
- this.draggedConnectionManager_.getInsertionMarkers) {
473
- return this.draggedConnectionManager_.getInsertionMarkers();
460
+ const initIconData = function(block) {
461
+ // Build a list of icons that need to be moved and where they started.
462
+ const dragIconData = [];
463
+ const descendants =
464
+ /** @type {!Array<!BlockSvg>} */ (block.getDescendants(false));
465
+
466
+ for (let i = 0, descendant; (descendant = descendants[i]); i++) {
467
+ const icons = descendant.getIcons();
468
+ for (let j = 0; j < icons.length; j++) {
469
+ const data = {
470
+ // Coordinate with x and y properties (workspace
471
+ // coordinates).
472
+ location: icons[j].getIconLocation(),
473
+ // Blockly.Icon
474
+ icon: icons[j],
475
+ };
476
+ dragIconData.push(data);
477
+ }
474
478
  }
475
- return [];
479
+ return dragIconData;
476
480
  };
477
481
 
478
482
  registry.register(registry.Type.BLOCK_DRAGGER, registry.DEFAULT, BlockDragger);