blockly 7.20211209.2 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/blockly.d.ts +18963 -18432
  2. package/blockly.min.js +852 -844
  3. package/blockly_compressed.js +669 -664
  4. package/blockly_compressed.js.map +1 -1
  5. package/blocks/blocks.js +47 -0
  6. package/blocks/colour.js +13 -3
  7. package/blocks/lists.js +22 -13
  8. package/blocks/logic.js +13 -3
  9. package/blocks/loops.js +24 -11
  10. package/blocks/math.js +12 -3
  11. package/blocks/procedures.js +41 -27
  12. package/blocks/text.js +22 -13
  13. package/blocks/variables.js +14 -3
  14. package/blocks/variables_dynamic.js +13 -3
  15. package/blocks_compressed.js +146 -141
  16. package/blocks_compressed.js.map +1 -1
  17. package/core/block.js +1869 -1814
  18. package/core/block_drag_surface.js +201 -200
  19. package/core/block_dragger.js +377 -373
  20. package/core/block_svg.js +1593 -1479
  21. package/core/blockly.js +8 -22
  22. package/core/blocks.js +9 -2
  23. package/core/browser_events.js +22 -5
  24. package/core/bubble.js +841 -797
  25. package/core/bubble_dragger.js +213 -206
  26. package/core/bump_objects.js +2 -2
  27. package/core/clipboard.js +9 -9
  28. package/core/comment.js +353 -332
  29. package/core/common.js +46 -17
  30. package/core/component_manager.js +181 -174
  31. package/core/config.js +87 -0
  32. package/core/connection.js +595 -584
  33. package/core/connection_checker.js +242 -244
  34. package/core/connection_db.js +235 -230
  35. package/core/contextmenu.js +9 -6
  36. package/core/contextmenu_items.js +1 -2
  37. package/core/contextmenu_registry.js +93 -89
  38. package/core/css.js +474 -474
  39. package/core/delete_area.js +45 -42
  40. package/core/drag_target.js +57 -56
  41. package/core/dropdowndiv.js +153 -163
  42. package/core/events/events.js +2 -2
  43. package/core/events/events_abstract.js +89 -77
  44. package/core/events/events_block_base.js +37 -36
  45. package/core/events/events_block_change.js +130 -124
  46. package/core/events/events_block_create.js +73 -71
  47. package/core/events/events_block_delete.js +84 -82
  48. package/core/events/events_block_drag.js +50 -49
  49. package/core/events/events_block_move.js +147 -140
  50. package/core/events/events_bubble_open.js +51 -50
  51. package/core/events/events_click.js +48 -44
  52. package/core/events/events_comment_base.js +72 -69
  53. package/core/events/events_comment_change.js +63 -61
  54. package/core/events/events_comment_create.js +44 -42
  55. package/core/events/events_comment_delete.js +42 -40
  56. package/core/events/events_comment_move.js +106 -104
  57. package/core/events/events_marker_move.js +65 -64
  58. package/core/events/events_selected.js +46 -45
  59. package/core/events/events_theme_change.js +36 -35
  60. package/core/events/events_toolbox_item_select.js +46 -45
  61. package/core/events/events_trashcan_open.js +37 -36
  62. package/core/events/events_ui.js +47 -46
  63. package/core/events/events_ui_base.js +30 -29
  64. package/core/events/events_var_base.js +37 -36
  65. package/core/events/events_var_create.js +50 -48
  66. package/core/events/events_var_delete.js +50 -48
  67. package/core/events/events_var_rename.js +51 -49
  68. package/core/events/events_viewport.js +66 -65
  69. package/core/events/utils.js +29 -14
  70. package/core/events/workspace_events.js +49 -55
  71. package/core/extensions.js +4 -3
  72. package/core/field.js +1061 -997
  73. package/core/field_angle.js +462 -442
  74. package/core/field_checkbox.js +194 -182
  75. package/core/field_colour.js +519 -505
  76. package/core/field_dropdown.js +617 -598
  77. package/core/field_image.js +229 -220
  78. package/core/field_label.js +102 -91
  79. package/core/field_label_serializable.js +42 -41
  80. package/core/field_multilineinput.js +372 -358
  81. package/core/field_number.js +272 -253
  82. package/core/field_textinput.js +499 -467
  83. package/core/field_variable.js +458 -420
  84. package/core/flyout_base.js +1005 -952
  85. package/core/flyout_button.js +277 -260
  86. package/core/flyout_horizontal.js +304 -302
  87. package/core/flyout_metrics_manager.js +64 -64
  88. package/core/flyout_vertical.js +306 -300
  89. package/core/generator.js +459 -446
  90. package/core/gesture.js +829 -813
  91. package/core/grid.js +166 -163
  92. package/core/icon.js +168 -159
  93. package/core/inject.js +7 -5
  94. package/core/input.js +257 -248
  95. package/core/insertion_marker_manager.js +655 -624
  96. package/core/internal_constants.js +0 -129
  97. package/core/keyboard_nav/ast_node.js +605 -596
  98. package/core/keyboard_nav/basic_cursor.js +166 -165
  99. package/core/keyboard_nav/cursor.js +99 -97
  100. package/core/keyboard_nav/marker.js +83 -79
  101. package/core/keyboard_nav/tab_navigate_cursor.js +18 -23
  102. package/core/marker_manager.js +153 -141
  103. package/core/menu.js +377 -372
  104. package/core/menuitem.js +223 -217
  105. package/core/metrics_manager.js +403 -390
  106. package/core/mutator.js +468 -437
  107. package/core/names.js +229 -188
  108. package/core/options.js +290 -284
  109. package/core/procedures.js +29 -17
  110. package/core/registry.js +19 -16
  111. package/core/rendered_connection.js +482 -463
  112. package/core/renderers/common/block_rendering.js +9 -3
  113. package/core/renderers/common/constants.js +1119 -1112
  114. package/core/renderers/common/debug.js +14 -0
  115. package/core/renderers/common/debugger.js +338 -316
  116. package/core/renderers/common/drawer.js +380 -370
  117. package/core/renderers/common/i_path_object.js +2 -2
  118. package/core/renderers/common/info.js +626 -618
  119. package/core/renderers/common/marker_svg.js +579 -541
  120. package/core/renderers/common/path_object.js +203 -200
  121. package/core/renderers/common/renderer.js +220 -218
  122. package/core/renderers/geras/constants.js +36 -36
  123. package/core/renderers/geras/drawer.js +155 -147
  124. package/core/renderers/geras/highlight_constants.js +244 -238
  125. package/core/renderers/geras/highlighter.js +231 -179
  126. package/core/renderers/geras/info.js +392 -369
  127. package/core/renderers/geras/measurables/inline_input.js +25 -19
  128. package/core/renderers/geras/measurables/statement_input.js +23 -17
  129. package/core/renderers/geras/path_object.js +106 -121
  130. package/core/renderers/geras/renderer.js +96 -98
  131. package/core/renderers/measurables/base.js +30 -18
  132. package/core/renderers/measurables/bottom_row.js +83 -80
  133. package/core/renderers/measurables/connection.js +22 -15
  134. package/core/renderers/measurables/external_value_input.js +35 -22
  135. package/core/renderers/measurables/field.js +35 -20
  136. package/core/renderers/measurables/hat.js +18 -13
  137. package/core/renderers/measurables/icon.js +24 -17
  138. package/core/renderers/measurables/in_row_spacer.js +15 -13
  139. package/core/renderers/measurables/inline_input.js +43 -33
  140. package/core/renderers/measurables/input_connection.js +41 -28
  141. package/core/renderers/measurables/input_row.js +50 -44
  142. package/core/renderers/measurables/jagged_edge.js +14 -12
  143. package/core/renderers/measurables/next_connection.js +16 -14
  144. package/core/renderers/measurables/output_connection.js +26 -20
  145. package/core/renderers/measurables/previous_connection.js +16 -15
  146. package/core/renderers/measurables/round_corner.js +20 -18
  147. package/core/renderers/measurables/row.js +184 -168
  148. package/core/renderers/measurables/spacer_row.js +38 -23
  149. package/core/renderers/measurables/square_corner.js +18 -16
  150. package/core/renderers/measurables/statement_input.js +23 -20
  151. package/core/renderers/measurables/top_row.js +88 -85
  152. package/core/renderers/minimalist/constants.js +8 -7
  153. package/core/renderers/minimalist/drawer.js +11 -10
  154. package/core/renderers/minimalist/info.js +18 -18
  155. package/core/renderers/minimalist/renderer.js +40 -39
  156. package/core/renderers/thrasos/info.js +258 -248
  157. package/core/renderers/thrasos/renderer.js +20 -20
  158. package/core/renderers/zelos/constants.js +898 -873
  159. package/core/renderers/zelos/drawer.js +186 -169
  160. package/core/renderers/zelos/info.js +502 -479
  161. package/core/renderers/zelos/marker_svg.js +129 -115
  162. package/core/renderers/zelos/measurables/bottom_row.js +31 -30
  163. package/core/renderers/zelos/measurables/inputs.js +22 -21
  164. package/core/renderers/zelos/measurables/row_elements.js +14 -13
  165. package/core/renderers/zelos/measurables/top_row.js +34 -33
  166. package/core/renderers/zelos/path_object.js +181 -180
  167. package/core/renderers/zelos/renderer.js +91 -92
  168. package/core/scrollbar.js +759 -713
  169. package/core/scrollbar_pair.js +250 -245
  170. package/core/serialization/blocks.js +19 -9
  171. package/core/serialization/workspaces.js +3 -2
  172. package/core/shortcut_registry.js +286 -277
  173. package/core/sprites.js +31 -0
  174. package/core/theme.js +135 -141
  175. package/core/theme_manager.js +147 -143
  176. package/core/toolbox/category.js +602 -576
  177. package/core/toolbox/collapsible_category.js +226 -227
  178. package/core/toolbox/separator.js +70 -61
  179. package/core/toolbox/toolbox.js +934 -927
  180. package/core/toolbox/toolbox_item.js +115 -99
  181. package/core/tooltip.js +108 -35
  182. package/core/touch.js +8 -3
  183. package/core/touch_gesture.js +254 -251
  184. package/core/trashcan.js +606 -595
  185. package/core/utils/coordinate.js +97 -95
  186. package/core/utils/dom.js +2 -2
  187. package/core/utils/global.js +2 -0
  188. package/core/utils/rect.js +41 -37
  189. package/core/utils/sentinel.js +25 -0
  190. package/core/utils/size.js +30 -27
  191. package/core/utils/svg.js +18 -16
  192. package/core/variable_map.js +325 -341
  193. package/core/variable_model.js +55 -54
  194. package/core/variables.js +9 -2
  195. package/core/variables_dynamic.js +3 -1
  196. package/core/warning.js +126 -120
  197. package/core/widgetdiv.js +4 -4
  198. package/core/workspace.js +685 -664
  199. package/core/workspace_audio.js +124 -118
  200. package/core/workspace_comment.js +308 -298
  201. package/core/workspace_comment_svg.js +1029 -951
  202. package/core/workspace_drag_surface_svg.js +147 -140
  203. package/core/workspace_dragger.js +70 -71
  204. package/core/workspace_svg.js +2322 -2297
  205. package/core/xml.js +30 -20
  206. package/core/zoom_controls.js +431 -439
  207. package/dart_compressed.js +40 -43
  208. package/dart_compressed.js.map +1 -1
  209. package/generators/dart/colour.js +56 -64
  210. package/generators/dart/lists.js +61 -50
  211. package/generators/dart/math.js +160 -148
  212. package/generators/dart/text.js +83 -61
  213. package/generators/javascript/colour.js +37 -34
  214. package/generators/javascript/lists.js +50 -43
  215. package/generators/javascript/math.js +123 -139
  216. package/generators/javascript/text.js +67 -81
  217. package/generators/lua/colour.js +25 -23
  218. package/generators/lua/lists.js +97 -69
  219. package/generators/lua/logic.js +1 -2
  220. package/generators/lua/math.js +182 -144
  221. package/generators/lua/text.js +116 -99
  222. package/generators/php/colour.js +38 -32
  223. package/generators/php/lists.js +109 -89
  224. package/generators/php/math.js +90 -81
  225. package/generators/php/text.js +63 -61
  226. package/generators/python/colour.js +18 -18
  227. package/generators/python/lists.js +38 -30
  228. package/generators/python/loops.js +12 -8
  229. package/generators/python/math.js +104 -106
  230. package/generators/python/text.js +34 -30
  231. package/javascript_compressed.js +37 -39
  232. package/javascript_compressed.js.map +1 -1
  233. package/lua_compressed.js +39 -42
  234. package/lua_compressed.js.map +1 -1
  235. package/msg/az.js +2 -2
  236. package/msg/be.js +4 -4
  237. package/msg/cs.js +15 -15
  238. package/msg/de.js +1 -1
  239. package/msg/diq.js +1 -1
  240. package/msg/eo.js +1 -1
  241. package/msg/es.js +1 -1
  242. package/msg/fa.js +1 -1
  243. package/msg/fr.js +4 -4
  244. package/msg/he.js +1 -1
  245. package/msg/hr.js +2 -2
  246. package/msg/hy.js +2 -2
  247. package/msg/id.js +12 -12
  248. package/msg/inh.js +14 -14
  249. package/msg/ja.js +7 -7
  250. package/msg/lv.js +29 -29
  251. package/msg/pa.js +3 -3
  252. package/msg/smn.js +436 -0
  253. package/msg/te.js +1 -1
  254. package/msg/yue.js +1 -1
  255. package/msg/zh-hans.js +3 -3
  256. package/msg/zh-hant.js +3 -3
  257. package/package.json +7 -6
  258. package/php_compressed.js +38 -42
  259. package/php_compressed.js.map +1 -1
  260. package/python_compressed.js +26 -25
  261. package/python_compressed.js.map +1 -1
  262. package/blocks/all.js +0 -23
