blockly 7.20211209.4 → 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
@@ -17,12 +17,11 @@ goog.module('Blockly.HorizontalFlyout');
17
17
 
18
18
  const WidgetDiv = goog.require('Blockly.WidgetDiv');
19
19
  const browserEvents = goog.require('Blockly.browserEvents');
20
- const object = goog.require('Blockly.utils.object');
20
+ const dropDownDiv = goog.require('Blockly.dropDownDiv');
21
21
  const registry = goog.require('Blockly.registry');
22
22
  const toolbox = goog.require('Blockly.utils.toolbox');
23
23
  /* eslint-disable-next-line no-unused-vars */
24
24
  const {Coordinate} = goog.requireType('Blockly.utils.Coordinate');
25
- const {DropDownDiv} = goog.require('Blockly.DropDownDiv');
26
25
  const {Flyout} = goog.require('Blockly.Flyout');
27
26
  /* eslint-disable-next-line no-unused-vars */
28
27
  const {Options} = goog.requireType('Blockly.Options');
@@ -32,355 +31,358 @@ const {Scrollbar} = goog.require('Blockly.Scrollbar');
32
31
 
33
32
  /**
34
33
  * Class for a flyout.
35
- * @param {!Options} workspaceOptions Dictionary of options for the
36
- * workspace.
37
34
  * @extends {Flyout}
38
- * @constructor
39
35
  * @alias Blockly.HorizontalFlyout
40
36
  */
