@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.
- package/AppSkin/AppSkin.css +1268 -0
- package/AppSkin/AppSkin.js +2748 -0
- package/AppSkin/Themes/Default.css +241 -0
- package/Base/Base.js +3407 -0
- package/Base/ComponentIcons.css +66 -0
- package/Base/Font/ComponentIcons.woff +0 -0
- package/Base/Font/UI.woff +0 -0
- package/Base/Library.js +8432 -0
- package/Base/NavigationManager.js +462 -0
- package/Base/ResponsiveTemplates.js +371 -0
- package/Base/Sanitizer.js +288 -0
- package/Base/Themes/Default.css +255 -0
- package/Base/UI.css +618 -0
- package/Base/UIResourcePath.js +6 -0
- package/Bindary/Bindary.js +2011 -0
- package/Bindary/Modules/Connection.js +216 -0
- package/Bindary/Modules/Core.js +854 -0
- package/Bindary/Modules/DataUpdater.js +351 -0
- package/Bindary/Modules/ExpressionEngine.js +347 -0
- package/Bindary/Modules/ProxyManager.js +482 -0
- package/Bindary/Modules/Renderer.js +605 -0
- package/Bindary/Modules/Router.js +291 -0
- package/Bindary/Modules/Scroller.js +89 -0
- package/Bindary/Modules/Template.js +1273 -0
- package/BookmarkSpy/BookmarkSpy.js +430 -0
- package/Box/Box.css +36 -0
- package/Box/Box.js +1685 -0
- package/Button/Button.css +470 -0
- package/Button/Button.js +1398 -0
- package/Button/Themes/Default.css +200 -0
- package/Carousel/Carousel.css +273 -0
- package/Carousel/Carousel.js +607 -0
- package/ColorButton/ColorButton.css +39 -0
- package/ColorButton/ColorButton.js +336 -0
- package/ColorPicker/ColorPicker.css +359 -0
- package/ColorPicker/ColorPicker.js +972 -0
- package/ComboBox/ComboBox.css +357 -0
- package/ComboBox/ComboBox.js +2342 -0
- package/ComboBox/Themes/Default.css +23 -0
- package/DataPager/DataPager.css +72 -0
- package/DataPager/DataPager.js +674 -0
- package/DatePicker/DatePicker.css +227 -0
- package/DatePicker/DatePicker.js +1531 -0
- package/DatePicker/Themes/Default.css +26 -0
- package/Dialog/Dialog.css +106 -0
- package/Dialog/Dialog.js +572 -0
- package/Dialog/Themes/Default.css +10 -0
- package/Editor/Data/Emoji.json +8285 -0
- package/Editor/Data/Special.json +1042 -0
- package/Editor/Editor.css +1562 -0
- package/Editor/Editor.js +4058 -0
- package/Editor/Font/Editor.woff +0 -0
- package/Editor/Modules/ComponentFactory.js +565 -0
- package/Editor/Modules/ContentManager.js +748 -0
- package/Editor/Modules/DialogManager.js +1234 -0
- package/Editor/Modules/EventManager.js +458 -0
- package/Editor/Modules/Format.js +950 -0
- package/Editor/Modules/History.js +191 -0
- package/Editor/Modules/LayoutState.js +379 -0
- package/Editor/Modules/ListManager.js +296 -0
- package/Editor/Modules/MenuManager.js +388 -0
- package/Editor/Modules/NodeManager.js +681 -0
- package/Editor/Modules/ParagraphButtons.js +122 -0
- package/Editor/Modules/Resizer.js +176 -0
- package/Editor/Modules/SelectionRange.js +564 -0
- package/Editor/Modules/SourceViewBuilder.js +212 -0
- package/Editor/Modules/SymbolPicker.js +208 -0
- package/Editor/Modules/Table.js +2327 -0
- package/Editor/Modules/TableDialog.js +757 -0
- package/Editor/Modules/Toolbar.js +375 -0
- package/Editor/Modules/TooltipMenu.js +125 -0
- package/Editor/Modules/Utility.js +131 -0
- package/Editor/Themes/Default.css +204 -0
- package/FileUpload/FileUpload.css +156 -0
- package/FileUpload/FileUpload.js +898 -0
- package/FileUpload/Themes/Default.css +17 -0
- package/Form/Form.css +1934 -0
- package/Form/Form.js +4943 -0
- package/Form/Modules/ActionManager.js +368 -0
- package/Form/Modules/BuildPanelManager.js +319 -0
- package/Form/Modules/ComponentFactory.js +468 -0
- package/Form/Modules/ComponentPanel.js +265 -0
- package/Form/Modules/ConfigPanelManager.js +685 -0
- package/Form/Modules/DataBinder.js +602 -0
- package/Form/Modules/DataObserver.js +717 -0
- package/Form/Modules/Draggable.js +756 -0
- package/Form/Modules/OptionsPanel.js +342 -0
- package/Form/Modules/Renderer.js +1889 -0
- package/Form/Modules/RuleEngine.js +585 -0
- package/Form/Modules/RulesPanel.js +1158 -0
- package/Form/Modules/Types.js +1709 -0
- package/Form/Modules/ValidationManager.js +194 -0
- package/Form/Themes/Default.css +216 -0
- package/FormField/FormField.css +468 -0
- package/FormField/FormField.js +576 -0
- package/FormField/Themes/Default.css +99 -0
- package/Grid/Grid.css +544 -0
- package/Grid/Grid.js +3761 -0
- package/Grid/Themes/Default.css +43 -0
- package/LICENSE +126 -0
- package/MaskedTextBox/MaskedTextBox.css +28 -0
- package/MaskedTextBox/MaskedTextBox.js +642 -0
- package/MaskedTextBox/Themes/Default.css +6 -0
- package/Menu/Menu.css +328 -0
- package/Menu/Menu.js +2386 -0
- package/Menu/Themes/Default.css +24 -0
- package/NumericBox/NumericBox.css +120 -0
- package/NumericBox/NumericBox.js +984 -0
- package/PanelBar/PanelBar.css +123 -0
- package/PanelBar/PanelBar.js +505 -0
- package/PanelBar/Themes/Default.css +51 -0
- package/PieChart/PieChart.css +95 -0
- package/PieChart/PieChart.js +820 -0
- package/PieChart/Themes/Default.css +9 -0
- package/README.md +178 -3
- package/Slider/Slider.css +348 -0
- package/Slider/Slider.js +1306 -0
- package/Slider/Themes/Default.css +44 -0
- package/TabStrip/TabStrip.css +52 -0
- package/TabStrip/TabStrip.js +362 -0
- package/TabStrip/Themes/Default.css +35 -0
- package/TimePicker/Themes/Default.css +30 -0
- package/TimePicker/TimePicker.css +253 -0
- package/TimePicker/TimePicker.js +1485 -0
- package/TooltipManager/Themes/Default.css +21 -0
- package/TooltipManager/TooltipManager.css +227 -0
- package/TooltipManager/TooltipManager.js +791 -0
- package/Validator/Validator.css +54 -0
- package/Validator/Validator.js +2508 -0
- package/componyx.html-data.json +619 -0
- package/index.js +27 -0
- package/package.json +43 -4
- package/types/AppSkin.d.ts +842 -0
- package/types/Base.d.ts +1034 -0
- package/types/Bindary.d.ts +1196 -0
- package/types/BookmarkSpy.d.ts +112 -0
- package/types/Box.d.ts +374 -0
- package/types/Button.d.ts +455 -0
- package/types/Carousel.d.ts +136 -0
- package/types/ColorButton.d.ts +120 -0
- package/types/ColorPicker.d.ts +225 -0
- package/types/ComboBox.d.ts +507 -0
- package/types/DataPager.d.ts +152 -0
- package/types/DatePicker.d.ts +354 -0
- package/types/Dialog.d.ts +160 -0
- package/types/Editor.d.ts +1289 -0
- package/types/FileUpload.d.ts +206 -0
- package/types/Form.d.ts +3078 -0
- package/types/FormField.d.ts +204 -0
- package/types/Grid.d.ts +911 -0
- package/types/Library.d.ts +1899 -0
- package/types/MaskedTextBox.d.ts +91 -0
- package/types/Menu.d.ts +577 -0
- package/types/NumericBox.d.ts +310 -0
- package/types/PanelBar.d.ts +223 -0
- package/types/PieChart.d.ts +224 -0
- package/types/ResponsiveTemplates.d.ts +108 -0
- package/types/Slider.d.ts +227 -0
- package/types/TabStrip.d.ts +185 -0
- package/types/TimePicker.d.ts +265 -0
- package/types/TooltipManager.d.ts +178 -0
- package/types/UI.d.ts +29 -0
- package/types/Validator.d.ts +653 -0
- package/types/index.d.ts +59 -0
- package/ui.css +11783 -0
- package/ui.js +79477 -0
- package/ui.min.css +138 -0
- package/ui.min.js +264 -0
- 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 };
|