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
@@ -34,688 +34,714 @@ const {ToolboxItem} = goog.require('Blockly.ToolboxItem');
34
34
 
35
35
  /**
36
36
  * Class for a category in a toolbox.
37
- * @param {!toolbox.CategoryInfo} categoryDef The information needed
38
- * to create a category in the toolbox.
39
- * @param {!IToolbox} toolbox The parent toolbox for the category.
40
- * @param {ICollapsibleToolboxItem=} opt_parent The parent category or null if
41
- * the category does not have a parent.
42
- * @constructor
43
- * @extends {ToolboxItem}
44
37
  * @implements {ISelectableToolboxItem}
45
38
  * @alias Blockly.ToolboxCategory
46
39
  */
47
- const ToolboxCategory = function(categoryDef, toolbox, opt_parent) {
48
- ToolboxCategory.superClass_.constructor.call(
49
- this, categoryDef, toolbox, opt_parent);
40
+ class ToolboxCategory extends ToolboxItem {
41
+ /**
42
+ * @param {!toolbox.CategoryInfo} categoryDef The information needed
43
+ * to create a category in the toolbox.
44
+ * @param {!IToolbox} toolbox The parent toolbox for the category.
45
+ * @param {ICollapsibleToolboxItem=} opt_parent The parent category or null if
46
+ * the category does not have a parent.
47
+ */
48
+ constructor(categoryDef, toolbox, opt_parent) {
49
+ super(categoryDef, toolbox, opt_parent);
50
+
51
+ /** @type {!toolbox.CategoryInfo} */
52
+ this.toolboxItemDef_;
53
+
54
+ /**
55
+ * The name that will be displayed on the category.
56
+ * @type {string}
57
+ * @protected
58
+ */
59
+ this.name_ = '';
60
+
61
+ /**
62
+ * The colour of the category.
63
+ * @type {string}
64
+ * @protected
65
+ */
66
+ this.colour_ = '';
67
+
68
+ /**
69
+ * The html container for the category.
70
+ * @type {?HTMLDivElement}
71
+ * @protected
72
+ */
73
+ this.htmlDiv_ = null;
74
+
75
+ /**
76
+ * The html element for the category row.
77
+ * @type {?HTMLDivElement}
78
+ * @protected
79
+ */
80
+ this.rowDiv_ = null;
81
+
82
+ /**
83
+ * The html element that holds children elements of the category row.
84
+ * @type {?HTMLDivElement}
85
+ * @protected
86
+ */
87
+ this.rowContents_ = null;
88
+
89
+ /**
90
+ * The html element for the toolbox icon.
91
+ * @type {?Element}
92
+ * @protected
93
+ */
94
+ this.iconDom_ = null;
95
+
96
+ /**
97
+ * The html element for the toolbox label.
98
+ * @type {?Element}
99
+ * @protected
100
+ */
101
+ this.labelDom_ = null;
102
+
103
+ /**
104
+ * All the css class names that are used to create a category.
105
+ * @type {!ToolboxCategory.CssConfig}
106
+ * @protected
107
+ */
108
+ this.cssConfig_ = this.makeDefaultCssConfig_();
109
+
110
+ /**
111
+ * True if the category is meant to be hidden, false otherwise.
112
+ * @type {boolean}
113
+ * @protected
114
+ */
115
+ this.isHidden_ = false;
116
+
117
+ /**
118
+ * True if this category is disabled, false otherwise.
119
+ * @type {boolean}
120
+ * @protected
121
+ */
122
+ this.isDisabled_ = false;
123
+
124
+ /**
125
+ * The flyout items for this category.
126
+ * @type {string|!toolbox.FlyoutItemInfoArray}
127
+ * @protected
128
+ */
129
+ this.flyoutItems_ = [];
130
+ }
131
+
132
+ /**
133
+ * Initializes the toolbox item.
134
+ * This includes creating the DOM and updating the state of any items based
135
+ * on the info object.
136
+ * Init should be called immediately after the construction of the toolbox
137
+ * item, to ensure that the category contents are properly parsed.
138
+ * @override
139
+ */
140
+ init() {
141
+ this.parseCategoryDef_(this.toolboxItemDef_);
142
+ this.parseContents_(this.toolboxItemDef_);
143
+ this.createDom_();
144
+ if (this.toolboxItemDef_['hidden'] === 'true') {
145
+ this.hide();
146
+ }
147
+ }
148
+
50
149
 
51
150
  /**
52
- * The name that will be displayed on the category.
53
- * @type {string}
151
+ * Creates an object holding the default classes for a category.
152
+ * @return {!ToolboxCategory.CssConfig} The configuration object holding
153
+ * all the CSS classes for a category.
54
154
  * @protected
55
155
  */
56
- this.name_ = parsing.replaceMessageReferences(categoryDef['name']);
156
+ makeDefaultCssConfig_() {
157
+ return {
158
+ 'container': 'blocklyToolboxCategory',
159
+ 'row': 'blocklyTreeRow',
160
+ 'rowcontentcontainer': 'blocklyTreeRowContentContainer',
161
+ 'icon': 'blocklyTreeIcon',
162
+ 'label': 'blocklyTreeLabel',
163
+ 'contents': 'blocklyToolboxContents',
164
+ 'selected': 'blocklyTreeSelected',
165
+ 'openicon': 'blocklyTreeIconOpen',
166
+ 'closedicon': 'blocklyTreeIconClosed',
167
+ };
168
+ }
57
169
 
58
170
  /**
59
- * The colour of the category.
60
- * @type {string}
171
+ * Parses the contents array depending on if the category is a dynamic
172
+ * category, or if its contents are meant to be shown in the flyout.
173
+ * @param {!toolbox.CategoryInfo} categoryDef The information needed
174
+ * to create a category.
61
175
  * @protected
62
176
  */
63
- this.colour_ = this.getColour_(categoryDef);
177
+ parseContents_(categoryDef) {
178
+ const contents = categoryDef['contents'];
179
+
180
+ if (categoryDef['custom']) {
181
+ this.flyoutItems_ = categoryDef['custom'];
182
+ } else if (contents) {
183
+ for (let i = 0; i < contents.length; i++) {
184
+ const itemDef = contents[i];
185
+ const flyoutItem =
186
+ /** @type {toolbox.FlyoutItemInfo} */ (itemDef);
187
+ this.flyoutItems_.push(flyoutItem);
188
+ }
189
+ }
190
+ }
64
191
 
65
192
  /**
66
- * The html container for the category.
67
- * @type {?Element}
193
+ * Parses the non-contents parts of the category def.
194
+ * @param {!toolbox.CategoryInfo} categoryDef The information needed to create
195
+ * a category.
68
196
  * @protected
69
197
  */
70
- this.htmlDiv_ = null;
198
+ parseCategoryDef_(categoryDef) {
199
+ this.name_ = parsing.replaceMessageReferences(categoryDef['name']);
200
+ this.colour_ = this.getColour_(categoryDef);
201
+ object.mixin(
202
+ this.cssConfig_, categoryDef['cssconfig'] || categoryDef['cssConfig']);
203
+ }
71
204
 
72
205
  /**
73
- * The html element for the category row.
74
- * @type {?Element}
206
+ * Creates the DOM for the category.
207
+ * @return {!HTMLDivElement} The parent element for the category.
75
208
  * @protected
76
209
  */
77
- this.rowDiv_ = null;
210
+ createDom_() {
211
+ this.htmlDiv_ = this.createContainer_();
212
+ aria.setRole(this.htmlDiv_, aria.Role.TREEITEM);
213
+ aria.setState(
214
+ /** @type {!HTMLDivElement} */ (this.htmlDiv_), aria.State.SELECTED,
215
+ false);
216
+ aria.setState(
217
+ /** @type {!HTMLDivElement} */ (this.htmlDiv_), aria.State.LEVEL,
218
+ this.level_);
219
+
220
+ this.rowDiv_ = this.createRowContainer_();
221
+ this.rowDiv_.style.pointerEvents = 'auto';
222
+ this.htmlDiv_.appendChild(this.rowDiv_);
223
+
224
+ this.rowContents_ = this.createRowContentsContainer_();
225
+ this.rowContents_.style.pointerEvents = 'none';
226
+ this.rowDiv_.appendChild(this.rowContents_);
227
+
228
+ this.iconDom_ = this.createIconDom_();
229
+ aria.setRole(this.iconDom_, aria.Role.PRESENTATION);
230
+ this.rowContents_.appendChild(this.iconDom_);
231
+
232
+ this.labelDom_ = this.createLabelDom_(this.name_);
233
+ this.rowContents_.appendChild(this.labelDom_);
234
+ aria.setState(
235
+ /** @type {!Element} */ (this.htmlDiv_), aria.State.LABELLEDBY,
236
+ this.labelDom_.getAttribute('id'));
237
+
238
+ this.addColourBorder_(this.colour_);
239
+
240
+ return this.htmlDiv_;
241
+ }
78
242
 
79
243
  /**
80
- * The html element that holds children elements of the category row.
81
- * @type {?Element}
244
+ * Creates the container that holds the row and any subcategories.
245
+ * @return {!HTMLDivElement} The div that holds the icon and the label.
82
246
  * @protected
83
247
  */
84
- this.rowContents_ = null;
248
+ createContainer_() {
249
+ const container =
250
+ /** @type {!HTMLDivElement} */ (document.createElement('div'));
251
+ dom.addClass(container, this.cssConfig_['container']);
252
+ return container;
253
+ }
85
254
 
86
255
  /**
87
- * The html element for the toolbox icon.
88
- * @type {?Element}
256
+ * Creates the parent of the contents container. All clicks will happen on
257
+ * this div.
258
+ * @return {!HTMLDivElement} The div that holds the contents container.
89
259
  * @protected
90
260
  */
91
- this.iconDom_ = null;
261
+ createRowContainer_() {
262
+ const rowDiv =
263
+ /** @type {!HTMLDivElement} */ (document.createElement('div'));
264
+ dom.addClass(rowDiv, this.cssConfig_['row']);
265
+ let nestedPadding = ToolboxCategory.nestedPadding * this.getLevel();
266
+ nestedPadding = nestedPadding.toString() + 'px';
267
+ this.workspace_.RTL ? rowDiv.style.paddingRight = nestedPadding :
268
+ rowDiv.style.paddingLeft = nestedPadding;
269
+ return rowDiv;
270
+ }
92
271
 
93
272
  /**
94
- * The html element for the toolbox label.
95
- * @type {?Element}
273
+ * Creates the container for the label and icon.
274
+ * This is necessary so we can set all subcategory pointer events to none.
275
+ * @return {!HTMLDivElement} The div that holds the icon and the label.
96
276
  * @protected
97
277
  */
98
- this.labelDom_ = null;
278
+ createRowContentsContainer_() {
279
+ const contentsContainer =
280
+ /** @type {!HTMLDivElement} */ (document.createElement('div'));
281
+ dom.addClass(contentsContainer, this.cssConfig_['rowcontentcontainer']);
282
+ return contentsContainer;
283
+ }
99
284
 
100
285
  /**
101
- * All the css class names that are used to create a category.
102
- * @type {!ToolboxCategory.CssConfig}
286
+ * Creates the span that holds the category icon.
287
+ * @return {!Element} The span that holds the category icon.
103
288
  * @protected
104
289
  */
105
- this.cssConfig_ = this.makeDefaultCssConfig_();
290
+ createIconDom_() {
291
+ const toolboxIcon = document.createElement('span');
292
+ if (!this.parentToolbox_.isHorizontal()) {
293
+ dom.addClass(toolboxIcon, this.cssConfig_['icon']);
294
+ }
106
295
 
107
- const cssConfig = categoryDef['cssconfig'] || categoryDef['cssConfig'];
108
- object.mixin(this.cssConfig_, cssConfig);
296
+ toolboxIcon.style.display = 'inline-block';
297
+ return toolboxIcon;
298
+ }
109
299
 
110
300
  /**
111
- * True if the category is meant to be hidden, false otherwise.
112
- * @type {boolean}
301
+ * Creates the span that holds the category label.
302
+ * This should have an ID for accessibility purposes.
303
+ * @param {string} name The name of the category.
304
+ * @return {!Element} The span that holds the category label.
113
305
  * @protected
114
306
  */
115
- this.isHidden_ = false;
307
+ createLabelDom_(name) {
308
+ const toolboxLabel = document.createElement('span');
309
+ toolboxLabel.setAttribute('id', this.getId() + '.label');
310
+ toolboxLabel.textContent = name;
311
+ dom.addClass(toolboxLabel, this.cssConfig_['label']);
312
+ return toolboxLabel;
313
+ }
116
314
 
117
315
  /**
118
- * True if this category is disabled, false otherwise.
119
- * @type {boolean}
120
- * @protected
316
+ * Updates the colour for this category.
317
+ * @public
121
318
  */
122
- this.isDisabled_ = false;
319
+ refreshTheme() {
320
+ this.colour_ = this.getColour_(/** @type {toolbox.CategoryInfo} **/
321
+ (this.toolboxItemDef_));
322
+ this.addColourBorder_(this.colour_);
323
+ }
123
324
 
124
325
  /**
125
- * The flyout items for this category.
126
- * @type {string|!toolbox.FlyoutItemInfoArray}
326
+ * Add the strip of colour to the toolbox category.
327
+ * @param {string} colour The category colour.
127
328
  * @protected
128
329
  */
129
- this.flyoutItems_ = [];
130
-
131
- this.parseContents_(categoryDef);
132
- };
133
-
134
- object.inherits(ToolboxCategory, ToolboxItem);
135
-
136
- /**
137
- * All the CSS class names that are used to create a category.
138
- * @typedef {{
139
- * container:(string|undefined),
140
- * row:(string|undefined),
141
- * rowcontentcontainer:(string|undefined),
142
- * icon:(string|undefined),
143
- * label:(string|undefined),
144
- * selected:(string|undefined),
145
- * openicon:(string|undefined),
146
- * closedicon:(string|undefined)
147
- * }}
148
- */
149
- ToolboxCategory.CssConfig;
150
-
151
- /**
152
- * Name used for registering a toolbox category.
153
- * @const {string}
154
- */
155
- ToolboxCategory.registrationName = 'category';
156
-
157
- /**
158
- * The number of pixels to move the category over at each nested level.
159
- * @type {number}
160
- */
161
- ToolboxCategory.nestedPadding = 19;
162
-
163
- /**
164
- * The width in pixels of the strip of colour next to each category.
165
- * @type {number}
166
- */
167
- ToolboxCategory.borderWidth = 8;
168
-
169
- /**
170
- * The default colour of the category. This is used as the background colour of
171
- * the category when it is selected.
172
- * @type {string}
173
- */
174
- ToolboxCategory.defaultBackgroundColour = '#57e';
330
+ addColourBorder_(colour) {
331
+ if (colour) {
332
+ const border =
333
+ ToolboxCategory.borderWidth + 'px solid ' + (colour || '#ddd');
334
+ if (this.workspace_.RTL) {
335
+ this.rowDiv_.style.borderRight = border;
336
+ } else {
337
+ this.rowDiv_.style.borderLeft = border;
338
+ }
339
+ }
340
+ }
175
341
 
176
- /**
177
- * Creates an object holding the default classes for a category.
178
- * @return {!ToolboxCategory.CssConfig} The configuration object holding
179
- * all the CSS classes for a category.
180
- * @protected
181
- */
182
- ToolboxCategory.prototype.makeDefaultCssConfig_ = function() {
183
- return {
184
- 'container': 'blocklyToolboxCategory',
185
- 'row': 'blocklyTreeRow',
186
- 'rowcontentcontainer': 'blocklyTreeRowContentContainer',
187
- 'icon': 'blocklyTreeIcon',
188
- 'label': 'blocklyTreeLabel',
189
- 'contents': 'blocklyToolboxContents',
190
- 'selected': 'blocklyTreeSelected',
191
- 'openicon': 'blocklyTreeIconOpen',
192
- 'closedicon': 'blocklyTreeIconClosed',
193
- };
194
- };
342
+ /**
343
+ * Gets either the colour or the style for a category.
344
+ * @param {!toolbox.CategoryInfo} categoryDef The object holding
345
+ * information on the category.
346
+ * @return {string} The hex colour for the category.
347
+ * @protected
348
+ */
349
+ getColour_(categoryDef) {
350
+ const styleName =
351
+ categoryDef['categorystyle'] || categoryDef['categoryStyle'];
352
+ const colour = categoryDef['colour'];
195
353
 
196
- /**
197
- * Parses the contents array depending on if the category is a dynamic category,
198
- * or if its contents are meant to be shown in the flyout.
199
- * @param {!toolbox.CategoryInfo} categoryDef The information needed
200
- * to create a category.
201
- * @protected
202
- */
203
- ToolboxCategory.prototype.parseContents_ = function(categoryDef) {
204
- const contents = categoryDef['contents'];
205
-
206
- if (categoryDef['custom']) {
207
- this.flyoutItems_ = categoryDef['custom'];
208
- } else if (contents) {
209
- for (let i = 0; i < contents.length; i++) {
210
- const itemDef = contents[i];
211
- const flyoutItem =
212
- /** @type {toolbox.FlyoutItemInfo} */ (itemDef);
213
- this.flyoutItems_.push(flyoutItem);
354
+ if (colour && styleName) {
355
+ console.warn(
356
+ 'Toolbox category "' + this.name_ +
357
+ '" must not have both a style and a colour');
358
+ } else if (styleName) {
359
+ return this.getColourfromStyle_(styleName);
360
+ } else {
361
+ return this.parseColour_(colour);
214
362
  }
363
+ return '';
215
364
  }
216
- };
217
365
 
218
- /**
219
- * @override
220
- */
221
- ToolboxCategory.prototype.init = function() {
222
- this.createDom_();
223
- if (this.toolboxItemDef_['hidden'] === 'true') {
224
- this.hide();
366
+ /**
367
+ * Sets the colour for the category using the style name and returns the new
368
+ * colour as a hex string.
369
+ * @param {string} styleName Name of the style.
370
+ * @return {string} The hex colour for the category.
371
+ * @private
372
+ */
373
+ getColourfromStyle_(styleName) {
374
+ const theme = this.workspace_.getTheme();
375
+ if (styleName && theme) {
376
+ const style = theme.categoryStyles[styleName];
377
+ if (style && style.colour) {
378
+ return this.parseColour_(style.colour);
379
+ } else {
380
+ console.warn(
381
+ 'Style "' + styleName + '" must exist and contain a colour value');
382
+ }
383
+ }
384
+ return '';
225
385
  }
226
- };
227
-
228
- /**
229
- * Creates the DOM for the category.
230
- * @return {!Element} The parent element for the category.
231
- * @protected
232
- */
233
- ToolboxCategory.prototype.createDom_ = function() {
234
- this.htmlDiv_ = this.createContainer_();
235
- aria.setRole(this.htmlDiv_, aria.Role.TREEITEM);
236
- aria.setState(
237
- /** @type {!Element} */ (this.htmlDiv_), aria.State.SELECTED, false);
238
- aria.setState(
239
- /** @type {!Element} */ (this.htmlDiv_), aria.State.LEVEL, this.level_);
240
-
241
- this.rowDiv_ = this.createRowContainer_();
242
- this.rowDiv_.style.pointerEvents = 'auto';
243
- this.htmlDiv_.appendChild(this.rowDiv_);
244
-
245
- this.rowContents_ = this.createRowContentsContainer_();
246
- this.rowContents_.style.pointerEvents = 'none';
247
- this.rowDiv_.appendChild(this.rowContents_);
248
-
249
- this.iconDom_ = this.createIconDom_();
250
- aria.setRole(this.iconDom_, aria.Role.PRESENTATION);
251
- this.rowContents_.appendChild(this.iconDom_);
252
-
253
- this.labelDom_ = this.createLabelDom_(this.name_);
254
- this.rowContents_.appendChild(this.labelDom_);
255
- aria.setState(
256
- /** @type {!Element} */ (this.htmlDiv_), aria.State.LABELLEDBY,
257
- this.labelDom_.getAttribute('id'));
258
386
 
259
- this.addColourBorder_(this.colour_);
387
+ /**
388
+ * Gets the HTML element that is clickable.
389
+ * The parent toolbox element receives clicks. The parent toolbox will add an
390
+ * ID to this element so it can pass the onClick event to the correct
391
+ * toolboxItem.
392
+ * @return {!Element} The HTML element that receives clicks.
393
+ * @public
394
+ */
395
+ getClickTarget() {
396
+ return /** @type {!Element} */ (this.rowDiv_);
397
+ }
260
398
 
261
- return this.htmlDiv_;
262
- };
399
+ /**
400
+ * Parses the colour on the category.
401
+ * @param {number|string} colourValue HSV hue value (0 to 360), #RRGGBB
402
+ * string, or a message reference string pointing to one of those two
403
+ * values.
404
+ * @return {string} The hex colour for the category.
405
+ * @private
406
+ */
407
+ parseColour_(colourValue) {
408
+ // Decode the colour for any potential message references
409
+ // (eg. `%{BKY_MATH_HUE}`).
410
+ const colour = parsing.replaceMessageReferences(colourValue);
411
+ if (colour == null || colour === '') {
412
+ // No attribute. No colour.
413
+ return '';
414
+ } else {
415
+ const hue = Number(colour);
416
+ if (!isNaN(hue)) {
417
+ return colourUtils.hueToHex(hue);
418
+ } else {
419
+ const hex = colourUtils.parse(colour);
420
+ if (hex) {
421
+ return hex;
422
+ } else {
423
+ console.warn(
424
+ 'Toolbox category "' + this.name_ +
425
+ '" has unrecognized colour attribute: ' + colour);
426
+ return '';
427
+ }
428
+ }
429
+ }
430
+ }
263
431
 
264
- /**
265
- * Creates the container that holds the row and any subcategories.
266
- * @return {!Element} The div that holds the icon and the label.
267
- * @protected
268
- */
269
- ToolboxCategory.prototype.createContainer_ = function() {
270
- const container = document.createElement('div');
271
- dom.addClass(container, this.cssConfig_['container']);
272
- return container;
273
- };
432
+ /**
433
+ * Adds appropriate classes to display an open icon.
434
+ * @param {?Element} iconDiv The div that holds the icon.
435
+ * @protected
436
+ */
437
+ openIcon_(iconDiv) {
438
+ if (!iconDiv) {
439
+ return;
440
+ }
441
+ dom.removeClasses(iconDiv, this.cssConfig_['closedicon']);
442
+ dom.addClass(iconDiv, this.cssConfig_['openicon']);
443
+ }
274
444
 
275
- /**
276
- * Creates the parent of the contents container. All clicks will happen on this
277
- * div.
278
- * @return {!Element} The div that holds the contents container.
279
- * @protected
280
- */
281
- ToolboxCategory.prototype.createRowContainer_ = function() {
282
- const rowDiv = document.createElement('div');
283
- dom.addClass(rowDiv, this.cssConfig_['row']);
284
- let nestedPadding = ToolboxCategory.nestedPadding * this.getLevel();
285
- nestedPadding = nestedPadding.toString() + 'px';
286
- this.workspace_.RTL ? rowDiv.style.paddingRight = nestedPadding :
287
- rowDiv.style.paddingLeft = nestedPadding;
288
- return rowDiv;
289
- };
445
+ /**
446
+ * Adds appropriate classes to display a closed icon.
447
+ * @param {?Element} iconDiv The div that holds the icon.
448
+ * @protected
449
+ */
450
+ closeIcon_(iconDiv) {
451
+ if (!iconDiv) {
452
+ return;
453
+ }
454
+ dom.removeClasses(iconDiv, this.cssConfig_['openicon']);
455
+ dom.addClass(iconDiv, this.cssConfig_['closedicon']);
456
+ }
290
457
 
291
- /**
292
- * Creates the container for the label and icon.
293
- * This is necessary so we can set all subcategory pointer events to none.
294
- * @return {!Element} The div that holds the icon and the label.
295
- * @protected
296
- */
297
- ToolboxCategory.prototype.createRowContentsContainer_ = function() {
298
- const contentsContainer = document.createElement('div');
299
- dom.addClass(contentsContainer, this.cssConfig_['rowcontentcontainer']);
300
- return contentsContainer;
301
- };
458
+ /**
459
+ * Sets whether the category is visible or not.
460
+ * For a category to be visible its parent category must also be expanded.
461
+ * @param {boolean} isVisible True if category should be visible.
462
+ * @protected
463
+ */
464
+ setVisible_(isVisible) {
465
+ this.htmlDiv_.style.display = isVisible ? 'block' : 'none';
466
+ this.isHidden_ = !isVisible;
302
467
 
303
- /**
304
- * Creates the span that holds the category icon.
305
- * @return {!Element} The span that holds the category icon.
306
- * @protected
307
- */
308
- ToolboxCategory.prototype.createIconDom_ = function() {
309
- const toolboxIcon = document.createElement('span');
310
- if (!this.parentToolbox_.isHorizontal()) {
311
- dom.addClass(toolboxIcon, this.cssConfig_['icon']);
468
+ if (this.parentToolbox_.getSelectedItem() === this) {
469
+ this.parentToolbox_.clearSelection();
470
+ }
312
471
  }
313
472
 
314
- toolboxIcon.style.display = 'inline-block';
315
- return toolboxIcon;
316
- };
473
+ /**
474
+ * Hide the category.
475
+ */
476
+ hide() {
477
+ this.setVisible_(false);
478
+ }
317
479
 
318
- /**
319
- * Creates the span that holds the category label.
320
- * This should have an ID for accessibility purposes.
321
- * @param {string} name The name of the category.
322
- * @return {!Element} The span that holds the category label.
323
- * @protected
324
- */
325
- ToolboxCategory.prototype.createLabelDom_ = function(name) {
326
- const toolboxLabel = document.createElement('span');
327
- toolboxLabel.setAttribute('id', this.getId() + '.label');
328
- toolboxLabel.textContent = name;
329
- dom.addClass(toolboxLabel, this.cssConfig_['label']);
330
- return toolboxLabel;
331
- };
480
+ /**
481
+ * Show the category. Category will only appear if its parent category is also
482
+ * expanded.
483
+ */
484
+ show() {
485
+ this.setVisible_(true);
486
+ }
332
487
 
333
- /**
334
- * Updates the colour for this category.
335
- * @public
336
- */
337
- ToolboxCategory.prototype.refreshTheme = function() {
338
- this.colour_ = this.getColour_(/** @type {toolbox.CategoryInfo} **/
339
- (this.toolboxItemDef_));
340
- this.addColourBorder_(this.colour_);
341
- };
488
+ /**
489
+ * Whether the category is visible.
490
+ * A category is only visible if all of its ancestors are expanded and
491
+ * isHidden_ is false.
492
+ * @return {boolean} True if the category is visible, false otherwise.
493
+ * @public
494
+ */
495
+ isVisible() {
496
+ return !this.isHidden_ && this.allAncestorsExpanded_();
497
+ }
342
498
 
343
- /**
344
- * Add the strip of colour to the toolbox category.
345
- * @param {string} colour The category colour.
346
- * @protected
347
- */
348
- ToolboxCategory.prototype.addColourBorder_ = function(colour) {
349
- if (colour) {
350
- const border =
351
- ToolboxCategory.borderWidth + 'px solid ' + (colour || '#ddd');
352
- if (this.workspace_.RTL) {
353
- this.rowDiv_.style.borderRight = border;
354
- } else {
355
- this.rowDiv_.style.borderLeft = border;
499
+ /**
500
+ * Whether all ancestors of a category (parent and parent's parent, etc.) are
501
+ * expanded.
502
+ * @return {boolean} True only if every ancestor is expanded
503
+ * @protected
504
+ */
505
+ allAncestorsExpanded_() {
506
+ let category = this;
507
+ while (category.getParent()) {
508
+ category = category.getParent();
509
+ if (!category.isExpanded()) {
510
+ return false;
511
+ }
356
512
  }
513
+ return true;
357
514
  }
358
- };
359
-
360
- /**
361
- * Gets either the colour or the style for a category.
362
- * @param {!toolbox.CategoryInfo} categoryDef The object holding
363
- * information on the category.
364
- * @return {string} The hex colour for the category.
365
- * @protected
366
- */
367
- ToolboxCategory.prototype.getColour_ = function(categoryDef) {
368
- const styleName =
369
- categoryDef['categorystyle'] || categoryDef['categoryStyle'];
370
- const colour = categoryDef['colour'];
371
-
372
- if (colour && styleName) {
373
- console.warn(
374
- 'Toolbox category "' + this.name_ +
375
- '" must not have both a style and a colour');
376
- } else if (styleName) {
377
- return this.getColourfromStyle_(styleName);
378
- } else {
379
- return this.parseColour_(colour);
380
- }
381
- return '';
382
- };
383
515
 
384
- /**
385
- * Sets the colour for the category using the style name and returns the new
386
- * colour as a hex string.
387
- * @param {string} styleName Name of the style.
388
- * @return {string} The hex colour for the category.
389
- * @private
390
- */
391
- ToolboxCategory.prototype.getColourfromStyle_ = function(styleName) {
392
- const theme = this.workspace_.getTheme();
393
- if (styleName && theme) {
394
- const style = theme.categoryStyles[styleName];
395
- if (style && style.colour) {
396
- return this.parseColour_(style.colour);
397
- } else {
398
- console.warn(
399
- 'Style "' + styleName + '" must exist and contain a colour value');
400
- }
516
+ /**
517
+ * @override
518
+ */
519
+ isSelectable() {
520
+ return this.isVisible() && !this.isDisabled_;
401
521
  }
402
- return '';
403
- };
404
522
 
405
- /**
406
- * Gets the HTML element that is clickable.
407
- * The parent toolbox element receives clicks. The parent toolbox will add an ID
408
- * to this element so it can pass the onClick event to the correct toolboxItem.
409
- * @return {!Element} The HTML element that receives clicks.
410
- * @public
411
- */
412
- ToolboxCategory.prototype.getClickTarget = function() {
413
- return /** @type {!Element} */ (this.rowDiv_);
414
- };
523
+ /**
524
+ * Handles when the toolbox item is clicked.
525
+ * @param {!Event} _e Click event to handle.
526
+ * @public
527
+ */
528
+ onClick(_e) {
529
+ // No-op
530
+ }
415
531
 
416
- /**
417
- * Parses the colour on the category.
418
- * @param {number|string} colourValue HSV hue value (0 to 360), #RRGGBB string,
419
- * or a message reference string pointing to one of those two values.
420
- * @return {string} The hex colour for the category.
421
- * @private
422
- */
423
- ToolboxCategory.prototype.parseColour_ = function(colourValue) {
424
- // Decode the colour for any potential message references
425
- // (eg. `%{BKY_MATH_HUE}`).
426
- const colour = parsing.replaceMessageReferences(colourValue);
427
- if (colour == null || colour === '') {
428
- // No attribute. No colour.
429
- return '';
430
- } else {
431
- const hue = Number(colour);
432
- if (!isNaN(hue)) {
433
- return colourUtils.hueToHex(hue);
532
+ /**
533
+ * Sets the current category as selected.
534
+ * @param {boolean} isSelected True if this category is selected, false
535
+ * otherwise.
536
+ * @public
537
+ */
538
+ setSelected(isSelected) {
539
+ if (isSelected) {
540
+ const defaultColour =
541
+ this.parseColour_(ToolboxCategory.defaultBackgroundColour);
542
+ this.rowDiv_.style.backgroundColor = this.colour_ || defaultColour;
543
+ dom.addClass(this.rowDiv_, this.cssConfig_['selected']);
434
544
  } else {
435
- const hex = colourUtils.parse(colour);
436
- if (hex) {
437
- return hex;
438
- } else {
439
- console.warn(
440
- 'Toolbox category "' + this.name_ +
441
- '" has unrecognized colour attribute: ' + colour);
442
- return '';
443
- }
545
+ this.rowDiv_.style.backgroundColor = '';
546
+ dom.removeClass(this.rowDiv_, this.cssConfig_['selected']);
444
547
  }
548
+ aria.setState(
549
+ /** @type {!Element} */ (this.htmlDiv_), aria.State.SELECTED,
550
+ isSelected);
445
551
  }
446
- };
447
552
 
448
- /**
449
- * Adds appropriate classes to display an open icon.
450
- * @param {?Element} iconDiv The div that holds the icon.
451
- * @protected
452
- */
453
- ToolboxCategory.prototype.openIcon_ = function(iconDiv) {
454
- if (!iconDiv) {
455
- return;
553
+ /**
554
+ * Sets whether the category is disabled.
555
+ * @param {boolean} isDisabled True to disable the category, false otherwise.
556
+ */
557
+ setDisabled(isDisabled) {
558
+ this.isDisabled_ = isDisabled;
559
+ this.getDiv().setAttribute('disabled', isDisabled);
560
+ isDisabled ? this.getDiv().setAttribute('disabled', 'true') :
561
+ this.getDiv().removeAttribute('disabled');
456
562
  }
457
- dom.removeClasses(iconDiv, this.cssConfig_['closedicon']);
458
- dom.addClass(iconDiv, this.cssConfig_['openicon']);
459
- };
460
563
 
461
- /**
462
- * Adds appropriate classes to display a closed icon.
463
- * @param {?Element} iconDiv The div that holds the icon.
464
- * @protected
465
- */
466
- ToolboxCategory.prototype.closeIcon_ = function(iconDiv) {
467
- if (!iconDiv) {
468
- return;
564
+ /**
565
+ * Gets the name of the category. Used for emitting events.
566
+ * @return {string} The name of the toolbox item.
567
+ * @public
568
+ */
569
+ getName() {
570
+ return this.name_;
469
571
  }
470
- dom.removeClasses(iconDiv, this.cssConfig_['openicon']);
471
- dom.addClass(iconDiv, this.cssConfig_['closedicon']);
472
- };
473
572
 
474
- /**
475
- * Sets whether the category is visible or not.
476
- * For a category to be visible its parent category must also be expanded.
477
- * @param {boolean} isVisible True if category should be visible.
478
- * @protected
479
- */
480
- ToolboxCategory.prototype.setVisible_ = function(isVisible) {
481
- this.htmlDiv_.style.display = isVisible ? 'block' : 'none';
482
- this.isHidden_ = !isVisible;
483
-
484
- if (this.parentToolbox_.getSelectedItem() === this) {
485
- this.parentToolbox_.clearSelection();
573
+ /**
574
+ * @override
575
+ */
576
+ getParent() {
577
+ return this.parent_;
486
578
  }
487
- };
488
579
 
489
- /**
490
- * Hide the category.
491
- */
492
- ToolboxCategory.prototype.hide = function() {
493
- this.setVisible_(false);
494
- };
580
+ /**
581
+ * @override
582
+ */
583
+ getDiv() {
584
+ return this.htmlDiv_;
585
+ }
495
586
 
496
- /**
497
- * Show the category. Category will only appear if its parent category is also
498
- * expanded.
499
- */
500
- ToolboxCategory.prototype.show = function() {
501
- this.setVisible_(true);
502
- };
587
+ /**
588
+ * Gets the contents of the category. These are items that are meant to be
589
+ * displayed in the flyout.
590
+ * @return {!toolbox.FlyoutItemInfoArray|string} The definition
591
+ * of items to be displayed in the flyout.
592
+ * @public
593
+ */
594
+ getContents() {
595
+ return this.flyoutItems_;
596
+ }
503
597
 
504
- /**
505
- * Whether the category is visible.
506
- * A category is only visible if all of its ancestors are expanded and isHidden_
507
- * is false.
508
- * @return {boolean} True if the category is visible, false otherwise.
509
- * @public
510
- */
511
- ToolboxCategory.prototype.isVisible = function() {
512
- return !this.isHidden_ && this.allAncestorsExpanded_();
513
- };
598
+ /**
599
+ * Updates the contents to be displayed in the flyout.
600
+ * If the flyout is open when the contents are updated, refreshSelection on
601
+ * the toolbox must also be called.
602
+ * @param {!toolbox.FlyoutDefinition|string} contents The contents
603
+ * to be displayed in the flyout. A string can be supplied to create a
604
+ * dynamic category.
605
+ * @public
606
+ */
607
+ updateFlyoutContents(contents) {
608
+ this.flyoutItems_ = [];
514
609
 
515
- /**
516
- * Whether all ancestors of a category (parent and parent's parent, etc.) are
517
- * expanded.
518
- * @return {boolean} True only if every ancestor is expanded
519
- * @protected
520
- */
521
- ToolboxCategory.prototype.allAncestorsExpanded_ = function() {
522
- let category = this;
523
- while (category.getParent()) {
524
- category = category.getParent();
525
- if (!category.isExpanded()) {
526
- return false;
610
+ if (typeof contents === 'string') {
611
+ this.toolboxItemDef_['custom'] = contents;
612
+ } else {
613
+ // Removes old custom field when contents is updated.
614
+ delete this.toolboxItemDef_['custom'];
615
+ this.toolboxItemDef_['contents'] =
616
+ toolbox.convertFlyoutDefToJsonArray(contents);
527
617
  }
618
+ this.parseContents_(
619
+ /** @type {toolbox.CategoryInfo} */ (this.toolboxItemDef_));
528
620
  }
529
- return true;
530
- };
531
-
532
- /**
533
- * @override
534
- */
535
- ToolboxCategory.prototype.isSelectable = function() {
536
- return this.isVisible() && !this.isDisabled_;
537
- };
538
-
539
- /**
540
- * Handles when the toolbox item is clicked.
541
- * @param {!Event} _e Click event to handle.
542
- * @public
543
- */
544
- ToolboxCategory.prototype.onClick = function(_e) {
545
- // No-op
546
- };
547
621
 
548
- /**
549
- * Sets the current category as selected.
550
- * @param {boolean} isSelected True if this category is selected, false
551
- * otherwise.
552
- * @public
553
- */
554
- ToolboxCategory.prototype.setSelected = function(isSelected) {
555
- if (isSelected) {
556
- const defaultColour =
557
- this.parseColour_(ToolboxCategory.defaultBackgroundColour);
558
- this.rowDiv_.style.backgroundColor = this.colour_ || defaultColour;
559
- dom.addClass(this.rowDiv_, this.cssConfig_['selected']);
560
- } else {
561
- this.rowDiv_.style.backgroundColor = '';
562
- dom.removeClass(this.rowDiv_, this.cssConfig_['selected']);
563
- }
564
- aria.setState(
565
- /** @type {!Element} */ (this.htmlDiv_), aria.State.SELECTED, isSelected);
566
- };
567
-
568
- /**
569
- * Sets whether the category is disabled.
570
- * @param {boolean} isDisabled True to disable the category, false otherwise.
571
- */
572
- ToolboxCategory.prototype.setDisabled = function(isDisabled) {
573
- this.isDisabled_ = isDisabled;
574
- this.getDiv().setAttribute('disabled', isDisabled);
575
- isDisabled ? this.getDiv().setAttribute('disabled', 'true') :
576
- this.getDiv().removeAttribute('disabled');
577
- };
578
-
579
- /**
580
- * Gets the name of the category. Used for emitting events.
581
- * @return {string} The name of the toolbox item.
582
- * @public
583
- */
584
- ToolboxCategory.prototype.getName = function() {
585
- return this.name_;
586
- };
622
+ /**
623
+ * @override
624
+ */
625
+ dispose() {
626
+ dom.removeNode(this.htmlDiv_);
627
+ }
628
+ }
587
629
 
588
630
  /**
589
- * @override
631
+ * All the CSS class names that are used to create a category.
632
+ * @typedef {{
633
+ * container:(string|undefined),
634
+ * row:(string|undefined),
635
+ * rowcontentcontainer:(string|undefined),
636
+ * icon:(string|undefined),
637
+ * label:(string|undefined),
638
+ * selected:(string|undefined),
639
+ * openicon:(string|undefined),
640
+ * closedicon:(string|undefined)
641
+ * }}
590
642
  */
591
- ToolboxCategory.prototype.getParent = function() {
592
- return this.parent_;
593
- };
643
+ ToolboxCategory.CssConfig;
594
644
 
595
645
  /**
596
- * @override
646
+ * Name used for registering a toolbox category.
647
+ * @type {string}
597
648
  */
598
- ToolboxCategory.prototype.getDiv = function() {
599
- return this.htmlDiv_;
600
- };
649
+ ToolboxCategory.registrationName = 'category';
601
650
 
602
651
  /**
603
- * Gets the contents of the category. These are items that are meant to be
604
- * displayed in the flyout.
605
- * @return {!toolbox.FlyoutItemInfoArray|string} The definition
606
- * of items to be displayed in the flyout.
607
- * @public
652
+ * The number of pixels to move the category over at each nested level.
653
+ * @type {number}
608
654
  */
609
- ToolboxCategory.prototype.getContents = function() {
610
- return this.flyoutItems_;
611
- };
655
+ ToolboxCategory.nestedPadding = 19;
612
656
 
613
657
  /**
614
- * Updates the contents to be displayed in the flyout.
615
- * If the flyout is open when the contents are updated, refreshSelection on the
616
- * toolbox must also be called.
617
- * @param {!toolbox.FlyoutDefinition|string} contents The contents
618
- * to be displayed in the flyout. A string can be supplied to create a
619
- * dynamic category.
620
- * @public
658
+ * The width in pixels of the strip of colour next to each category.
659
+ * @type {number}
621
660
  */
622
- ToolboxCategory.prototype.updateFlyoutContents = function(contents) {
623
- this.flyoutItems_ = [];
624
-
625
- if (typeof contents === 'string') {
626
- this.toolboxItemDef_['custom'] = contents;
627
- } else {
628
- // Removes old custom field when contents is updated.
629
- delete this.toolboxItemDef_['custom'];
630
- this.toolboxItemDef_['contents'] =
631
- toolbox.convertFlyoutDefToJsonArray(contents);
632
- }
633
- this.parseContents_(
634
- /** @type {toolbox.CategoryInfo} */ (this.toolboxItemDef_));
635
- };
661
+ ToolboxCategory.borderWidth = 8;
636
662
 
637
663
  /**
638
- * @override
664
+ * The default colour of the category. This is used as the background colour of
665
+ * the category when it is selected.
666
+ * @type {string}
639
667
  */
640
- ToolboxCategory.prototype.dispose = function() {
641
- dom.removeNode(this.htmlDiv_);
642
- };
668
+ ToolboxCategory.defaultBackgroundColour = '#57e';
643
669
 
644
670
  /**
645
671
  * CSS for Toolbox. See css.js for use.
646
672
  */
647
673
  Css.register(`
648
- .blocklyTreeRow:not(.blocklyTreeSelected):hover {
649
- background-color: rgba(255, 255, 255, 0.2);
650
- }
651
-
652
- .blocklyToolboxDiv[layout="h"] .blocklyToolboxCategory {
653
- margin: 1px 5px 1px 0;
654
- }
655
-
656
- .blocklyToolboxDiv[dir="RTL"][layout="h"] .blocklyToolboxCategory {
657
- margin: 1px 0 1px 5px;
658
- }
659
-
660
- .blocklyTreeRow {
661
- height: 22px;
662
- line-height: 22px;
663
- margin-bottom: 3px;
664
- padding-right: 8px;
665
- white-space: nowrap;
666
- }
667
-
668
- .blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {
669
- margin-left: 8px;
670
- padding-right: 0;
671
- }
672
-
673
- .blocklyTreeIcon {
674
- background-image: url(<<<PATH>>>/sprites.png);
675
- height: 16px;
676
- vertical-align: middle;
677
- visibility: hidden;
678
- width: 16px;
679
- }
680
-
681
- .blocklyTreeIconClosed {
682
- background-position: -32px -1px;
683
- }
684
-
685
- .blocklyToolboxDiv[dir="RTL"] .blocklyTreeIconClosed {
686
- background-position: 0 -1px;
687
- }
688
-
689
- .blocklyTreeSelected>.blocklyTreeIconClosed {
690
- background-position: -32px -17px;
691
- }
692
-
693
- .blocklyToolboxDiv[dir="RTL"] .blocklyTreeSelected>.blocklyTreeIconClosed {
694
- background-position: 0 -17px;
695
- }
696
-
697
- .blocklyTreeIconOpen {
698
- background-position: -16px -1px;
699
- }
700
-
701
- .blocklyTreeSelected>.blocklyTreeIconOpen {
702
- background-position: -16px -17px;
703
- }
704
-
705
- .blocklyTreeLabel {
706
- cursor: default;
707
- font: 16px sans-serif;
708
- padding: 0 3px;
709
- vertical-align: middle;
710
- }
711
-
712
- .blocklyToolboxDelete .blocklyTreeLabel {
713
- cursor: url("<<<PATH>>>/handdelete.cur"), auto;
714
- }
715
-
716
- .blocklyTreeSelected .blocklyTreeLabel {
717
- color: #fff;
718
- }
674
+ .blocklyTreeRow:not(.blocklyTreeSelected):hover {
675
+ background-color: rgba(255, 255, 255, .2);
676
+ }
677
+
678
+ .blocklyToolboxDiv[layout="h"] .blocklyToolboxCategory {
679
+ margin: 1px 5px 1px 0;
680
+ }
681
+
682
+ .blocklyToolboxDiv[dir="RTL"][layout="h"] .blocklyToolboxCategory {
683
+ margin: 1px 0 1px 5px;
684
+ }
685
+
686
+ .blocklyTreeRow {
687
+ height: 22px;
688
+ line-height: 22px;
689
+ margin-bottom: 3px;
690
+ padding-right: 8px;
691
+ white-space: nowrap;
692
+ }
693
+
694
+ .blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow {
695
+ margin-left: 8px;
696
+ padding-right: 0;
697
+ }
698
+
699
+ .blocklyTreeIcon {
700
+ background-image: url(<<<PATH>>>/sprites.png);
701
+ height: 16px;
702
+ vertical-align: middle;
703
+ visibility: hidden;
704
+ width: 16px;
705
+ }
706
+
707
+ .blocklyTreeIconClosed {
708
+ background-position: -32px -1px;
709
+ }
710
+
711
+ .blocklyToolboxDiv[dir="RTL"] .blocklyTreeIconClosed {
712
+ background-position: 0 -1px;
713
+ }
714
+
715
+ .blocklyTreeSelected>.blocklyTreeIconClosed {
716
+ background-position: -32px -17px;
717
+ }
718
+
719
+ .blocklyToolboxDiv[dir="RTL"] .blocklyTreeSelected>.blocklyTreeIconClosed {
720
+ background-position: 0 -17px;
721
+ }
722
+
723
+ .blocklyTreeIconOpen {
724
+ background-position: -16px -1px;
725
+ }
726
+
727
+ .blocklyTreeSelected>.blocklyTreeIconOpen {
728
+ background-position: -16px -17px;
729
+ }
730
+
731
+ .blocklyTreeLabel {
732
+ cursor: default;
733
+ font: 16px sans-serif;
734
+ padding: 0 3px;
735
+ vertical-align: middle;
736
+ }
737
+
738
+ .blocklyToolboxDelete .blocklyTreeLabel {
739
+ cursor: url("<<<PATH>>>/handdelete.cur"), auto;
740
+ }
741
+
742
+ .blocklyTreeSelected .blocklyTreeLabel {
743
+ color: #fff;
744
+ }
719
745
  `);
720
746
 
721
747
  registry.register(