41
- const HorizontalFlyout = function(workspaceOptions) {
42
- HorizontalFlyout.superClass_.constructor.call(this, workspaceOptions);
43
- this.horizontalLayout = true;
44
- };
45
- object.inherits(HorizontalFlyout, Flyout);
46
-
47
- /**
48
- * Sets the translation of the flyout to match the scrollbars.
49
- * @param {!{x:number,y:number}} xyRatio Contains a y property which is a float
50
- * between 0 and 1 specifying the degree of scrolling and a
51
- * similar x property.
52
- * @protected
53
- */
54
- HorizontalFlyout.prototype.setMetrics_ = function(xyRatio) {
55
- if (!this.isVisible()) {
56
- return;
37
+ class HorizontalFlyout extends Flyout {
38
+ /**
39
+ * @param {!Options} workspaceOptions Dictionary of options for the
40
+ * workspace.
41
+ */
42
+ constructor(workspaceOptions) {
43
+ super(workspaceOptions);
44
+ this.horizontalLayout = true;
57
45
  }
58
46
 
59
- const metricsManager = this.workspace_.getMetricsManager();
60
- const scrollMetrics = metricsManager.getScrollMetrics();
61
- const viewMetrics = metricsManager.getViewMetrics();
62
- const absoluteMetrics = metricsManager.getAbsoluteMetrics();
47
+ /**
48
+ * Sets the translation of the flyout to match the scrollbars.
49
+ * @param {!{x:number,y:number}} xyRatio Contains a y property which is a
50
+ * float between 0 and 1 specifying the degree of scrolling and a similar
51
+ * x property.
52
+ * @protected
53
+ */
54
+ setMetrics_(xyRatio) {
55
+ if (!this.isVisible()) {
56
+ return;
57
+ }
63
58
 
64
- if (typeof xyRatio.x === 'number') {
65
- this.workspace_.scrollX =
66
- -(scrollMetrics.left +
67
- (scrollMetrics.width - viewMetrics.width) * xyRatio.x);
68
- }
59
+ const metricsManager = this.workspace_.getMetricsManager();
60
+ const scrollMetrics = metricsManager.getScrollMetrics();
61
+ const viewMetrics = metricsManager.getViewMetrics();
62
+ const absoluteMetrics = metricsManager.getAbsoluteMetrics();
69
63
 
70
- this.workspace_.translate(
71
- this.workspace_.scrollX + absoluteMetrics.left,
72
- this.workspace_.scrollY + absoluteMetrics.top);
73
- };
64
+ if (typeof xyRatio.x === 'number') {
65
+ this.workspace_.scrollX =
66
+ -(scrollMetrics.left +
67
+ (scrollMetrics.width - viewMetrics.width) * xyRatio.x);
68
+ }
74
69
 
75
- /**
76
- * Calculates the x coordinate for the flyout position.
77
- * @return {number} X coordinate.
78
- */
79
- HorizontalFlyout.prototype.getX = function() {
80
- // X is always 0 since this is a horizontal flyout.
81
- return 0;
82
- };
70
+ this.workspace_.translate(
71
+ this.workspace_.scrollX + absoluteMetrics.left,
72
+ this.workspace_.scrollY + absoluteMetrics.top);
73
+ }
83
74
 
84
- /**
85
- * Calculates the y coordinate for the flyout position.
86
- * @return {number} Y coordinate.
87
- */
88
- HorizontalFlyout.prototype.getY = function() {
89
- if (!this.isVisible()) {
75
+ /**
76
+ * Calculates the x coordinate for the flyout position.
77
+ * @return {number} X coordinate.
78
+ */
79
+ getX() {
80
+ // X is always 0 since this is a horizontal flyout.
90
81
  return 0;
91
82
  }
92
- const metricsManager = this.targetWorkspace.getMetricsManager();
93
- const absoluteMetrics = metricsManager.getAbsoluteMetrics();
94
- const viewMetrics = metricsManager.getViewMetrics();
95
- const toolboxMetrics = metricsManager.getToolboxMetrics();
96
-
97
- let y = 0;
98
- const atTop = this.toolboxPosition_ === toolbox.Position.TOP;
99
- // If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
100
- if (this.targetWorkspace.toolboxPosition === this.toolboxPosition_) {
101
- // If there is a category toolbox.
102
- if (this.targetWorkspace.getToolbox()) {
103
- if (atTop) {
104
- y = toolboxMetrics.height;
83
+
84
+ /**
85
+ * Calculates the y coordinate for the flyout position.
86
+ * @return {number} Y coordinate.
87
+ */
88
+ getY() {
89
+ if (!this.isVisible()) {
90
+ return 0;
91
+ }
92
+ const metricsManager = this.targetWorkspace.getMetricsManager();
93
+ const absoluteMetrics = metricsManager.getAbsoluteMetrics();
94
+ const viewMetrics = metricsManager.getViewMetrics();
95
+ const toolboxMetrics = metricsManager.getToolboxMetrics();
96
+
97
+ let y = 0;
98
+ const atTop = this.toolboxPosition_ === toolbox.Position.TOP;
99
+ // If this flyout is not the trashcan flyout (e.g. toolbox or mutator).
100
+ if (this.targetWorkspace.toolboxPosition === this.toolboxPosition_) {
101
+ // If there is a category toolbox.
102
+ if (this.targetWorkspace.getToolbox()) {
103
+ if (atTop) {
104
+ y = toolboxMetrics.height;
105
+ } else {
106
+ y = viewMetrics.height - this.height_;
107
+ }
108
+ // Simple (flyout-only) toolbox.
105
109
  } else {
106
- y = viewMetrics.height - this.height_;
110
+ if (atTop) {
111
+ y = 0;
112
+ } else {
113
+ // The simple flyout does not cover the workspace.
114
+ y = viewMetrics.height;
115
+ }
107
116
  }
108
- // Simple (flyout-only) toolbox.
117
+ // Trashcan flyout is opposite the main flyout.
109
118
  } else {
110
119
  if (atTop) {
111
120
  y = 0;
112
121
  } else {
113
- // The simple flyout does not cover the workspace.
114
- y = viewMetrics.height;
122
+ // Because the anchor point of the flyout is on the top, but we want
123
+ // to align the bottom edge of the flyout with the bottom edge of the
124
+ // blocklyDiv, we calculate the full height of the div minus the height
125
+ // of the flyout.
126
+ y = viewMetrics.height + absoluteMetrics.top - this.height_;
115
127
  }
116
128
  }
117
- // Trashcan flyout is opposite the main flyout.
118
- } else {
119
- if (atTop) {
120
- y = 0;
121
- } else {
122
- // Because the anchor point of the flyout is on the top, but we want
123
- // to align the bottom edge of the flyout with the bottom edge of the
124
- // blocklyDiv, we calculate the full height of the div minus the height
125
- // of the flyout.
126
- y = viewMetrics.height + absoluteMetrics.top - this.height_;
127
- }
128
- }
129
129
 
130
- return y;
131
- };
132
-
133
- /**
134
- * Move the flyout to the edge of the workspace.
135
- */
136
- HorizontalFlyout.prototype.position = function() {
137
- if (!this.isVisible() || !this.targetWorkspace.isVisible()) {
138
- return;
130
+ return y;
139
131
  }
140
- const metricsManager = this.targetWorkspace.getMetricsManager();
141
- const targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
142
132
 
143
- // Record the width for workspace metrics.
144
- this.width_ = targetWorkspaceViewMetrics.width;
133
+ /**
134
+ * Move the flyout to the edge of the workspace.
135
+ */
136
+ position() {
137
+ if (!this.isVisible() || !this.targetWorkspace.isVisible()) {
138
+ return;
139
+ }
140
+ const metricsManager = this.targetWorkspace.getMetricsManager();
141
+ const targetWorkspaceViewMetrics = metricsManager.getViewMetrics();
145
142
 
146
- const edgeWidth = targetWorkspaceViewMetrics.width - 2 * this.CORNER_RADIUS;
147
- const edgeHeight = this.height_ - this.CORNER_RADIUS;
148
- this.setBackgroundPath_(edgeWidth, edgeHeight);
143
+ // Record the width for workspace metrics.
144
+ this.width_ = targetWorkspaceViewMetrics.width;
149
145
 
150
- const x = this.getX();
151
- const y = this.getY();
146
+ const edgeWidth = targetWorkspaceViewMetrics.width - 2 * this.CORNER_RADIUS;
147
+ const edgeHeight = this.height_ - this.CORNER_RADIUS;
148
+ this.setBackgroundPath_(edgeWidth, edgeHeight);
152
149
 
153
- this.positionAt_(this.width_, this.height_, x, y);
154
- };
150
+ const x = this.getX();
151
+ const y = this.getY();
155
152
 
156
- /**
157
- * Create and set the path for the visible boundaries of the flyout.
158
- * @param {number} width The width of the flyout, not including the
159
- * rounded corners.
160
- * @param {number} height The height of the flyout, not including
161
- * rounded corners.
162
- * @private
163
- */
164
- HorizontalFlyout.prototype.setBackgroundPath_ = function(width, height) {
165
- const atTop = this.toolboxPosition_ === toolbox.Position.TOP;
166
- // Start at top left.
167
- const path = ['M 0,' + (atTop ? 0 : this.CORNER_RADIUS)];
168
-
169
- if (atTop) {
170
- // Top.
171
- path.push('h', width + 2 * this.CORNER_RADIUS);
172
- // Right.
173
- path.push('v', height);
174
- // Bottom.
175
- path.push(
176
- 'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
177
- -this.CORNER_RADIUS, this.CORNER_RADIUS);
178
- path.push('h', -width);
179
- // Left.
180
- path.push(
181
- 'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
182
- -this.CORNER_RADIUS, -this.CORNER_RADIUS);
183
- path.push('z');
184
- } else {
185
- // Top.
186
- path.push(
187
- 'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
188
- this.CORNER_RADIUS, -this.CORNER_RADIUS);
189
- path.push('h', width);
190
- // Right.
191
- path.push(
192
- 'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
193
- this.CORNER_RADIUS, this.CORNER_RADIUS);
194
- path.push('v', height);
195
- // Bottom.
196
- path.push('h', -width - 2 * this.CORNER_RADIUS);
197
- // Left.
198
- path.push('z');
153
+ this.positionAt_(this.width_, this.height_, x, y);
199
154
  }
200
- this.svgBackground_.setAttribute('d', path.join(' '));
201
- };
202
-
203
- /**
204
- * Scroll the flyout to the top.
205
- */
206
- HorizontalFlyout.prototype.scrollToStart = function() {
207
- this.workspace_.scrollbar.setX(this.RTL ? Infinity : 0);
208
- };
209
-
210
- /**
211
- * Scroll the flyout.
212
- * @param {!Event} e Mouse wheel scroll event.
213
- * @protected
214
- */
215
- HorizontalFlyout.prototype.wheel_ = function(e) {
216
- const scrollDelta = browserEvents.getScrollDeltaPixels(e);
217
- const delta = scrollDelta.x || scrollDelta.y;
218
155
 
219
- if (delta) {
220
- const metricsManager = this.workspace_.getMetricsManager();
221
- const scrollMetrics = metricsManager.getScrollMetrics();
222
- const viewMetrics = metricsManager.getViewMetrics();
156
+ /**
157
+ * Create and set the path for the visible boundaries of the flyout.
158
+ * @param {number} width The width of the flyout, not including the
159
+ * rounded corners.
160
+ * @param {number} height The height of the flyout, not including
161
+ * rounded corners.
162
+ * @private
163
+ */
164
+ setBackgroundPath_(width, height) {
165
+ const atTop = this.toolboxPosition_ === toolbox.Position.TOP;
166
+ // Start at top left.
167
+ const path = ['M 0,' + (atTop ? 0 : this.CORNER_RADIUS)];
223
168
 
224
- const pos = (viewMetrics.left - scrollMetrics.left) + delta;
225
- this.workspace_.scrollbar.setX(pos);
226
- // When the flyout moves from a wheel event, hide WidgetDiv and DropDownDiv.
227
- WidgetDiv.hide();
228
- DropDownDiv.hideWithoutAnimation();
169
+ if (atTop) {
170
+ // Top.
171
+ path.push('h', width + 2 * this.CORNER_RADIUS);
172
+ // Right.
173
+ path.push('v', height);
174
+ // Bottom.
175
+ path.push(
176
+ 'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
177
+ -this.CORNER_RADIUS, this.CORNER_RADIUS);
178
+ path.push('h', -width);
179
+ // Left.
180
+ path.push(
181
+ 'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
182
+ -this.CORNER_RADIUS, -this.CORNER_RADIUS);
183
+ path.push('z');
184
+ } else {
185
+ // Top.
186
+ path.push(
187
+ 'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
188
+ this.CORNER_RADIUS, -this.CORNER_RADIUS);
189
+ path.push('h', width);
190
+ // Right.
191
+ path.push(
192
+ 'a', this.CORNER_RADIUS, this.CORNER_RADIUS, 0, 0, 1,
193
+ this.CORNER_RADIUS, this.CORNER_RADIUS);
194
+ path.push('v', height);
195
+ // Bottom.
196
+ path.push('h', -width - 2 * this.CORNER_RADIUS);
197
+ // Left.
198
+ path.push('z');
199
+ }
200
+ this.svgBackground_.setAttribute('d', path.join(' '));
229
201
  }
230
202
 
231
- // Don't scroll the page.
232
- e.preventDefault();
233
- // Don't propagate mousewheel event (zooming).
234
- e.stopPropagation();
235
- };
236
-
237
- /**
238
- * Lay out the blocks in the flyout.
239
- * @param {!Array<!Object>} contents The blocks and buttons to lay out.
240
- * @param {!Array<number>} gaps The visible gaps between blocks.
241
- * @protected
242
- */
243
- HorizontalFlyout.prototype.layout_ = function(contents, gaps) {
244
- this.workspace_.scale = this.targetWorkspace.scale;
245
- const margin = this.MARGIN;
246
- let cursorX = margin + this.tabWidth_;
247
- const cursorY = margin;
248
- if (this.RTL) {
249
- contents = contents.reverse();
203
+ /**
204
+ * Scroll the flyout to the top.
205
+ */
206
+ scrollToStart() {
207
+ this.workspace_.scrollbar.setX(this.RTL ? Infinity : 0);
250
208
  }
251
209
 
252
- for (let i = 0, item; (item = contents[i]); i++) {
253
- if (item.type === 'block') {
254
- const block = item.block;
255
- const allBlocks = block.getDescendants(false);
256
- for (let j = 0, child; (child = allBlocks[j]); j++) {
257
- // Mark blocks as being inside a flyout. This is used to detect and
258
- // prevent the closure of the flyout if the user right-clicks on such a
259
- // block.
260
- child.isInFlyout = true;
261
- }
262
- block.render();
263
- const root = block.getSvgRoot();
264
- const blockHW = block.getHeightWidth();
265
-
266
- // Figure out where to place the block.
267
- const tab = block.outputConnection ? this.tabWidth_ : 0;
268
- let moveX;
269
- if (this.RTL) {
270
- moveX = cursorX + blockHW.width;
271
- } else {
272
- moveX = cursorX - tab;
273
- }
274
- block.moveBy(moveX, cursorY);
210
+ /**
211
+ * Scroll the flyout.
212
+ * @param {!Event} e Mouse wheel scroll event.
213
+ * @protected
214
+ */
215
+ wheel_(e) {
216
+ const scrollDelta = browserEvents.getScrollDeltaPixels(e);
217
+ const delta = scrollDelta.x || scrollDelta.y;
218
+
219
+ if (delta) {
220
+ const metricsManager = this.workspace_.getMetricsManager();
221
+ const scrollMetrics = metricsManager.getScrollMetrics();
222
+ const viewMetrics = metricsManager.getViewMetrics();
223
+
224
+ const pos = (viewMetrics.left - scrollMetrics.left) + delta;
225
+ this.workspace_.scrollbar.setX(pos);
226
+ // When the flyout moves from a wheel event, hide WidgetDiv and
227
+ // dropDownDiv.
228
+ WidgetDiv.hide();
229
+ dropDownDiv.hideWithoutAnimation();
230
+ }
275
231
 
276
- const rect = this.createRect_(block, moveX, cursorY, blockHW, i);
277
- cursorX += (blockHW.width + gaps[i]);
232
+ // Don't scroll the page.
233
+ e.preventDefault();
234
+ // Don't propagate mousewheel event (zooming).
235
+ e.stopPropagation();
236
+ }
278
237
 
279
- this.addBlockListeners_(root, block, rect);
280
- } else if (item.type === 'button') {
281
- this.initFlyoutButton_(item.button, cursorX, cursorY);
282
- cursorX += (item.button.width + gaps[i]);
238
+ /**
239
+ * Lay out the blocks in the flyout.
240
+ * @param {!Array<!Object>} contents The blocks and buttons to lay out.
241
+ * @param {!Array<number>} gaps The visible gaps between blocks.
242
+ * @protected
243
+ */
244
+ layout_(contents, gaps) {
245
+ this.workspace_.scale = this.targetWorkspace.scale;
246
+ const margin = this.MARGIN;
247
+ let cursorX = margin + this.tabWidth_;
248
+ const cursorY = margin;
249
+ if (this.RTL) {
250
+ contents = contents.reverse();
283
251
  }
284
- }
285
- };
286
252
 
287
- /**
288
- * Determine if a drag delta is toward the workspace, based on the position
289
- * and orientation of the flyout. This is used in determineDragIntention_ to
290
- * determine if a new block should be created or if the flyout should scroll.
291
- * @param {!Coordinate} currentDragDeltaXY How far the pointer has
292
- * moved from the position at mouse down, in pixel units.
293
- * @return {boolean} True if the drag is toward the workspace.
294
- * @package
295
- */
296
- HorizontalFlyout.prototype.isDragTowardWorkspace = function(
297
- currentDragDeltaXY) {
298
- const dx = currentDragDeltaXY.x;
299
- const dy = currentDragDeltaXY.y;
300
- // Direction goes from -180 to 180, with 0 toward the right and 90 on top.
301
- const dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
302
-
303
- const range = this.dragAngleRange_;
304
- // Check for up or down dragging.
305
- if ((dragDirection < 90 + range && dragDirection > 90 - range) ||
306
- (dragDirection > -90 - range && dragDirection < -90 + range)) {
307
- return true;
253
+ for (let i = 0, item; (item = contents[i]); i++) {
254
+ if (item.type === 'block') {
255
+ const block = item.block;
256
+ const allBlocks = block.getDescendants(false);
257
+ for (let j = 0, child; (child = allBlocks[j]); j++) {
258
+ // Mark blocks as being inside a flyout. This is used to detect and
259
+ // prevent the closure of the flyout if the user right-clicks on such
260
+ // a block.
261
+ child.isInFlyout = true;
262
+ }
263
+ block.render();
264
+ const root = block.getSvgRoot();
265
+ const blockHW = block.getHeightWidth();
266
+
267
+ // Figure out where to place the block.
268
+ const tab = block.outputConnection ? this.tabWidth_ : 0;
269
+ let moveX;
270
+ if (this.RTL) {
271
+ moveX = cursorX + blockHW.width;
272
+ } else {
273
+ moveX = cursorX - tab;
274
+ }
275
+ block.moveBy(moveX, cursorY);
276
+
277
+ const rect = this.createRect_(block, moveX, cursorY, blockHW, i);
278
+ cursorX += (blockHW.width + gaps[i]);
279
+
280
+ this.addBlockListeners_(root, block, rect);
281
+ } else if (item.type === 'button') {
282
+ this.initFlyoutButton_(item.button, cursorX, cursorY);
283
+ cursorX += (item.button.width + gaps[i]);
284
+ }
285
+ }
308
286
  }
309
- return false;
310
- };
311
287
 
312
- /**
313
- * Returns the bounding rectangle of the drag target area in pixel units
314
- * relative to viewport.
315
- * @return {?Rect} The component's bounding box. Null if drag
316
- * target area should be ignored.
317
- */
318
- HorizontalFlyout.prototype.getClientRect = function() {
319
- if (!this.svgGroup_ || this.autoClose || !this.isVisible()) {
320
- // The bounding rectangle won't compute correctly if the flyout is closed
321
- // and auto-close flyouts aren't valid drag targets (or delete areas).
322
- return null;
288
+ /**
289
+ * Determine if a drag delta is toward the workspace, based on the position
290
+ * and orientation of the flyout. This is used in determineDragIntention_ to
291
+ * determine if a new block should be created or if the flyout should scroll.
292
+ * @param {!Coordinate} currentDragDeltaXY How far the pointer has
293
+ * moved from the position at mouse down, in pixel units.
294
+ * @return {boolean} True if the drag is toward the workspace.
295
+ * @package
296
+ */
297
+ isDragTowardWorkspace(currentDragDeltaXY) {
298
+ const dx = currentDragDeltaXY.x;
299
+ const dy = currentDragDeltaXY.y;
300
+ // Direction goes from -180 to 180, with 0 toward the right and 90 on top.
301
+ const dragDirection = Math.atan2(dy, dx) / Math.PI * 180;
302
+
303
+ const range = this.dragAngleRange_;
304
+ // Check for up or down dragging.
305
+ if ((dragDirection < 90 + range && dragDirection > 90 - range) ||
306
+ (dragDirection > -90 - range && dragDirection < -90 + range)) {
307
+ return true;
308
+ }
309
+ return false;
323
310
  }
324
311
 
325
- const flyoutRect = this.svgGroup_.getBoundingClientRect();
326
- // BIG_NUM is offscreen padding so that blocks dragged beyond the shown flyout
327
- // area are still deleted. Must be larger than the largest screen size,
328
- // but be smaller than half Number.MAX_SAFE_INTEGER (not available on IE).
329
- const BIG_NUM = 1000000000;
330
- const top = flyoutRect.top;
331
-
332
- if (this.toolboxPosition_ === toolbox.Position.TOP) {
333
- const height = flyoutRect.height;
334
- return new Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM);
335
- } else { // Bottom.
336
- return new Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM);
337
- }
338
- };
312
+ /**
313
+ * Returns the bounding rectangle of the drag target area in pixel units
314
+ * relative to viewport.
315
+ * @return {?Rect} The component's bounding box. Null if drag
316
+ * target area should be ignored.
317
+ */
318
+ getClientRect() {
319
+ if (!this.svgGroup_ || this.autoClose || !this.isVisible()) {
320
+ // The bounding rectangle won't compute correctly if the flyout is closed
321
+ // and auto-close flyouts aren't valid drag targets (or delete areas).
322
+ return null;
323
+ }
339
324
 
340
- /**
341
- * Compute height of flyout. toolbox.Position mat under each block.
342
- * For RTL: Lay out the blocks right-aligned.
343
- * @protected
344
- */
345
- HorizontalFlyout.prototype.reflowInternal_ = function() {
346
- this.workspace_.scale = this.getFlyoutScale();
347
- let flyoutHeight = 0;
348
- const blocks = this.workspace_.getTopBlocks(false);
349
- for (let i = 0, block; (block = blocks[i]); i++) {
350
- flyoutHeight = Math.max(flyoutHeight, block.getHeightWidth().height);
351
- }
352
- const buttons = this.buttons_;
353
- for (let i = 0, button; (button = buttons[i]); i++) {
354
- flyoutHeight = Math.max(flyoutHeight, button.height);
325
+ const flyoutRect = this.svgGroup_.getBoundingClientRect();
326
+ // BIG_NUM is offscreen padding so that blocks dragged beyond the shown
327
+ // flyout area are still deleted. Must be larger than the largest screen
328
+ // size, but be smaller than half Number.MAX_SAFE_INTEGER (not available on
329
+ // IE).
330
+ const BIG_NUM = 1000000000;
331
+ const top = flyoutRect.top;
332
+
333
+ if (this.toolboxPosition_ === toolbox.Position.TOP) {
334
+ const height = flyoutRect.height;
335
+ return new Rect(-BIG_NUM, top + height, -BIG_NUM, BIG_NUM);
336
+ } else { // Bottom.
337
+ return new Rect(top, BIG_NUM, -BIG_NUM, BIG_NUM);
338
+ }
355
339
  }
356
- flyoutHeight += this.MARGIN * 1.5;
357
- flyoutHeight *= this.workspace_.scale;
358
- flyoutHeight += Scrollbar.scrollbarThickness;
359
340
 
360
- if (this.height_ !== flyoutHeight) {
341
+ /**
342
+ * Compute height of flyout. toolbox.Position mat under each block.
343
+ * For RTL: Lay out the blocks right-aligned.
344
+ * @protected
345
+ */
346
+ reflowInternal_() {
347
+ this.workspace_.scale = this.getFlyoutScale();
348
+ let flyoutHeight = 0;
349
+ const blocks = this.workspace_.getTopBlocks(false);
361
350
  for (let i = 0, block; (block = blocks[i]); i++) {
362
- if (block.flyoutRect_) {
363
- this.moveRectToBlock_(block.flyoutRect_, block);
364
- }
351
+ flyoutHeight = Math.max(flyoutHeight, block.getHeightWidth().height);
365
352
  }
366
-
367
- if (this.targetWorkspace.toolboxPosition === this.toolboxPosition_ &&
368
- this.toolboxPosition_ === toolbox.Position.TOP &&
369
- !this.targetWorkspace.getToolbox()) {
370
- // This flyout is a simple toolbox. Reposition the workspace so that (0,0)
371
- // is in the correct position relative to the new absolute edge (ie
372
- // toolbox edge).
373
- this.targetWorkspace.translate(
374
- this.targetWorkspace.scrollX,
375
- this.targetWorkspace.scrollY + flyoutHeight);
353
+ const buttons = this.buttons_;
354
+ for (let i = 0, button; (button = buttons[i]); i++) {
355
+ flyoutHeight = Math.max(flyoutHeight, button.height);
376
356
  }
357
+ flyoutHeight += this.MARGIN * 1.5;
358
+ flyoutHeight *= this.workspace_.scale;
359
+ flyoutHeight += Scrollbar.scrollbarThickness;
360
+
361
+ if (this.height_ !== flyoutHeight) {
362
+ for (let i = 0, block; (block = blocks[i]); i++) {
363
+ if (this.rectMap_.has(block)) {
364
+ this.moveRectToBlock_(this.rectMap_.get(block), block);
365
+ }
366
+ }
367
+
368
+ if (this.targetWorkspace.toolboxPosition === this.toolboxPosition_ &&
369
+ this.toolboxPosition_ === toolbox.Position.TOP &&
370
+ !this.targetWorkspace.getToolbox()) {
371
+ // This flyout is a simple toolbox. Reposition the workspace so that
372
+ // (0,0) is in the correct position relative to the new absolute edge
373
+ // (ie toolbox edge).
374
+ this.targetWorkspace.translate(
375
+ this.targetWorkspace.scrollX,
376
+ this.targetWorkspace.scrollY + flyoutHeight);
377
+ }
377
378
 
378
- // Record the height for workspace metrics and .position.
379
- this.height_ = flyoutHeight;
380
- this.position();
381
- this.targetWorkspace.recordDragTargets();
379
+ // Record the height for workspace metrics and .position.
380
+ this.height_ = flyoutHeight;
381
+ this.position();
382
+ this.targetWorkspace.recordDragTargets();
383
+ }
382
384
  }
383
- };
385
+ }
384
386
 
385
387
  registry.register(
386
388
  registry.Type.FLYOUTS_HORIZONTAL_TOOLBOX, registry.DEFAULT,