package/core/menu.js CHANGED
@@ -29,449 +29,454 @@ const {Size} = goog.requireType('Blockly.utils.Size');
29
29
 
30
30
  /**
31
31
  * A basic menu class.
32
- * @constructor
33
32
  * @alias Blockly.Menu
34
33
  */
35
- const Menu = function() {
34
+ const Menu = class {
36
35
  /**
37
- * Array of menu items.
38
- * (Nulls are never in the array, but typing the array as nullable prevents
39
- * the compiler from objecting to .indexOf(null))
40
- * @type {!Array<MenuItem>}
41
- * @private
36
+ * Constructs a new Menu instance.
42
37
  */
43
- this.menuItems_ = [];
38
+ constructor() {
39
+ /**
40
+ * Array of menu items.
41
+ * (Nulls are never in the array, but typing the array as nullable prevents
42
+ * the compiler from objecting to .indexOf(null))
43
+ * @type {!Array<MenuItem>}
44
+ * @private
45
+ */
46
+ this.menuItems_ = [];
47
+
48
+ /**
49
+ * Coordinates of the mousedown event that caused this menu to open. Used to
50
+ * prevent the consequent mouseup event due to a simple click from
51
+ * activating a menu item immediately.
52
+ * @type {?Coordinate}
53
+ * @package
54
+ */
55
+ this.openingCoords = null;
56
+
57
+ /**
58
+ * This is the element that we will listen to the real focus events on.
59
+ * A value of null means no menu item is highlighted.
60
+ * @type {?MenuItem}
61
+ * @private
62
+ */
63
+ this.highlightedItem_ = null;
44
64
 
45
- /**
46
- * Coordinates of the mousedown event that caused this menu to open. Used to
47
- * prevent the consequent mouseup event due to a simple click from activating
48
- * a menu item immediately.
49
- * @type {?Coordinate}
50
- * @package
51
- */
52
- this.openingCoords = null;
65
+ /**
66
+ * Mouse over event data.
67
+ * @type {?browserEvents.Data}
68
+ * @private
69
+ */
70
+ this.mouseOverHandler_ = null;
53
71
 
54
- /**
55
- * This is the element that we will listen to the real focus events on.
56
- * A value of null means no menu item is highlighted.
57
- * @type {?MenuItem}
58
- * @private
59
- */
60
- this.highlightedItem_ = null;
72
+ /**
73
+ * Click event data.
74
+ * @type {?browserEvents.Data}
75
+ * @private
76
+ */
77
+ this.clickHandler_ = null;
78
+
79
+ /**
80
+ * Mouse enter event data.
81
+ * @type {?browserEvents.Data}
82
+ * @private
83
+ */
84
+ this.mouseEnterHandler_ = null;
85
+
86
+ /**
87
+ * Mouse leave event data.
88
+ * @type {?browserEvents.Data}
89
+ * @private
90
+ */
91
+ this.mouseLeaveHandler_ = null;
92
+
93
+ /**
94
+ * Key down event data.
95
+ * @type {?browserEvents.Data}
96
+ * @private
97
+ */
98
+ this.onKeyDownHandler_ = null;
99
+
100
+ /**
101
+ * The menu's root DOM element.
102
+ * @type {?HTMLDivElement}
103
+ * @private
104
+ */
105
+ this.element_ = null;
106
+
107
+ /**
108
+ * ARIA name for this menu.
109
+ * @type {?aria.Role}
110
+ * @private
111
+ */
112
+ this.roleName_ = null;
113
+ }
61
114
 
62
115
  /**
63
- * Mouse over event data.
64
- * @type {?browserEvents.Data}
65
- * @private
116
+ * Add a new menu item to the bottom of this menu.
117
+ * @param {!MenuItem} menuItem Menu item to append.
66
118
  */
67
- this.mouseOverHandler_ = null;
119
+ addChild(menuItem) {
120
+ this.menuItems_.push(menuItem);
121
+ }
68
122
 
69
123
  /**
70
- * Click event data.
71
- * @type {?browserEvents.Data}
72
- * @private
124
+ * Creates the menu DOM.
125
+ * @param {!Element} container Element upon which to append this menu.
73
126
  */
74
- this.clickHandler_ = null;
127
+ render(container) {
128
+ const element =
129
+ /** @type {!HTMLDivElement} */ (document.createElement('div'));
130
+ // goog-menu is deprecated, use blocklyMenu. May 2020.
131
+ element.className = 'blocklyMenu goog-menu blocklyNonSelectable';
132
+ element.tabIndex = 0;
133
+ if (this.roleName_) {
134
+ aria.setRole(element, this.roleName_);
135
+ }
136
+ this.element_ = element;
137
+
138
+ // Add menu items.
139
+ for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
140
+ element.appendChild(menuItem.createDom());
141
+ }
142
+
143
+ // Add event handlers.
144
+ this.mouseOverHandler_ = browserEvents.conditionalBind(
145
+ element, 'mouseover', this, this.handleMouseOver_, true);
146
+ this.clickHandler_ = browserEvents.conditionalBind(
147
+ element, 'click', this, this.handleClick_, true);
148
+ this.mouseEnterHandler_ = browserEvents.conditionalBind(
149
+ element, 'mouseenter', this, this.handleMouseEnter_, true);
150
+ this.mouseLeaveHandler_ = browserEvents.conditionalBind(
151
+ element, 'mouseleave', this, this.handleMouseLeave_, true);
152
+ this.onKeyDownHandler_ = browserEvents.conditionalBind(
153
+ element, 'keydown', this, this.handleKeyEvent_);
154
+
155
+ container.appendChild(element);
156
+ }
75
157
 
76
158
  /**
77
- * Mouse enter event data.
78
- * @type {?browserEvents.Data}
79
- * @private
159
+ * Gets the menu's element.
160
+ * @return {?Element} The DOM element.
161
+ * @package
80
162
  */
81
- this.mouseEnterHandler_ = null;
163
+ getElement() {
164
+ return this.element_;
165
+ }
82
166
 
83
167
  /**
84
- * Mouse leave event data.
85
- * @type {?browserEvents.Data}
86
- * @private
168
+ * Focus the menu element.
169
+ * @package
87
170
  */
88
- this.mouseLeaveHandler_ = null;
171
+ focus() {
172
+ const el = this.getElement();
173
+ if (el) {
174
+ el.focus({preventScroll: true});
175
+ dom.addClass(el, 'blocklyFocused');
176
+ }
177
+ }
89
178
 
90
179
  /**
91
- * Key down event data.
92
- * @type {?browserEvents.Data}
180
+ * Blur the menu element.
93
181
  * @private
94
182
  */
95
- this.onKeyDownHandler_ = null;
183
+ blur_() {
184
+ const el = this.getElement();
185
+ if (el) {
186
+ el.blur();
187
+ dom.removeClass(el, 'blocklyFocused');
188
+ }
189
+ }
96
190
 
97
191
  /**
98
- * The menu's root DOM element.
99
- * @type {?Element}
100
- * @private
192
+ * Set the menu accessibility role.
193
+ * @param {!aria.Role} roleName role name.
194
+ * @package
101
195
  */
102
- this.element_ = null;
196
+ setRole(roleName) {
197
+ this.roleName_ = roleName;
198
+ }
103
199
 
104
200
  /**
105
- * ARIA name for this menu.
106
- * @type {?aria.Role}
107
- * @private
201
+ * Dispose of this menu.
108
202
  */
109
- this.roleName_ = null;
110
- };
111
-
112
-
113
- /**
114
- * Add a new menu item to the bottom of this menu.
115
- * @param {!MenuItem} menuItem Menu item to append.
116
- */
117
- Menu.prototype.addChild = function(menuItem) {
118
- this.menuItems_.push(menuItem);
119
- };
203
+ dispose() {
204
+ // Remove event handlers.
205
+ if (this.mouseOverHandler_) {
206
+ browserEvents.unbind(this.mouseOverHandler_);
207
+ this.mouseOverHandler_ = null;
208
+ }
209
+ if (this.clickHandler_) {
210
+ browserEvents.unbind(this.clickHandler_);
211
+ this.clickHandler_ = null;
212
+ }
213
+ if (this.mouseEnterHandler_) {
214
+ browserEvents.unbind(this.mouseEnterHandler_);
215
+ this.mouseEnterHandler_ = null;
216
+ }
217
+ if (this.mouseLeaveHandler_) {
218
+ browserEvents.unbind(this.mouseLeaveHandler_);
219
+ this.mouseLeaveHandler_ = null;
220
+ }
221
+ if (this.onKeyDownHandler_) {
222
+ browserEvents.unbind(this.onKeyDownHandler_);
223
+ this.onKeyDownHandler_ = null;
224
+ }
120
225
 
121
- /**
122
- * Creates the menu DOM.
123
- * @param {!Element} container Element upon which to append this menu.
124
- */
125
- Menu.prototype.render = function(container) {
126
- const element =
127
- /** @type {!HTMLDivElement} */ (document.createElement('div'));
128
- // goog-menu is deprecated, use blocklyMenu. May 2020.
129
- element.className = 'blocklyMenu goog-menu blocklyNonSelectable';
130
- element.tabIndex = 0;
131
- if (this.roleName_) {
132
- aria.setRole(element, this.roleName_);
226
+ // Remove menu items.
227
+ for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
228
+ menuItem.dispose();
229
+ }
230
+ this.element_ = null;
133
231
  }
134
- this.element_ = element;
135
232
 
136
- // Add menu items.
137
- for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
138
- element.appendChild(menuItem.createDom());
233
+ // Child component management.
234
+
235
+ /**
236
+ * Returns the child menu item that owns the given DOM element,
237
+ * or null if no such menu item is found.
238
+ * @param {Element} elem DOM element whose owner is to be returned.
239
+ * @return {?MenuItem} Menu item for which the DOM element belongs to.
240
+ * @private
241
+ */
242
+ getMenuItem_(elem) {
243
+ const menuElem = this.getElement();
244
+ // Node might be the menu border (resulting in no associated menu item), or
245
+ // a menu item's div, or some element within the menu item.
246
+ // Walk up parents until one meets either the menu's root element, or
247
+ // a menu item's div.
248
+ while (elem && elem !== menuElem) {
249
+ if (dom.hasClass(elem, 'blocklyMenuItem')) {
250
+ // Having found a menu item's div, locate that menu item in this menu.
251
+ for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
252
+ if (menuItem.getElement() === elem) {
253
+ return menuItem;
254
+ }
255
+ }
256
+ }
257
+ elem = elem.parentElement;
258
+ }
259
+ return null;
139
260
  }
