@componyx/ui 0.0.0-stage → 1.0.4

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 (169) hide show
  1. package/AppSkin/AppSkin.css +1268 -0
  2. package/AppSkin/AppSkin.js +2748 -0
  3. package/AppSkin/Themes/Default.css +241 -0
  4. package/Base/Base.js +3407 -0
  5. package/Base/ComponentIcons.css +66 -0
  6. package/Base/Font/ComponentIcons.woff +0 -0
  7. package/Base/Font/UI.woff +0 -0
  8. package/Base/Library.js +8432 -0
  9. package/Base/NavigationManager.js +462 -0
  10. package/Base/ResponsiveTemplates.js +371 -0
  11. package/Base/Sanitizer.js +288 -0
  12. package/Base/Themes/Default.css +255 -0
  13. package/Base/UI.css +618 -0
  14. package/Base/UIResourcePath.js +6 -0
  15. package/Bindary/Bindary.js +2011 -0
  16. package/Bindary/Modules/Connection.js +216 -0
  17. package/Bindary/Modules/Core.js +854 -0
  18. package/Bindary/Modules/DataUpdater.js +351 -0
  19. package/Bindary/Modules/ExpressionEngine.js +347 -0
  20. package/Bindary/Modules/ProxyManager.js +482 -0
  21. package/Bindary/Modules/Renderer.js +605 -0
  22. package/Bindary/Modules/Router.js +291 -0
  23. package/Bindary/Modules/Scroller.js +89 -0
  24. package/Bindary/Modules/Template.js +1273 -0
  25. package/BookmarkSpy/BookmarkSpy.js +430 -0
  26. package/Box/Box.css +36 -0
  27. package/Box/Box.js +1685 -0
  28. package/Button/Button.css +470 -0
  29. package/Button/Button.js +1398 -0
  30. package/Button/Themes/Default.css +200 -0
  31. package/Carousel/Carousel.css +273 -0
  32. package/Carousel/Carousel.js +607 -0
  33. package/ColorButton/ColorButton.css +39 -0
  34. package/ColorButton/ColorButton.js +336 -0
  35. package/ColorPicker/ColorPicker.css +359 -0
  36. package/ColorPicker/ColorPicker.js +972 -0
  37. package/ComboBox/ComboBox.css +357 -0
  38. package/ComboBox/ComboBox.js +2342 -0
  39. package/ComboBox/Themes/Default.css +23 -0
  40. package/DataPager/DataPager.css +72 -0
  41. package/DataPager/DataPager.js +674 -0
  42. package/DatePicker/DatePicker.css +227 -0
  43. package/DatePicker/DatePicker.js +1531 -0
  44. package/DatePicker/Themes/Default.css +26 -0
  45. package/Dialog/Dialog.css +106 -0
  46. package/Dialog/Dialog.js +572 -0
  47. package/Dialog/Themes/Default.css +10 -0
  48. package/Editor/Data/Emoji.json +8285 -0
  49. package/Editor/Data/Special.json +1042 -0
  50. package/Editor/Editor.css +1562 -0
  51. package/Editor/Editor.js +4058 -0
  52. package/Editor/Font/Editor.woff +0 -0
  53. package/Editor/Modules/ComponentFactory.js +565 -0
  54. package/Editor/Modules/ContentManager.js +748 -0
  55. package/Editor/Modules/DialogManager.js +1234 -0
  56. package/Editor/Modules/EventManager.js +458 -0
  57. package/Editor/Modules/Format.js +950 -0
  58. package/Editor/Modules/History.js +191 -0
  59. package/Editor/Modules/LayoutState.js +379 -0
  60. package/Editor/Modules/ListManager.js +296 -0
  61. package/Editor/Modules/MenuManager.js +388 -0
  62. package/Editor/Modules/NodeManager.js +681 -0
  63. package/Editor/Modules/ParagraphButtons.js +122 -0
  64. package/Editor/Modules/Resizer.js +176 -0
  65. package/Editor/Modules/SelectionRange.js +564 -0
  66. package/Editor/Modules/SourceViewBuilder.js +212 -0
  67. package/Editor/Modules/SymbolPicker.js +208 -0
  68. package/Editor/Modules/Table.js +2327 -0
  69. package/Editor/Modules/TableDialog.js +757 -0
  70. package/Editor/Modules/Toolbar.js +375 -0
  71. package/Editor/Modules/TooltipMenu.js +125 -0
  72. package/Editor/Modules/Utility.js +131 -0
  73. package/Editor/Themes/Default.css +204 -0
  74. package/FileUpload/FileUpload.css +156 -0
  75. package/FileUpload/FileUpload.js +898 -0
  76. package/FileUpload/Themes/Default.css +17 -0
  77. package/Form/Form.css +1934 -0
  78. package/Form/Form.js +4943 -0
  79. package/Form/Modules/ActionManager.js +368 -0
  80. package/Form/Modules/BuildPanelManager.js +319 -0
  81. package/Form/Modules/ComponentFactory.js +468 -0
  82. package/Form/Modules/ComponentPanel.js +265 -0
  83. package/Form/Modules/ConfigPanelManager.js +685 -0
  84. package/Form/Modules/DataBinder.js +602 -0
  85. package/Form/Modules/DataObserver.js +717 -0
  86. package/Form/Modules/Draggable.js +756 -0
  87. package/Form/Modules/OptionsPanel.js +342 -0
  88. package/Form/Modules/Renderer.js +1889 -0
  89. package/Form/Modules/RuleEngine.js +585 -0
  90. package/Form/Modules/RulesPanel.js +1158 -0
  91. package/Form/Modules/Types.js +1709 -0
  92. package/Form/Modules/ValidationManager.js +194 -0
  93. package/Form/Themes/Default.css +216 -0
  94. package/FormField/FormField.css +468 -0
  95. package/FormField/FormField.js +576 -0
  96. package/FormField/Themes/Default.css +99 -0
  97. package/Grid/Grid.css +544 -0
  98. package/Grid/Grid.js +3761 -0
  99. package/Grid/Themes/Default.css +43 -0
  100. package/LICENSE +126 -0
  101. package/MaskedTextBox/MaskedTextBox.css +28 -0
  102. package/MaskedTextBox/MaskedTextBox.js +642 -0
  103. package/MaskedTextBox/Themes/Default.css +6 -0
  104. package/Menu/Menu.css +328 -0
  105. package/Menu/Menu.js +2386 -0
  106. package/Menu/Themes/Default.css +24 -0
  107. package/NumericBox/NumericBox.css +120 -0
  108. package/NumericBox/NumericBox.js +984 -0
  109. package/PanelBar/PanelBar.css +123 -0
  110. package/PanelBar/PanelBar.js +505 -0
  111. package/PanelBar/Themes/Default.css +51 -0
  112. package/PieChart/PieChart.css +95 -0
  113. package/PieChart/PieChart.js +820 -0
  114. package/PieChart/Themes/Default.css +9 -0
  115. package/README.md +178 -3
  116. package/Slider/Slider.css +348 -0
  117. package/Slider/Slider.js +1306 -0
  118. package/Slider/Themes/Default.css +44 -0
  119. package/TabStrip/TabStrip.css +52 -0
  120. package/TabStrip/TabStrip.js +362 -0
  121. package/TabStrip/Themes/Default.css +35 -0
  122. package/TimePicker/Themes/Default.css +30 -0
  123. package/TimePicker/TimePicker.css +253 -0
  124. package/TimePicker/TimePicker.js +1485 -0
  125. package/TooltipManager/Themes/Default.css +21 -0
  126. package/TooltipManager/TooltipManager.css +227 -0
  127. package/TooltipManager/TooltipManager.js +791 -0
  128. package/Validator/Validator.css +54 -0
  129. package/Validator/Validator.js +2508 -0
  130. package/componyx.html-data.json +619 -0
  131. package/index.js +27 -0
  132. package/package.json +43 -4
  133. package/types/AppSkin.d.ts +842 -0
  134. package/types/Base.d.ts +1034 -0
  135. package/types/Bindary.d.ts +1196 -0
  136. package/types/BookmarkSpy.d.ts +112 -0
  137. package/types/Box.d.ts +374 -0
  138. package/types/Button.d.ts +455 -0
  139. package/types/Carousel.d.ts +136 -0
  140. package/types/ColorButton.d.ts +120 -0
  141. package/types/ColorPicker.d.ts +225 -0
  142. package/types/ComboBox.d.ts +507 -0
  143. package/types/DataPager.d.ts +152 -0
  144. package/types/DatePicker.d.ts +354 -0
  145. package/types/Dialog.d.ts +160 -0
  146. package/types/Editor.d.ts +1289 -0
  147. package/types/FileUpload.d.ts +206 -0
  148. package/types/Form.d.ts +3078 -0
  149. package/types/FormField.d.ts +204 -0
  150. package/types/Grid.d.ts +911 -0
  151. package/types/Library.d.ts +1899 -0
  152. package/types/MaskedTextBox.d.ts +91 -0
  153. package/types/Menu.d.ts +577 -0
  154. package/types/NumericBox.d.ts +310 -0
  155. package/types/PanelBar.d.ts +223 -0
  156. package/types/PieChart.d.ts +224 -0
  157. package/types/ResponsiveTemplates.d.ts +108 -0
  158. package/types/Slider.d.ts +227 -0
  159. package/types/TabStrip.d.ts +185 -0
  160. package/types/TimePicker.d.ts +265 -0
  161. package/types/TooltipManager.d.ts +178 -0
  162. package/types/UI.d.ts +29 -0
  163. package/types/Validator.d.ts +653 -0
  164. package/types/index.d.ts +59 -0
  165. package/ui.css +11783 -0
  166. package/ui.js +79477 -0
  167. package/ui.min.css +138 -0
  168. package/ui.min.js +264 -0
  169. package/ui.min.js.map +1 -0
