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/gesture.js CHANGED
@@ -28,6 +28,7 @@ const registry = goog.require('Blockly.registry');
28
28
  /* eslint-disable-next-line no-unused-vars */
29
29
  const {BlockSvg} = goog.requireType('Blockly.BlockSvg');
30
30
  const {BubbleDragger} = goog.require('Blockly.BubbleDragger');
31
+ const {config} = goog.require('Blockly.config');
31
32
  const {Coordinate} = goog.require('Blockly.utils.Coordinate');
32
33
  /* eslint-disable-next-line no-unused-vars */
33
34
  const {Field} = goog.requireType('Blockly.Field');
@@ -55,956 +56,971 @@ goog.require('Blockly.Events.Click');
55
56
 
56
57
  /**
57
58
  * Class for one gesture.
58
- * @param {!Event} e The event that kicked off this gesture.
59
- * @param {!WorkspaceSvg} creatorWorkspace The workspace that created
60
- * this gesture and has a reference to it.
61
- * @constructor
62
59
  * @alias Blockly.Gesture
63
60
  */
64
- const Gesture = function(e, creatorWorkspace) {
61
+ class Gesture {
65
62
  /**
66
- * The position of the mouse when the gesture started. Units are CSS pixels,
67
- * with (0, 0) at the top left of the browser window (mouseEvent clientX/Y).
68
- * @type {Coordinate}
69
- * @private
63
+ * @param {!Event} e The event that kicked off this gesture.
64
+ * @param {!WorkspaceSvg} creatorWorkspace The workspace that created
65
+ * this gesture and has a reference to it.
70
66
  */
71
- this.mouseDownXY_ = null;
67
+ constructor(e, creatorWorkspace) {
68
+ /**
69
+ * The position of the mouse when the gesture started. Units are CSS
70
+ * pixels, with (0, 0) at the top left of the browser window (mouseEvent
71
+ * clientX/Y).
72
+ * @type {Coordinate}
73
+ * @private
74
+ */
75
+ this.mouseDownXY_ = null;
76
+
77
+ /**
78
+ * How far the mouse has moved during this drag, in pixel units.
79
+ * (0, 0) is at this.mouseDownXY_.
80
+ * @type {!Coordinate}
81
+ * @private
82
+ */
83
+ this.currentDragDeltaXY_ = new Coordinate(0, 0);
84
+
85
+ /**
86
+ * The bubble that the gesture started on, or null if it did not start on a
87
+ * bubble.
88
+ * @type {IBubble}
89
+ * @private
90
+ */
91
+ this.startBubble_ = null;
92
+
93
+ /**
94
+ * The field that the gesture started on, or null if it did not start on a
95
+ * field.
96
+ * @type {Field}
97
+ * @private
98
+ */
99
+ this.startField_ = null;
100
+
101
+ /**
102
+ * The block that the gesture started on, or null if it did not start on a
103
+ * block.
104
+ * @type {BlockSvg}
105
+ * @private
106
+ */
107
+ this.startBlock_ = null;
72
108
 
73
- /**
74
- * How far the mouse has moved during this drag, in pixel units.
75
- * (0, 0) is at this.mouseDownXY_.
76
- * @type {!Coordinate}
77
- * @private
78
- */
79
- this.currentDragDeltaXY_ = new Coordinate(0, 0);
109
+ /**
110
+ * The block that this gesture targets. If the gesture started on a
111
+ * shadow block, this is the first non-shadow parent of the block. If the
112
+ * gesture started in the flyout, this is the root block of the block group
113
+ * that was clicked or dragged.
114
+ * @type {BlockSvg}
115
+ * @private
116
+ */
117
+ this.targetBlock_ = null;
118
+
119
+ /**
120
+ * The workspace that the gesture started on. There may be multiple
121
+ * workspaces on a page; this is more accurate than using
122
+ * Blockly.common.getMainWorkspace().
123
+ * @type {WorkspaceSvg}
124
+ * @protected
125
+ */
126
+ this.startWorkspace_ = null;
127
+
128
+ /**
129
+ * The workspace that created this gesture. This workspace keeps a
130
+ * reference to the gesture, which will need to be cleared at deletion. This
131
+ * may be different from the start workspace. For instance, a flyout is a
132
+ * workspace, but its parent workspace manages gestures for it.
133
+ * @type {!WorkspaceSvg}
134
+ * @private
135
+ */
136
+ this.creatorWorkspace_ = creatorWorkspace;
137
+
138
+ /**
139
+ * Whether the pointer has at any point moved out of the drag radius.
140
+ * A gesture that exceeds the drag radius is a drag even if it ends exactly
141
+ * at its start point.
142
+ * @type {boolean}
143
+ * @private
144
+ */
145
+ this.hasExceededDragRadius_ = false;
146
+
147
+ /**
148
+ * Whether the workspace is currently being dragged.
149
+ * @type {boolean}
150
+ * @private
151
+ */
152
+ this.isDraggingWorkspace_ = false;
153
+
154
+ /**
155
+ * Whether the block is currently being dragged.
156
+ * @type {boolean}
157
+ * @private
158
+ */
159
+ this.isDraggingBlock_ = false;
160
+
161
+ /**
162
+ * Whether the bubble is currently being dragged.
163
+ * @type {boolean}
164
+ * @private
165
+ */
166
+ this.isDraggingBubble_ = false;
167
+
168
+ /**
169
+ * The event that most recently updated this gesture.
170
+ * @type {!Event}
171
+ * @private
172
+ */
173
+ this.mostRecentEvent_ = e;
174
+
175
+ /**
176
+ * A handle to use to unbind a mouse move listener at the end of a drag.
177
+ * Opaque data returned from Blockly.bindEventWithChecks_.
178
+ * @type {?browserEvents.Data}
179
+ * @protected
180
+ */
181
+ this.onMoveWrapper_ = null;
182
+
183
+ /**
184
+ * A handle to use to unbind a mouse up listener at the end of a drag.
185
+ * Opaque data returned from Blockly.bindEventWithChecks_.
186
+ * @type {?browserEvents.Data}
187
+ * @protected
188
+ */
189
+ this.onUpWrapper_ = null;
190
+
191
+ /**
192
+ * The object tracking a bubble drag, or null if none is in progress.
193
+ * @type {BubbleDragger}
194
+ * @private
195
+ */
196
+ this.bubbleDragger_ = null;
197
+
198
+ /**
199
+ * The object tracking a block drag, or null if none is in progress.
200
+ * @type {?IBlockDragger}
201
+ * @private
202
+ */
203
+ this.blockDragger_ = null;
204
+
205
+ /**
206
+ * The object tracking a workspace or flyout workspace drag, or null if none
207
+ * is in progress.
208
+ * @type {WorkspaceDragger}
209
+ * @private
210
+ */
211
+ this.workspaceDragger_ = null;
212
+
213
+ /**
214
+ * The flyout a gesture started in, if any.
215
+ * @type {IFlyout}
216
+ * @private
217
+ */
218
+ this.flyout_ = null;
219
+
220
+ /**
221
+ * Boolean for sanity-checking that some code is only called once.
222
+ * @type {boolean}
223
+ * @private
224
+ */
225
+ this.calledUpdateIsDragging_ = false;
226
+
227
+ /**
228
+ * Boolean for sanity-checking that some code is only called once.
229
+ * @type {boolean}
230
+ * @private
231
+ */
232
+ this.hasStarted_ = false;
233
+
234
+ /**
235
+ * Boolean used internally to break a cycle in disposal.
236
+ * @type {boolean}
237
+ * @protected
238
+ */
239
+ this.isEnding_ = false;
240
+
241
+ /**
242
+ * Boolean used to indicate whether or not to heal the stack after
243
+ * disconnecting a block.
244
+ * @type {boolean}
245
+ * @private
246
+ */
247
+ this.healStack_ = !internalConstants.DRAG_STACK;
248
+ }
80
249
 
81
250
  /**
82
- * The bubble that the gesture started on, or null if it did not start on a
83
- * bubble.
84
- * @type {IBubble}
85
- * @private
251
+ * Sever all links from this object.
252
+ * @package
86
253
  */
87
- this.startBubble_ = null;
254
+ dispose() {
255
+ Touch.clearTouchIdentifier();
256
+ Tooltip.unblock();
257
+ // Clear the owner's reference to this gesture.
258
+ this.creatorWorkspace_.clearGesture();
259
+
260
+ if (this.onMoveWrapper_) {
261
+ browserEvents.unbind(this.onMoveWrapper_);
262
+ }
263
+ if (this.onUpWrapper_) {
264
+ browserEvents.unbind(this.onUpWrapper_);
265
+ }
88
266
 
89
- /**
90
- * The field that the gesture started on, or null if it did not start on a
91
- * field.
92
- * @type {Field}
93
- * @private
94
- */
95
- this.startField_ = null;
267
+ if (this.blockDragger_) {
268
+ this.blockDragger_.dispose();
269
+ }
270
+ if (this.workspaceDragger_) {
271
+ this.workspaceDragger_.dispose();
272
+ }
273
+ if (this.bubbleDragger_) {
274
+ this.bubbleDragger_.dispose();
275
+ }
276
+ }
96
277
 
97
278
  /**
98
- * The block that the gesture started on, or null if it did not start on a
99
- * block.
100
- * @type {BlockSvg}
279
+ * Update internal state based on an event.
280
+ * @param {!Event} e The most recent mouse or touch event.
101
281
  * @private
102
282
  */
103
- this.startBlock_ = null;
283
+ updateFromEvent_(e) {
284
+ const currentXY = new Coordinate(e.clientX, e.clientY);
285
+ const changed = this.updateDragDelta_(currentXY);
286
+ // Exceeded the drag radius for the first time.
287
+ if (changed) {
288
+ this.updateIsDragging_();
289
+ Touch.longStop();
290
+ }
291
+ this.mostRecentEvent_ = e;
292
+ }
104
293
 
105
294
  /**
106
- * The block that this gesture targets. If the gesture started on a
107
- * shadow block, this is the first non-shadow parent of the block. If the
108
- * gesture started in the flyout, this is the root block of the block group
109
- * that was clicked or dragged.
110
- * @type {BlockSvg}
295
+ * DO MATH to set currentDragDeltaXY_ based on the most recent mouse position.
296
+ * @param {!Coordinate} currentXY The most recent mouse/pointer
297
+ * position, in pixel units, with (0, 0) at the window's top left corner.
298
+ * @return {boolean} True if the drag just exceeded the drag radius for the
299
+ * first time.
111
300
  * @private
112
301
  */
113
- this.targetBlock_ = null;
302
+ updateDragDelta_(currentXY) {
303
+ this.currentDragDeltaXY_ = Coordinate.difference(
304
+ currentXY,
305
+ /** @type {!Coordinate} */ (this.mouseDownXY_));
114
306
 
115
- /**
116
- * The workspace that the gesture started on. There may be multiple
117
- * workspaces on a page; this is more accurate than using
118
- * Blockly.common.getMainWorkspace().
119
- * @type {WorkspaceSvg}
120
- * @protected
121
- */
122
- this.startWorkspace_ = null;
307
+ if (!this.hasExceededDragRadius_) {
308
+ const currentDragDelta = Coordinate.magnitude(this.currentDragDeltaXY_);
123
309
 
124
- /**
125
- * The workspace that created this gesture. This workspace keeps a reference
126
- * to the gesture, which will need to be cleared at deletion.
127
- * This may be different from the start workspace. For instance, a flyout is
128
- * a workspace, but its parent workspace manages gestures for it.
129
- * @type {!WorkspaceSvg}
130
- * @private
131
- */
132
- this.creatorWorkspace_ = creatorWorkspace;
310
+ // The flyout has a different drag radius from the rest of Blockly.
311
+ const limitRadius =
312
+ this.flyout_ ? config.flyoutDragRadius : config.dragRadius;
133
313
 
134
- /**
135
- * Whether the pointer has at any point moved out of the drag radius.
136
- * A gesture that exceeds the drag radius is a drag even if it ends exactly
137
- * at its start point.
138
- * @type {boolean}
139
- * @private
140
- */
141
- this.hasExceededDragRadius_ = false;
314
+ this.hasExceededDragRadius_ = currentDragDelta > limitRadius;
315
+ return this.hasExceededDragRadius_;
316
+ }
317
+ return false;
318
+ }
142
319
 
143
320
  /**
144
- * Whether the workspace is currently being dragged.
145
- * @type {boolean}
321
+ * Update this gesture to record whether a block is being dragged from the
322
+ * flyout.
323
+ * This function should be called on a mouse/touch move event the first time
324
+ * the drag radius is exceeded. It should be called no more than once per
325
+ * gesture. If a block should be dragged from the flyout this function creates
326
+ * the new block on the main workspace and updates targetBlock_ and
327
+ * startWorkspace_.
328
+ * @return {boolean} True if a block is being dragged from the flyout.
146
329
  * @private
147
330
  */
148
- this.isDraggingWorkspace_ = false;
331
+ updateIsDraggingFromFlyout_() {
332
+ if (!this.targetBlock_) {
333
+ return false;
334
+ }
335
+ if (!this.flyout_.isBlockCreatable_(this.targetBlock_)) {
336
+ return false;
337
+ }
338
+ if (!this.flyout_.isScrollable() ||
339
+ this.flyout_.isDragTowardWorkspace(this.currentDragDeltaXY_)) {
340
+ this.startWorkspace_ = this.flyout_.targetWorkspace;
341
+ this.startWorkspace_.updateScreenCalculationsIfScrolled();
342
+ // Start the event group now, so that the same event group is used for
343
+ // block creation and block dragging.
344
+ if (!eventUtils.getGroup()) {
345
+ eventUtils.setGroup(true);
346
+ }
347
+ // The start block is no longer relevant, because this is a drag.
348
+ this.startBlock_ = null;
349
+ this.targetBlock_ = this.flyout_.createBlock(this.targetBlock_);
350
+ this.targetBlock_.select();
351
+ return true;
352
+ }
353
+ return false;
354
+ }
149
355
 
150
356
  /**
151
- * Whether the block is currently being dragged.
152
- * @type {boolean}
357
+ * Update this gesture to record whether a bubble is being dragged.
358
+ * This function should be called on a mouse/touch move event the first time
359
+ * the drag radius is exceeded. It should be called no more than once per
360
+ * gesture. If a bubble should be dragged this function creates the necessary
361
+ * BubbleDragger and starts the drag.
362
+ * @return {boolean} True if a bubble is being dragged.
153
363
  * @private
154
364
  */
155
- this.isDraggingBlock_ = false;
365
+ updateIsDraggingBubble_() {
366
+ if (!this.startBubble_) {
367
+ return false;
368
+ }
156
369
 
157
- /**
158
- * Whether the bubble is currently being dragged.
159
- * @type {boolean}
160
- * @private
161
- */
162
- this.isDraggingBubble_ = false;
370
+ this.isDraggingBubble_ = true;
371
+ this.startDraggingBubble_();
372
+ return true;
373
+ }
163
374
 
164
375
  /**
165
- * The event that most recently updated this gesture.
166
- * @type {!Event}
376
+ * Update this gesture to record whether a block is being dragged.
377
+ * This function should be called on a mouse/touch move event the first time
378
+ * the drag radius is exceeded. It should be called no more than once per
379
+ * gesture. If a block should be dragged, either from the flyout or in the
380
+ * workspace, this function creates the necessary BlockDragger and starts the
381
+ * drag.
382
+ * @return {boolean} True if a block is being dragged.
167
383
  * @private
168
384
  */
169
- this.mostRecentEvent_ = e;
385
+ updateIsDraggingBlock_() {
386
+ if (!this.targetBlock_) {
387
+ return false;
388
+ }
170
389
 
171
- /**
172
- * A handle to use to unbind a mouse move listener at the end of a drag.
173
- * Opaque data returned from Blockly.bindEventWithChecks_.
174
- * @type {?browserEvents.Data}
175
- * @protected
176
- */
177
- this.onMoveWrapper_ = null;
390
+ if (this.flyout_) {
391
+ this.isDraggingBlock_ = this.updateIsDraggingFromFlyout_();
392
+ } else if (this.targetBlock_.isMovable()) {
393
+ this.isDraggingBlock_ = true;
394
+ }
178
395
 
179
- /**
180
- * A handle to use to unbind a mouse up listener at the end of a drag.
181
- * Opaque data returned from Blockly.bindEventWithChecks_.
182
- * @type {?browserEvents.Data}
183
- * @protected
184
- */
185
- this.onUpWrapper_ = null;
396
+ if (this.isDraggingBlock_) {
397
+ this.startDraggingBlock_();
398
+ return true;
399
+ }
400
+ return false;
401
+ }
186
402
 
187
403
  /**
188
- * The object tracking a bubble drag, or null if none is in progress.
189
- * @type {BubbleDragger}
404
+ * Update this gesture to record whether a workspace is being dragged.
405
+ * This function should be called on a mouse/touch move event the first time
406
+ * the drag radius is exceeded. It should be called no more than once per
407
+ * gesture. If a workspace is being dragged this function creates the
408
+ * necessary WorkspaceDragger and starts the drag.
190
409
  * @private
191
410
  */
192
- this.bubbleDragger_ = null;
411
+ updateIsDraggingWorkspace_() {
412
+ const wsMovable = this.flyout_ ?
413
+ this.flyout_.isScrollable() :
414
+ this.startWorkspace_ && this.startWorkspace_.isDraggable();
193
415
 
194
- /**
195
- * The object tracking a block drag, or null if none is in progress.
196
- * @type {?IBlockDragger}
197
- * @private
198
- */
199
- this.blockDragger_ = null;
416
+ if (!wsMovable) {
417
+ return;
418
+ }
200
419
 
201
- /**
202
- * The object tracking a workspace or flyout workspace drag, or null if none
203
- * is in progress.
204
- * @type {WorkspaceDragger}
205
- * @private
206
- */
207
- this.workspaceDragger_ = null;
420
+ this.workspaceDragger_ = new WorkspaceDragger(
421
+ /** @type {!WorkspaceSvg} */ (this.startWorkspace_));
208
422
 
209
- /**
210
- * The flyout a gesture started in, if any.
211
- * @type {IFlyout}
212
- * @private
213
- */
214
- this.flyout_ = null;
423
+ this.isDraggingWorkspace_ = true;
424
+ this.workspaceDragger_.startDrag();
425
+ }
215
426
 
216
427
  /**
217
- * Boolean for sanity-checking that some code is only called once.
218
- * @type {boolean}
428
+ * Update this gesture to record whether anything is being dragged.
429
+ * This function should be called on a mouse/touch move event the first time
430
+ * the drag radius is exceeded. It should be called no more than once per
431
+ * gesture.
219
432
  * @private
220
433
  */
221
- this.calledUpdateIsDragging_ = false;
434
+ updateIsDragging_() {
435
+ // Sanity check.
436
+ if (this.calledUpdateIsDragging_) {
437
+ throw Error('updateIsDragging_ should only be called once per gesture.');
438
+ }
439
+ this.calledUpdateIsDragging_ = true;
222
440
 
223
- /**
224
- * Boolean for sanity-checking that some code is only called once.
225
- * @type {boolean}
226
- * @private
227
- */
228
- this.hasStarted_ = false;
441
+ // First check if it was a bubble drag. Bubbles always sit on top of
442
+ // blocks.
443
+ if (this.updateIsDraggingBubble_()) {
444
+ return;
445
+ }
446
+ // Then check if it was a block drag.
447
+ if (this.updateIsDraggingBlock_()) {
448
+ return;
449
+ }
450
+ // Then check if it's a workspace drag.
451
+ this.updateIsDraggingWorkspace_();
452
+ }
229
453
 
230
454
  /**
231
- * Boolean used internally to break a cycle in disposal.
232
- * @type {boolean}
233
- * @protected
455
+ * Create a block dragger and start dragging the selected block.
456
+ * @private
234
457
  */
235
- this.isEnding_ = false;
458
+ startDraggingBlock_() {
459
+ const BlockDraggerClass = registry.getClassFromOptions(
460
+ registry.Type.BLOCK_DRAGGER, this.creatorWorkspace_.options, true);
461
+
462
+ this.blockDragger_ = new BlockDraggerClass(
463
+ /** @type {!BlockSvg} */ (this.targetBlock_),
464
+ /** @type {!WorkspaceSvg} */ (this.startWorkspace_));
465
+ this.blockDragger_.startDrag(this.currentDragDeltaXY_, this.healStack_);
466
+ this.blockDragger_.drag(this.mostRecentEvent_, this.currentDragDeltaXY_);
467
+ }
236
468
 
469
+ // TODO (fenichel): Possibly combine this and startDraggingBlock_.
237
470
  /**
238
- * Boolean used to indicate whether or not to heal the stack after
239
- * disconnecting a block.
240
- * @type {boolean}
471
+ * Create a bubble dragger and start dragging the selected bubble.
241
472
  * @private
242
473
  */
243
- this.healStack_ = !internalConstants.DRAG_STACK;
244
- };
245
-
246
- /**
247
- * Sever all links from this object.
248
- * @package
249
- */
250
- Gesture.prototype.dispose = function() {
251
- Touch.clearTouchIdentifier();
252
- Tooltip.unblock();
253
- // Clear the owner's reference to this gesture.
254
- this.creatorWorkspace_.clearGesture();
255
-
256
- if (this.onMoveWrapper_) {
257
- browserEvents.unbind(this.onMoveWrapper_);
258
- }
259
- if (this.onUpWrapper_) {
260
- browserEvents.unbind(this.onUpWrapper_);
474
+ startDraggingBubble_() {
475
+ this.bubbleDragger_ = new BubbleDragger(
476
+ /** @type {!IBubble} */ (this.startBubble_),
477
+ /** @type {!WorkspaceSvg} */ (this.startWorkspace_));
478
+ this.bubbleDragger_.startBubbleDrag();
479
+ this.bubbleDragger_.dragBubble(
480
+ this.mostRecentEvent_, this.currentDragDeltaXY_);
261
481
  }
262
482
 
263
- if (this.blockDragger_) {
264
- this.blockDragger_.dispose();
265
- }
266
- if (this.workspaceDragger_) {
267
- this.workspaceDragger_.dispose();
268
- }
269
- if (this.bubbleDragger_) {
270
- this.bubbleDragger_.dispose();
271
- }
272
- };
483
+ /**
484
+ * Start a gesture: update the workspace to indicate that a gesture is in
485
+ * progress and bind mousemove and mouseup handlers.
486
+ * @param {!Event} e A mouse down or touch start event.
487
+ * @package
488
+ */
489
+ doStart(e) {
490
+ if (browserEvents.isTargetInput(e)) {
491
+ this.cancel();
492
+ return;
493
+ }
494
+ this.hasStarted_ = true;
273
495
 
274
- /**
275
- * Update internal state based on an event.
276
- * @param {!Event} e The most recent mouse or touch event.
277
- * @private
278
- */
279
- Gesture.prototype.updateFromEvent_ = function(e) {
280
- const currentXY = new Coordinate(e.clientX, e.clientY);
281
- const changed = this.updateDragDelta_(currentXY);
282
- // Exceeded the drag radius for the first time.
283
- if (changed) {
284
- this.updateIsDragging_();
285
- Touch.longStop();
286
- }
287
- this.mostRecentEvent_ = e;
288
- };
496
+ blockAnimations.disconnectUiStop();
497
+ this.startWorkspace_.updateScreenCalculationsIfScrolled();
498
+ if (this.startWorkspace_.isMutator) {
499
+ // Mutator's coordinate system could be out of date because the bubble was
500
+ // dragged, the block was moved, the parent workspace zoomed, etc.
501
+ this.startWorkspace_.resize();
502
+ }
289
503
 
290
- /**
291
- * DO MATH to set currentDragDeltaXY_ based on the most recent mouse position.
292
- * @param {!Coordinate} currentXY The most recent mouse/pointer
293
- * position, in pixel units, with (0, 0) at the window's top left corner.
294
- * @return {boolean} True if the drag just exceeded the drag radius for the
295
- * first time.
296
- * @private
297
- */
298
- Gesture.prototype.updateDragDelta_ = function(currentXY) {
299
- this.currentDragDeltaXY_ = Coordinate.difference(
300
- currentXY,
301
- /** @type {!Coordinate} */ (this.mouseDownXY_));
504
+ // Hide chaff also hides the flyout, so don't do it if the click is in a
505
+ // flyout.
506
+ this.startWorkspace_.hideChaff(!!this.flyout_);
302
507
 
303
- if (!this.hasExceededDragRadius_) {
304
- const currentDragDelta = Coordinate.magnitude(this.currentDragDeltaXY_);
508
+ this.startWorkspace_.markFocused();
509
+ this.mostRecentEvent_ = e;
305
510
 
306
- // The flyout has a different drag radius from the rest of Blockly.
307
- const limitRadius = this.flyout_ ? internalConstants.FLYOUT_DRAG_RADIUS :
308
- internalConstants.DRAG_RADIUS;
511
+ Tooltip.block();
309
512
 
310
- this.hasExceededDragRadius_ = currentDragDelta > limitRadius;
311
- return this.hasExceededDragRadius_;
312
- }
313
- return false;
314
- };
513
+ if (this.targetBlock_) {
514
+ this.targetBlock_.select();
515
+ }
315
516
 
316
- /**
317
- * Update this gesture to record whether a block is being dragged from the
318
- * flyout.
319
- * This function should be called on a mouse/touch move event the first time the
320
- * drag radius is exceeded. It should be called no more than once per gesture.
321
- * If a block should be dragged from the flyout this function creates the new
322
- * block on the main workspace and updates targetBlock_ and startWorkspace_.
323
- * @return {boolean} True if a block is being dragged from the flyout.
324
- * @private
325
- */
326
- Gesture.prototype.updateIsDraggingFromFlyout_ = function() {
327
- if (!this.targetBlock_) {
328
- return false;
329
- }
330
- if (!this.flyout_.isBlockCreatable_(this.targetBlock_)) {
331
- return false;
332
- }
333
- if (!this.flyout_.isScrollable() ||
334
- this.flyout_.isDragTowardWorkspace(this.currentDragDeltaXY_)) {
335
- this.startWorkspace_ = this.flyout_.targetWorkspace;
336
- this.startWorkspace_.updateScreenCalculationsIfScrolled();
337
- // Start the event group now, so that the same event group is used for block
338
- // creation and block dragging.
339
- if (!eventUtils.getGroup()) {
340
- eventUtils.setGroup(true);
517
+ if (browserEvents.isRightButton(e)) {
518
+ this.handleRightClick(e);
519
+ return;
341
520
  }
342
- // The start block is no longer relevant, because this is a drag.
343
- this.startBlock_ = null;
344
- this.targetBlock_ = this.flyout_.createBlock(this.targetBlock_);
345
- this.targetBlock_.select();
346
- return true;
347
- }
348
- return false;
349
- };
350
521
 
351
- /**
352
- * Update this gesture to record whether a bubble is being dragged.
353
- * This function should be called on a mouse/touch move event the first time the
354
- * drag radius is exceeded. It should be called no more than once per gesture.
355
- * If a bubble should be dragged this function creates the necessary
356
- * BubbleDragger and starts the drag.
357
- * @return {boolean} True if a bubble is being dragged.
358
- * @private
359
- */
360
- Gesture.prototype.updateIsDraggingBubble_ = function() {
361
- if (!this.startBubble_) {
362
- return false;
363
- }
522
+ if ((e.type.toLowerCase() === 'touchstart' ||
523
+ e.type.toLowerCase() === 'pointerdown') &&
524
+ e.pointerType !== 'mouse') {
525
+ Touch.longStart(e, this);
526
+ }
364
527
 
365
- this.isDraggingBubble_ = true;
366
- this.startDraggingBubble_();
367
- return true;
368
- };
528
+ this.mouseDownXY_ = new Coordinate(e.clientX, e.clientY);
529
+ this.healStack_ = e.altKey || e.ctrlKey || e.metaKey;
369
530
 
370
- /**
371
- * Update this gesture to record whether a block is being dragged.
372
- * This function should be called on a mouse/touch move event the first time the
373
- * drag radius is exceeded. It should be called no more than once per gesture.
374
- * If a block should be dragged, either from the flyout or in the workspace,
375
- * this function creates the necessary BlockDragger and starts the drag.
376
- * @return {boolean} True if a block is being dragged.
377
- * @private
378
- */
379
- Gesture.prototype.updateIsDraggingBlock_ = function() {
380
- if (!this.targetBlock_) {
381
- return false;
531
+ this.bindMouseEvents(e);
382
532
  }
383
533
 
384
- if (this.flyout_) {
385
- this.isDraggingBlock_ = this.updateIsDraggingFromFlyout_();
386
- } else if (this.targetBlock_.isMovable()) {
387
- this.isDraggingBlock_ = true;
534
+ /**
535
+ * Bind gesture events.
536
+ * @param {!Event} e A mouse down or touch start event.
537
+ * @package
538
+ */
539
+ bindMouseEvents(e) {
540
+ this.onMoveWrapper_ = browserEvents.conditionalBind(
541
+ document, 'mousemove', null, this.handleMove.bind(this));
542
+ this.onUpWrapper_ = browserEvents.conditionalBind(
543
+ document, 'mouseup', null, this.handleUp.bind(this));
544
+
545
+ e.preventDefault();
546
+ e.stopPropagation();
388
547
  }
389
548
 
390
- if (this.isDraggingBlock_) {
391
- this.startDraggingBlock_();
392
- return true;
549
+ /**
550
+ * Handle a mouse move or touch move event.
551
+ * @param {!Event} e A mouse move or touch move event.
552
+ * @package
553
+ */
554
+ handleMove(e) {
555
+ this.updateFromEvent_(e);
556
+ if (this.isDraggingWorkspace_) {
557
+ this.workspaceDragger_.drag(this.currentDragDeltaXY_);
558
+ } else if (this.isDraggingBlock_) {
559
+ this.blockDragger_.drag(this.mostRecentEvent_, this.currentDragDeltaXY_);
560
+ } else if (this.isDraggingBubble_) {
561
+ this.bubbleDragger_.dragBubble(
562
+ this.mostRecentEvent_, this.currentDragDeltaXY_);
563
+ }
564
+ e.preventDefault();
565
+ e.stopPropagation();
393
566
  }
394
- return false;
395
- };
396
-
397
- /**
398
- * Update this gesture to record whether a workspace is being dragged.
399
- * This function should be called on a mouse/touch move event the first time the
400
- * drag radius is exceeded. It should be called no more than once per gesture.
401
- * If a workspace is being dragged this function creates the necessary
402
- * WorkspaceDragger and starts the drag.
403
- * @private
404
- */
405
- Gesture.prototype.updateIsDraggingWorkspace_ = function() {
406
- const wsMovable = this.flyout_ ?
407
- this.flyout_.isScrollable() :
408
- this.startWorkspace_ && this.startWorkspace_.isDraggable();
409
567
 
410
- if (!wsMovable) {
411
- return;
412
- }
568
+ /**
569
+ * Handle a mouse up or touch end event.
570
+ * @param {!Event} e A mouse up or touch end event.
571
+ * @package
572
+ */
573
+ handleUp(e) {
574
+ this.updateFromEvent_(e);
575
+ Touch.longStop();
413
576
 
414
- this.workspaceDragger_ = new WorkspaceDragger(
415
- /** @type {!WorkspaceSvg} */ (this.startWorkspace_));
577
+ if (this.isEnding_) {
578
+ console.log('Trying to end a gesture recursively.');
579
+ return;
580
+ }
581
+ this.isEnding_ = true;
582
+ // The ordering of these checks is important: drags have higher priority
583
+ // than clicks. Fields have higher priority than blocks; blocks have higher
584
+ // priority than workspaces.
585
+ // The ordering within drags does not matter, because the three types of
586
+ // dragging are exclusive.
587
+ if (this.isDraggingBubble_) {
588
+ this.bubbleDragger_.endBubbleDrag(e, this.currentDragDeltaXY_);
589
+ } else if (this.isDraggingBlock_) {
590
+ this.blockDragger_.endDrag(e, this.currentDragDeltaXY_);
591
+ } else if (this.isDraggingWorkspace_) {
592
+ this.workspaceDragger_.endDrag(this.currentDragDeltaXY_);
593
+ } else if (this.isBubbleClick_()) {
594
+ // Bubbles are in front of all fields and blocks.
595
+ this.doBubbleClick_();
596
+ } else if (this.isFieldClick_()) {
597
+ this.doFieldClick_();
598
+ } else if (this.isBlockClick_()) {
599
+ this.doBlockClick_();
600
+ } else if (this.isWorkspaceClick_()) {
601
+ this.doWorkspaceClick_(e);
602
+ }
416
603
 
417
- this.isDraggingWorkspace_ = true;
418
- this.workspaceDragger_.startDrag();
419
- };
604
+ e.preventDefault();
605
+ e.stopPropagation();
420
606
 
421
- /**
422
- * Update this gesture to record whether anything is being dragged.
423
- * This function should be called on a mouse/touch move event the first time the
424
- * drag radius is exceeded. It should be called no more than once per gesture.
425
- * @private
426
- */
427
- Gesture.prototype.updateIsDragging_ = function() {
428
- // Sanity check.
429
- if (this.calledUpdateIsDragging_) {
430
- throw Error('updateIsDragging_ should only be called once per gesture.');
607
+ this.dispose();
431
608
  }
432
- this.calledUpdateIsDragging_ = true;
433
609
 
434
- // First check if it was a bubble drag. Bubbles always sit on top of blocks.
435
- if (this.updateIsDraggingBubble_()) {
436
- return;
437
- }
438
- // Then check if it was a block drag.
439
- if (this.updateIsDraggingBlock_()) {
440
- return;
610
+ /**
611
+ * Cancel an in-progress gesture. If a workspace or block drag is in
612
+ * progress, end the drag at the most recent location.
613
+ * @package
614
+ */
615
+ cancel() {
616
+ // Disposing of a block cancels in-progress drags, but dragging to a delete
617
+ // area disposes of a block and leads to recursive disposal. Break that
618
+ // cycle.
619
+ if (this.isEnding_) {
620
+ return;
621
+ }
622
+ Touch.longStop();
623
+ if (this.isDraggingBubble_) {
624
+ this.bubbleDragger_.endBubbleDrag(
625
+ this.mostRecentEvent_, this.currentDragDeltaXY_);
626
+ } else if (this.isDraggingBlock_) {
627
+ this.blockDragger_.endDrag(
628
+ this.mostRecentEvent_, this.currentDragDeltaXY_);
629
+ } else if (this.isDraggingWorkspace_) {
630
+ this.workspaceDragger_.endDrag(this.currentDragDeltaXY_);
631
+ }
632
+ this.dispose();
441
633
  }
442
- // Then check if it's a workspace drag.
443
- this.updateIsDraggingWorkspace_();
444
- };
445
634
 
446
- /**
447
- * Create a block dragger and start dragging the selected block.
448
- * @private
449
- */
450
- Gesture.prototype.startDraggingBlock_ = function() {
451
- const BlockDraggerClass = registry.getClassFromOptions(
452
- registry.Type.BLOCK_DRAGGER, this.creatorWorkspace_.options, true);
635
+ /**
636
+ * Handle a real or faked right-click event by showing a context menu.
637
+ * @param {!Event} e A mouse move or touch move event.
638
+ * @package
639
+ */
640
+ handleRightClick(e) {
641
+ if (this.targetBlock_) {
642
+ this.bringBlockToFront_();
643
+ this.targetBlock_.workspace.hideChaff(!!this.flyout_);
644
+ this.targetBlock_.showContextMenu(e);
645
+ } else if (this.startBubble_) {
646
+ this.startBubble_.showContextMenu(e);
647
+ } else if (this.startWorkspace_ && !this.flyout_) {
648
+ this.startWorkspace_.hideChaff();
649
+ this.startWorkspace_.showContextMenu(e);
650
+ }
453
651
 
454
- this.blockDragger_ = new BlockDraggerClass(
455
- /** @type {!BlockSvg} */ (this.targetBlock_),
456
- /** @type {!WorkspaceSvg} */ (this.startWorkspace_));
457
- this.blockDragger_.startDrag(this.currentDragDeltaXY_, this.healStack_);
458
- this.blockDragger_.drag(this.mostRecentEvent_, this.currentDragDeltaXY_);
459
- };
652
+ // TODO: Handle right-click on a bubble.
653
+ e.preventDefault();
654
+ e.stopPropagation();
460
655
 
461
- /**
462
- * Create a bubble dragger and start dragging the selected bubble.
463
- * @private
464
- */
465
- // TODO (fenichel): Possibly combine this and startDraggingBlock_.
466
- Gesture.prototype.startDraggingBubble_ = function() {
467
- this.bubbleDragger_ = new BubbleDragger(
468
- /** @type {!IBubble} */ (this.startBubble_),
469
- /** @type {!WorkspaceSvg} */ (this.startWorkspace_));
470
- this.bubbleDragger_.startBubbleDrag();
471
- this.bubbleDragger_.dragBubble(
472
- this.mostRecentEvent_, this.currentDragDeltaXY_);
473
- };
474
- /**
475
- * Start a gesture: update the workspace to indicate that a gesture is in
476
- * progress and bind mousemove and mouseup handlers.
477
- * @param {!Event} e A mouse down or touch start event.
478
- * @package
479
- */
480
- Gesture.prototype.doStart = function(e) {
481
- if (browserEvents.isTargetInput(e)) {
482
- this.cancel();
483
- return;
656
+ this.dispose();
484
657
  }
485
- this.hasStarted_ = true;
486
658
 
487
- blockAnimations.disconnectUiStop();
488
- this.startWorkspace_.updateScreenCalculationsIfScrolled();
489
- if (this.startWorkspace_.isMutator) {
490
- // Mutator's coordinate system could be out of date because the bubble was
491
- // dragged, the block was moved, the parent workspace zoomed, etc.
492
- this.startWorkspace_.resize();
659
+ /**
660
+ * Handle a mousedown/touchstart event on a workspace.
661
+ * @param {!Event} e A mouse down or touch start event.
662
+ * @param {!WorkspaceSvg} ws The workspace the event hit.
663
+ * @package
664
+ */
665
+ handleWsStart(e, ws) {
666
+ if (this.hasStarted_) {
667
+ throw Error(
668
+ 'Tried to call gesture.handleWsStart, ' +
669
+ 'but the gesture had already been started.');
670
+ }
671
+ this.setStartWorkspace_(ws);
672
+ this.mostRecentEvent_ = e;
673
+ this.doStart(e);
493
674
  }
494
675
 
495
- // Hide chaff also hides the flyout, so don't do it if the click is in a
496
- // flyout.
497
- this.startWorkspace_.hideChaff(!!this.flyout_);
498
-
499
- this.startWorkspace_.markFocused();
500
- this.mostRecentEvent_ = e;
501
-
502
- Tooltip.block();
503
-
504
- if (this.targetBlock_) {
505
- this.targetBlock_.select();
676
+ /**
677
+ * Fires a workspace click event.
678
+ * @param {!WorkspaceSvg} ws The workspace that a user clicks on.
679
+ * @private
680
+ */
681
+ fireWorkspaceClick_(ws) {
682
+ eventUtils.fire(
683
+ new (eventUtils.get(eventUtils.CLICK))(null, ws.id, 'workspace'));
506
684
  }
507
685
 
508
- if (browserEvents.isRightButton(e)) {
509
- this.handleRightClick(e);
510
- return;
686
+ /**
687
+ * Handle a mousedown/touchstart event on a flyout.
688
+ * @param {!Event} e A mouse down or touch start event.
689
+ * @param {!IFlyout} flyout The flyout the event hit.
690
+ * @package
691
+ */
692
+ handleFlyoutStart(e, flyout) {
693
+ if (this.hasStarted_) {
694
+ throw Error(
695
+ 'Tried to call gesture.handleFlyoutStart, ' +
696
+ 'but the gesture had already been started.');
697
+ }
698
+ this.setStartFlyout_(flyout);
699
+ this.handleWsStart(e, flyout.getWorkspace());
511
700
  }
512
701
 
513
- if ((e.type.toLowerCase() === 'touchstart' ||
514
- e.type.toLowerCase() === 'pointerdown') &&
515
- e.pointerType !== 'mouse') {
516
- Touch.longStart(e, this);
702
+ /**
703
+ * Handle a mousedown/touchstart event on a block.
704
+ * @param {!Event} e A mouse down or touch start event.
705
+ * @param {!BlockSvg} block The block the event hit.
706
+ * @package
707
+ */
708
+ handleBlockStart(e, block) {
709
+ if (this.hasStarted_) {
710
+ throw Error(
711
+ 'Tried to call gesture.handleBlockStart, ' +
712
+ 'but the gesture had already been started.');
713
+ }
714
+ this.setStartBlock(block);
715
+ this.mostRecentEvent_ = e;
517
716
  }
518
717
 
519
- this.mouseDownXY_ = new Coordinate(e.clientX, e.clientY);
520
- this.healStack_ = e.altKey || e.ctrlKey || e.metaKey;
521
-
522
- this.bindMouseEvents(e);
523
- };
524
-
525
- /**
526
- * Bind gesture events.
527
- * @param {!Event} e A mouse down or touch start event.
528
- * @package
529
- */
530
- Gesture.prototype.bindMouseEvents = function(e) {
531
- this.onMoveWrapper_ = browserEvents.conditionalBind(
532
- document, 'mousemove', null, this.handleMove.bind(this));
533
- this.onUpWrapper_ = browserEvents.conditionalBind(
534
- document, 'mouseup', null, this.handleUp.bind(this));
535
-
536
- e.preventDefault();
537
- e.stopPropagation();
538
- };
539
-
540
- /**
541
- * Handle a mouse move or touch move event.
542
- * @param {!Event} e A mouse move or touch move event.
543
- * @package
544
- */
545
- Gesture.prototype.handleMove = function(e) {
546
- this.updateFromEvent_(e);
547
- if (this.isDraggingWorkspace_) {
548
- this.workspaceDragger_.drag(this.currentDragDeltaXY_);
549
- } else if (this.isDraggingBlock_) {
550
- this.blockDragger_.drag(this.mostRecentEvent_, this.currentDragDeltaXY_);
551
- } else if (this.isDraggingBubble_) {
552
- this.bubbleDragger_.dragBubble(
553
- this.mostRecentEvent_, this.currentDragDeltaXY_);
718
+ /**
719
+ * Handle a mousedown/touchstart event on a bubble.
720
+ * @param {!Event} e A mouse down or touch start event.
721
+ * @param {!IBubble} bubble The bubble the event hit.
722
+ * @package
723
+ */
724
+ handleBubbleStart(e, bubble) {
725
+ if (this.hasStarted_) {
726
+ throw Error(
727
+ 'Tried to call gesture.handleBubbleStart, ' +
728
+ 'but the gesture had already been started.');
729
+ }
730
+ this.setStartBubble(bubble);
731
+ this.mostRecentEvent_ = e;
554
732
  }
555
- e.preventDefault();
556
- e.stopPropagation();
557
- };
558
733
 
559
- /**
560
- * Handle a mouse up or touch end event.
561
- * @param {!Event} e A mouse up or touch end event.
562
- * @package
563
- */
564
- Gesture.prototype.handleUp = function(e) {
565
- this.updateFromEvent_(e);
566
- Touch.longStop();
567
-
568
- if (this.isEnding_) {
569
- console.log('Trying to end a gesture recursively.');
570
- return;
571
- }
572
- this.isEnding_ = true;
573
- // The ordering of these checks is important: drags have higher priority than
574
- // clicks. Fields have higher priority than blocks; blocks have higher
575
- // priority than workspaces.
576
- // The ordering within drags does not matter, because the three types of
577
- // dragging are exclusive.
578
- if (this.isDraggingBubble_) {
579
- this.bubbleDragger_.endBubbleDrag(e, this.currentDragDeltaXY_);
580
- } else if (this.isDraggingBlock_) {
581
- this.blockDragger_.endDrag(e, this.currentDragDeltaXY_);
582
- } else if (this.isDraggingWorkspace_) {
583
- this.workspaceDragger_.endDrag(this.currentDragDeltaXY_);
584
- } else if (this.isBubbleClick_()) {
585
- // Bubbles are in front of all fields and blocks.
586
- this.doBubbleClick_();
587
- } else if (this.isFieldClick_()) {
588
- this.doFieldClick_();
589
- } else if (this.isBlockClick_()) {
590
- this.doBlockClick_();
591
- } else if (this.isWorkspaceClick_()) {
592
- this.doWorkspaceClick_(e);
593
- }
594
-
595
- e.preventDefault();
596
- e.stopPropagation();
597
-
598
- this.dispose();
599
- };
734
+ /* Begin functions defining what actions to take to execute clicks on each
735
+ * type of target. Any developer wanting to add behaviour on clicks should
736
+ * modify only this code. */
600
737
 
601
- /**
602
- * Cancel an in-progress gesture. If a workspace or block drag is in progress,
603
- * end the drag at the most recent location.
604
- * @package
605
- */
606
- Gesture.prototype.cancel = function() {
607
- // Disposing of a block cancels in-progress drags, but dragging to a delete
608
- // area disposes of a block and leads to recursive disposal. Break that cycle.
609
- if (this.isEnding_) {
610
- return;
611
- }
612
- Touch.longStop();
613
- if (this.isDraggingBubble_) {
614
- this.bubbleDragger_.endBubbleDrag(
615
- this.mostRecentEvent_, this.currentDragDeltaXY_);
616
- } else if (this.isDraggingBlock_) {
617
- this.blockDragger_.endDrag(this.mostRecentEvent_, this.currentDragDeltaXY_);
618
- } else if (this.isDraggingWorkspace_) {
619
- this.workspaceDragger_.endDrag(this.currentDragDeltaXY_);
738
+ /**
739
+ * Execute a bubble click.
740
+ * @private
741
+ */
742
+ doBubbleClick_() {
743
+ // TODO (#1673): Consistent handling of single clicks.
744
+ this.startBubble_.setFocus && this.startBubble_.setFocus();
745
+ this.startBubble_.select && this.startBubble_.select();
620
746
  }
621
- this.dispose();
622
- };
623
747
 
624
- /**
625
- * Handle a real or faked right-click event by showing a context menu.
626
- * @param {!Event} e A mouse move or touch move event.
627
- * @package
628
- */
629
- Gesture.prototype.handleRightClick = function(e) {
630
- if (this.targetBlock_) {
748
+ /**
749
+ * Execute a field click.
750
+ * @private
751
+ */
752
+ doFieldClick_() {
753
+ this.startField_.showEditor(this.mostRecentEvent_);
631
754
  this.bringBlockToFront_();
632
- this.targetBlock_.workspace.hideChaff(!!this.flyout_);
633
- this.targetBlock_.showContextMenu(e);
634
- } else if (this.startBubble_) {
635
- this.startBubble_.showContextMenu(e);
636
- } else if (this.startWorkspace_ && !this.flyout_) {
637
- this.startWorkspace_.hideChaff();
638
- this.startWorkspace_.showContextMenu(e);
639
- }
640
-
641
- // TODO: Handle right-click on a bubble.
642
- e.preventDefault();
643
- e.stopPropagation();
644
-
645
- this.dispose();
646
- };
647
-
648
- /**
649
- * Handle a mousedown/touchstart event on a workspace.
650
- * @param {!Event} e A mouse down or touch start event.
651
- * @param {!WorkspaceSvg} ws The workspace the event hit.
652
- * @package
653
- */
654
- Gesture.prototype.handleWsStart = function(e, ws) {
655
- if (this.hasStarted_) {
656
- throw Error(
657
- 'Tried to call gesture.handleWsStart, ' +
658
- 'but the gesture had already been started.');
659
- }
660
- this.setStartWorkspace_(ws);
661
- this.mostRecentEvent_ = e;
662
- this.doStart(e);
663
- };
664
-
665
- /**
666
- * Fires a workspace click event.
667
- * @param {!WorkspaceSvg} ws The workspace that a user clicks on.
668
- * @private
669
- */
670
- Gesture.prototype.fireWorkspaceClick_ = function(ws) {
671
- eventUtils.fire(
672
- new (eventUtils.get(eventUtils.CLICK))(null, ws.id, 'workspace'));
673
- };
674
-
675
- /**
676
- * Handle a mousedown/touchstart event on a flyout.
677
- * @param {!Event} e A mouse down or touch start event.
678
- * @param {!IFlyout} flyout The flyout the event hit.
679
- * @package
680
- */
681
- Gesture.prototype.handleFlyoutStart = function(e, flyout) {
682
- if (this.hasStarted_) {
683
- throw Error(
684
- 'Tried to call gesture.handleFlyoutStart, ' +
685
- 'but the gesture had already been started.');
686
755
  }
687
- this.setStartFlyout_(flyout);
688
- this.handleWsStart(e, flyout.getWorkspace());
689
- };
690
756
 
691
- /**
692
- * Handle a mousedown/touchstart event on a block.
693
- * @param {!Event} e A mouse down or touch start event.
694
- * @param {!BlockSvg} block The block the event hit.
695
- * @package
696
- */
697
- Gesture.prototype.handleBlockStart = function(e, block) {
698
- if (this.hasStarted_) {
699
- throw Error(
700
- 'Tried to call gesture.handleBlockStart, ' +
701
- 'but the gesture had already been started.');
757
+ /**
758
+ * Execute a block click.
759
+ * @private
760
+ */
761
+ doBlockClick_() {
762
+ // Block click in an autoclosing flyout.
763
+ if (this.flyout_ && this.flyout_.autoClose) {
764
+ if (this.targetBlock_.isEnabled()) {
765
+ if (!eventUtils.getGroup()) {
766
+ eventUtils.setGroup(true);
767
+ }
768
+ const newBlock = this.flyout_.createBlock(this.targetBlock_);
769
+ newBlock.scheduleSnapAndBump();
770
+ }
771
+ } else {
772
+ // Clicks events are on the start block, even if it was a shadow.
773
+ const event = new (eventUtils.get(eventUtils.CLICK))(
774
+ this.startBlock_, this.startWorkspace_.id, 'block');
775
+ eventUtils.fire(event);
776
+ }
777
+ this.bringBlockToFront_();
778
+ eventUtils.setGroup(false);
702
779
  }
703
- this.setStartBlock(block);
704
- this.mostRecentEvent_ = e;
705
- };
706
780
 
707
- /**
708
- * Handle a mousedown/touchstart event on a bubble.
709
- * @param {!Event} e A mouse down or touch start event.
710
- * @param {!IBubble} bubble The bubble the event hit.
711
- * @package
712
- */
713
- Gesture.prototype.handleBubbleStart = function(e, bubble) {
714
- if (this.hasStarted_) {
715
- throw Error(
716
- 'Tried to call gesture.handleBubbleStart, ' +
717
- 'but the gesture had already been started.');
781
+ /**
782
+ * Execute a workspace click. When in accessibility mode shift clicking will
783
+ * move the cursor.
784
+ * @param {!Event} _e A mouse up or touch end event.
785
+ * @private
786
+ */
787
+ doWorkspaceClick_(_e) {
788
+ const ws = this.creatorWorkspace_;
789
+ if (common.getSelected()) {
790
+ common.getSelected().unselect();
791
+ }
792
+ this.fireWorkspaceClick_(this.startWorkspace_ || ws);
718
793
  }
719
- this.setStartBubble(bubble);
720
- this.mostRecentEvent_ = e;
721
- };
722
-
723
- /* Begin functions defining what actions to take to execute clicks on each type
724
- * of target. Any developer wanting to add behaviour on clicks should modify
725
- * only this code. */
726
794
 
727
- /**
728
- * Execute a bubble click.
729
- * @private
730
- */
731
- Gesture.prototype.doBubbleClick_ = function() {
732
- // TODO (#1673): Consistent handling of single clicks.
733
- this.startBubble_.setFocus && this.startBubble_.setFocus();
734
- this.startBubble_.select && this.startBubble_.select();
735
- };
795
+ /* End functions defining what actions to take to execute clicks on each type
796
+ * of target. */
736
797
 
737
- /**
738
- * Execute a field click.
739
- * @private
740
- */
741
- Gesture.prototype.doFieldClick_ = function() {
742
- this.startField_.showEditor(this.mostRecentEvent_);
743
- this.bringBlockToFront_();
744
- };
798
+ // TODO (fenichel): Move bubbles to the front.
745
799
 
746
- /**
747
- * Execute a block click.
748
- * @private
749
- */
750
- Gesture.prototype.doBlockClick_ = function() {
751
- // Block click in an autoclosing flyout.
752
- if (this.flyout_ && this.flyout_.autoClose) {
753
- if (this.targetBlock_.isEnabled()) {
754
- if (!eventUtils.getGroup()) {
755
- eventUtils.setGroup(true);
756
- }
757
- const newBlock = this.flyout_.createBlock(this.targetBlock_);
758
- newBlock.scheduleSnapAndBump();
800
+ /**
801
+ * Move the dragged/clicked block to the front of the workspace so that it is
802
+ * not occluded by other blocks.
803
+ * @private
804
+ */
805
+ bringBlockToFront_() {
806
+ // Blocks in the flyout don't overlap, so skip the work.
807
+ if (this.targetBlock_ && !this.flyout_) {
808
+ this.targetBlock_.bringToFront();
759
809
  }
760
- } else {
761
- // Clicks events are on the start block, even if it was a shadow.
762
- const event = new (eventUtils.get(eventUtils.CLICK))(
763
- this.startBlock_, this.startWorkspace_.id, 'block');
764
- eventUtils.fire(event);
765
810
  }
766
- this.bringBlockToFront_();
767
- eventUtils.setGroup(false);
768
- };
769
811
 
770
- /**
771
- * Execute a workspace click. When in accessibility mode shift clicking will
772
- * move the cursor.
773
- * @param {!Event} _e A mouse up or touch end event.
774
- * @private
775
- */
776
- Gesture.prototype.doWorkspaceClick_ = function(_e) {
777
- const ws = this.creatorWorkspace_;
778
- if (common.getSelected()) {
779
- common.getSelected().unselect();
780
- }
781
- this.fireWorkspaceClick_(this.startWorkspace_ || ws);
782
- };
812
+ /* Begin functions for populating a gesture at mouse down. */
783
813
 
784
- /* End functions defining what actions to take to execute clicks on each type
785
- * of target. */
786
-
787
- // TODO (fenichel): Move bubbles to the front.
788
- /**
789
- * Move the dragged/clicked block to the front of the workspace so that it is
790
- * not occluded by other blocks.
791
- * @private
792
- */
793
- Gesture.prototype.bringBlockToFront_ = function() {
794
- // Blocks in the flyout don't overlap, so skip the work.
795
- if (this.targetBlock_ && !this.flyout_) {
796
- this.targetBlock_.bringToFront();
814
+ /**
815
+ * Record the field that a gesture started on.
816
+ * @param {Field} field The field the gesture started on.
817
+ * @package
818
+ */
819
+ setStartField(field) {
820
+ if (this.hasStarted_) {
821
+ throw Error(
822
+ 'Tried to call gesture.setStartField, ' +
823
+ 'but the gesture had already been started.');
824
+ }
825
+ if (!this.startField_) {
826
+ this.startField_ = field;
827
+ }
797
828
  }
798
- };
799
829
 
800
- /* Begin functions for populating a gesture at mouse down. */
801
-
802
- /**
803
- * Record the field that a gesture started on.
804
- * @param {Field} field The field the gesture started on.
805
- * @package
806
- */
807
- Gesture.prototype.setStartField = function(field) {
808
- if (this.hasStarted_) {
809
- throw Error(
810
- 'Tried to call gesture.setStartField, ' +
811
- 'but the gesture had already been started.');
812
- }
813
- if (!this.startField_) {
814
- this.startField_ = field;
830
+ /**
831
+ * Record the bubble that a gesture started on
832
+ * @param {IBubble} bubble The bubble the gesture started on.
833
+ * @package
834
+ */
835
+ setStartBubble(bubble) {
836
+ if (!this.startBubble_) {
837
+ this.startBubble_ = bubble;
838
+ }
815
839
  }
816
- };
817
840
 
818
- /**
819
- * Record the bubble that a gesture started on
820
- * @param {IBubble} bubble The bubble the gesture started on.
821
- * @package
822
- */
823
- Gesture.prototype.setStartBubble = function(bubble) {
824
- if (!this.startBubble_) {
825
- this.startBubble_ = bubble;
841
+ /**
842
+ * Record the block that a gesture started on, and set the target block
843
+ * appropriately.
844
+ * @param {BlockSvg} block The block the gesture started on.
845
+ * @package
846
+ */
847
+ setStartBlock(block) {
848
+ // If the gesture already went through a bubble, don't set the start block.
849
+ if (!this.startBlock_ && !this.startBubble_) {
850
+ this.startBlock_ = block;
851
+ if (block.isInFlyout && block !== block.getRootBlock()) {
852
+ this.setTargetBlock_(block.getRootBlock());
853
+ } else {
854
+ this.setTargetBlock_(block);
855
+ }
856
+ }
826
857
  }
827
- };
828
858
 
829
- /**
830
- * Record the block that a gesture started on, and set the target block
831
- * appropriately.
832
- * @param {BlockSvg} block The block the gesture started on.
833
- * @package
834
- */
835
- Gesture.prototype.setStartBlock = function(block) {
836
- // If the gesture already went through a bubble, don't set the start block.
837
- if (!this.startBlock_ && !this.startBubble_) {
838
- this.startBlock_ = block;
839
- if (block.isInFlyout && block !== block.getRootBlock()) {
840
- this.setTargetBlock_(block.getRootBlock());
859
+ /**
860
+ * Record the block that a gesture targets, meaning the block that will be
861
+ * dragged if this turns into a drag. If this block is a shadow, that will be
862
+ * its first non-shadow parent.
863
+ * @param {BlockSvg} block The block the gesture targets.
864
+ * @private
865
+ */
866
+ setTargetBlock_(block) {
867
+ if (block.isShadow()) {
868
+ this.setTargetBlock_(block.getParent());
841
869
  } else {
842
- this.setTargetBlock_(block);
870
+ this.targetBlock_ = block;
843
871
  }
844
872
  }
845
- };
846
-
847
- /**
848
- * Record the block that a gesture targets, meaning the block that will be
849
- * dragged if this turns into a drag. If this block is a shadow, that will be
850
- * its first non-shadow parent.
851
- * @param {BlockSvg} block The block the gesture targets.
852
- * @private
853
- */
854
- Gesture.prototype.setTargetBlock_ = function(block) {
855
- if (block.isShadow()) {
856
- this.setTargetBlock_(block.getParent());
857
- } else {
858
- this.targetBlock_ = block;
859
- }
860
- };
861
873
 
862
- /**
863
- * Record the workspace that a gesture started on.
864
- * @param {WorkspaceSvg} ws The workspace the gesture started on.
865
- * @private
866
- */
867
- Gesture.prototype.setStartWorkspace_ = function(ws) {
868
- if (!this.startWorkspace_) {
869
- this.startWorkspace_ = ws;
874
+ /**
875
+ * Record the workspace that a gesture started on.
876
+ * @param {WorkspaceSvg} ws The workspace the gesture started on.
877
+ * @private
878
+ */
879
+ setStartWorkspace_(ws) {
880
+ if (!this.startWorkspace_) {
881
+ this.startWorkspace_ = ws;
882
+ }
870
883
  }
871
- };
872
884
 
873
- /**
874
- * Record the flyout that a gesture started on.
875
- * @param {IFlyout} flyout The flyout the gesture started on.
876
- * @private
877
- */
878
- Gesture.prototype.setStartFlyout_ = function(flyout) {
879
- if (!this.flyout_) {
880
- this.flyout_ = flyout;
885
+ /**
886
+ * Record the flyout that a gesture started on.
887
+ * @param {IFlyout} flyout The flyout the gesture started on.
888
+ * @private
889
+ */
890
+ setStartFlyout_(flyout) {
891
+ if (!this.flyout_) {
892
+ this.flyout_ = flyout;
893
+ }
881
894
  }
882
- };
883
895
 
896
+ /* End functions for populating a gesture at mouse down. */
884
897
 
885
- /* End functions for populating a gesture at mouse down. */
898
+ /* Begin helper functions defining types of clicks. Any developer wanting
899
+ * to change the definition of a click should modify only this code. */
886
900
 
887
- /* Begin helper functions defining types of clicks. Any developer wanting
888
- * to change the definition of a click should modify only this code. */
889
-
890
- /**
891
- * Whether this gesture is a click on a bubble. This should only be called when
892
- * ending a gesture (mouse up, touch end).
893
- * @return {boolean} Whether this gesture was a click on a bubble.
894
- * @private
895
- */
896
- Gesture.prototype.isBubbleClick_ = function() {
897
- // A bubble click starts on a bubble and never escapes the drag radius.
898
- const hasStartBubble = !!this.startBubble_;
899
- return hasStartBubble && !this.hasExceededDragRadius_;
900
- };
901
+ /**
902
+ * Whether this gesture is a click on a bubble. This should only be called
903
+ * when ending a gesture (mouse up, touch end).
904
+ * @return {boolean} Whether this gesture was a click on a bubble.
905
+ * @private
906
+ */
907
+ isBubbleClick_() {
908
+ // A bubble click starts on a bubble and never escapes the drag radius.
909
+ const hasStartBubble = !!this.startBubble_;
910
+ return hasStartBubble && !this.hasExceededDragRadius_;
911
+ }
901
912
 
902
- /**
903
- * Whether this gesture is a click on a block. This should only be called when
904
- * ending a gesture (mouse up, touch end).
905
- * @return {boolean} Whether this gesture was a click on a block.
906
- * @private
907
- */
908
- Gesture.prototype.isBlockClick_ = function() {
909
- // A block click starts on a block, never escapes the drag radius, and is not
910
- // a field click.
911
- const hasStartBlock = !!this.startBlock_;
912
- return hasStartBlock && !this.hasExceededDragRadius_ && !this.isFieldClick_();
913
- };
913
+ /**
914
+ * Whether this gesture is a click on a block. This should only be called
915
+ * when ending a gesture (mouse up, touch end).
916
+ * @return {boolean} Whether this gesture was a click on a block.
917
+ * @private
918
+ */
919
+ isBlockClick_() {
920
+ // A block click starts on a block, never escapes the drag radius, and is
921
+ // not a field click.
922
+ const hasStartBlock = !!this.startBlock_;
923
+ return hasStartBlock && !this.hasExceededDragRadius_ &&
924
+ !this.isFieldClick_();
925
+ }
914
926
 
915
- /**
916
- * Whether this gesture is a click on a field. This should only be called when
917
- * ending a gesture (mouse up, touch end).
918
- * @return {boolean} Whether this gesture was a click on a field.
919
- * @private
920
- */
921
- Gesture.prototype.isFieldClick_ = function() {
922
- const fieldClickable =
923
- this.startField_ ? this.startField_.isClickable() : false;
924
- return fieldClickable && !this.hasExceededDragRadius_ &&
925
- (!this.flyout_ || !this.flyout_.autoClose);
926
- };
927
+ /**
928
+ * Whether this gesture is a click on a field. This should only be called
929
+ * when ending a gesture (mouse up, touch end).
930
+ * @return {boolean} Whether this gesture was a click on a field.
931
+ * @private
932
+ */
933
+ isFieldClick_() {
934
+ const fieldClickable =
935
+ this.startField_ ? this.startField_.isClickable() : false;
936
+ return fieldClickable && !this.hasExceededDragRadius_ &&
937
+ (!this.flyout_ || !this.flyout_.autoClose);
938
+ }
927
939
 
928
- /**
929
- * Whether this gesture is a click on a workspace. This should only be called
930
- * when ending a gesture (mouse up, touch end).
931
- * @return {boolean} Whether this gesture was a click on a workspace.
932
- * @private
933
- */
934
- Gesture.prototype.isWorkspaceClick_ = function() {
935
- const onlyTouchedWorkspace =
936
- !this.startBlock_ && !this.startBubble_ && !this.startField_;
937
- return onlyTouchedWorkspace && !this.hasExceededDragRadius_;
938
- };
940
+ /**
941
+ * Whether this gesture is a click on a workspace. This should only be called
942
+ * when ending a gesture (mouse up, touch end).
943
+ * @return {boolean} Whether this gesture was a click on a workspace.
944
+ * @private
945
+ */
946
+ isWorkspaceClick_() {
947
+ const onlyTouchedWorkspace =
948
+ !this.startBlock_ && !this.startBubble_ && !this.startField_;
949
+ return onlyTouchedWorkspace && !this.hasExceededDragRadius_;
950
+ }
939
951
 
940
- /* End helper functions defining types of clicks. */
952
+ /* End helper functions defining types of clicks. */
941
953
 
942
- /**
943
- * Whether this gesture is a drag of either a workspace or block.
944
- * This function is called externally to block actions that cannot be taken
945
- * mid-drag (e.g. using the keyboard to delete the selected blocks).
946
- * @return {boolean} True if this gesture is a drag of a workspace or block.
947
- * @package
948
- */
949
- Gesture.prototype.isDragging = function() {
950
- return this.isDraggingWorkspace_ || this.isDraggingBlock_ ||
951
- this.isDraggingBubble_;
952
- };
954
+ /**
955
+ * Whether this gesture is a drag of either a workspace or block.
956
+ * This function is called externally to block actions that cannot be taken
957
+ * mid-drag (e.g. using the keyboard to delete the selected blocks).
958
+ * @return {boolean} True if this gesture is a drag of a workspace or block.
959
+ * @package
960
+ */
961
+ isDragging() {
962
+ return this.isDraggingWorkspace_ || this.isDraggingBlock_ ||
963
+ this.isDraggingBubble_;
964
+ }
953
965
 
954
- /**
955
- * Whether this gesture has already been started. In theory every mouse down
956
- * has a corresponding mouse up, but in reality it is possible to lose a
957
- * mouse up, leaving an in-process gesture hanging.
958
- * @return {boolean} Whether this gesture was a click on a workspace.
959
- * @package
960
- */
961
- Gesture.prototype.hasStarted = function() {
962
- return this.hasStarted_;
963
- };
966
+ /**
967
+ * Whether this gesture has already been started. In theory every mouse down
968
+ * has a corresponding mouse up, but in reality it is possible to lose a
969
+ * mouse up, leaving an in-process gesture hanging.
970
+ * @return {boolean} Whether this gesture was a click on a workspace.
971
+ * @package
972
+ */
973
+ hasStarted() {
974
+ return this.hasStarted_;
975
+ }
964
976
 
965
- /**
966
- * Get a list of the insertion markers that currently exist. Block drags have
967
- * 0, 1, or 2 insertion markers.
968
- * @return {!Array<!BlockSvg>} A possibly empty list of insertion
969
- * marker blocks.
970
- * @package
971
- */
972
- Gesture.prototype.getInsertionMarkers = function() {
973
- if (this.blockDragger_) {
974
- return this.blockDragger_.getInsertionMarkers();
977
+ /**
978
+ * Get a list of the insertion markers that currently exist. Block drags have
979
+ * 0, 1, or 2 insertion markers.
980
+ * @return {!Array<!BlockSvg>} A possibly empty list of insertion
981
+ * marker blocks.
982
+ * @package
983
+ */
984
+ getInsertionMarkers() {
985
+ if (this.blockDragger_) {
986
+ return this.blockDragger_.getInsertionMarkers();
987
+ }
988
+ return [];
975
989
  }
976
- return [];
977
- };
978
990
 
979
- /**
980
- * Gets the current dragger if an item is being dragged. Null if nothing is
981
- * being dragged.
982
- * @return {!WorkspaceDragger|!BubbleDragger|!IBlockDragger|null}
983
- * The dragger that is currently in use or null if no drag is in progress.
984
- */
985
- Gesture.prototype.getCurrentDragger = function() {
986
- if (this.isDraggingBlock_) {
987
- return this.blockDragger_;
988
- } else if (this.isDraggingWorkspace_) {
989
- return this.workspaceDragger_;
990
- } else if (this.isDraggingBubble_) {
991
- return this.bubbleDragger_;
991
+ /**
992
+ * Gets the current dragger if an item is being dragged. Null if nothing is
993
+ * being dragged.
994
+ * @return {!WorkspaceDragger|!BubbleDragger|!IBlockDragger|null}
995
+ * The dragger that is currently in use or null if no drag is in progress.
996
+ */
997
+ getCurrentDragger() {
998
+ if (this.isDraggingBlock_) {
999
+ return this.blockDragger_;
1000
+ } else if (this.isDraggingWorkspace_) {
1001
+ return this.workspaceDragger_;
1002
+ } else if (this.isDraggingBubble_) {
1003
+ return this.bubbleDragger_;
1004
+ }
1005
+ return null;
992
1006
  }
993
- return null;
994
- };
995
1007
 
996
- /**
997
- * Is a drag or other gesture currently in progress on any workspace?
998
- * @return {boolean} True if gesture is occurring.
999
- */
1000
- Gesture.inProgress = function() {
1001
- const workspaces = Workspace.getAll();
1002
- for (let i = 0, workspace; (workspace = workspaces[i]); i++) {
1003
- if (workspace.currentGesture_) {
1004
- return true;
1008
+ /**
1009
+ * Is a drag or other gesture currently in progress on any workspace?
1010
+ * @return {boolean} True if gesture is occurring.
1011
+ */
1012
+ static inProgress() {
1013
+ const workspaces = Workspace.getAll();
1014
+ for (let i = 0, workspace; (workspace = workspaces[i]); i++) {
1015
+ // Not actually necessarily a WorkspaceSvg, but it doesn't matter b/c
1016
+ // we're just checking if the property exists. Theoretically we would
1017
+ // want to use instanceof, but that causes a circular dependency.
1018
+ if (/** @type {!WorkspaceSvg} */ (workspace).currentGesture_) {
1019
+ return true;
1020
+ }
1005
1021
  }
1022
+ return false;
1006
1023
  }
1007
- return false;
1008
- };
1024
+ }
1009
1025
 
1010
1026
  exports.Gesture = Gesture;