140
261
 
141
- // Add event handlers.
142
- this.mouseOverHandler_ = browserEvents.conditionalBind(
143
- element, 'mouseover', this, this.handleMouseOver_, true);
144
- this.clickHandler_ = browserEvents.conditionalBind(
145
- element, 'click', this, this.handleClick_, true);
146
- this.mouseEnterHandler_ = browserEvents.conditionalBind(
147
- element, 'mouseenter', this, this.handleMouseEnter_, true);
148
- this.mouseLeaveHandler_ = browserEvents.conditionalBind(
149
- element, 'mouseleave', this, this.handleMouseLeave_, true);
150
- this.onKeyDownHandler_ = browserEvents.conditionalBind(
151
- element, 'keydown', this, this.handleKeyEvent_);
152
-
153
- container.appendChild(element);
154
- };
262
+ // Highlight management.
155
263
 
156
- /**
157
- * Gets the menu's element.
158
- * @return {?Element} The DOM element.
159
- * @package
160
- */
161
- Menu.prototype.getElement = function() {
162
- return this.element_;
163
- };
164
-
165
- /**
166
- * Focus the menu element.
167
- * @package
168
- */
169
- Menu.prototype.focus = function() {
170
- const el = this.getElement();
171
- if (el) {
172
- el.focus({preventScroll: true});
173
- dom.addClass(el, 'blocklyFocused');
264
+ /**
265
+ * Highlights the given menu item, or clears highlighting if null.
266
+ * @param {?MenuItem} item Item to highlight, or null.
267
+ * @package
268
+ */
269
+ setHighlighted(item) {
270
+ const currentHighlighted = this.highlightedItem_;
271
+ if (currentHighlighted) {
272
+ currentHighlighted.setHighlighted(false);
273
+ this.highlightedItem_ = null;
274
+ }
275
+ if (item) {
276
+ item.setHighlighted(true);
277
+ this.highlightedItem_ = item;
278
+ // Bring the highlighted item into view. This has no effect if the menu is
279
+ // not scrollable.
280
+ const el = /** @type {!Element} */ (this.getElement());
281
+ style.scrollIntoContainerView(
282
+ /** @type {!Element} */ (item.getElement()), el);
283
+
284
+ aria.setState(el, aria.State.ACTIVEDESCENDANT, item.getId());
285
+ }
174
286
  }
175
- };
176
287
 
177
- /**
178
- * Blur the menu element.
179
- * @private
180
- */
181
- Menu.prototype.blur_ = function() {
182
- const el = this.getElement();
183
- if (el) {
184
- el.blur();
185
- dom.removeClass(el, 'blocklyFocused');
288
+ /**
289
+ * Highlights the next highlightable item (or the first if nothing is
290
+ * currently highlighted).
291
+ * @package
292
+ */
293
+ highlightNext() {
294
+ const index = this.menuItems_.indexOf(this.highlightedItem_);
295
+ this.highlightHelper_(index, 1);
186
296
  }
187
- };
188
-
189
- /**
190
- * Set the menu accessibility role.
191
- * @param {!aria.Role} roleName role name.
192
- * @package
193
- */
194
- Menu.prototype.setRole = function(roleName) {
195
- this.roleName_ = roleName;
196
- };
197
297
 
198
- /**
199
- * Dispose of this menu.
200
- */
201
- Menu.prototype.dispose = function() {
202
- // Remove event handlers.
203
- if (this.mouseOverHandler_) {
204
- browserEvents.unbind(this.mouseOverHandler_);
205
- this.mouseOverHandler_ = null;
206
- }
207
- if (this.clickHandler_) {
208
- browserEvents.unbind(this.clickHandler_);
209
- this.clickHandler_ = null;
210
- }
211
- if (this.mouseEnterHandler_) {
212
- browserEvents.unbind(this.mouseEnterHandler_);
213
- this.mouseEnterHandler_ = null;
214
- }
215
- if (this.mouseLeaveHandler_) {
216
- browserEvents.unbind(this.mouseLeaveHandler_);
217
- this.mouseLeaveHandler_ = null;
218
- }
219
- if (this.onKeyDownHandler_) {
220
- browserEvents.unbind(this.onKeyDownHandler_);
221
- this.onKeyDownHandler_ = null;
298
+ /**
299
+ * Highlights the previous highlightable item (or the last if nothing is
300
+ * currently highlighted).
301
+ * @package
302
+ */
303
+ highlightPrevious() {
304
+ const index = this.menuItems_.indexOf(this.highlightedItem_);
305
+ this.highlightHelper_(index < 0 ? this.menuItems_.length : index, -1);
222
306
  }
223
307
 
224
- // Remove menu items.
225
- for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
226
- menuItem.dispose();
308
+ /**
309
+ * Highlights the first highlightable item.
310
+ * @private
311
+ */
312
+ highlightFirst_() {
313
+ this.highlightHelper_(-1, 1);
227
314
  }
228
- this.element_ = null;
229
- };
230
315
 
231
- // Child component management.
316
+ /**
317
+ * Highlights the last highlightable item.
318
+ * @private
319
+ */
320
+ highlightLast_() {
321
+ this.highlightHelper_(this.menuItems_.length, -1);
322
+ }
232
323
 
233
- /**
234
- * Returns the child menu item that owns the given DOM element,
235
- * or null if no such menu item is found.
236
- * @param {Element} elem DOM element whose owner is to be returned.
237
- * @return {?MenuItem} Menu item for which the DOM element belongs to.
238
- * @private
239
- */
240
- Menu.prototype.getMenuItem_ = function(elem) {
241
- const menuElem = this.getElement();
242
- // Node might be the menu border (resulting in no associated menu item), or
243
- // a menu item's div, or some element within the menu item.
244
- // Walk up parents until one meets either the menu's root element, or
245
- // a menu item's div.
246
- while (elem && elem !== menuElem) {
247
- if (dom.hasClass(elem, 'blocklyMenuItem')) {
248
- // Having found a menu item's div, locate that menu item in this menu.
249
- for (let i = 0, menuItem; (menuItem = this.menuItems_[i]); i++) {
250
- if (menuItem.getElement() === elem) {
251
- return menuItem;
252
- }
324
+ /**
325
+ * Helper function that manages the details of moving the highlight among
326
+ * child menuitems in response to keyboard events.
327
+ * @param {number} startIndex Start index.
328
+ * @param {number} delta Step direction: 1 to go down, -1 to go up.
329
+ * @private
330
+ */
331
+ highlightHelper_(startIndex, delta) {
332
+ let index = startIndex + delta;
333
+ let menuItem;
334
+ while ((menuItem = this.menuItems_[index])) {
335
+ if (menuItem.isEnabled()) {
336
+ this.setHighlighted(menuItem);
337
+ break;
253
338
  }
339
+ index += delta;
254
340
  }
255
- elem = elem.parentElement;
256
341
  }
257
- return null;
258
- };
259
-
260
- // Highlight management.
261
342
 
262
- /**
263
- * Highlights the given menu item, or clears highlighting if null.
264
- * @param {?MenuItem} item Item to highlight, or null.
265
- * @package
266
- */
267
- Menu.prototype.setHighlighted = function(item) {
268
- const currentHighlighted = this.highlightedItem_;
269
- if (currentHighlighted) {
270
- currentHighlighted.setHighlighted(false);
271
- this.highlightedItem_ = null;
272
- }
273
- if (item) {
274
- item.setHighlighted(true);
275
- this.highlightedItem_ = item;
276
- // Bring the highlighted item into view. This has no effect if the menu is
277
- // not scrollable.
278
- const el = /** @type {!Element} */ (this.getElement());
279
- style.scrollIntoContainerView(
280
- /** @type {!Element} */ (item.getElement()), el);
281
-
282
- aria.setState(el, aria.State.ACTIVEDESCENDANT, item.getId());
283
- }
284
- };
343
+ // Mouse events.
285
344
 
286
- /**
287
- * Highlights the next highlightable item (or the first if nothing is currently
288
- * highlighted).
289
- * @package
290
- */
291
- Menu.prototype.highlightNext = function() {
292
- const index = this.menuItems_.indexOf(this.highlightedItem_);
293
- this.highlightHelper_(index, 1);
294
- };
295
-
296
- /**
297
- * Highlights the previous highlightable item (or the last if nothing is
298
- * currently highlighted).
299
- * @package
300
- */
301
- Menu.prototype.highlightPrevious = function() {
302
- const index = this.menuItems_.indexOf(this.highlightedItem_);
303
- this.highlightHelper_(index < 0 ? this.menuItems_.length : index, -1);
304
- };
305
-
306
- /**
307
- * Highlights the first highlightable item.
308
- * @private
309
- */
310
- Menu.prototype.highlightFirst_ = function() {
311
- this.highlightHelper_(-1, 1);
312
- };
313
-
314
- /**
315
- * Highlights the last highlightable item.
316
- * @private
317
- */
318
- Menu.prototype.highlightLast_ = function() {
319
- this.highlightHelper_(this.menuItems_.length, -1);
320
- };
345
+ /**
346
+ * Handles mouseover events. Highlight menuitems as the user hovers over them.
347
+ * @param {!Event} e Mouse event to handle.
348
+ * @private
349
+ */
350
+ handleMouseOver_(e) {
351
+ const menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
321
352
 
322
- /**
323
- * Helper function that manages the details of moving the highlight among
324
- * child menuitems in response to keyboard events.
325
- * @param {number} startIndex Start index.
326
- * @param {number} delta Step direction: 1 to go down, -1 to go up.
327
- * @private
328
- */
329
- Menu.prototype.highlightHelper_ = function(startIndex, delta) {
330
- let index = startIndex + delta;
331
- let menuItem;
332
- while ((menuItem = this.menuItems_[index])) {
333
- if (menuItem.isEnabled()) {
334
- this.setHighlighted(menuItem);
335
- break;
353
+ if (menuItem) {
354
+ if (menuItem.isEnabled()) {
355
+ if (this.highlightedItem_ !== menuItem) {
356
+ this.setHighlighted(menuItem);
357
+ }
358
+ } else {
359
+ this.setHighlighted(null);
360
+ }
336
361
  }
337
- index += delta;
338
362
  }
339
- };
340
-
341
- // Mouse events.
342
-
343
- /**
344
- * Handles mouseover events. Highlight menuitems as the user hovers over them.
345
- * @param {!Event} e Mouse event to handle.
346
- * @private
347
- */
348
- Menu.prototype.handleMouseOver_ = function(e) {
349
- const menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
350
363
 
351
- if (menuItem) {
352
- if (menuItem.isEnabled()) {
353
- if (this.highlightedItem_ !== menuItem) {
354
- this.setHighlighted(menuItem);
364
+ /**
365
+ * Handles click events. Pass the event onto the child menuitem to handle.
366
+ * @param {!Event} e Click event to handle.
367
+ * @private
368
+ */
369
+ handleClick_(e) {
370
+ const oldCoords = this.openingCoords;
371
+ // Clear out the saved opening coords immediately so they're not used twice.
372
+ this.openingCoords = null;
373
+ if (oldCoords && typeof e.clientX === 'number') {
374
+ const newCoords = new Coordinate(e.clientX, e.clientY);
375
+ if (Coordinate.distance(oldCoords, newCoords) < 1) {
376
+ // This menu was opened by a mousedown and we're handling the consequent
377
+ // click event. The coords haven't changed, meaning this was the same
378
+ // opening event. Don't do the usual behavior because the menu just
379
+ // popped up under the mouse and the user didn't mean to activate this
380
+ // item.
381
+ return;
355
382
  }
356
- } else {
357
- this.setHighlighted(null);
358
383
  }
359
- }
360
- };
361
384
 
362
- /**
363
- * Handles click events. Pass the event onto the child menuitem to handle.
364
- * @param {!Event} e Click event to handle.
365
- * @private
366
- */
367
- Menu.prototype.handleClick_ = function(e) {
368
- const oldCoords = this.openingCoords;
369
- // Clear out the saved opening coords immediately so they're not used twice.
370
- this.openingCoords = null;
371
- if (oldCoords && typeof e.clientX === 'number') {
372
- const newCoords = new Coordinate(e.clientX, e.clientY);
373
- if (Coordinate.distance(oldCoords, newCoords) < 1) {
374
- // This menu was opened by a mousedown and we're handling the consequent
375
- // click event. The coords haven't changed, meaning this was the same
376
- // opening event. Don't do the usual behavior because the menu just popped
377
- // up under the mouse and the user didn't mean to activate this item.
378
- return;
385
+ const menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
386
+ if (menuItem) {
387
+ menuItem.performAction();
379
388
  }
380
389
  }
381
390
 
382
- const menuItem = this.getMenuItem_(/** @type {Element} */ (e.target));
383
- if (menuItem) {
384
- menuItem.performAction();
391
+ /**
392
+ * Handles mouse enter events. Focus the element.
393
+ * @param {!Event} _e Mouse event to handle.
394
+ * @private
395
+ */
396
+ handleMouseEnter_(_e) {
397
+ this.focus();
385
398
  }
386
- };
387
-
388
- /**
389
- * Handles mouse enter events. Focus the element.
390
- * @param {!Event} _e Mouse event to handle.
391
- * @private
392
- */
393
- Menu.prototype.handleMouseEnter_ = function(_e) {
394
- this.focus();
395
- };
396
399
 
397
- /**
398
- * Handles mouse leave events. Blur and clear highlight.
399
- * @param {!Event} _e Mouse event to handle.
400
- * @private
401
- */
402
- Menu.prototype.handleMouseLeave_ = function(_e) {
403
- if (this.getElement()) {
404
- this.blur_();
405
- this.setHighlighted(null);
400
+ /**
401
+ * Handles mouse leave events. Blur and clear highlight.
402
+ * @param {!Event} _e Mouse event to handle.
403
+ * @private
404
+ */
405
+ handleMouseLeave_(_e) {
406
+ if (this.getElement()) {
407
+ this.blur_();
408
+ this.setHighlighted(null);
409
+ }
406
410
  }
407
- };
408
411
 
409
- // Keyboard events.
412
+ // Keyboard events.
410
413
 
411
- /**
412
- * Attempts to handle a keyboard event, if the menu item is enabled, by calling
413
- * {@link handleKeyEventInternal_}.
414
- * @param {!Event} e Key event to handle.
415
- * @private
416
- */
417
- Menu.prototype.handleKeyEvent_ = function(e) {
418
- if (!this.menuItems_.length) {
419
- // Empty menu.
420
- return;
421
- }
422
- if (e.shiftKey || e.ctrlKey || e.metaKey || e.altKey) {
423
- // Do not handle the key event if any modifier key is pressed.
424
- return;
425
- }
414
+ /**
415
+ * Attempts to handle a keyboard event, if the menu item is enabled, by
416
+ * calling
417
+ * {@link handleKeyEventInternal_}.
418
+ * @param {!Event} e Key event to handle.
419
+ * @private
420
+ */
421
+ handleKeyEvent_(e) {
422
+ if (!this.menuItems_.length) {
423
+ // Empty menu.
424
+ return;
425
+ }
426
+ if (e.shiftKey || e.ctrlKey || e.metaKey || e.altKey) {
427
+ // Do not handle the key event if any modifier key is pressed.
428
+ return;
429
+ }
426
430
 
427
- const highlighted = this.highlightedItem_;
428
- switch (e.keyCode) {
429
- case KeyCodes.ENTER:
430
- case KeyCodes.SPACE:
431
- if (highlighted) {
432
- highlighted.performAction();
433
- }
434
- break;
431
+ const highlighted = this.highlightedItem_;
432
+ switch (e.keyCode) {
433
+ case KeyCodes.ENTER:
434
+ case KeyCodes.SPACE:
435
+ if (highlighted) {
436
+ highlighted.performAction();
437
+ }
438
+ break;
435
439
 
436
- case KeyCodes.UP:
437
- this.highlightPrevious();
438
- break;
440
+ case KeyCodes.UP:
441
+ this.highlightPrevious();
442
+ break;
439
443
 
440
- case KeyCodes.DOWN:
441
- this.highlightNext();
442
- break;
444
+ case KeyCodes.DOWN:
445
+ this.highlightNext();
446
+ break;
443
447
 
444
- case KeyCodes.PAGE_UP:
445
- case KeyCodes.HOME:
446
- this.highlightFirst_();
447
- break;
448
+ case KeyCodes.PAGE_UP:
449
+ case KeyCodes.HOME:
450
+ this.highlightFirst_();
451
+ break;
448
452
 
449
- case KeyCodes.PAGE_DOWN:
450
- case KeyCodes.END:
451
- this.highlightLast_();
452
- break;
453
+ case KeyCodes.PAGE_DOWN:
454
+ case KeyCodes.END:
455
+ this.highlightLast_();
456
+ break;
453
457
 
454
- default:
455
- // Not a key the menu is interested in.
456
- return;
458
+ default:
459
+ // Not a key the menu is interested in.
460
+ return;
461
+ }
462
+ // The menu used this key, don't let it have secondary effects.
463
+ e.preventDefault();
464
+ e.stopPropagation();
457
465
  }
458
- // The menu used this key, don't let it have secondary effects.
459
- e.preventDefault();
460
- e.stopPropagation();
461
- };
462
466
 
463
- /**
464
- * Get the size of a rendered menu.
465
- * @return {!Size} Object with width and height properties.
466
- * @package
467
- */
468
- Menu.prototype.getSize = function() {
469
- const menuDom = this.getElement();
470
- const menuSize = style.getSize(/** @type {!Element} */
471
- (menuDom));
472
- // Recalculate height for the total content, not only box height.
473
- menuSize.height = menuDom.scrollHeight;
474
- return menuSize;
467
+ /**
468
+ * Get the size of a rendered menu.
469
+ * @return {!Size} Object with width and height properties.
470
+ * @package
471
+ */
472
+ getSize() {
473
+ const menuDom = this.getElement();
474
+ const menuSize = style.getSize(/** @type {!Element} */
475
+ (menuDom));
476
+ // Recalculate height for the total content, not only box height.
477
+ menuSize.height = menuDom.scrollHeight;
478
+ return menuSize;
479
+ }
475
480
  };
476
481
 
477
482
  exports.Menu = Menu;