package/Menu/Menu.js ADDED
@@ -0,0 +1,2386 @@
1
+ /*! Componyx.UI | (c) E.H. Daanen / Componyx | BUSL-1.1 | componyx.com/license */
2
+ import '../Base/Base.js';
3
+ import '../Base/Library.js';
4
+ import '../Base/NavigationManager.js';
5
+ import '../Box/Box.js';
6
+ import '../Button/Button.js';
7
+
8
+ (async function (window)
9
+ {
10
+ /**
11
+ * Namespace for menu modules.
12
+ * @namespace componyx.UI.menu_modules
13
+ */
14
+ componyx.UI.menu_modules = componyx.UI.menu_modules || {};
15
+
16
+ /**
17
+ * Promise that resolves when all menu modules are loaded asynchronously.
18
+ * @type {Promise<void>}
19
+ * @memberof componyx.UI.menu_modules
20
+ */
21
+ componyx.UI.menu_modules.loaded = (async () =>
22
+ {
23
+ // these dynamic imports are removed when files are bundled into UI(.min).js
24
+ })();
25
+
26
+ await componyx.UI.menu_modules.loaded;
27
+ const NavigationManager = componyx.base_modules.NavigationManager;
28
+
29
+ /**
30
+ * Menu class.
31
+ * @class
32
+ * @memberof componyx.UI
33
+ * @augments componyx.UI.base.Component
34
+ * @mixes componyx.UI.base.methods
35
+ * @param {String} id The id of the component.
36
+ * @param {Object|HTMLElement} properties The properties used to initialize the component or the container element.
37
+ * @property {componyx.UI.base.AjaxMethod} ajax.load - AJAX method used to load items on demand.
38
+ * @returns {Object} An instance of the component.
39
+ */
40
+ componyx.UI.Menu = function Menu(id, properties)
41
+ {
42
+ var _instance = this,
43
+ _toggle = false,
44
+ _hasDynamicGroup = false,
45
+ _pointerEnterEvent = false,
46
+ _cancelExpand = null,
47
+ _allowExpand = true,
48
+ _allowCollapse = true,
49
+ _expandStates = {},
50
+ _expandList = [],
51
+ _currentExpandId = null,
52
+ _queuedExpandItemId = null,
53
+ _timerId = null,
54
+ _cachedExpand = false,
55
+ _expanderElement = null,
56
+ _selectedItemId = null,
57
+ _collapseInstant = false,
58
+ _categoryId,
59
+ _pointerCoordinates,
60
+ _expandOnClickOption = componyx.UI.Menu.ExpandOnClickOption,
61
+ _expandDirectionOption = componyx.UI.Menu.ExpandDirectionOption,
62
+ _typeOption = componyx.UI.Menu.TypeOption,
63
+ _collapseTypeOption = componyx.UI.Menu.CollapseTypeOption,
64
+ _expandStateOption =
65
+ {
66
+ EXPANDING: 0,
67
+ EXPANDED: 1,
68
+ COLLAPSING: 2,
69
+ COLLAPSED: 3
70
+ },
71
+ _classOption =
72
+ {
73
+ HORIZONTALROOT: 'horizontal',
74
+ ITEM: 'button item',
75
+ ITEMGROUP: 'item-group box',
76
+ ITEMGROUPROOT: 'root',
77
+ ITEMGROUPVISIBLEROOT: 'visible-root',
78
+ ITEMGROUPSTATIC: 'static',
79
+ CATEGORY: 'cat',
80
+ CATEGORY_NAVIGATOR: 'cat-nav',
81
+ CATEGORY_CONTAINER: 'cat-container',
82
+ SUBGROUP: 'sub-group',
83
+ ITEMCHILDLESS: 'childless',
84
+ SELECTEDCHILD: 'sel-child',
85
+ EXPANDED: 'expanded'
86
+ };
87
+
88
+ // define public properties
89
+ /**
90
+ * Gets or sets the default css class of an item group.
91
+ * @type {String}
92
+ */
93
+ this.cssClassItemGroup = '';
94
+
95
+ /**
96
+ * Gets or sets the css class of the root item group.
97
+ * @type {String}
98
+ */
99
+ this.cssClassItemGroupRoot = '';
100
+
101
+ /**
102
+ * Gets or sets the css class of the root item group when horizontalRoot is true.
103
+ * @type {String}
104
+ */
105
+ this.cssClassItemGroupHorizontalRoot = '';
106
+
107
+ /**
108
+ * Gets or sets the css class of the root item group when visibleRoot is true.
109
+ * @type {String}
110
+ */
111
+ this.cssClassItemGroupVisibleRoot = '';
112
+
113
+ /**
114
+ * Gets or sets the css class of the root item group when visibleRoot is false.
115
+ * @type {String}
116
+ */
117
+ this.cssClassItemGroupHiddenRoot = '';
118
+
119
+ /**
120
+ * Gets or sets the default css class of a subgroup.
121
+ * @type {String}
122
+ */
123
+ this.cssClassSubGroup = '';
124
+
125
+ /**
126
+ * Gets or sets the default css class of an item.
127
+ * @type {String}
128
+ */
129
+ this.cssClassItem = '';
130
+
131
+ /**
132
+ * Gets or sets the css class of a childless item.
133
+ * @type {String}
134
+ */
135
+ this.cssClassItemChildless = '';
136
+
137
+ /**
138
+ * Gets or sets the text label of the main category.
139
+ * @type {String}
140
+ */
141
+ this.mainCategoryLabel = '';
142
+
143
+ /**
144
+ * Gets or sets the default template id of an item.
145
+ * @type {String|null}
146
+ */
147
+ this.itemTemplateId = null;
148
+
149
+ /**
150
+ * Gets or sets the css style of the item group.
151
+ * @type {String}
152
+ */
153
+ this.itemGroupStyle = '';
154
+
155
+ /**
156
+ * Gets or sets a value indicating whether the root level is visible.
157
+ * @type {Boolean}
158
+ */
159
+ this.visibleRoot = true;
160
+
161
+ /**
162
+ * Gets or sets a value indicating whether the root level menu items are horizontally rendered.
163
+ * @type {Boolean}
164
+ */
165
+ this.horizontalRoot = true;
166
+
167
+ /**
168
+ * Gets or sets a value indicating if we can move inside the menu with the tab key or if the tab key moves to the next focusable element outside of the menu.
169
+ * @type {Boolean}
170
+ */
171
+ this.tabNavigation = true;
172
+
173
+ /**
174
+ * Gets or sets a value indicating if child-items are rendered ahead (default) when available or rendered when the parent-item expands.
175
+ * @type {Boolean}
176
+ */
177
+ this.renderOnExpand = false;
178
+
179
+ /**
180
+ * Gets or sets a value indicating if the item can be expanded/collapsed (true) or is always in expanded state (false). Option has effect only when the corresponding item-group is statically positioned.
181
+ * @type {Boolean}
182
+ */
183
+ this.expandable = true;
184
+
185
+ /**
186
+ * Gets or sets a value indicating if one (true) or more (false) items per group can expanded simultaneously. Option has effect only when the corresponding item-group is statically positioned.
187
+ * @type {Boolean}
188
+ */
189
+ this.singleExpand = false;
190
+
191
+ /**
192
+ * Gets or sets a value indicating if a selectable item with child-items is expanded when selected.
193
+ * @type {Boolean}
194
+ */
195
+ this.expandOnSelect = true;
196
+
197
+ /**
198
+ * Gets or sets a value indicating if all items are collapsed when an item is selected. Option has effect only when the corresponding item-group is not statically positioned.
199
+ * @type {Boolean}
200
+ */
201
+ this.collapseAllOnSelect = false;
202
+
203
+ /**
204
+ * Gets or sets a value indicating if an item is expanded on a pointerenter event, click-event or on a click-event for the root level and on a pointerenter event for deeper levels. Option has effect only when the corresponding item-group is not statically positioned.
205
+ * @type {componyx.UI.Menu.ExpandOnClickOption}
206
+ */
207
+ this.expandOnClick = _expandOnClickOption.ROOT;
208
+
209
+ /**
210
+ * Gets or sets the default expand direction of a root menu item.
211
+ * @type {componyx.UI.Menu.ExpandDirectionOption|null}
212
+ */
213
+ this.rootExpandDirection = null;
214
+
215
+ /**
216
+ * Gets or sets the default expand direction of a menu item.
217
+ * @type {componyx.UI.Menu.ExpandDirectionOption|null}
218
+ */
219
+ this.expandDirection = null;
220
+
221
+ /**
222
+ * Gets or sets a value indicating how items are collapsed when a new item is expanded.
223
+ * @type {componyx.UI.Menu.CollapseTypeOption}
224
+ */
225
+ this.collapseType = _collapseTypeOption.SINGLE;
226
+
227
+ /**
228
+ * Gets or sets a value indicating how items are collapsed when all items are collapsed through a click outside the menu boundaries.
229
+ * @type {componyx.UI.Menu.CollapseTypeOption}
230
+ */
231
+ this.collapseAllType = _collapseTypeOption.CASCADE;
232
+
233
+ /**
234
+ * Gets or sets the delay in milliseconds before expanding a menu-item through a pointer-enter/leave event.
235
+ * @type {Number}
236
+ */
237
+ this.expandDelay = 100;
238
+
239
+ /**
240
+ * Gets or sets the delay in milliseconds before collapsing all menu-items.
241
+ * @type {Number}
242
+ */
243
+ this.collapseDelay = 100;
244
+
245
+ /**
246
+ * Gets or sets the id of the base item button.
247
+ * @type {String|null}
248
+ */
249
+ this.buttonId = null;
250
+
251
+ /**
252
+ * Gets or sets the id of the base item-group box for the root level container.
253
+ * @type {String|null}
254
+ */
255
+ this.rootItemGroupBoxId = null;
256
+
257
+ /**
258
+ * Gets or sets the id of the base item-group box.
259
+ * @type {String|null}
260
+ */
261
+ this.itemGroupBoxId = null;
262
+
263
+ /**
264
+ * Gets or sets the list of items.
265
+ * @type {componyx.UI.Menu.Item[]}
266
+ */
267
+ this.itemList = [];
268
+
269
+ /** @private
270
+ * @type {componyx.base_modules.NavigationManager}
271
+ */
272
+ this.navigationManager = null;
273
+
274
+ /**
275
+ * @class
276
+ * @augments componyx.UI.base.Events
277
+ * @memberof componyx.UI.Menu
278
+ * @property {componyx.UI.base.Event} onItemClick - Event which fires on an item mouseclick. @see {@link componyx.UI.Menu.MenuItemEventArgs}
279
+ * @property {componyx.UI.base.Event} onItemSelect - Event which fires on an item select. @see {@link componyx.UI.Menu.MenuItemEventArgs}
280
+ * @property {componyx.UI.base.Event} onItemDeselect - Event which fires on an item deselect. @see {@link componyx.UI.Menu.MenuItemEventArgs}
281
+ * @property {componyx.UI.base.Event} onItemExpand - Event which fires on an item expand. @see {@link componyx.UI.Menu.MenuItemEventArgs}
282
+ * @property {componyx.UI.base.Event} onItemExpandComplete - Event which fires when an item expand completed. @see {@link componyx.UI.Menu.MenuItemEventArgs}
283
+ * @property {componyx.UI.base.Event} onItemCollapse - Event which fires on an item collapse. @see {@link componyx.UI.Menu.MenuItemEventArgs}
284
+ * @property {componyx.UI.base.Event} onItemCollapseComplete - Event which fires when an item collapse completed. @see {@link componyx.UI.Menu.MenuItemEventArgs}
285
+ * @property {componyx.UI.base.Event} onLastItemCollapseComplete - Event which fires when the last item collapse in the cascade collapse chain has completed. @see {@link componyx.UI.Menu.MenuItemEventArgs}
286
+ * @property {componyx.UI.base.Event} onPreRenderItemGroup - Event which fires before an itemgroup (box component) is rendered. @see {@link componyx.UI.Menu.MenuItemEventArgs}
287
+ * @property {componyx.UI.base.Event} onPostRenderItemGroup - Event which fires after an itemgroup (box component) is rendered. @see {@link componyx.UI.Menu.MenuItemEventArgs}
288
+ * @property {componyx.UI.base.Event} onPreRenderItem - Event which fires before an item is rendered. @see {@link componyx.UI.Menu.MenuItemEventArgs}
289
+ * @property {componyx.UI.base.Event} onPostRenderItem - Event which fires after an item is rendered. @see {@link componyx.UI.Menu.MenuItemEventArgs}
290
+ * @property {componyx.UI.base.Event} onPreLoadItemList - Event which fires before the item-list data is loaded. @see {@link componyx.UI.Menu.MenuEventArgs}
291
+ * @property {componyx.UI.base.Event} onPostLoadItemList - Event which fires when the item-list data is loaded. @see {@link componyx.UI.Menu.MenuEventArgs}
292
+ * @property {componyx.UI.base.Event} onPostRenderItemList - Event which fires when the item-list is rendered. @see {@link componyx.UI.Menu.MenuEventArgs}
293
+ * @see {@link componyx.UI.base.Events}
294
+ */
295
+ function MenuEvents(events)
296
+ {
297
+ Object.assign(this, events);
298
+ this.onItemClick = $base.static.createEvent('onItemClick');
299
+ this.onItemSelect = $base.static.createEvent('onItemSelect');
300
+ this.onItemDeselect = $base.static.createEvent('onItemDeselect');
301
+ this.onItemExpand = $base.static.createEvent('onItemExpand');
302
+ this.onItemExpandComplete = $base.static.createEvent('onItemExpandComplete');
303
+ this.onItemCollapse = $base.static.createEvent('onItemCollapse');
304
+ this.onItemCollapseComplete = $base.static.createEvent('onItemCollapseComplete');
305
+ this.onLastItemCollapseComplete = $base.static.createEvent('onLastItemCollapseComplete');
306
+ this.onPreRenderItemGroup = $base.static.createEvent('onPreRenderItemGroup');
307
+ this.onPostRenderItemGroup = $base.static.createEvent('onPostRenderItemGroup');
308
+ this.onPreRenderItem = $base.static.createEvent('onPreRenderItem');
309
+ this.onPostRenderItem = $base.static.createEvent('onPostRenderItem');
310
+ this.onPreLoadItemList = $base.static.createEvent('onPreLoadItemList');
311
+ this.onPostLoadItemList = $base.static.createEvent('onPostLoadItemList');
312
+ this.onPostRenderItemList = $base.static.createEvent('onPostRenderItemList');
313
+ }
314
+
315
+ /**
316
+ * Menu events
317
+ * @type {componyx.UI.Menu.MenuEvents}
318
+ */
319
+ this.events = new MenuEvents(this.events);
320
+
321
+ /**
322
+ * @typedef {Object} componyx.UI.Menu.MenuEventArgs
323
+ * @property {componyx.UI.Menu} Menu - The Menu instance.
324
+ * @property {null} eventArgs - Not used, always null.
325
+ */
326
+
327
+ /**
328
+ * @typedef {Object} componyx.UI.Menu.MenuItemEventArgs
329
+ * @property {componyx.UI.Menu} Menu - The Menu instance.
330
+ * @property {Object} eventArgs - The event object containing more detailed information about the event.
331
+ * @property {componyx.UI.Menu.Item|null} eventArgs.item - The menu item (for item-group events: the parent item, null for the root item group).
332
+ * @property {HTMLElement|null} eventArgs.itemElement - The item element, null when there is no item.
333
+ * @property {Event} eventArgs.event - The original event object.
334
+ */
335
+
336
+ // inherit base instance members
337
+ $base.Component.apply(this, [id, properties]);
338
+
339
+ /**
340
+ * Expands the menu with the given item id(s). Animations are disabled when multiple item id's are provided.
341
+ * @param {String|String[]|null} [id] The item identifier(s). The root level is expanded if the item id is not specified.
342
+ * @param {HTMLElement} [expanderElement] The element to which the expand is positioned when the expanding item-group is at root-level and not static positioned. The mouse cursor position is used when no expander element is specified for the previous mentioned scenario.
343
+ * @param {Boolean} [toggle] A value indicating if the item must collapse if it is already expanded.
344
+ * @param {Boolean} [instant=false] A value indicating if the item must be expanded (or collapsed) instantly (without animation). The option has effect only when a single item-id is provided.
345
+ */
346
+ this.expand = function (id, expanderElement, toggle, instant)
347
+ {
348
+ var hasExpandedItem = !$lib.isEmpty(_currentExpandId);
349
+
350
+ if (hasExpandedItem && _expanderElement !== expanderElement)
351
+ {
352
+ hasExpandedItem = false;
353
+ _instance.collapseAll(true);
354
+ _expanderElement = null;
355
+ }
356
+
357
+ id = id || ['root'];
358
+
359
+ if (!$lib.isArray(id))
360
+ id = [id];
361
+
362
+ if (_instance.visibleRoot)
363
+ {
364
+ id = id.filter(x => x !== 'root');
365
+
366
+ if (!id.length)
367
+ {
368
+ console.warn(`Ignoring expand of root level for menu ${_instance.id} because visibleRoot is true.`);
369
+ return;
370
+ }
371
+ }
372
+
373
+ instant = (id.length > 1 || instant);
374
+ _allowExpand = true;
375
+ _allowCollapse = false;
376
+ _collapseInstant = instant;
377
+
378
+ $lib.each(id, function (id)
379
+ {
380
+ var itemExpanded = _expandStates[id] <= _expandStateOption.EXPANDED,
381
+ box = getItemBox(id),
382
+ a = box.animation,
383
+ showType = a.showType;
384
+
385
+ if (_collapseInstant)
386
+ box.animation.showType = 0;
387
+
388
+ if (!itemExpanded)
389
+ {
390
+ var item = getItem(id);
391
+
392
+ if (expanderElement)
393
+ _expanderElement = (typeof (expanderElement) == 'string') ? $lib('#' + expanderElement) : expanderElement;
394
+
395
+ if (item.isCategory)
396
+ showCategory(id, null, _collapseInstant);
397
+ else
398
+ {
399
+ expand(id, instant);
400
+ }
401
+ }
402
+ else if (toggle)
403
+ {
404
+ if (id == 'root')
405
+ _instance.collapseAll();
406
+ else
407
+ collapse(id);
408
+ }
409
+
410
+ if (_collapseInstant)
411
+ a.showType = showType;
412
+ });
413
+
414
+ _collapseInstant = false;
415
+ };
416
+
417
+ /**
418
+ * Collapses the menu with the given item id(s). Animations are disabled when multiple item id's are provided.
419
+ * @param {String|String[]} [id] The item identifier(s). The root level is expanded if the item id is not specified.
420
+ * @param {Boolean} [instant=false] A value indicating if the item must be collapsed instantly (without animation). The option has effect only when a single item-id is provided.
421
+ */
422
+ this.collapse = function (id, instant)
423
+ {
424
+ id = id || ['root'];
425
+
426
+ if (!$lib.isArray(id))
427
+ id = [id];
428
+
429
+ _collapseInstant = (id.length > 1 || instant);
430
+
431
+ $lib.each(id, function (id)
432
+ {
433
+ collapse(id);
434
+ });
435
+
436
+ _collapseInstant = false;
437
+ };
438
+
439
+ /**
440
+ * Cancels the current expand action.
441
+ */
442
+ this.cancelExpand = function ()
443
+ {
444
+ _cancelExpand = true;
445
+ };
446
+
447
+ /**
448
+ * Shows the item category.
449
+ * @param {String} id The item identifier.
450
+ * @param {String} [previous=false] A value indicating that this category is previous to the current visible category.
451
+ * @param {Boolean} [instant=false] A value indicating if the category must be shown instantly (without animation).
452
+ */
453
+ this.showCategory = function (id, previous, instant)
454
+ {
455
+ showCategory(id, previous, instant);
456
+ };
457
+
458
+ /**
459
+ * Loads the item with the specified id.
460
+ * @param {String} id The item identifier.
461
+ * @returns {componyx.library.Path} The Path object offers methods to navigate in any direction from a specific item within the tree.
462
+ */
463
+ this.loadItem = function (id)
464
+ {
465
+ return loadItem(id);
466
+ };
467
+
468
+ /**
469
+ * Selects the item.
470
+ * @param {String} id The item identifier.
471
+ */
472
+ this.selectItem = function (id)
473
+ {
474
+ selectItem(id);
475
+ };
476
+
477
+ /**
478
+ * Deselects the current selected item or the item with the specified id.
479
+ * @param {String} [id] The item identifier.
480
+ */
481
+ this.deselectItem = function (id)
482
+ {
483
+ id = $lib.isEmpty(id) ? _selectedItemId : id;
484
+
485
+ if (id)
486
+ deselectItem(id);
487
+ };
488
+
489
+ /**
490
+ * Enables the item.
491
+ * @param {String} id The item identifier.
492
+ */
493
+ this.enableItem = function (id)
494
+ {
495
+ enableItem(id);
496
+ };
497
+
498
+ /**
499
+ * Disables the item.
500
+ * @param {String} id The item identifier.
501
+ * @param {Boolean} [keepSelected=false] A value indicating if the item must remain selected.
502
+ */
503
+ this.disableItem = function (id, keepSelected)
504
+ {
505
+ disableItem(id, keepSelected);
506
+ };
507
+
508
+ /**
509
+ * Gets the identifier of the active category.
510
+ * @returns {String} The id of the active category.
511
+ */
512
+ this.getActiveCategoryId = function ()
513
+ {
514
+ return _categoryId;
515
+ };
516
+
517
+ /**
518
+ * Gets the identifier of the selected item or the identifier of the selected item within the specified radio group.
519
+ * @param {String} [radioGroupId] The id of the radio group.
520
+ * @returns {String} The selected item id.
521
+ */
522
+ this.getSelectedItemId = function (radioGroupId)
523
+ {
524
+ var item = _instance.getSelectedItem(radioGroupId);
525
+ return (item) ? item.id : null;
526
+ };
527
+
528
+ /**
529
+ * Gets the selected item or the selected item within the specified radio group.
530
+ * @param {String} [radioGroupId] The id of the radio group.
531
+ * @returns {componyx.UI.Menu.Item} The selected item.
532
+ */
533
+ this.getSelectedItem = function (radioGroupId)
534
+ {
535
+ if (!$lib.isEmpty(radioGroupId) && componyx.UI.Button.RadioGroups[_instance.id + '_' + radioGroupId])
536
+ return getItem(componyx.UI.Button.RadioGroups[_instance.id + '_' + radioGroupId].id.replace(_instance.id + '_', ''));
537
+ else if (!$lib.isEmpty(_selectedItemId))
538
+ return getItem(_selectedItemId);
539
+
540
+ return null;
541
+ };
542
+
543
+ /**
544
+ * Gets the expanded items.
545
+ * @returns {componyx.UI.Menu.Item[]} A list of expanded items.
546
+ */
547
+ this.getExpandedItems = function ()
548
+ {
549
+ var paths = $lib.path(_instance.itemList, 'itemList', function (item) { return (item.expanded); }),
550
+ itemList = [];
551
+
552
+ $lib.each(paths, function (path) { itemList.push(path.item); });
553
+ return itemList;
554
+ };
555
+
556
+ /**
557
+ * Collapses all expanded items with the delay configured through the collapseDelay property.
558
+ * @param {Boolean} [instant=false] A value indicating if all items must be collapsed instantly (without animations).
559
+ */
560
+ this.collapseAllDelayed = function (instant)
561
+ {
562
+ _allowCollapse = true;
563
+ collapseAllDelayed(null, instant);
564
+ };
565
+
566
+ /**
567
+ * Collapses all expanded items.
568
+ * @param {Boolean} [instant=false] A value indicating if all items must be collapsed instantly (without animations).
569
+ */
570
+ this.collapseAll = function (instant)
571
+ {
572
+ collapseAll(instant);
573
+ };
574
+
575
+ /**
576
+ * Gets the root item-group box or the item-group box for the specified item id.
577
+ * @param {String} [id] The item identifier.
578
+ * @returns {componyx.UI.Box} The box component.
579
+ */
580
+ this.getItemGroupBox = function (id)
581
+ {
582
+ return getItemBox(id);
583
+ };
584
+
585
+ /**
586
+ * Removes the item with the specified id.
587
+ * @param {String} id The item identifier.
588
+ */
589
+ this.removeItem = function (id)
590
+ {
591
+ var itemPath = loadItem(id);
592
+
593
+ if (itemPath)
594
+ removeItem(itemPath.item);
595
+ };
596
+
597
+ /**
598
+ * Renders the specified item by creating a new element or overwriting the existing element.
599
+ * The item must exist in the item list and the item's position in the item group will equal the item's position within the item list.
600
+ * @param {componyx.UI.Menu.Item} item The item to render.
601
+ */
602
+ this.renderItem = function (item)
603
+ {
604
+ var itemPath = loadItem(item.id),
605
+ index = itemPath.index,
606
+ parentItem = itemPath.hasParent() ? itemPath.parent().item : null,
607
+ parentId = parentItem?.id;
608
+
609
+ drawItem(getItemBox(parentId).contentElement, item, parentItem, (index == itemPath.start().length() - 1) ? null : index);
610
+ };
611
+
612
+ /**
613
+ * Shows the component.
614
+ */
615
+ this.show = function ()
616
+ {
617
+ $base.methods.show.call(_instance);
618
+
619
+ if (_instance.renderState == $base.static.RenderState.RENDERED && _instance.visibleRoot && _instance.itemList && _instance.itemList.length)
620
+ getItemBox().show();
621
+ };
622
+
623
+ /**
624
+ * Hides the component.
625
+ * @param {Boolean} [instant=false] A value indicating if all items must be collapsed instantly (without animations). By default the root item-group has no show/hide animations set. If a hide animation was set manually and instant hiding on the root item-group is required, disable the hide animation in advance.
626
+ */
627
+ this.hide = function (instant)
628
+ {
629
+ if (_instance.renderState != $base.static.RenderState.RENDERED)
630
+ {
631
+ $base.methods.hide.call(_instance);
632
+ return;
633
+ }
634
+
635
+ var fn = function ()
636
+ {
637
+ if (_instance.visibleRoot)
638
+ {
639
+ var box = getItemBox();
640
+ box.events.onHideComplete.priorityAdd(function () { $base.methods.hide.call(_instance); }, null, true);
641
+ box.hide();
642
+ }
643
+ else
644
+ $base.methods.hide.call(_instance);
645
+ };
646
+
647
+ if (!isCollapsing())
648
+ fn();
649
+ else
650
+ {
651
+ this.collapseAll(instant);
652
+ }
653
+ };
654
+
655
+ /**
656
+ * Renders the component
657
+ */
658
+ this.render = function ()
659
+ {
660
+ if (_instance.renderState != $base.static.RenderState.RENDERING)
661
+ {
662
+ // call base render and return
663
+ $base.methods.render.call(_instance, preRender, 'menu');
664
+ return;
665
+ }
666
+
667
+ // render logic after loading resources
668
+
669
+ // create default templates
670
+ if (!_instance.hasTemplate('Default'))
671
+ _instance.addTemplate('Default', '{text}', true);
672
+
673
+ _instance.element.tabIndex = Number(_instance.tabIndex) || 0; // menu widget is focusable, arrows are used to navigate menu-items
674
+ bindGlobalEvents();
675
+ _instance.allowPostRender = false; // block postRender call
676
+ load();
677
+ _instance.allowPostRender = true;
678
+ _instance.renderChildren();
679
+ };
680
+
681
+ /**
682
+ * Executes the post render procedure.
683
+ */
684
+ this.postRender = function ()
685
+ {
686
+ if (_instance.renderState != $base.static.RenderState.RENDERING) // extra safety to never execute a postRender when the component state is incorrect
687
+ return;
688
+
689
+ $base.methods.postRender.call(this);
690
+
691
+ if (_instance.visibleRoot && getItemBox())
692
+ getItemBox().show();
693
+
694
+ _allowExpand = true;
695
+ $lib.each(_expandList, function (itemId) // expand items from initial expand list
696
+ {
697
+ var box = getItemBox(itemId), a = box.animation,
698
+ showType = a.showType;
699
+
700
+ _collapseInstant = true;
701
+ box.animation.showType = 0;
702
+ expand(itemId, true);
703
+ a.showType = showType;
704
+ _collapseInstant = false;
705
+ });
706
+
707
+ if (_instance.visibleRoot && _instance.expandOnClick <= _expandOnClickOption.ALWAYS)
708
+ _allowExpand = false;
709
+
710
+ _expandList = [];
711
+ };
712
+
713
+ /**
714
+ * Destroys the component.
715
+ * @see {@link componyx.UI.base.methods#destroy}
716
+ */
717
+ this.destroy = function (...args)
718
+ {
719
+ dispose();
720
+ $base.methods.destroy.call(this, ...args);
721
+ };
722
+
723
+ /**
724
+ * Draws the item list.
725
+ */
726
+ this.draw = function (itemList)
727
+ {
728
+ draw(itemList);
729
+ };
730
+
731
+ function preRender()
732
+ {
733
+ // initialize script and css
734
+ return ['Menu', ['Box', 'Button']];
735
+ }
736
+
737
+ function load(parentItem)
738
+ {
739
+ var query;
740
+
741
+ _instance.events.onPreLoadItemList.fire(_instance, null);
742
+
743
+ if (_instance.ajax.load && _instance.ajax.load.isDefined())
744
+ {
745
+ query = '"parentItem": ';
746
+ query += (parentItem) ? window.JSON.stringify(parentItem) : 'null';
747
+ _instance.ajaxCall('load', query, { onSuccess: function () { dataLoaded(parentItem); } });
748
+ }
749
+ else
750
+ {
751
+ if (parentItem)
752
+ draw(parentItem.itemList, parentItem);
753
+ else
754
+ draw(_instance.itemList);
755
+ }
756
+ }
757
+
758
+ function dataLoaded(parentItem, ajaxArgs)
759
+ {
760
+ var itemList = [];
761
+
762
+ if (ajaxArgs)
763
+ {
764
+ if (ajaxArgs.data)
765
+ {
766
+ var ajaxResult = (typeof ajaxArgs.data === 'string') ? window.JSON.parse(ajaxArgs.data) : ajaxArgs.data;
767
+ itemList = (ajaxResult) ? ajaxResult.itemList || [] : [];
768
+ }
769
+
770
+ if (!itemList)
771
+ itemList = [];
772
+ }
773
+
774
+ _instance.events.onPostLoadItemList.fire(_instance, null);
775
+
776
+ if (parentItem)
777
+ {
778
+ parentItem.itemList = itemList;
779
+ draw(parentItem.itemList, parentItem);
780
+ }
781
+ else
782
+ {
783
+ _instance.itemList = itemList;
784
+ draw(_instance.itemList);
785
+ }
786
+
787
+ _instance.events.onPostRenderItemList.fire(_instance, null);
788
+ }
789
+
790
+ function draw(itemList, parentItem)
791
+ {
792
+ if (!itemList || !itemList.length)
793
+ return;
794
+
795
+ let itemGroup, index = -1;
796
+
797
+ if (!parentItem || !$UI.store[getItemId(parentItem.id + '_Box')])
798
+ itemGroup = createItemGroup(parentItem);
799
+ else
800
+ itemGroup = $UI.store[getItemId(parentItem.id + '_Box')].contentElement; // existing item-group
801
+
802
+ // clear container
803
+ $lib.removeChildren(itemGroup);
804
+
805
+ if (parentItem && parentItem.isCategory)
806
+ {
807
+ var item = createCategoryNavigator(parentItem);
808
+ drawItem(itemGroup, item, parentItem);
809
+ }
810
+
811
+ while (++index < itemList.length)
812
+ {
813
+ drawItem(itemGroup, itemList[index], parentItem);
814
+ }
815
+
816
+ if (_cachedExpand && parentItem && _queuedExpandItemId == parentItem.id)
817
+ expandCachedItem();
818
+ }
819
+ function createNavigationManager()
820
+ {
821
+ if (_instance.navigationManager)
822
+ return;
823
+
824
+ _instance.navigationManager = new NavigationManager(_instance.element,
825
+ {
826
+ itemList: _instance.itemList,
827
+ horizontalRoot: _instance.horizontalRoot,
828
+ tabNavigation: _instance.tabNavigation,
829
+ getButton: (item) => $UI.store[getItemId(item.id)]?.element,
830
+ getExpander: () => _expanderElement,
831
+ getCollapseTarget: (item) =>
832
+ {
833
+ const itemId = item.id,
834
+ itemPath = loadItem(itemId);
835
+
836
+ if (itemPath?.hasParent())
837
+ return itemPath.parent().item;
838
+
839
+ if (!_instance.visibleRoot)
840
+ return getItem('root');
841
+
842
+ return null;
843
+ },
844
+ isExpanded: (item) => { return _expandStates[item.id] === _expandStateOption.EXPANDED; },
845
+ isExpandable: (item) => { return hasChildItems(item); },
846
+ isFocusable: (item) => { return !Boolean(item.disabled); },
847
+ onExpand: (item) => { _allowExpand = true; expand(item.id); },
848
+ onCollapse: (item) => { collapse(item.id); },
849
+ onCollapseAll: () => { collapseAll(true); _allowExpand = true; }
850
+ });
851
+ }
852
+
853
+ function drawItem(itemGroup, item, parentItem, pos)
854
+ {
855
+ var button, box,
856
+ exists = $UI.store[getItemId(item.id)] != null,
857
+ container = getSubGroup(item),
858
+ subGroupId = (!$lib.isEmpty(item.subGroupId)) ? _instance.id + '_' + item.subGroupId : null,
859
+ cssClassSubGroup = (item.cssClassSubGroup) ? item.cssClassSubGroup : _instance.cssClassSubGroup || _classOption.SUBGROUP,
860
+ expandable = ($lib.isEmpty(item.expandable)) ? _instance.expandable : item.expandable,
861
+ mustExpand;
862
+
863
+ if (exists)
864
+ removeItem(item); // remove item
865
+
866
+ // set default values
867
+ if ($lib.isEmpty(item.id))
868
+ item.id = $lib.format('{0}{1}', (parentItem) ? parentItem.id + '_' : '', $lib.guid());
869
+
870
+ item.type = item.type || _typeOption.COMMANDBUTTON;
871
+ item.selectable = ($lib.isEmpty(item.selectable) && (!hasChildItems(item) || item.type != _typeOption.COMMANDBUTTON || item.href)) ? true : item.selectable;
872
+
873
+ if (subGroupId && (!container || container.id != subGroupId))
874
+ container = $lib.element(itemGroup, '', '', null, { "id": subGroupId, "class": cssClassSubGroup });
875
+
876
+ button = createButton(container || itemGroup, item, parentItem, pos);
877
+ _instance.events.onPreRenderItem.fire(_instance, eventArgs(item));
878
+
879
+ if (!hasChildItems(item))
880
+ $lib.addClass(button.element, _instance.cssClassItemChildless || _classOption.ITEMCHILDLESS);
881
+
882
+ if (hasChildItems(item))
883
+ {
884
+ createItemGroup(item);
885
+ box = getItemBox(item.id);
886
+ item.__static = box.__static;
887
+
888
+ if (item.__static)
889
+ $lib.addClass(button.element, 'static');
890
+
891
+ }
892
+
893
+ bindItemEvents(button, item, parentItem);
894
+
895
+ if (item.selected)
896
+ {
897
+ item.selected = false;
898
+ selectItem(item.id);
899
+ }
900
+ else if (item.selectedChild)
901
+ $lib.addClass(button.element, _classOption.SELECTEDCHILD);
902
+
903
+ if (item.disabled)
904
+ disableItem(item.id, true);
905
+
906
+ // expand and render children only when child-items directly available, not supported for load on demand
907
+ if (item.itemList && item.itemList.length > 0)
908
+ {
909
+ mustExpand = (expandable == false || item.expanded) && (parentItem || _instance.visibleRoot);
910
+
911
+ if (mustExpand)
912
+ _expandList.push(item.id);
913
+
914
+ if (mustExpand || !_instance.renderOnExpand)
915
+ draw(item.itemList, item);
916
+ }
917
+
918
+ _instance.events.onPostRenderItem.fire(_instance, eventArgs(item));
919
+ }
920
+
921
+ function createButton(container, item, parentItem, pos)
922
+ {
923
+ var id = getItemId(item.id),
924
+ templateId = item.templateId || _instance.itemTemplateId || 'Default',
925
+ temp = document.createElement('div'),
926
+ cloneId = item.buttonId || _instance.buttonId,
927
+ button = $UI.createComponent(componyx.UI.Button, { id: id, containerElement: container }),
928
+ expandDirection = ($lib.isEmpty(item.expandDirection)) ? defaultDirection(_instance.visibleRoot && !parentItem) : item.expandDirection,
929
+ expandOnSelect = ($lib.isEmpty(item.expandOnSelect)) ? _instance.expandOnSelect : item.expandOnSelect,
930
+ cssClass = `${_classOption.ITEM} ${(item.cssClass || _instance.cssClassItem || '').replace(/\s\s+/g, ' ')}`;
931
+
932
+ if (item.selectable)
933
+ cssClass += ' selectable';
934
+ else if (!item.command && !item.href)
935
+ cssClass += ' no-action';
936
+
937
+ button.clone($UI.store[cloneId], _instance);
938
+ button.transparent = true;
939
+ button.split = (button.split == true) ? true : (!expandOnSelect && !item.isCategory && item.expandable != false && item.selectable && hasChildItems(item));
940
+ button.cssClass = cssClass;
941
+ button.cssClassIcon = item.cssClassIcon || _instance.cssClassItemIcon || '';
942
+ button.style = item.style;
943
+ button.expandDirection = expandDirection;
944
+ button.contentAlign = 0;
945
+ button.iconAlign = 0;
946
+ button.hasIcon = item.hasIcon;
947
+ button.iconURL = item.iconURL;
948
+ button.selected = item.selected;
949
+ button.disabled = item.disabled;
950
+ button.tabIndex = -1;
951
+ button.keyboardExpand = false;
952
+ button.type = item.type || 0;
953
+ button.renderId = false;
954
+ button.target = item.target;
955
+ button.href = item.href;
956
+ button.title = item.title;
957
+
958
+ button.events.onPostRender.priorityAdd(function (pos, button)
959
+ {
960
+ let itemList = (parentItem) ? parentItem.itemList : _instance.itemList;
961
+
962
+ if (!$lib.isEmpty(pos) && itemList[pos + 1])
963
+ {
964
+ let before = $UI.store[getItemId(itemList[pos + 1].id)]; // get next button
965
+ button.move(container, before.element);
966
+ }
967
+
968
+ let box = getItemBox(parentItem?.id),
969
+ role = (box.__static) ? 'treeitem' : 'menuitem';
970
+
971
+ setAriaRoleAttr(button.getCommandButton(), role);
972
+
973
+ if (button.split)
974
+ setAriaRoleAttr(button.getExpandButton(), role);
975
+
976
+ createNavigationManager();
977
+ setTimeout(() => { _instance.isReady.apply(_instance); });
978
+ }, [pos]);
979
+ button.events.onSelect.priorityAdd(function (itemId) { selectItem(itemId); }, [item.id]);
980
+ button.events.onDeselect.priorityAdd(function (itemId) { deselectItem(itemId); }, [item.id]);
981
+ button.__menuItem = item; // bind item to button
982
+
983
+ if (hasChildItems(item) && !item.isCategory)
984
+ button.expandCommand = function () { }; // define noop command to show expand icon
985
+
986
+ if (item.type == _typeOption.RADIOBUTTON)
987
+ {
988
+ button.radioGroupId = (!$lib.isEmpty(item.radioGroupId)) ? _instance.id + '_' + item.radioGroupId : (parentItem) ? getItemId(parentItem.id) : _instance.id;
989
+ button.hasIcon = true;
990
+ }
991
+ else if (item.type == _typeOption.CHECKBUTTON)
992
+ button.hasIcon = true;
993
+
994
+ _instance.applyTemplate(temp, templateId, item);
995
+ button.setContentTemplate($lib.extract(temp));
996
+ button.showing = true;
997
+ button.render();
998
+
999
+ return button;
1000
+ }
1001
+
1002
+ function createItemGroup(parentItem)
1003
+ {
1004
+ var id = (parentItem) ? getItemId(parentItem.id + '_Box') : _instance.id + '_Box',
1005
+ groupBoxId = (!parentItem && !$lib.isEmpty(_instance.rootItemGroupBoxId)) ? _instance.rootItemGroupBoxId : _instance.itemGroupBoxId,
1006
+ itemGroupStyle = (parentItem) ? parentItem.itemGroupStyle || _instance.itemGroupStyle : _instance.itemGroupStyle,
1007
+ box = $UI.createComponent(componyx.UI.Box, { id: id, containerElement: _instance.element }), cssClass;
1008
+
1009
+ if (parentItem && !$lib.isEmpty(parentItem.itemGroupBoxId))
1010
+ groupBoxId = parentItem.itemGroupBoxId;
1011
+
1012
+ _instance.events.onPreRenderItemGroup.fire(_instance, eventArgs(parentItem));
1013
+
1014
+ if (parentItem)
1015
+ {
1016
+ cssClass = parentItem.cssClassItemGroup || _instance.cssClassItemGroup || _classOption.ITEMGROUP;
1017
+ }
1018
+ else
1019
+ {
1020
+ cssClass = _instance.cssClassItemGroup || _classOption.ITEMGROUP;
1021
+ cssClass += ' ' + (_instance.cssClassItemGroupRoot || _classOption.ITEMGROUPROOT);
1022
+
1023
+ if (_instance.horizontalRoot)
1024
+ {
1025
+ cssClass += ' ' + (_instance.cssClassItemGroupHorizontalRoot || _classOption.HORIZONTALROOT);
1026
+ $lib.addClass(_instance.element, _classOption.HORIZONTALROOT);
1027
+ }
1028
+
1029
+ if (_instance.visibleRoot)
1030
+ {
1031
+ cssClass += ' ' + (_instance.cssClassItemGroupVisibleRoot || _classOption.ITEMGROUPVISIBLEROOT);
1032
+ box.autoFit = false;
1033
+ }
1034
+ }
1035
+
1036
+ box.clone($UI.store[groupBoxId], _instance);
1037
+
1038
+ if (itemGroupStyle)
1039
+ box.style = itemGroupStyle;
1040
+
1041
+ box.theme = $base.static.ThemeOption.NONE;
1042
+ box.cssClass += (box.cssClass) ? ' ' + cssClass : cssClass;
1043
+ box.modal = box.draggable = false;
1044
+ box.contentTag = 'nav';
1045
+ box.events.onPostRender.priorityAdd(function (parentItem, box)
1046
+ {
1047
+ box.__static = isStaticBox(box);
1048
+ let role = box.__static ? 'tree' : 'menu';
1049
+
1050
+ setAriaRoleAttr(box.contentElement, role);
1051
+
1052
+ if (box.__static)
1053
+ {
1054
+ if (parentItem && !parentItem.isCategory) // position box after parent-item element
1055
+ {
1056
+ let button = $UI.store[getItemId(parentItem.id)];
1057
+ let parentEl = button.element;
1058
+ box.move(parentEl.parentNode, parentEl.nextSibling);
1059
+ }
1060
+
1061
+ box.autoPosition = 0;
1062
+ box.autoFit = false;
1063
+ $lib.addClass(box.element, _classOption.ITEMGROUPSTATIC);
1064
+ box.animation.showDirection = box.animation.hideDirection = 'down';
1065
+ }
1066
+ else
1067
+ {
1068
+ if (parentItem)
1069
+ {
1070
+ let button = $UI.store[getItemId(parentItem.id)];
1071
+ setAriaPopupAttr(button.getCommandButton());
1072
+
1073
+ if (button.split)
1074
+ setAriaPopupAttr(button.getExpandButton());
1075
+ }
1076
+
1077
+ bindBoxEvents(box, parentItem);
1078
+ _hasDynamicGroup = true;
1079
+ }
1080
+
1081
+ _instance.events.onPostRenderItemGroup.fire(_instance, eventArgs(parentItem));
1082
+ _instance.isReady.apply(_instance);
1083
+ }, [parentItem]);
1084
+
1085
+ if (!parentItem && _instance.visibleRoot)
1086
+ {
1087
+ if (box.animation.showType == null)
1088
+ box.animation.showType = 0;
1089
+
1090
+ if (box.animation.hideType == null)
1091
+ box.animation.hideType = 0;
1092
+
1093
+ box.events.onShowComplete.priorityAdd(expandItemComplete, [null]);
1094
+ _expandStates['root'] == _expandStateOption.EXPANDED;
1095
+ }
1096
+
1097
+ box.render();
1098
+
1099
+ return box.contentElement;
1100
+ }
1101
+
1102
+ function setAriaPopupAttr(el)
1103
+ {
1104
+ el.setAttribute('aria-haspopup', 'menu');
1105
+ }
1106
+
1107
+ function setAriaRoleAttr(el, role)
1108
+ {
1109
+ el.setAttribute('role', role);
1110
+ }
1111
+
1112
+ function createCategoryNavigator(parentItem)
1113
+ {
1114
+ var item = new componyx.UI.Menu.Item(),
1115
+ ancestorItem = getParentCategoryItem(parentItem.id),
1116
+ id = (ancestorItem) ? ancestorItem.id : null;
1117
+
1118
+ item.text = (ancestorItem) ? ancestorItem.text : _instance.mainCategoryLabel;
1119
+ item.hasChildItems = item.expandable = false;
1120
+ item.hasIcon = true;
1121
+ item.cssClass = _classOption.CATEGORY_NAVIGATOR + ((ancestorItem) ? '' : ' root');
1122
+ item.command = function () { showCategory(id, true); _allowExpand = false; };
1123
+ item.__nav = true;
1124
+ return item;
1125
+ }
1126
+
1127
+ function getParentCategoryItem(itemId)
1128
+ {
1129
+ var itemPath = loadItem(itemId),
1130
+ item = (itemPath.hasParent()) ? itemPath.parent().item : null;
1131
+
1132
+ while (item)
1133
+ {
1134
+ if (item.isCategory)
1135
+ return item;
1136
+ else if (itemPath.hasParent())
1137
+ item = itemPath.parent().item;
1138
+ else
1139
+ item = null;
1140
+ }
1141
+
1142
+ return item;
1143
+ }
1144
+
1145
+ function removeItem(item)
1146
+ {
1147
+ var container;
1148
+
1149
+ $lib.each(item.itemList, function (item, index)
1150
+ {
1151
+ removeItem(item); // first remove children if any
1152
+ });
1153
+
1154
+ var box = getItemBox(item.id);
1155
+
1156
+ if ($UI.store[getItemId(item.id)])
1157
+ $UI.store[getItemId(item.id)].destroy(); // remove button
1158
+
1159
+ if (box)
1160
+ {
1161
+ box.destroy();
1162
+ box.showing = false;
1163
+ }
1164
+
1165
+ container = getSubGroup(item);
1166
+
1167
+ if (container && !container.childNodes.length)
1168
+ $lib.remove(container);
1169
+
1170
+ delete _expandStates[item.id];
1171
+ }
1172
+
1173
+ function isStaticBox(box)
1174
+ {
1175
+ var el = box.element;
1176
+
1177
+ el.classList.remove('hidden');
1178
+ let isStaticPosition = ('absolute fixed'.indexOf($lib.styleValue(el, 'position', true)) == -1);
1179
+ el.classList.add('hidden');
1180
+
1181
+ return isStaticPosition;
1182
+ }
1183
+
1184
+ function getItemBox(itemId)
1185
+ {
1186
+ return ($lib.isEmpty(itemId) || itemId == 'root') ? $UI.store[_instance.id + '_Box'] : $UI.store[getItemId(itemId + '_Box')];
1187
+ }
1188
+
1189
+ function getSubGroup(item)
1190
+ {
1191
+ var subGroupId = item.subGroupId;
1192
+
1193
+ if ($lib.isEmpty(subGroupId))
1194
+ return null;
1195
+
1196
+ return $lib($lib.format('#{0}_{1}', _instance.id, subGroupId));
1197
+ }
1198
+
1199
+ function getItemId(itemId)
1200
+ {
1201
+ return _instance.id + '_' + itemId;
1202
+ }
1203
+
1204
+ function getItem(itemId)
1205
+ {
1206
+ if (itemId && typeof (itemId) != 'string')
1207
+ return itemId;
1208
+
1209
+ if (itemId && itemId != 'root')
1210
+ {
1211
+ return ($UI.store[getItemId(itemId)]?.__menuItem) ? $UI.store[getItemId(itemId)].__menuItem : loadItem(itemId).item;
1212
+ }
1213
+
1214
+ let item = new componyx.UI.Menu.Item();
1215
+ item.id = 'root';
1216
+ item.hasChildItems = true;
1217
+ item.__lastCollapse = true;
1218
+ item.__static = getItemBox(item.id).__static;
1219
+ return item;
1220
+ }
1221
+
1222
+ function loadItem(itemId)
1223
+ {
1224
+ if (itemId == 'root')
1225
+ return null;
1226
+
1227
+ let path = $lib.path(_instance.itemList, 'itemList', function (item) { return (item.id === itemId) }, true);
1228
+
1229
+ if (!path)
1230
+ return null;
1231
+
1232
+ return path.create(); // always create a new instance to avoid issues with modifications to the same Path instance
1233
+ }
1234
+
1235
+ function defaultDirection(isRoot)
1236
+ {
1237
+ if (isRoot)
1238
+ {
1239
+ if (_instance.rootExpandDirection != null)
1240
+ return _instance.rootExpandDirection;
1241
+ else
1242
+ return (_instance.horizontalRoot) ? _expandDirectionOption.DOWN : _expandDirectionOption.RIGHT;
1243
+ }
1244
+ else
1245
+ return (_instance.expandDirection != null) ? _instance.expandDirection : _expandDirectionOption.RIGHT;
1246
+ }
1247
+
1248
+ function eventArgs(item)
1249
+ {
1250
+ return {
1251
+ item: item || null,
1252
+ itemElement: (item) ? $lib('#' + getItemId(item.id)) : null,
1253
+ event: $lib.event
1254
+ }
1255
+ }
1256
+
1257
+ function bindGlobalEvents()
1258
+ {
1259
+ // collapse on document click
1260
+ $lib.on(document, 'pointerup', collapseAllDelayed, null, _instance);
1261
+ $lib.on(document, 'pointerup', allowance);
1262
+
1263
+ // cancel collapse on component click
1264
+ $lib.on(_instance.element, 'pointerup', function ()
1265
+ {
1266
+ _allowCollapse = false;
1267
+
1268
+ if (!_instance.visibleRoot)
1269
+ _allowExpand = false;
1270
+ });
1271
+
1272
+ $lib.on(_instance.element, 'focus', focus);
1273
+ }
1274
+
1275
+ function focus()
1276
+ {
1277
+ if (!_instance.navigationManager)
1278
+ return;
1279
+
1280
+ const active = _instance.element.ownerDocument.activeElement;
1281
+ if (_instance.element.contains(active) && active !== _instance.element)
1282
+ return; // focus is already on a child, so skip resetting focus
1283
+
1284
+ let item = _instance.itemList[0],
1285
+ itemPath = _currentExpandId ? loadItem(_currentExpandId) : null;
1286
+
1287
+ if (itemPath != null)
1288
+ item = itemPath.firstChild()?.item || item;
1289
+
1290
+ _instance.navigationManager.setFocus(item.id);
1291
+ }
1292
+
1293
+ function allowance()
1294
+ {
1295
+ _allowCollapse = true;
1296
+
1297
+ if (!_instance.visibleRoot)
1298
+ _allowExpand = true;
1299
+ }
1300
+
1301
+ function bindBoxEvents(box, parentItem)
1302
+ {
1303
+ if (_instance.expandOnClick == _expandOnClickOption.NEVER)
1304
+ {
1305
+ $lib.on(box.element, 'pointerenter', function ()
1306
+ {
1307
+ var parentItemId = (parentItem) ? parentItem.id : 'root';
1308
+
1309
+ if (_expandStates[parentItemId] < _expandStateOption.COLLAPSING)
1310
+ expand(parentItemId);
1311
+ }, null, _instance);
1312
+
1313
+ $lib.on(box.element, 'pointerleave', function ()
1314
+ {
1315
+ collapseAllDelayed();
1316
+ }, null, _instance);
1317
+ }
1318
+ }
1319
+
1320
+ function bindItemEvents(button, item, parentItem)
1321
+ {
1322
+ item.id;
1323
+
1324
+ button.events.onClick.priorityAdd((button, event) => { _instance.navigationManager.setFocusFromEvent(item, event); });
1325
+
1326
+ if (item.type == _typeOption.COMMANDBUTTON) // for button type check/radio (de)selectItem() is called through button events
1327
+ button.events.onCommandClick.priorityAdd(function (button, buttonArgs) { selectItem(item.id); });
1328
+
1329
+ if (item.expandable == false) // child-items already expanded and/or can't be collapsed
1330
+ return;
1331
+
1332
+ let isRoot = _instance.visibleRoot && (!parentItem || parentItem.isCategory);
1333
+
1334
+ if (item.__static || !hasChildItems(item.id) ||
1335
+ _instance.expandOnClick == _expandOnClickOption.ALWAYS ||
1336
+ (_instance.expandOnClick == _expandOnClickOption.ROOT && isRoot))
1337
+ {
1338
+ let fn = function (item) { expandItemClick(item.id); }.bind(_instance, item);
1339
+
1340
+ if (button.split)
1341
+ button.events.onExpandClick.priorityAdd(fn);
1342
+ else
1343
+ button.events.onCommandClick.priorityAdd(fn);
1344
+ }
1345
+
1346
+ button.events.onCommandClick.priorityAdd(function (item)
1347
+ {
1348
+ _pointerEnterEvent = false;
1349
+ collapseOnSelect(item);
1350
+
1351
+ if (_cancelExpand)
1352
+ {
1353
+ _cancelExpand = null;
1354
+ return;
1355
+ }
1356
+
1357
+ var expandOnSelect = ($lib.isEmpty(item.expandOnSelect)) ? _instance.expandOnSelect : item.expandOnSelect;
1358
+
1359
+ if (!button.split || (expandOnSelect && item.selectable))
1360
+ expand(item.id);
1361
+
1362
+ }.bind(_instance, item));
1363
+
1364
+ if (button.split)
1365
+ {
1366
+ button.events.onExpandClick.priorityAdd(function (item)
1367
+ {
1368
+ _pointerEnterEvent = false;
1369
+ expand(item.id);
1370
+ }.bind(_instance, item));
1371
+ }
1372
+
1373
+ if (item.__static)
1374
+ return;
1375
+
1376
+ if (_instance.expandOnClick != _expandOnClickOption.ALWAYS)
1377
+ {
1378
+ button.events.onPointerEnter.priorityAdd(function (item)
1379
+ {
1380
+ if (!_hasDynamicGroup)
1381
+ return;
1382
+
1383
+ _pointerEnterEvent = true;
1384
+ expand(item.id);
1385
+ }.bind(_instance, item));
1386
+ }
1387
+ }
1388
+
1389
+ function collapseOnSelect(item)
1390
+ {
1391
+ var collapseAllOnSelect = ($lib.isEmpty(item.collapseAllOnSelect)) ? _instance.collapseAllOnSelect : item.collapseAllOnSelect;
1392
+
1393
+ if (item.selectable && (!item.__static) && collapseAllOnSelect)
1394
+ {
1395
+ _instance.cancelExpand();
1396
+ expand(item.id, true);
1397
+ collapseAll();
1398
+ }
1399
+ }
1400
+
1401
+ function expandItemClick(itemId)
1402
+ {
1403
+ var item = getItem(itemId);
1404
+
1405
+ if (item.__static || !hasChildItems(itemId))
1406
+ _allowExpand = true;
1407
+ else
1408
+ {
1409
+ if (_allowExpand)
1410
+ collapse(_currentExpandId);
1411
+
1412
+ _allowExpand = !_allowExpand;
1413
+ }
1414
+ }
1415
+
1416
+ function expandCachedItem()
1417
+ {
1418
+ var itemId = _queuedExpandItemId;
1419
+
1420
+ _cachedExpand = _queuedExpandItemId = null;
1421
+ expand(itemId, true);
1422
+ }
1423
+
1424
+ function expand(itemId, instant)
1425
+ {
1426
+ var itemPath = (itemId != 'root') ? loadItem(itemId) : null,
1427
+ item = (itemId == 'root') ? getItem(itemId) : itemPath.item,
1428
+ parentItemId = (itemPath && itemPath.hasParent()) ? itemPath.parent().item.id : 'root',
1429
+ box = getItemBox(itemId),
1430
+ expandDelay = (instant || item.__static) ? 0 : ($lib.isEmpty(item.expandDelay)) ? _instance.expandDelay : item.expandDelay;
1431
+
1432
+ if (!_allowExpand || item.disabled || itemId == _queuedExpandItemId || (itemId != 'root' && _expandStates[parentItemId] >= _expandStateOption.COLLAPSING))
1433
+ return;
1434
+
1435
+ if (item.isCategory)
1436
+ {
1437
+ if (!_pointerEnterEvent)
1438
+ showCategory(itemId, null, instant);
1439
+
1440
+ return;
1441
+ }
1442
+
1443
+ clearTimeout(_timerId);
1444
+ _toggle = false;
1445
+
1446
+ if (box && box.showing && item.__static) // toggle action
1447
+ {
1448
+ _toggle = true;
1449
+ _currentExpandId = itemId; // change current expand id
1450
+ collapse(itemId);
1451
+ return;
1452
+ }
1453
+ else if (box && !box.showing && !$lib.isEmpty(_currentExpandId) && (itemId == _currentExpandId || inPath(_currentExpandId, itemId)))
1454
+ {
1455
+ _currentExpandId = null; // static group should expand if box is not showing
1456
+ }
1457
+
1458
+ if ((!box || box.showing) && !$lib.isEmpty(_currentExpandId) && (itemId == _currentExpandId || inPath(_currentExpandId, itemId))) // check if item is equal or parent of the current expanded item
1459
+ return;
1460
+
1461
+ _pointerCoordinates = null;
1462
+
1463
+ if ($lib.event)
1464
+ {
1465
+ const x = $lib.clientX($lib.event),
1466
+ y = $lib.clientY($lib.event);
1467
+
1468
+ if (!$lib.isEmpty(x) || !$lib.isEmpty(y))
1469
+ _pointerCoordinates = { clientX: x, clientY: y };
1470
+ }
1471
+
1472
+ if (!expandDelay)
1473
+ expandItem(itemId);
1474
+ else
1475
+ {
1476
+ _timerId = setTimeout(function ()
1477
+ {
1478
+ expandItem(itemId);
1479
+ }, expandDelay);
1480
+ }
1481
+ }
1482
+
1483
+ function expandItem(itemId)
1484
+ {
1485
+ var isRootId = itemId === 'root',
1486
+ itemPath = (!isRootId) ? loadItem(itemId) : null,
1487
+ item = (isRootId) ? getItem(itemId) : itemPath.item,
1488
+ parentItemId = (itemPath && itemPath.hasParent()) ? itemPath.parent().item.id : null,
1489
+ isVirtualRoot = isVirtualRootExpand(itemId, parentItemId),
1490
+ isRootLevelExpand = isVirtualRoot || (!parentItemId && _expandStates['root'] === undefined),
1491
+ lastExpandId = _currentExpandId,
1492
+ box = getItemBox(itemId),
1493
+ button = $UI.store[getItemId(itemId)],
1494
+ itemGroup = (box) ? box.contentElement : null,
1495
+ expandDirection = ($lib.isEmpty(item.expandDirection)) ? defaultDirection(isRootLevelExpand) : item.expandDirection;
1496
+
1497
+ clearTimeout(_timerId);
1498
+
1499
+ if (isVirtualRoot && !_instance.visibleRoot)
1500
+ {
1501
+ _allowExpand = true;
1502
+
1503
+ if ($lib.event && $lib.event.type == 'click')
1504
+ _allowCollapse = false;
1505
+ }
1506
+
1507
+ if ((parentItemId && _expandStates[parentItemId] == _expandStateOption.EXPANDING) || (!_instance.visibleRoot && _expandStates['root'] == _expandStateOption.EXPANDING))
1508
+ {
1509
+ // parent is expanding, cache the expand
1510
+ _queuedExpandItemId = item.id;
1511
+ _cachedExpand = true;
1512
+ return;
1513
+ }
1514
+
1515
+ if (hasChildItems(item) && (!itemGroup || itemGroup.childNodes.length == 0))
1516
+ {
1517
+ // first load or draw the items and cache the expand
1518
+ _cachedExpand = true;
1519
+ _queuedExpandItemId = item.id;
1520
+
1521
+ if (!$lib.isEmpty(item.itemList))
1522
+ draw(item.itemList, item);
1523
+ else
1524
+ load(item);
1525
+
1526
+ return;
1527
+ }
1528
+
1529
+ _currentExpandId = _queuedExpandItemId = null;
1530
+ _cachedExpand = false;
1531
+
1532
+ const canExpand = item.__static
1533
+ || (isVirtualRoot && !_instance.visibleRoot)
1534
+ || (!parentItemId && _instance.visibleRoot)
1535
+ || (!parentItemId && _expandStates['root'] === _expandStateOption.EXPANDED)
1536
+ || _expandStates[parentItemId] === _expandStateOption.EXPANDED;
1537
+
1538
+ if (canExpand)
1539
+ {
1540
+ _currentExpandId = item.id;
1541
+
1542
+ if (hasChildItems(item) && (!_expandStates[item.id] || _expandStates[item.id] >= _expandStateOption.COLLAPSING))
1543
+ _expandStates[item.id] = _expandStateOption.EXPANDING;
1544
+ else
1545
+ _expandStates[item.id] = _expandStateOption.EXPANDED;
1546
+ }
1547
+
1548
+ if ((lastExpandId != _currentExpandId && !inPath(_currentExpandId, lastExpandId)) && (!item.__static || _instance.singleExpand))
1549
+ collapse(lastExpandId); // collapse last expanded item
1550
+
1551
+ if (_expandStates[item.id] != _expandStateOption.EXPANDING) // return if there is no item to expand
1552
+ return;
1553
+
1554
+ box.stopAnimation();
1555
+ box.autoInvertFit = false;
1556
+ box.autoResizeFit = false;
1557
+
1558
+ if (!item.__static)
1559
+ {
1560
+ let expander = (isVirtualRoot) ? _expanderElement : $UI.store[getItemId(itemId)]?.element;
1561
+
1562
+ if (expander) // use the parent item to position the item group box
1563
+ {
1564
+ box.autoInvertFit = true;
1565
+ box.autoResizeFit = true;
1566
+ box.expander = expander;
1567
+ box.expandDirection = expandDirection;
1568
+ box.autoPosition = componyx.UI.Box.AutoPositionOption.EXPAND;
1569
+ }
1570
+ else // use the mouse cursor positions to position the item group box
1571
+ {
1572
+ box.autoPosition = componyx.UI.Box.AutoPositionOption.POINTER;
1573
+ }
1574
+ }
1575
+ else if (button)
1576
+ {
1577
+ $lib.addClass(button.element, _classOption.EXPANDED); // no expander element, set expanded class manually
1578
+ toggleButtonDirection(itemId);
1579
+ }
1580
+
1581
+ box.events.onShowComplete.remove(expandItemComplete);
1582
+ box.events.onHideComplete.remove(collapseItemComplete);
1583
+
1584
+ box.events.onShowComplete.priorityAdd(expandItemComplete, [item.id]);
1585
+ box.events.onHideComplete.priorityAdd(collapseItemComplete, [item.id, box.animation.hideType]);
1586
+
1587
+ box.show(false, _pointerCoordinates);
1588
+ _instance.events.onItemExpand.fire(_instance, eventArgs(item));
1589
+ }
1590
+
1591
+ function expandItemComplete(itemId)
1592
+ {
1593
+ let item = getItem(itemId),
1594
+ button = $UI.store[getItemId(itemId)],
1595
+ itemPath,
1596
+ parentId;
1597
+
1598
+ if (_expandStates[item.id] != _expandStateOption.EXPANDING)
1599
+ return;
1600
+
1601
+ setTimeout(() => { _allowCollapse = true; });
1602
+ _expandStates[item.id] = _expandStateOption.EXPANDED;
1603
+ item.expanded = true;
1604
+
1605
+ if (button)
1606
+ button.element.setAttribute('aria-expanded', 'true');
1607
+ else if (_expanderElement)
1608
+ _expanderElement.setAttribute('aria-expanded', 'true');
1609
+
1610
+ _instance.navigationManager.expandComplete(itemId);
1611
+ _instance.events.onItemExpandComplete.fire(_instance, eventArgs(item));
1612
+
1613
+ if (_cachedExpand)
1614
+ {
1615
+ itemPath = loadItem(_queuedExpandItemId);
1616
+
1617
+ if (itemPath)
1618
+ {
1619
+ parentId = (itemPath.hasParent()) ? itemPath.parent().item.id : null;
1620
+ }
1621
+
1622
+ if (item.id == 'root' || (item.id == parentId))
1623
+ expandCachedItem();
1624
+ }
1625
+ }
1626
+
1627
+ function isCollapsing()
1628
+ {
1629
+ var collapsing = false;
1630
+
1631
+ $lib.each(_expandStates, function (val)
1632
+ {
1633
+ collapsing = (val === _expandStateOption.COLLAPSING);
1634
+ return !collapsing;
1635
+ });
1636
+
1637
+ return collapsing;
1638
+ }
1639
+
1640
+ function collapseAllDelayed(e, instant)
1641
+ {
1642
+ if (!_allowCollapse || !_hasDynamicGroup)
1643
+ return;
1644
+
1645
+ _queuedExpandItemId = null;
1646
+ _cachedExpand = false;
1647
+ clearTimeout(_timerId);
1648
+
1649
+ if (!_currentExpandId)
1650
+ return;
1651
+
1652
+ _timerId = setTimeout(function (instant)
1653
+ {
1654
+ collapseAll(instant);
1655
+ }.bind(_instance, instant), _instance.collapseDelay);
1656
+ }
1657
+
1658
+ function collapseAll(instant = false)
1659
+ {
1660
+ if (!_hasDynamicGroup)
1661
+ return;
1662
+
1663
+ _collapseInstant = instant;
1664
+ _queuedExpandItemId = null;
1665
+ _cachedExpand = false;
1666
+
1667
+ let startExpandId = _currentExpandId;
1668
+
1669
+ if (_instance.expandOnClick <= _expandOnClickOption.ALWAYS && _instance.visibleRoot && startExpandId == 'root')
1670
+ {
1671
+ _allowExpand = false;
1672
+ return;
1673
+ }
1674
+
1675
+ _currentExpandId = null; // clear last expanded item id to avoid collapsible checks while collapsing, since there is no expanded item
1676
+
1677
+ startExpandId = findValidCollapseStart(startExpandId);
1678
+
1679
+ if (startExpandId)
1680
+ collapse(startExpandId);
1681
+
1682
+ _collapseInstant = false;
1683
+ }
1684
+
1685
+ function findValidCollapseStart(itemId)
1686
+ {
1687
+ while (itemId)
1688
+ {
1689
+ let state = _expandStates[itemId];
1690
+ if (state === _expandStateOption.EXPANDING || state === _expandStateOption.EXPANDED)
1691
+ {
1692
+ return itemId; // Found valid expanded item
1693
+ }
1694
+
1695
+ const itemPath = (itemId !== 'root') ? loadItem(itemId) : null;
1696
+ itemId = (itemPath && itemPath.hasParent()) ? itemPath.parent().item.id : null;
1697
+ }
1698
+
1699
+ return null; // No valid expanded item found
1700
+ }
1701
+
1702
+ function collapse(itemId)
1703
+ {
1704
+ if (!itemId)
1705
+ return;
1706
+
1707
+ if (itemId != 'root')
1708
+ itemId = concurrentCollapse(itemId, (_currentExpandId) ? _instance.collapseType : _instance.collapseAllType);
1709
+
1710
+ if (itemId)
1711
+ collapseItem(itemId);
1712
+ }
1713
+
1714
+ function concurrentCollapse(itemId, collapseType)
1715
+ {
1716
+ if (collapseType == _collapseTypeOption.CASCADE) // no concurrent collapse
1717
+ return itemId;
1718
+
1719
+ // collapse all expanded simultaneously, collapseItem will check if the item is collapsible
1720
+ var itemPath = loadItem(itemId),
1721
+ item = itemPath.item, lastCollapse;
1722
+
1723
+ while (item)
1724
+ {
1725
+ lastCollapse = item.__lastCollapse = isLastCollapsible(item);
1726
+ collapseItem(item.id);
1727
+
1728
+ if (!lastCollapse && itemPath.hasParent())
1729
+ item = itemPath.parent().item;
1730
+ else
1731
+ item = null;
1732
+ }
1733
+ }
1734
+
1735
+ function collapseItem(itemId, isPointerEnter)
1736
+ {
1737
+ if ($lib.isEmpty(itemId))
1738
+ return;
1739
+
1740
+ var item = getItem(itemId),
1741
+ cascadeCollapse = (_currentExpandId) ? (_instance.collapseType == _collapseTypeOption.CASCADE) : false,
1742
+ box = getItemBox(itemId),
1743
+ lastCollapse = item.__lastCollapse,
1744
+ isKeyboardNavigation = _instance.navigationManager.isCollapsing(itemId);
1745
+
1746
+ isPointerEnter = $lib.isEmpty(isPointerEnter) ? Boolean(_pointerEnterEvent) : Boolean(isPointerEnter);
1747
+
1748
+ if ($lib.isEmpty(lastCollapse))
1749
+ lastCollapse = item.__lastCollapse = isLastCollapsible(item);
1750
+
1751
+ if (collapsible(item, lastCollapse, isPointerEnter, isKeyboardNavigation))
1752
+ {
1753
+ if (lastCollapse)
1754
+ _pointerEnterEvent = false; // reset event
1755
+
1756
+ if (box && isInstantCollapse(lastCollapse)) // decide instant (or animated)
1757
+ box.animation.hideType = componyx.UI.Box.AnimationTypeOption.NONE;
1758
+
1759
+ _expandStates[item.id] = _expandStateOption.COLLAPSING;
1760
+ item.expanded = false;
1761
+
1762
+ if (box)
1763
+ {
1764
+ if (box.__static)
1765
+ toggleButtonDirection(itemId, true);
1766
+
1767
+ box.__pointerEnterEvent = isPointerEnter; // pass through when cascade collapse
1768
+ box.hide();
1769
+ _instance.events.onItemCollapse.fire(_instance, eventArgs(item));
1770
+ }
1771
+ else
1772
+ collapseItemComplete(itemId); // item has no child-items
1773
+ }
1774
+ else if (!lastCollapse && cascadeCollapse && item.__static) // instant skip
1775
+ {
1776
+ var itemPath = (itemId != 'root') ? loadItem(itemId) : null,
1777
+ parentItemId = (itemPath && itemPath.hasParent()) ? itemPath.parent().item.id : null;
1778
+ collapseItem(parentItemId);
1779
+ }
1780
+ }
1781
+
1782
+ function isInstantCollapse(lastCollapse)
1783
+ {
1784
+ if (_collapseInstant) // instant forced
1785
+ return true;
1786
+
1787
+ var collapseType = (_currentExpandId) ? _instance.collapseType : _instance.collapseAllType;
1788
+
1789
+ if (collapseType == _collapseTypeOption.CASCADE)
1790
+ return false;
1791
+
1792
+ if (collapseType > _collapseTypeOption.SINGLE)
1793
+ return true; // concurrent and instant types
1794
+
1795
+ if (_currentExpandId == null) // collapse all action
1796
+ return false;
1797
+
1798
+ return !lastCollapse; // single type, all deeper levels are instant
1799
+ }
1800
+
1801
+ function collapseItemComplete(itemId, hideType)
1802
+ {
1803
+ let itemPath = (itemId != 'root') ? loadItem(itemId) : null,
1804
+ item = (itemId == 'root') ? getItem(itemId) : itemPath.item,
1805
+ box = getItemBox(itemId),
1806
+ lastCollapse = isLastCollapsible(item),
1807
+ collapseType = (_currentExpandId) ? _instance.collapseType : _instance.collapseAllType,
1808
+ parentItemId = (itemPath && itemPath.hasParent()) ? itemPath.parent().item.id : null,
1809
+ button = $UI.store[getItemId(itemId)],
1810
+ lastItemId = null, isPointerEnter;
1811
+
1812
+ if (_expandStates[item.id] != _expandStateOption.COLLAPSING) // wrong state
1813
+ return;
1814
+
1815
+ _expandStates[item.id] = _expandStateOption.COLLAPSED;
1816
+ _instance.navigationManager.collapseComplete(itemId);
1817
+
1818
+ if (button)
1819
+ {
1820
+ $lib.removeClass(button.element, _classOption.EXPANDED); // expanded class is set manually for static-box expand
1821
+ button.element.setAttribute('aria-expanded', 'false');
1822
+ }
1823
+ else if (_expanderElement)
1824
+ _expanderElement.setAttribute('aria-expanded', 'false');
1825
+
1826
+ if (box)
1827
+ {
1828
+ // reset hide type when collapse was instant
1829
+ if (box.animation.hideType != hideType)
1830
+ box.animation.hideType = hideType;
1831
+
1832
+ isPointerEnter = box.__pointerEnterEvent; // cascade collapse was initiated on a pointerenter event
1833
+ delete box.__pointerEnterEvent;
1834
+ _instance.events.onItemCollapseComplete.fire(_instance, eventArgs(item));
1835
+ }
1836
+
1837
+ if (collapseType != _collapseTypeOption.CASCADE && item.__lastCollapse && !lastCollapse && parentItemId) // item is no longer the last collapsible item
1838
+ {
1839
+ delete item.__lastCollapse;
1840
+ collapse(parentItemId);
1841
+ }
1842
+ if (collapseType == _collapseTypeOption.CASCADE && !lastCollapse && parentItemId != null) // cascade collapse
1843
+ collapseItem(parentItemId, isPointerEnter);
1844
+ else if (parentItemId == null && !_instance.visibleRoot && (lastItemId = getLaunchItemId())) // get launching item-id for invisible root
1845
+ collapseItem(lastItemId, isPointerEnter);
1846
+ else if (parentItemId == null && _instance.visibleRoot && _instance.expandOnClick <= _expandOnClickOption.ALWAYS && !_currentExpandId)
1847
+ _allowExpand = false;
1848
+
1849
+ if (box && item.__lastCollapse)
1850
+ {
1851
+ delete item.__lastCollapse;
1852
+ _instance.events.onLastItemCollapseComplete.fire(_instance, eventArgs(item));
1853
+ }
1854
+
1855
+ _collapseInstant = false; // instant collapse was forced
1856
+ }
1857
+
1858
+ function isVirtualRootExpand(itemId, parentItemId)
1859
+ {
1860
+ if (_instance.visibleRoot)
1861
+ return false;
1862
+
1863
+ if (itemId === 'root')
1864
+ return true;
1865
+
1866
+ if (!parentItemId)
1867
+ return _expandStates['root'] === undefined; // there is no expanding/expanded root item to which this expand belongs
1868
+
1869
+ return _expandStates[parentItemId] === undefined; // there is no expanding/expanded parent item to which this expand belongs
1870
+ }
1871
+
1872
+ function getLaunchItemId()
1873
+ {
1874
+ var launchId = null;
1875
+
1876
+ $lib.each(_expandStates, function (expandState, itemId)
1877
+ {
1878
+ var itemPath = loadItem(itemId);
1879
+
1880
+ if (expandState <= _expandStateOption.EXPANDED && (itemId == 'root' || !itemPath.hasParent()))
1881
+ {
1882
+ launchId = itemId;
1883
+ return false;
1884
+ }
1885
+ });
1886
+
1887
+ return launchId;
1888
+ }
1889
+
1890
+ function isLastCollapsible(item)
1891
+ {
1892
+ if (item.isCategory || item.id == 'root')
1893
+ return true;
1894
+
1895
+ if ($lib.isEmpty(_currentExpandId)) // collapse all action
1896
+ {
1897
+ var last = true;
1898
+
1899
+ $lib.each(_expandStates, function (state, id)
1900
+ {
1901
+ if (item.id != id && state < _expandStateOption.COLLAPSING)
1902
+ return (last = false);
1903
+ });
1904
+
1905
+ return last;
1906
+ }
1907
+
1908
+ var itemPath = loadItem(item.id);
1909
+
1910
+ if (!itemPath.hasParent())
1911
+ return true;
1912
+
1913
+ if (_toggle)
1914
+ return (item.id == _currentExpandId);
1915
+ else
1916
+ {
1917
+ item = itemPath.parent().item; // set item to parent
1918
+ return (item.id == _currentExpandId || inPath(_currentExpandId, item.id)); // item is last collapsible when parent-item is either parent of current expand-item or current expand-item
1919
+ }
1920
+ }
1921
+
1922
+ function collapsible(item, lastCollapse, isPointerEnter, isKeyboardNavigation)
1923
+ {
1924
+ let singleExpand = _instance.singleExpand;
1925
+
1926
+ if (isKeyboardNavigation)
1927
+ return true;
1928
+
1929
+ if (item.expandable == false || item.isCategory || _expandStates[item.id] >= _expandStateOption.COLLAPSING ||
1930
+ (item.id == 'root' && (_instance.visibleRoot || !$lib.isEmpty(_currentExpandId))))
1931
+ return false;
1932
+
1933
+ if (_toggle)
1934
+ return true; // toggle action
1935
+ else if (item.__static)
1936
+ {
1937
+ if (isPointerEnter) // collapse can only happen on click
1938
+ return false;
1939
+
1940
+ // singleExpand and not current expanded item and last collapse
1941
+ if (singleExpand && !$lib.isEmpty(_currentExpandId) && _currentExpandId != item.id && lastCollapse)
1942
+ return true;
1943
+ else
1944
+ return false;
1945
+ }
1946
+ else if (_currentExpandId == item.id) // there is no toggle action for popup menu-items via pointer events, so never collapse expanded item
1947
+ return false;
1948
+
1949
+ let collapsible = true;
1950
+ $lib.each(_expandStates, function (expandState, itemId)
1951
+ {
1952
+ if (itemId != item.id && expandState <= _expandStateOption.COLLAPSING && !item.__static)
1953
+ {
1954
+ // avoid collapse when the item to collapse is root or parent of expanding, expanded or collapsing child item
1955
+ collapsible = !inPath(itemId, item.id);
1956
+ }
1957
+
1958
+ return collapsible;
1959
+ });
1960
+
1961
+ return collapsible;
1962
+ }
1963
+
1964
+ function toggleButtonDirection(itemId, collapse)
1965
+ {
1966
+ var el = $UI.store[getItemId(itemId)].element;
1967
+ $lib.removeClass(el, 'right down');
1968
+ $lib.addClass(el, (collapse) ? 'right' : 'down');
1969
+ }
1970
+
1971
+ function inPath(itemId, checkItemId)
1972
+ {
1973
+ if (itemId == 'root')
1974
+ return false;
1975
+
1976
+ var itemPath = loadItem(itemId), match = false;
1977
+
1978
+ if (!itemPath)
1979
+ return match;
1980
+
1981
+ while (itemPath.hasParent() && itemPath.parent() && !match)
1982
+ {
1983
+ match = (itemPath.item.id === checkItemId) ? true : false;
1984
+ }
1985
+
1986
+ return match;
1987
+ }
1988
+
1989
+ function selectItem(itemId)
1990
+ {
1991
+ var item = getItem(itemId),
1992
+ button = $UI.store[getItemId(itemId)],
1993
+ command = function (item)
1994
+ {
1995
+ if (item.command = convertCommand(item.command))
1996
+ return item.command(_instance, eventArgs(item));
1997
+ };
1998
+
1999
+ if (!item || item.disabled)
2000
+ return;
2001
+
2002
+ command(item);
2003
+
2004
+ if (item.__nav) // category navigator
2005
+ return;
2006
+
2007
+ if (!item.selected && item.selectable)
2008
+ {
2009
+ if (item.type == _typeOption.COMMANDBUTTON)
2010
+ {
2011
+ if (_selectedItemId)
2012
+ deselectItem(_selectedItemId);
2013
+
2014
+ item.selected = true;
2015
+ _selectedItemId = item.id;
2016
+
2017
+ button.events.onSelect.disable(true);
2018
+ button.select();
2019
+ button.events.onSelect.enable(true);
2020
+ updateParents(item, true);
2021
+ }
2022
+ else
2023
+ {
2024
+ item.selected = true;
2025
+
2026
+ if (button && !button.selected) // API call instead of button click
2027
+ {
2028
+ button.events.onSelect.disable(true);
2029
+ button.select();
2030
+ button.events.onSelect.enable(true);
2031
+ }
2032
+ }
2033
+
2034
+ _instance.events.onItemSelect.fire(_instance, eventArgs(item));
2035
+ }
2036
+ }
2037
+
2038
+ function deselectItem(itemId)
2039
+ {
2040
+ var item = getItem(itemId),
2041
+ button = $UI.store[getItemId(itemId)];
2042
+
2043
+ if (!item || item.disabled || !item.selected || !item.selectable)
2044
+ return;
2045
+
2046
+ item.selected = false;
2047
+
2048
+ if (item.type == _typeOption.COMMANDBUTTON)
2049
+ {
2050
+ button.events.onDeselect.disable(true);
2051
+ button.deselect();
2052
+ button.events.onDeselect.enable(true);
2053
+
2054
+ _selectedItemId = null;
2055
+ updateParents(item, false);
2056
+ }
2057
+ else if (button.selected) // API call instead of button click
2058
+ button.deselect();
2059
+
2060
+ _instance.events.onItemDeselect.fire(_instance, eventArgs(item));
2061
+ }
2062
+
2063
+ function showCategory(itemId, previous, instant)
2064
+ {
2065
+ var box = getItemBox(itemId), container,
2066
+ current = getItemBox(_categoryId), currentId = _categoryId;
2067
+
2068
+ if (current === box) // already displaying
2069
+ return;
2070
+
2071
+ // finish current animation if not yet finished
2072
+ if (!$lib.isEmpty(current.__hidingId) && _expandStates[current.__hidingId] === _expandStateOption.COLLAPSING)
2073
+ getItemBox(current.__hidingId).hide(true);
2074
+ else if (_expandStates[_categoryId] === _expandStateOption.EXPANDING)
2075
+ current.show(true);
2076
+
2077
+ _categoryId = itemId;
2078
+ setCategoryBoxDisplay(box, true);
2079
+ setCategoryBoxDisplay(current, true);
2080
+
2081
+ if (!$lib.isEmpty(itemId))
2082
+ $lib.addClass(box.element, getItemBox().element.className); // copy root classes
2083
+
2084
+ $lib.addClass(_instance.element, _classOption.CATEGORY);
2085
+ container = $lib.element(_instance.element, '', '', null, { "class": _classOption.CATEGORY_CONTAINER });
2086
+
2087
+ if (previous)
2088
+ {
2089
+ box.move(container); // make sure that the new box is positioned before the currently visible box
2090
+ current.move(container);
2091
+ box.events.onShowComplete.priorityAdd(showCategoryComplete, [itemId, container, current, currentId]); // the current box will be hidden when the show completed
2092
+ _expandStates[itemId] = _expandStateOption.EXPANDING;
2093
+
2094
+ if (!$lib.isEmpty(currentId))
2095
+ _expandStates[currentId] = _expandStateOption.COLLAPSING;
2096
+
2097
+ box.show(instant);
2098
+ }
2099
+ else
2100
+ {
2101
+ current.move(container); // make sure that the current box is inside the category container
2102
+ box.move(container); // make sure that the new box is positioned after the currently visible box
2103
+ _expandStates[itemId] = _expandStateOption.EXPANDED;
2104
+ box.__hidingId = currentId;
2105
+ box.show(true); // instant show, not visible until current starts hiding.
2106
+
2107
+ current.events.onHideComplete.priorityAdd(hideCategoryComplete, [currentId, container]);
2108
+
2109
+ if (!$lib.isEmpty(currentId))
2110
+ _expandStates[currentId] = _expandStateOption.COLLAPSING;
2111
+
2112
+ current.hide(instant);
2113
+ }
2114
+ }
2115
+
2116
+ function setCategoryBoxDisplay(box, on)
2117
+ {
2118
+ var a = box.animation;
2119
+
2120
+ if (on)
2121
+ {
2122
+ a.showType = a.hideType = 3; // CSS
2123
+ $lib.addClass(box.element, _classOption.CATEGORY);
2124
+ box.autoFit = false;
2125
+ }
2126
+ else
2127
+ {
2128
+ a.showType = a.hideType = 0;
2129
+ $lib.removeClass(box.element, _classOption.CATEGORY);
2130
+ $lib.removeClass(_instance.element, _classOption.CATEGORY);
2131
+ }
2132
+ }
2133
+
2134
+ function showCategoryComplete(itemId, container, current, currentId)
2135
+ {
2136
+ var box = getItemBox(itemId);
2137
+
2138
+ if (!$lib.isEmpty(currentId))
2139
+ _expandStates[currentId] = _expandStateOption.COLLAPSED;
2140
+
2141
+ _expandStates[itemId] = _expandStateOption.EXPANDED;
2142
+ current.hide(true);
2143
+ setCategoryBoxDisplay(box);
2144
+ $lib.unsurround(container);
2145
+ box.events.onShowComplete.remove(showCategoryComplete);
2146
+ }
2147
+
2148
+ function hideCategoryComplete(itemId, container)
2149
+ {
2150
+ var box = getItemBox(itemId);
2151
+
2152
+ setCategoryBoxDisplay(box);
2153
+
2154
+ if (!$lib.isEmpty(itemId)) // remove root classes
2155
+ {
2156
+ $lib.removeClass(box.element, $lib.format('{0} {1} {2}', _classOption.ITEMGROUPROOT, _classOption.ITEMGROUPVISIBLEROOT, _classOption.HORIZONTALROOT));
2157
+ _expandStates[itemId] = _expandStateOption.COLLAPSED;
2158
+ }
2159
+
2160
+ $lib.unsurround(container);
2161
+ delete getItemBox(_categoryId).__hidingId;
2162
+ box.events.onHideComplete.remove(hideCategoryComplete);
2163
+ }
2164
+
2165
+ function disableItem(itemId, keepSelected)
2166
+ {
2167
+ var item = getItem(itemId),
2168
+ button = $UI.store[getItemId(itemId)];
2169
+
2170
+ if (!item)
2171
+ return;
2172
+
2173
+ if (item.selected && !keepSelected)
2174
+ deselectItem(item.id);
2175
+
2176
+ item.disabled = true;
2177
+
2178
+ if (button)
2179
+ button.disable();
2180
+ }
2181
+
2182
+ function enableItem(itemId)
2183
+ {
2184
+ var item = getItem(itemId),
2185
+ button = $UI.store[getItemId(itemId)];
2186
+
2187
+ if (!item)
2188
+ return;
2189
+
2190
+ item.disabled = false;
2191
+
2192
+ if (button)
2193
+ button.enable();
2194
+ }
2195
+
2196
+ function convertCommand(command)
2197
+ {
2198
+ return $base.static.getMethod(command);
2199
+ }
2200
+
2201
+ function updateParents(item, select)
2202
+ {
2203
+ var itemPath = loadItem(item.id);
2204
+
2205
+ if (!itemPath)
2206
+ return;
2207
+
2208
+ while (itemPath.hasParent())
2209
+ {
2210
+ item = itemPath.parent().item;
2211
+ var button = $UI.store[getItemId(item.id)],
2212
+ buttonEl = (button) ? button.element : null;
2213
+
2214
+ if (select)
2215
+ {
2216
+ item.selectedChild = true;
2217
+ $lib.addClass(buttonEl, _classOption.SELECTEDCHILD);
2218
+ }
2219
+ else
2220
+ {
2221
+ item.selectedChild = false;
2222
+ $lib.removeClass(buttonEl, _classOption.SELECTEDCHILD);
2223
+ }
2224
+ }
2225
+ }
2226
+
2227
+ function hasChildItems(item)
2228
+ {
2229
+ return (Boolean(item.hasChildItems) || !$lib.isEmpty(item.itemList));
2230
+ }
2231
+
2232
+ function dispose()
2233
+ {
2234
+ $lib.each(_instance.store, (id) =>
2235
+ {
2236
+ if ($UI.store[id])
2237
+ delete $UI.store[id].__menuItem;
2238
+ }); // remove custom item binding
2239
+
2240
+ // remove document event handlers
2241
+ $lib.off(document, 'mouseup', collapseAllDelayed);
2242
+ $lib.off(document, 'mouseup', allowance);
2243
+
2244
+ _instance.navigationManager?.destroy();
2245
+ _instance.navigationManager = null;
2246
+ _expandList = [];
2247
+ _expandStates = {};
2248
+ _hasDynamicGroup = false;
2249
+ _categoryId = _cachedExpand = _selectedItemId = _queuedExpandItemId = _currentExpandId = _expanderElement = null;
2250
+ _allowCollapse = _allowExpand = true;
2251
+ _collapseInstant = false;
2252
+ }
2253
+ };
2254
+
2255
+ /**
2256
+ * @see {@link componyx.UI.base.methods}
2257
+ */
2258
+ componyx.UI.Menu.prototype = Object.create($base.methods);
2259
+ componyx.UI.Menu.prototype.constructor = componyx.UI.Menu;
2260
+
2261
+ /**
2262
+ * ExpandDirectionOption
2263
+ * @readonly
2264
+ * @enum {number}
2265
+ */
2266
+ componyx.UI.Menu.ExpandDirectionOption =
2267
+ {
2268
+ DOWN: 0,
2269
+ RIGHT: 1,
2270
+ UP: 2,
2271
+ LEFT: 3,
2272
+
2273
+ getName: function (value) { return $base.static.getKeyByValue(this, value).toLowerCase(); }
2274
+ };
2275
+
2276
+ /**
2277
+ * TypeOption
2278
+ * @readonly
2279
+ * @enum {number}
2280
+ */
2281
+ componyx.UI.Menu.TypeOption =
2282
+ {
2283
+ COMMANDBUTTON: 0,
2284
+ CHECKBUTTON: 1,
2285
+ RADIOBUTTON: 2
2286
+ };
2287
+
2288
+ /**
2289
+ * ExpandOnClickOption
2290
+ * @readonly
2291
+ * @enum {number}
2292
+ */
2293
+ componyx.UI.Menu.ExpandOnClickOption =
2294
+ {
2295
+ ROOT: 0,
2296
+ ALWAYS: 1,
2297
+ NEVER: 2
2298
+ };
2299
+
2300
+ /**
2301
+ * CollapseTypeOption
2302
+ * @readonly
2303
+ * @enum {number}
2304
+ */
2305
+ componyx.UI.Menu.CollapseTypeOption =
2306
+ {
2307
+ /* collapse expanded items in cascade order */
2308
+ CASCADE: 0,
2309
+ /* collapse expanded items at current level, instant collapse (no animation) for deeper levels (option has no effect on collapse all action) */
2310
+ SINGLE: 1,
2311
+ /* collapse expanded items simultaneously */
2312
+ CONCURRENT: 2,
2313
+ /* instant collapse expanded items (no animation) */
2314
+ INSTANT: 3
2315
+ };
2316
+
2317
+ /**
2318
+ * Creates an instance of the Menu item.
2319
+ * @class
2320
+ * @param {Object} properties The properties used to initialize the object.
2321
+ * @property {String} cssClassItemGroup Gets or sets the css class of the child item-group.
2322
+ * @property {String} cssClassSubGroup Gets or sets the css class of a sub-group. Option has effect only when the subGroupId is specified.
2323
+ * @property {String} cssClassIcon Gets or sets the css class of the icon.
2324
+ * @property {String} style Gets or sets the css style of the item.
2325
+ * @property {String} itemGroupStyle Gets or sets the css style of the item-group.
2326
+ * @property {Boolean} hasIcon=false Gets or sets a value indicating if the item has an icon.
2327
+ * @property {String} iconURL Gets or sets the URL of the icon.
2328
+ * @property {TypeOption} type Gets or sets the item button type.
2329
+ * @property {String} href Gets or sets the href (hypertext reference) of the item. Applies to non-split buttons only.
2330
+ * @property {String} target Gets or sets the href target of the item. Applies to non-split buttons only.
2331
+ * @property {Function|String} command Gets or sets the command action of the item. A string wrapped function example: "app.section.doCommand".
2332
+ * @property {String} radioGroupId Gets or sets the id of the radio group to which this item belongs.
2333
+ * @property {String} subGroupId Gets or sets the id of the sub group (container) to which this item belongs. When provided, an HTML element will be created to serve as a container for all items with the same sub-group identifier
2334
+ * @property {ExpandDirectionOption} expandDirection Gets or sets the direction in which the menu item will expand it's children.
2335
+ * @property {Boolean} isCategory Gets or sets a value indicating that the item is a category. Child-items of a category are rendered as root-level navigation and are displayed when the category-item is selected (hiding the current root menu/category).
2336
+ * @property {Boolean} expandOnSelect Gets or sets a value indicating if a selectable item with child-items is expanded when selected.
2337
+ * @property {Boolean} collapseAllOnSelect Gets or sets a value indicating if all items are collapsed when an item is selected. Option has effect only when the corresponding item-group is not statically positioned.
2338
+ * @property {Boolean} expandable Gets or sets a value indicating if the item can be expanded/collapsed (true) or is always in expanded state (false). Option has effect only when the corresponding item-group is statically positioned.
2339
+ * @property {Boolean} expanded=false Gets or sets a value indicating if the item is initially expanded. Option has effect only when the item is expandable (otherwise child-items are always expanded) and the child-item list is loaded.
2340
+ * @property {Boolean} selectable=null Gets or sets a value indicating if the item is selectable. By default the item is selectable when there are no child-items or the item is a RADIO/CHECK-BUTTON type. Disable option when an item renders a template with no navigational purpose.
2341
+ * @property {Boolean} selectedChild=false Gets or sets a value indicating if a child-item is selected.
2342
+ * @property {Boolean} hasChildItems=false Gets or sets a value indicating if the item has children. Option has effect only when the child-items are loaded on demand.
2343
+ * @property {Number} expandDelay Gets or sets the delay in milliseconds before expanding a menu-item through a pointer-enter/leave event.
2344
+ * @property {String} buttonId Gets or sets the id of the base item button.
2345
+ * @property {String} itemGroupBoxId Gets or sets the id of the base item-group box.
2346
+ * @property {Item[]} itemList Gets or sets the child-item list of the item.
2347
+ * @augments componyx.UI.base.Item
2348
+ * @see {@link componyx.UI.base.Item}
2349
+ */
2350
+ componyx.UI.Menu.Item = function (properties)
2351
+ {
2352
+ this.cssClassItemGroup = '';
2353
+ this.cssClassSubGroup = '';
2354
+ this.cssClassIcon = '';
2355
+ this.style = '';
2356
+ this.itemGroupStyle = '';
2357
+ this.hasIcon = false;
2358
+ this.iconURL = null;
2359
+ this.type = componyx.UI.Menu.TypeOption.COMMANDBUTTON;
2360
+ this.href = null;
2361
+ this.target = null;
2362
+ this.command = null;
2363
+ this.radioGroupId = '';
2364
+ this.subGroupId = null;
2365
+ this.expandDirection = null;
2366
+ this.isCategory = null;
2367
+ this.expandOnSelect = null;
2368
+ this.collapseAllOnSelect = null;
2369
+ this.expandable = true;
2370
+ this.expanded = false;
2371
+ this.selectable = null;
2372
+ this.selectedChild = false;
2373
+ this.hasChildItems = false;
2374
+ this.expandDelay = null;
2375
+ this.itemGroupBoxId = null;
2376
+ this.buttonId = null;
2377
+ this.itemList = [];
2378
+
2379
+ $base.static.Item.call(this, properties);
2380
+ };
2381
+ })();
2382
+
2383
+
2384
+ const Menu = componyx.UI.Menu;
2385
+
2386
+ export { Menu };