@syncfusion/ej2-navigations 31.1.17 → 31.1.18
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/dist/ej2-navigations.min.js +1 -1
- package/dist/ej2-navigations.umd.min.js +1 -1
- package/dist/global/ej2-navigations.min.js +1 -1
- package/dist/global/index.d.ts +1 -1
- package/package.json +11 -64
- package/styles/bds-lite.css +2 -1
- package/styles/bds.css +2 -1
- package/styles/bootstrap-dark-lite.css +2 -1
- package/styles/bootstrap-dark.css +2 -1
- package/styles/bootstrap-lite.css +2 -1
- package/styles/bootstrap.css +2 -1
- package/styles/bootstrap4-lite.css +2 -1
- package/styles/bootstrap4.css +2 -1
- package/styles/bootstrap5-dark-lite.css +2 -1
- package/styles/bootstrap5-dark.css +2 -1
- package/styles/bootstrap5-lite.css +2 -1
- package/styles/bootstrap5.3-lite.css +2 -1
- package/styles/bootstrap5.3.css +2 -1
- package/styles/bootstrap5.css +2 -1
- package/styles/fabric-dark-lite.css +2 -1
- package/styles/fabric-dark.css +2 -1
- package/styles/fabric-lite.css +2 -1
- package/styles/fabric.css +2 -1
- package/styles/fluent-dark-lite.css +3 -2
- package/styles/fluent-dark.css +3 -2
- package/styles/fluent-lite.css +3 -2
- package/styles/fluent.css +3 -2
- package/styles/fluent2-lite.css +3 -2
- package/styles/fluent2.css +3 -2
- package/styles/highcontrast-light-lite.css +2 -1
- package/styles/highcontrast-light.css +2 -1
- package/styles/highcontrast-lite.css +2 -1
- package/styles/highcontrast.css +2 -1
- package/styles/material-dark-lite.css +2 -1
- package/styles/material-dark.css +2 -1
- package/styles/material-lite.css +2 -1
- package/styles/material.css +2 -1
- package/styles/material3-dark-lite.css +3 -2
- package/styles/material3-dark.css +3 -2
- package/styles/material3-lite.css +3 -2
- package/styles/material3.css +3 -2
- package/styles/menu/_bootstrap-dark-definition.scss +1 -0
- package/styles/menu/_bootstrap-definition.scss +1 -0
- package/styles/menu/_fluent-definition.scss +1 -1
- package/styles/menu/_fluent2-definition.scss +1 -1
- package/styles/menu/_layout.scss +7 -1
- package/styles/menu/_material3-definition.scss +1 -1
- package/styles/menu/bds.css +1 -0
- package/styles/menu/bootstrap-dark.css +1 -0
- package/styles/menu/bootstrap.css +1 -0
- package/styles/menu/bootstrap4.css +1 -0
- package/styles/menu/bootstrap5-dark.css +1 -0
- package/styles/menu/bootstrap5.3.css +1 -0
- package/styles/menu/bootstrap5.css +1 -0
- package/styles/menu/fabric-dark.css +1 -0
- package/styles/menu/fabric.css +1 -0
- package/styles/menu/fluent-dark.css +2 -1
- package/styles/menu/fluent.css +2 -1
- package/styles/menu/fluent2.css +2 -1
- package/styles/menu/highcontrast-light.css +1 -0
- package/styles/menu/highcontrast.css +1 -0
- package/styles/menu/material-dark.css +1 -0
- package/styles/menu/material.css +1 -0
- package/styles/menu/material3-dark.css +2 -1
- package/styles/menu/material3.css +2 -1
- package/styles/menu/tailwind-dark.css +1 -0
- package/styles/menu/tailwind.css +1 -0
- package/styles/menu/tailwind3.css +1 -0
- package/styles/tailwind-dark-lite.css +2 -1
- package/styles/tailwind-dark.css +2 -1
- package/styles/tailwind-lite.css +2 -1
- package/styles/tailwind.css +2 -1
- package/styles/tailwind3-lite.css +2 -1
- package/styles/tailwind3.css +2 -1
- package/styles/treeview/_layout.scss +1 -1
- package/styles/treeview/bds.css +1 -1
- package/styles/treeview/bootstrap-dark.css +1 -1
- package/styles/treeview/bootstrap.css +1 -1
- package/styles/treeview/bootstrap4.css +1 -1
- package/styles/treeview/bootstrap5-dark.css +1 -1
- package/styles/treeview/bootstrap5.3.css +1 -1
- package/styles/treeview/bootstrap5.css +1 -1
- package/styles/treeview/fabric-dark.css +1 -1
- package/styles/treeview/fabric.css +1 -1
- package/styles/treeview/fluent-dark.css +1 -1
- package/styles/treeview/fluent.css +1 -1
- package/styles/treeview/fluent2.css +1 -1
- package/styles/treeview/highcontrast-light.css +1 -1
- package/styles/treeview/highcontrast.css +1 -1
- package/styles/treeview/material-dark.css +1 -1
- package/styles/treeview/material.css +1 -1
- package/styles/treeview/material3-dark.css +1 -1
- package/styles/treeview/material3.css +1 -1
- package/styles/treeview/tailwind-dark.css +1 -1
- package/styles/treeview/tailwind.css +1 -1
- package/styles/treeview/tailwind3.css +1 -1
- package/dist/ts/accordion/accordion-model.d.ts +0 -285
- package/dist/ts/accordion/accordion.d.ts +0 -458
- package/dist/ts/accordion/accordion.ts +0 -1580
- package/dist/ts/accordion/index.d.ts +0 -5
- package/dist/ts/accordion/index.ts +0 -5
- package/dist/ts/appbar/appbar-model.d.ts +0 -76
- package/dist/ts/appbar/appbar.d.ts +0 -115
- package/dist/ts/appbar/appbar.ts +0 -281
- package/dist/ts/appbar/index.d.ts +0 -3
- package/dist/ts/appbar/index.ts +0 -3
- package/dist/ts/breadcrumb/breadcrumb-model.d.ts +0 -170
- package/dist/ts/breadcrumb/breadcrumb.d.ts +0 -297
- package/dist/ts/breadcrumb/breadcrumb.ts +0 -959
- package/dist/ts/breadcrumb/index.d.ts +0 -5
- package/dist/ts/breadcrumb/index.ts +0 -5
- package/dist/ts/carousel/carousel-model.d.ts +0 -282
- package/dist/ts/carousel/carousel.d.ts +0 -439
- package/dist/ts/carousel/carousel.ts +0 -1633
- package/dist/ts/carousel/index.d.ts +0 -3
- package/dist/ts/carousel/index.ts +0 -3
- package/dist/ts/common/h-scroll-model.d.ts +0 -16
- package/dist/ts/common/h-scroll.d.ts +0 -105
- package/dist/ts/common/h-scroll.ts +0 -481
- package/dist/ts/common/index.d.ts +0 -9
- package/dist/ts/common/index.ts +0 -10
- package/dist/ts/common/menu-base-model.d.ts +0 -308
- package/dist/ts/common/menu-base.d.ts +0 -558
- package/dist/ts/common/menu-base.ts +0 -2736
- package/dist/ts/common/menu-scroll.d.ts +0 -29
- package/dist/ts/common/menu-scroll.ts +0 -105
- package/dist/ts/common/v-scroll-model.d.ts +0 -16
- package/dist/ts/common/v-scroll.d.ts +0 -106
- package/dist/ts/common/v-scroll.ts +0 -454
- package/dist/ts/context-menu/context-menu-model.d.ts +0 -47
- package/dist/ts/context-menu/context-menu.d.ts +0 -102
- package/dist/ts/context-menu/context-menu.ts +0 -165
- package/dist/ts/context-menu/index.d.ts +0 -5
- package/dist/ts/context-menu/index.ts +0 -5
- package/dist/ts/index.d.ts +0 -16
- package/dist/ts/index.ts +0 -16
- package/dist/ts/menu/index.d.ts +0 -5
- package/dist/ts/menu/index.ts +0 -5
- package/dist/ts/menu/menu-model.d.ts +0 -70
- package/dist/ts/menu/menu.d.ts +0 -127
- package/dist/ts/menu/menu.ts +0 -313
- package/dist/ts/sidebar/index.d.ts +0 -5
- package/dist/ts/sidebar/index.ts +0 -5
- package/dist/ts/sidebar/sidebar-model.d.ts +0 -200
- package/dist/ts/sidebar/sidebar.d.ts +0 -336
- package/dist/ts/sidebar/sidebar.ts +0 -907
- package/dist/ts/stepper/index.d.ts +0 -3
- package/dist/ts/stepper/index.ts +0 -3
- package/dist/ts/stepper/stepper-model.d.ts +0 -159
- package/dist/ts/stepper/stepper.d.ts +0 -381
- package/dist/ts/stepper/stepper.ts +0 -1350
- package/dist/ts/stepper-base/index.d.ts +0 -5
- package/dist/ts/stepper-base/index.ts +0 -6
- package/dist/ts/stepper-base/stepper-base-model.d.ts +0 -124
- package/dist/ts/stepper-base/stepper-base.d.ts +0 -187
- package/dist/ts/stepper-base/stepper-base.ts +0 -290
- package/dist/ts/tab/index.d.ts +0 -5
- package/dist/ts/tab/index.ts +0 -5
- package/dist/ts/tab/tab-model.d.ts +0 -408
- package/dist/ts/tab/tab.d.ts +0 -715
- package/dist/ts/tab/tab.ts +0 -2842
- package/dist/ts/toolbar/index.d.ts +0 -5
- package/dist/ts/toolbar/index.ts +0 -5
- package/dist/ts/toolbar/toolbar-model.d.ts +0 -294
- package/dist/ts/toolbar/toolbar.d.ts +0 -541
- package/dist/ts/toolbar/toolbar.ts +0 -2646
- package/dist/ts/treeview/index.d.ts +0 -5
- package/dist/ts/treeview/index.ts +0 -5
- package/dist/ts/treeview/treeview-model.d.ts +0 -637
- package/dist/ts/treeview/treeview.d.ts +0 -1518
- package/dist/ts/treeview/treeview.ts +0 -6780
|
@@ -1,2736 +0,0 @@
|
|
|
1
|
-
import { Component, Property, ChildProperty, NotifyPropertyChanges, INotifyPropertyChanged, AnimationModel, isBlazor } from '@syncfusion/ej2-base';
|
|
2
|
-
import { Event, EventHandler, EmitType, BaseEventArgs, KeyboardEvents, KeyboardEventArgs, Touch, TapEventArgs } from '@syncfusion/ej2-base';
|
|
3
|
-
import { Animation, AnimationOptions, TouchEventArgs, MouseEventArgs } from '@syncfusion/ej2-base';
|
|
4
|
-
import { Browser, Collection, setValue, getValue, getUniqueID, getInstance, isNullOrUndefined } from '@syncfusion/ej2-base';
|
|
5
|
-
import { select, selectAll, closest, detach, append, rippleEffect, isVisible, Complex, addClass, removeClass } from '@syncfusion/ej2-base';
|
|
6
|
-
import { ListBase, ListBaseOptions } from '@syncfusion/ej2-lists';
|
|
7
|
-
import { getZindexPartial, calculatePosition, OffsetPosition, isCollide, fit, Popup } from '@syncfusion/ej2-popups';
|
|
8
|
-
import { SanitizeHtmlHelper } from '@syncfusion/ej2-base';
|
|
9
|
-
import { getScrollableParent } from '@syncfusion/ej2-popups';
|
|
10
|
-
import { MenuItemModel, MenuBaseModel, FieldSettingsModel, MenuAnimationSettingsModel } from './menu-base-model';
|
|
11
|
-
import { HScroll } from '../common/h-scroll';
|
|
12
|
-
import { VScroll } from '../common/v-scroll';
|
|
13
|
-
import { addScrolling, destroyScroll } from '../common/menu-scroll';
|
|
14
|
-
|
|
15
|
-
type objColl = { [key: string]: Object }[];
|
|
16
|
-
type obj = { [key: string]: Object };
|
|
17
|
-
|
|
18
|
-
const ENTER: string = 'enter';
|
|
19
|
-
|
|
20
|
-
const ESCAPE: string = 'escape';
|
|
21
|
-
|
|
22
|
-
const FOCUSED: string = 'e-focused';
|
|
23
|
-
|
|
24
|
-
const HEADER: string = 'e-menu-header';
|
|
25
|
-
|
|
26
|
-
const SELECTED: string = 'e-selected';
|
|
27
|
-
|
|
28
|
-
const SEPARATOR: string = 'e-separator';
|
|
29
|
-
|
|
30
|
-
const UPARROW: string = 'uparrow';
|
|
31
|
-
|
|
32
|
-
const DOWNARROW: string = 'downarrow';
|
|
33
|
-
|
|
34
|
-
const LEFTARROW: string = 'leftarrow';
|
|
35
|
-
|
|
36
|
-
const RIGHTARROW: string = 'rightarrow';
|
|
37
|
-
|
|
38
|
-
const HOME: string = 'home';
|
|
39
|
-
|
|
40
|
-
const END: string = 'end';
|
|
41
|
-
|
|
42
|
-
const TAB: string = 'tab';
|
|
43
|
-
|
|
44
|
-
const CARET: string = 'e-caret';
|
|
45
|
-
|
|
46
|
-
const ITEM: string = 'e-menu-item';
|
|
47
|
-
|
|
48
|
-
const DISABLED: string = 'e-disabled';
|
|
49
|
-
|
|
50
|
-
const HIDE: string = 'e-menu-hide';
|
|
51
|
-
|
|
52
|
-
const ICONS: string = 'e-icons';
|
|
53
|
-
|
|
54
|
-
const RTL: string = 'e-rtl';
|
|
55
|
-
|
|
56
|
-
const POPUP: string = 'e-menu-popup';
|
|
57
|
-
|
|
58
|
-
const TEMPLATE_PROPERTY: string = 'Template';
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Defines the different types of options available for opening a submenu.
|
|
62
|
-
* ```props
|
|
63
|
-
* Auto - The submenu opens automatically when clicked or hovered over, depending on the 'showItemOnClick' property.
|
|
64
|
-
* Click - The submenu opens when clicked the menu item.
|
|
65
|
-
* Hover - The submenu opens when the user hovers over the menu item with the mouse cursor.
|
|
66
|
-
* ```
|
|
67
|
-
*/
|
|
68
|
-
export type MenuOpenType = 'Auto' | 'Click' | 'Hover';
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Defines the different types of animation effects available for opening the sub menu.
|
|
72
|
-
* ```props
|
|
73
|
-
* None - The sub menu is opened / closed without any animation effect.
|
|
74
|
-
* SlideDown - The submenu is opened / closed with a slide down effect.
|
|
75
|
-
* ZoomIn - The submenu is opened / closed with a zoom in effect.
|
|
76
|
-
* FadeIn - The sub menu is opened / closed with a fade in effect.
|
|
77
|
-
* ```
|
|
78
|
-
*/
|
|
79
|
-
export type MenuEffect = 'None' | 'SlideDown' | 'ZoomIn' | 'FadeIn';
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* Configures the field options of the Menu.
|
|
83
|
-
*/
|
|
84
|
-
export class FieldSettings extends ChildProperty<FieldSettings> {
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Specifies the itemId field for Menu item.
|
|
88
|
-
*
|
|
89
|
-
* @default 'id'
|
|
90
|
-
*/
|
|
91
|
-
@Property('id')
|
|
92
|
-
public itemId: string | string[];
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Specifies the parentId field for Menu item.
|
|
96
|
-
*
|
|
97
|
-
* @default 'parentId'
|
|
98
|
-
*/
|
|
99
|
-
@Property('parentId')
|
|
100
|
-
public parentId: string | string[];
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Specifies the text field for Menu item.
|
|
104
|
-
*
|
|
105
|
-
* @default 'text'
|
|
106
|
-
*/
|
|
107
|
-
@Property('text')
|
|
108
|
-
public text: string | string[];
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Specifies the css icon field for Menu item.
|
|
112
|
-
*
|
|
113
|
-
* @default 'iconCss'
|
|
114
|
-
*/
|
|
115
|
-
@Property('iconCss')
|
|
116
|
-
public iconCss: string | string[];
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Specifies the Url field for Menu item.
|
|
120
|
-
*
|
|
121
|
-
* @default 'url'
|
|
122
|
-
*/
|
|
123
|
-
@Property('url')
|
|
124
|
-
public url: string | string[];
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Specifies the separator field for Menu item.
|
|
128
|
-
*
|
|
129
|
-
* @default 'separator'
|
|
130
|
-
*/
|
|
131
|
-
@Property('separator')
|
|
132
|
-
public separator: string | string[];
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Specifies the children field for Menu item.
|
|
136
|
-
*
|
|
137
|
-
* @default 'items'
|
|
138
|
-
*/
|
|
139
|
-
@Property('items')
|
|
140
|
-
public children: string | string[];
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Specifies menu items.
|
|
145
|
-
*/
|
|
146
|
-
export class MenuItem extends ChildProperty<MenuItem> {
|
|
147
|
-
/**
|
|
148
|
-
* Defines class/multiple classes separated by a space for the menu Item that is used to include an icon.
|
|
149
|
-
* Menu Item can include font icon and sprite image.
|
|
150
|
-
*
|
|
151
|
-
* @default null
|
|
152
|
-
*/
|
|
153
|
-
@Property(null)
|
|
154
|
-
public iconCss: string;
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Specifies the id for menu item.
|
|
158
|
-
*
|
|
159
|
-
* @default ''
|
|
160
|
-
*/
|
|
161
|
-
@Property('')
|
|
162
|
-
public id: string;
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Specifies separator between the menu items. Separator are either horizontal or vertical lines used to group menu items.
|
|
166
|
-
*
|
|
167
|
-
* @default false
|
|
168
|
-
*/
|
|
169
|
-
@Property(false)
|
|
170
|
-
public separator: boolean;
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Specifies the sub menu items that is the array of MenuItem model.
|
|
174
|
-
*
|
|
175
|
-
* @default []
|
|
176
|
-
*/
|
|
177
|
-
@Collection<MenuItemModel>([], MenuItem)
|
|
178
|
-
public items: MenuItemModel[];
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Specifies text for menu item.
|
|
182
|
-
*
|
|
183
|
-
* @default ''
|
|
184
|
-
*/
|
|
185
|
-
@Property('')
|
|
186
|
-
public text: string;
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Specifies url for menu item that creates the anchor link to navigate to the url provided.
|
|
190
|
-
*
|
|
191
|
-
* @default ''
|
|
192
|
-
*/
|
|
193
|
-
@Property('')
|
|
194
|
-
public url: string;
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Specifies the htmlAttributes property to support adding custom attributes to the menu items in the menu component.
|
|
198
|
-
*
|
|
199
|
-
* @default null
|
|
200
|
-
*/
|
|
201
|
-
@Property()
|
|
202
|
-
public htmlAttributes: Record<string, string>;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Animation configuration settings.
|
|
207
|
-
*/
|
|
208
|
-
export class MenuAnimationSettings extends ChildProperty<MenuAnimationSettings> {
|
|
209
|
-
/**
|
|
210
|
-
* Specifies the effect that shown in the sub menu transform.
|
|
211
|
-
* The possible effects are:
|
|
212
|
-
* * None: Specifies the sub menu transform with no animation effect.
|
|
213
|
-
* * SlideDown: Specifies the sub menu transform with slide down effect.
|
|
214
|
-
* * ZoomIn: Specifies the sub menu transform with zoom in effect.
|
|
215
|
-
* * FadeIn: Specifies the sub menu transform with fade in effect.
|
|
216
|
-
*
|
|
217
|
-
* @default 'SlideDown'
|
|
218
|
-
* @aspType Syncfusion.EJ2.Navigations.MenuEffect
|
|
219
|
-
* @blazorType Syncfusion.EJ2.Navigations.MenuEffect
|
|
220
|
-
* @isEnumeration true
|
|
221
|
-
*/
|
|
222
|
-
@Property('SlideDown')
|
|
223
|
-
public effect: MenuEffect;
|
|
224
|
-
/**
|
|
225
|
-
* Specifies the time duration to transform object.
|
|
226
|
-
*
|
|
227
|
-
* @default 400
|
|
228
|
-
*/
|
|
229
|
-
@Property(400)
|
|
230
|
-
public duration: number;
|
|
231
|
-
/**
|
|
232
|
-
* Specifies the easing effect applied while transform.
|
|
233
|
-
*
|
|
234
|
-
* @default 'ease'
|
|
235
|
-
*/
|
|
236
|
-
@Property('ease')
|
|
237
|
-
public easing: string;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Base class for Menu and ContextMenu components.
|
|
242
|
-
*
|
|
243
|
-
* @private
|
|
244
|
-
*/
|
|
245
|
-
@NotifyPropertyChanges
|
|
246
|
-
export abstract class MenuBase extends Component<HTMLUListElement> implements INotifyPropertyChanged {
|
|
247
|
-
private clonedElement: HTMLElement;
|
|
248
|
-
private targetElement: HTMLElement;
|
|
249
|
-
private delegateClickHandler: Function;
|
|
250
|
-
private delegateMoverHandler: Function;
|
|
251
|
-
private delegateMouseDownHandler: Function;
|
|
252
|
-
private navIdx: number[] = [];
|
|
253
|
-
private animation: Animation = new Animation({});
|
|
254
|
-
private isTapHold: boolean = false;
|
|
255
|
-
protected isMenu: boolean;
|
|
256
|
-
protected hamburgerMode: boolean;
|
|
257
|
-
protected title: string;
|
|
258
|
-
private rippleFn: Function;
|
|
259
|
-
private uList: HTMLElement;
|
|
260
|
-
private lItem: Element;
|
|
261
|
-
private popupObj: Popup;
|
|
262
|
-
private popupWrapper: HTMLElement;
|
|
263
|
-
private isNestedOrVertical: boolean;
|
|
264
|
-
private top: number;
|
|
265
|
-
private left: number;
|
|
266
|
-
private keyType: string;
|
|
267
|
-
private showSubMenu: boolean;
|
|
268
|
-
private action: string;
|
|
269
|
-
private cli: Element;
|
|
270
|
-
private cliIdx: number;
|
|
271
|
-
private isClosed: boolean;
|
|
272
|
-
private liTrgt: Element;
|
|
273
|
-
private isMenusClosed: boolean;
|
|
274
|
-
private isContextMenuClosed: boolean;
|
|
275
|
-
private isCMenu: boolean;
|
|
276
|
-
private pageX: number;
|
|
277
|
-
private pageY: number;
|
|
278
|
-
private tempItem: objColl = [];
|
|
279
|
-
private showSubMenuOn: MenuOpenType = 'Auto';
|
|
280
|
-
private defaultOption: boolean;
|
|
281
|
-
private timer: number;
|
|
282
|
-
private currentTarget: Element;
|
|
283
|
-
private isCmenuHover: boolean;
|
|
284
|
-
private isAnimationNone: boolean = false;
|
|
285
|
-
private isKBDAction: boolean = false;
|
|
286
|
-
private touchStartFn: (e: TouchEvent) => void;
|
|
287
|
-
private touchMoveFn: (e: TouchEvent) => void;
|
|
288
|
-
/**
|
|
289
|
-
* Triggers while rendering each menu item.
|
|
290
|
-
*
|
|
291
|
-
* @event beforeItemRender
|
|
292
|
-
* @blazorProperty 'OnItemRender'
|
|
293
|
-
*/
|
|
294
|
-
@Event()
|
|
295
|
-
public beforeItemRender: EmitType<MenuEventArgs>;
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Triggers before opening the menu item.
|
|
299
|
-
*
|
|
300
|
-
* @event beforeOpen
|
|
301
|
-
* @blazorProperty 'OnOpen'
|
|
302
|
-
*/
|
|
303
|
-
@Event()
|
|
304
|
-
public beforeOpen: EmitType<BeforeOpenCloseMenuEventArgs>;
|
|
305
|
-
|
|
306
|
-
/**
|
|
307
|
-
* Triggers while opening the menu item.
|
|
308
|
-
*
|
|
309
|
-
* @event onOpen
|
|
310
|
-
* @blazorProperty 'Opened'
|
|
311
|
-
*/
|
|
312
|
-
@Event()
|
|
313
|
-
public onOpen: EmitType<OpenCloseMenuEventArgs>;
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Triggers before closing the menu.
|
|
317
|
-
*
|
|
318
|
-
* @event beforeClose
|
|
319
|
-
* @blazorProperty 'OnClose'
|
|
320
|
-
*/
|
|
321
|
-
@Event()
|
|
322
|
-
public beforeClose: EmitType<BeforeOpenCloseMenuEventArgs>;
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Triggers while closing the menu.
|
|
326
|
-
*
|
|
327
|
-
* @event onClose
|
|
328
|
-
* @blazorProperty 'Closed'
|
|
329
|
-
*/
|
|
330
|
-
@Event()
|
|
331
|
-
public onClose: EmitType<OpenCloseMenuEventArgs>;
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Triggers while selecting menu item.
|
|
335
|
-
*
|
|
336
|
-
* @event select
|
|
337
|
-
* @blazorProperty 'ItemSelected'
|
|
338
|
-
*/
|
|
339
|
-
@Event()
|
|
340
|
-
public select: EmitType<MenuEventArgs>;
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Triggers once the component rendering is completed.
|
|
344
|
-
*
|
|
345
|
-
* @event created
|
|
346
|
-
* @blazorProperty 'Created'
|
|
347
|
-
*/
|
|
348
|
-
@Event()
|
|
349
|
-
public created: EmitType<Event>;
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Defines class/multiple classes separated by a space in the Menu wrapper.
|
|
353
|
-
*
|
|
354
|
-
* @default ''
|
|
355
|
-
*/
|
|
356
|
-
@Property('')
|
|
357
|
-
public cssClass: string;
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* If hoverDelay is set by particular number, the menu will open after that period.
|
|
361
|
-
*
|
|
362
|
-
* @default 0
|
|
363
|
-
*/
|
|
364
|
-
@Property(0)
|
|
365
|
-
public hoverDelay: number;
|
|
366
|
-
|
|
367
|
-
/**
|
|
368
|
-
* Specifies whether to show the sub menu or not on click.
|
|
369
|
-
* When set to true, the sub menu will open only on mouse click.
|
|
370
|
-
*
|
|
371
|
-
* @default false
|
|
372
|
-
*/
|
|
373
|
-
@Property(false)
|
|
374
|
-
public showItemOnClick: boolean;
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Specifies target element selector in which the ContextMenu should be opened.
|
|
378
|
-
* Specifies target element to open/close Menu while click in Hamburger mode.
|
|
379
|
-
*
|
|
380
|
-
* @default ''
|
|
381
|
-
* @private
|
|
382
|
-
*/
|
|
383
|
-
@Property('')
|
|
384
|
-
public target: string;
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Specifies the filter selector for elements inside the target in that the context menu will be opened.
|
|
388
|
-
* Not applicable to Menu component.
|
|
389
|
-
*
|
|
390
|
-
* @default ''
|
|
391
|
-
* @private
|
|
392
|
-
*/
|
|
393
|
-
@Property('')
|
|
394
|
-
public filter: string;
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* Specifies the template for Menu item.
|
|
398
|
-
* Not applicable to ContextMenu component.
|
|
399
|
-
*
|
|
400
|
-
* @default null
|
|
401
|
-
* @aspType string
|
|
402
|
-
* @private
|
|
403
|
-
*/
|
|
404
|
-
@Property(null)
|
|
405
|
-
public template: string | Function;
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Specifies whether to enable / disable the scrollable option in Menu.
|
|
409
|
-
* Not applicable to ContextMenu component.
|
|
410
|
-
*
|
|
411
|
-
* @default false
|
|
412
|
-
* @private
|
|
413
|
-
*/
|
|
414
|
-
@Property(false)
|
|
415
|
-
public enableScrolling: boolean;
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Specifies whether to enable the rendering of untrusted HTML values in the Context Menu component.
|
|
419
|
-
* If 'enableHtmlSanitizer' set to true, the component will sanitize any suspected untrusted strings and scripts before rendering them.
|
|
420
|
-
*
|
|
421
|
-
* @default true
|
|
422
|
-
*/
|
|
423
|
-
@Property(true)
|
|
424
|
-
public enableHtmlSanitizer: boolean;
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Specifies mapping fields from the dataSource.
|
|
428
|
-
* Not applicable to ContextMenu component.
|
|
429
|
-
*
|
|
430
|
-
* @default { itemId: "id", text: "text", parentId: "parentId", iconCss: "iconCss", url: "url", separator: "separator",
|
|
431
|
-
* children: "items" }
|
|
432
|
-
* @private
|
|
433
|
-
*/
|
|
434
|
-
// eslint:disable-next-line
|
|
435
|
-
@Complex<FieldSettingsModel>({ itemId: 'id', text: 'text', parentId: 'parentId', iconCss: 'iconCss', url: 'url', separator: 'separator', children: 'items' }, FieldSettings)
|
|
436
|
-
public fields: FieldSettingsModel;
|
|
437
|
-
|
|
438
|
-
/**
|
|
439
|
-
* Specifies menu items with its properties which will be rendered as Menu.
|
|
440
|
-
*
|
|
441
|
-
* @default []
|
|
442
|
-
*/
|
|
443
|
-
@Collection<MenuItemModel>([], MenuItem)
|
|
444
|
-
public items: MenuItemModel[] | { [key: string]: Object }[];
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* Specifies the animation settings for the sub menu open.
|
|
448
|
-
*
|
|
449
|
-
* @default { duration: 400, easing: 'ease', effect: 'SlideDown' }
|
|
450
|
-
*/
|
|
451
|
-
@Complex<MenuAnimationSettingsModel>({ duration: 400, easing: 'ease', effect: 'SlideDown' }, MenuAnimationSettings)
|
|
452
|
-
public animationSettings: MenuAnimationSettingsModel;
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Constructor for creating the widget.
|
|
456
|
-
*
|
|
457
|
-
* @private
|
|
458
|
-
* @param {MenuBaseModel} options - Specifies the menu base model
|
|
459
|
-
* @param {string | HTMLUListElement} element - Specifies the element
|
|
460
|
-
*/
|
|
461
|
-
constructor(options?: MenuBaseModel, element?: string | HTMLUListElement) {
|
|
462
|
-
super(options, <HTMLUListElement | string>element);
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
/**
|
|
466
|
-
* Initialized third party configuration settings.
|
|
467
|
-
*
|
|
468
|
-
* @private
|
|
469
|
-
* @returns {void}
|
|
470
|
-
*/
|
|
471
|
-
protected preRender(): void {
|
|
472
|
-
if (!this.isMenu) {
|
|
473
|
-
let ul: HTMLUListElement;
|
|
474
|
-
if (this.element.tagName === 'EJS-CONTEXTMENU') {
|
|
475
|
-
ul = this.createElement('ul', {
|
|
476
|
-
id: getUniqueID(this.getModuleName()), className: 'e-control e-lib e-' + this.getModuleName() }) as HTMLUListElement;
|
|
477
|
-
const ejInst: Object = getValue('ej2_instances', this.element);
|
|
478
|
-
removeClass([this.element], ['e-control', 'e-lib', 'e-' + this.getModuleName()]);
|
|
479
|
-
this.clonedElement = this.element; this.element = ul;
|
|
480
|
-
setValue('ej2_instances', ejInst, this.element);
|
|
481
|
-
} else {
|
|
482
|
-
ul = this.createElement('ul', { id: getUniqueID(this.getModuleName()) }) as HTMLUListElement;
|
|
483
|
-
append([].slice.call((this.element.cloneNode(true) as Element).children), ul);
|
|
484
|
-
const refEle: Element = this.element.nextElementSibling;
|
|
485
|
-
if (refEle) {
|
|
486
|
-
this.element.parentElement.insertBefore(ul, refEle);
|
|
487
|
-
} else {
|
|
488
|
-
this.element.parentElement.appendChild(ul);
|
|
489
|
-
}
|
|
490
|
-
this.clonedElement = ul;
|
|
491
|
-
}
|
|
492
|
-
this.clonedElement.style.display = 'none';
|
|
493
|
-
}
|
|
494
|
-
if (this.element.tagName === 'EJS-MENU') {
|
|
495
|
-
let ele: Element = this.element;
|
|
496
|
-
const ejInstance: Object = getValue('ej2_instances', ele);
|
|
497
|
-
const ul: Element = this.createElement('ul');
|
|
498
|
-
const wrapper: HTMLElement = this.createElement('EJS-MENU', { className: 'e-' + this.getModuleName() + '-wrapper' });
|
|
499
|
-
for (let idx: number = 0, len: number = ele.attributes.length; idx < len; idx++) {
|
|
500
|
-
ul.setAttribute(ele.attributes[idx as number].nodeName, ele.attributes[idx as number].nodeValue);
|
|
501
|
-
}
|
|
502
|
-
ele.parentNode.insertBefore(wrapper, ele);
|
|
503
|
-
detach(ele);
|
|
504
|
-
ele = ul;
|
|
505
|
-
wrapper.appendChild(ele);
|
|
506
|
-
setValue('ej2_instances', ejInstance, ele);
|
|
507
|
-
this.clonedElement = wrapper;
|
|
508
|
-
this.element = ele as HTMLUListElement;
|
|
509
|
-
if (!this.element.id) {
|
|
510
|
-
this.element.id = getUniqueID(this.getModuleName());
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* Initialize the control rendering.
|
|
517
|
-
*
|
|
518
|
-
* @private
|
|
519
|
-
* @returns {void}
|
|
520
|
-
*/
|
|
521
|
-
protected render(): void {
|
|
522
|
-
this.initialize();
|
|
523
|
-
this.renderItems();
|
|
524
|
-
this.wireEvents();
|
|
525
|
-
this.renderComplete();
|
|
526
|
-
const wrapper: HTMLElement = this.getWrapper() as HTMLElement;
|
|
527
|
-
// eslint-disable-next-line
|
|
528
|
-
if (this.template && this.enableScrolling && ((this as any).isReact || (this as any).isAngular)) {
|
|
529
|
-
requestAnimationFrame(() => {
|
|
530
|
-
addScrolling(this.createElement, wrapper, this.element, 'hscroll', this.enableRtl);
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
private enableTouchScroll(scrollList: HTMLElement): void {
|
|
536
|
-
let touchStartY: number = 0;
|
|
537
|
-
this.touchStartFn = (e: TouchEvent) => {
|
|
538
|
-
touchStartY = e.touches[0].clientY;
|
|
539
|
-
};
|
|
540
|
-
this.touchMoveFn = (e: TouchEvent) => {
|
|
541
|
-
const touchEndY: number = e.touches[0].clientY;
|
|
542
|
-
const touchDiff: number = touchStartY - touchEndY;
|
|
543
|
-
const atTop: boolean = scrollList.scrollTop === 0;
|
|
544
|
-
const atBottom: boolean = scrollList.scrollTop + scrollList.clientHeight === scrollList.scrollHeight;
|
|
545
|
-
if ((atTop && touchDiff < 0) || (atBottom && touchDiff > 0)) {
|
|
546
|
-
e.preventDefault();
|
|
547
|
-
}
|
|
548
|
-
touchStartY = touchEndY;
|
|
549
|
-
};
|
|
550
|
-
scrollList.addEventListener('touchstart', this.touchStartFn, { passive: false });
|
|
551
|
-
scrollList.addEventListener('touchmove', this.touchMoveFn, { passive: false });
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
private touchOutsideHandler(e: TouchEvent): void {
|
|
555
|
-
const target: Element = (e.target as Element);
|
|
556
|
-
if (!closest(target, '.e-' + this.getModuleName() + '-wrapper')) {
|
|
557
|
-
this.closeMenu();
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
protected initialize(): void {
|
|
562
|
-
let wrapper: Element = this.getWrapper();
|
|
563
|
-
if (!wrapper) {
|
|
564
|
-
wrapper = this.createElement('div', { className: 'e-' + this.getModuleName() + '-wrapper' });
|
|
565
|
-
if (this.isMenu) {
|
|
566
|
-
this.element.parentElement.insertBefore(wrapper, this.element);
|
|
567
|
-
} else {
|
|
568
|
-
document.body.appendChild(wrapper);
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
if (this.cssClass) {
|
|
572
|
-
addClass([wrapper], this.cssClass.replace(/\s+/g, ' ').trim().split(' '));
|
|
573
|
-
}
|
|
574
|
-
if (this.enableRtl) {
|
|
575
|
-
wrapper.classList.add(RTL);
|
|
576
|
-
}
|
|
577
|
-
wrapper.appendChild(this.element);
|
|
578
|
-
if (this.isMenu && this.hamburgerMode) {
|
|
579
|
-
if (!this.target) {
|
|
580
|
-
this.createHeaderContainer(wrapper);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
this.defaultOption = this.showItemOnClick;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
private renderItems(): void {
|
|
587
|
-
if (!(this.items as objColl).length) {
|
|
588
|
-
const items: { [key: string]: Object; }[] = ListBase.createJsonFromElement(this.element, { fields: { child: 'items' } });
|
|
589
|
-
this.setProperties({ items: items }, true);
|
|
590
|
-
if (isBlazor() && !this.isMenu) {
|
|
591
|
-
this.element = this.removeChildElement(this.element);
|
|
592
|
-
} else {
|
|
593
|
-
this.element.innerHTML = '';
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
const ul: Element = this.createItems(this.items as objColl);
|
|
597
|
-
append(Array.prototype.slice.call(ul.children), this.element);
|
|
598
|
-
this.element.classList.add('e-menu-parent');
|
|
599
|
-
if (this.isMenu) {
|
|
600
|
-
if (!this.hamburgerMode && this.element.classList.contains('e-vertical')) { this.setBlankIconStyle(this.element); }
|
|
601
|
-
if (this.enableScrolling) {
|
|
602
|
-
const wrapper: HTMLElement = this.getWrapper() as HTMLElement;
|
|
603
|
-
if (this.element.classList.contains('e-vertical')){
|
|
604
|
-
addScrolling(this.createElement, wrapper, this.element, 'vscroll', this.enableRtl);
|
|
605
|
-
} else {
|
|
606
|
-
addScrolling(this.createElement, wrapper, this.element, 'hscroll', this.enableRtl);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
} else {
|
|
610
|
-
this.element.parentElement.setAttribute('role', 'dialog');
|
|
611
|
-
this.element.parentElement.setAttribute('aria-label', 'context menu');
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
protected wireEvents(): void {
|
|
616
|
-
const wrapper: HTMLElement = this.getWrapper() as HTMLElement;
|
|
617
|
-
if (this.target) {
|
|
618
|
-
let target: HTMLElement;
|
|
619
|
-
const targetElems: HTMLElement[] = selectAll(this.target);
|
|
620
|
-
for (let i: number = 0, len: number = targetElems.length; i < len; i++) {
|
|
621
|
-
target = targetElems[i as number];
|
|
622
|
-
if (this.isMenu) {
|
|
623
|
-
EventHandler.add(target, 'click', this.menuHeaderClickHandler, this);
|
|
624
|
-
} else {
|
|
625
|
-
if (Browser.isIos) {
|
|
626
|
-
new Touch(target, { tapHold: this.touchHandler.bind(this) });
|
|
627
|
-
} else {
|
|
628
|
-
EventHandler.add(target, 'contextmenu', this.cmenuHandler, this);
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
this.targetElement = target;
|
|
633
|
-
if (!this.isMenu) {
|
|
634
|
-
EventHandler.add(this.targetElement, 'scroll', this.scrollHandler, this);
|
|
635
|
-
for (const parent of getScrollableParent(this.targetElement)) {
|
|
636
|
-
EventHandler.add(parent, 'scroll', this.scrollHandler, this);
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
if (!Browser.isDevice) {
|
|
641
|
-
this.delegateMoverHandler = this.moverHandler.bind(this);
|
|
642
|
-
this.delegateMouseDownHandler = this.mouseDownHandler.bind(this);
|
|
643
|
-
EventHandler.add(this.isMenu ? document : wrapper, 'mouseover', this.delegateMoverHandler, this);
|
|
644
|
-
EventHandler.add(document, 'mousedown', this.delegateMouseDownHandler, this);
|
|
645
|
-
EventHandler.add(document, 'keydown', this.domKeyHandler, this);
|
|
646
|
-
if (!this.isMenu && !this.target) {
|
|
647
|
-
EventHandler.add(document, 'scroll', this.scrollHandler, this);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
this.delegateClickHandler = this.clickHandler.bind(this);
|
|
651
|
-
EventHandler.add(document, 'click', this.delegateClickHandler, this);
|
|
652
|
-
this.wireKeyboardEvent(wrapper);
|
|
653
|
-
this.rippleFn = rippleEffect(wrapper, { selector: '.' + ITEM });
|
|
654
|
-
if (!this.isMenu && this.enableScrolling) {
|
|
655
|
-
this.enableTouchScroll(wrapper);
|
|
656
|
-
document.addEventListener('touchstart', this.touchOutsideHandler.bind(this), { passive: true });
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
private wireKeyboardEvent(element: HTMLElement): void {
|
|
661
|
-
const keyConfigs: { [key: string]: string; } = {
|
|
662
|
-
downarrow: DOWNARROW,
|
|
663
|
-
uparrow: UPARROW,
|
|
664
|
-
enter: ENTER,
|
|
665
|
-
leftarrow: LEFTARROW,
|
|
666
|
-
rightarrow: RIGHTARROW,
|
|
667
|
-
escape: ESCAPE
|
|
668
|
-
};
|
|
669
|
-
if (this.isMenu) {
|
|
670
|
-
keyConfigs.home = HOME;
|
|
671
|
-
keyConfigs.end = END;
|
|
672
|
-
keyConfigs.tab = TAB;
|
|
673
|
-
}
|
|
674
|
-
new KeyboardEvents(element, {
|
|
675
|
-
keyAction: this.keyBoardHandler.bind(this),
|
|
676
|
-
keyConfigs: keyConfigs
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
private mouseDownHandler(e: MouseEvent): void {
|
|
681
|
-
if (closest(e.target as Element, '.e-' + this.getModuleName() + '-wrapper') !== this.getWrapper()
|
|
682
|
-
&& (!closest(e.target as Element, '.e-' + this.getModuleName() + '-popup'))) {
|
|
683
|
-
this.closeMenu(this.isMenu ? null : this.navIdx.length, e);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
private keyHandler(e: KeyboardEvent): void {
|
|
688
|
-
if (e.keyCode === 38 || e.keyCode === 40) {
|
|
689
|
-
if (e.target && ((e.target as Element).classList.contains('e-contextmenu') || (e.target as Element).classList.contains('e-menu-item'))) {
|
|
690
|
-
e.preventDefault();
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
private domKeyHandler(e: KeyboardEventArgs): void {
|
|
696
|
-
if (e.keyCode === 27) {
|
|
697
|
-
if (this.isMenuVisible()) {
|
|
698
|
-
e.stopImmediatePropagation();
|
|
699
|
-
}
|
|
700
|
-
e.action = ESCAPE;
|
|
701
|
-
this.leftEscKeyHandler(e);
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
private keyBoardHandler(e: KeyboardEventArgs): void {
|
|
706
|
-
let actionName: string = '';
|
|
707
|
-
const trgt: Element = e.target as Element;
|
|
708
|
-
let actionNeeded: boolean = this.isMenu && !this.hamburgerMode && !this.element.classList.contains('e-vertical')
|
|
709
|
-
&& this.navIdx.length < 1;
|
|
710
|
-
e.preventDefault();
|
|
711
|
-
if (this.enableScrolling && e.keyCode === 13 && trgt.classList.contains('e-scroll-nav')) {
|
|
712
|
-
this.removeLIStateByClass([FOCUSED, SELECTED], [closest(trgt, '.e-' + this.getModuleName() + '-wrapper')]);
|
|
713
|
-
}
|
|
714
|
-
this.isKBDAction = true;
|
|
715
|
-
if (actionNeeded) {
|
|
716
|
-
switch (e.action) {
|
|
717
|
-
case RIGHTARROW:
|
|
718
|
-
actionName = RIGHTARROW;
|
|
719
|
-
e.action = DOWNARROW;
|
|
720
|
-
break;
|
|
721
|
-
case LEFTARROW:
|
|
722
|
-
actionName = LEFTARROW;
|
|
723
|
-
e.action = UPARROW;
|
|
724
|
-
break;
|
|
725
|
-
case DOWNARROW:
|
|
726
|
-
actionName = DOWNARROW;
|
|
727
|
-
e.action = RIGHTARROW;
|
|
728
|
-
break;
|
|
729
|
-
case UPARROW:
|
|
730
|
-
actionName = UPARROW;
|
|
731
|
-
e.action = '';
|
|
732
|
-
break;
|
|
733
|
-
}
|
|
734
|
-
} else if (this.enableRtl) {
|
|
735
|
-
switch (e.action) {
|
|
736
|
-
case LEFTARROW:
|
|
737
|
-
actionNeeded = true;
|
|
738
|
-
actionName = LEFTARROW;
|
|
739
|
-
e.action = RIGHTARROW;
|
|
740
|
-
break;
|
|
741
|
-
case RIGHTARROW:
|
|
742
|
-
actionNeeded = true;
|
|
743
|
-
actionName = RIGHTARROW;
|
|
744
|
-
e.action = LEFTARROW;
|
|
745
|
-
break;
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
switch (e.action) {
|
|
749
|
-
case DOWNARROW:
|
|
750
|
-
case UPARROW:
|
|
751
|
-
case END:
|
|
752
|
-
case HOME:
|
|
753
|
-
case TAB:
|
|
754
|
-
this.upDownKeyHandler(e);
|
|
755
|
-
break;
|
|
756
|
-
case RIGHTARROW:
|
|
757
|
-
this.rightEnterKeyHandler(e);
|
|
758
|
-
break;
|
|
759
|
-
case LEFTARROW:
|
|
760
|
-
this.leftEscKeyHandler(e);
|
|
761
|
-
break;
|
|
762
|
-
case ENTER:
|
|
763
|
-
if (this.hamburgerMode && trgt.tagName === 'SPAN' && trgt.classList.contains('e-menu-icon')) {
|
|
764
|
-
this.menuHeaderClickHandler(e);
|
|
765
|
-
} else {
|
|
766
|
-
this.rightEnterKeyHandler(e);
|
|
767
|
-
}
|
|
768
|
-
break;
|
|
769
|
-
}
|
|
770
|
-
if (this.isAnimationNone) {
|
|
771
|
-
this.isKBDAction = false;
|
|
772
|
-
}
|
|
773
|
-
if (actionNeeded) {
|
|
774
|
-
e.action = actionName;
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
private upDownKeyHandler(e: KeyboardEventArgs): void {
|
|
779
|
-
const cul: Element = this.getUlByNavIdx();
|
|
780
|
-
const defaultIdx: number = (e.action === DOWNARROW || e.action === HOME || e.action === TAB) ? 0 : cul.childElementCount - 1;
|
|
781
|
-
let fliIdx: number = defaultIdx;
|
|
782
|
-
const fli: Element = this.getLIByClass(cul, FOCUSED);
|
|
783
|
-
if (fli) {
|
|
784
|
-
if (e.action !== END && e.action !== HOME) {
|
|
785
|
-
fliIdx = this.getIdx(cul, fli);
|
|
786
|
-
}
|
|
787
|
-
fli.classList.remove(FOCUSED);
|
|
788
|
-
if (e.action !== END && e.action !== HOME) {
|
|
789
|
-
if (e.action === DOWNARROW) {
|
|
790
|
-
fliIdx++;
|
|
791
|
-
} else {
|
|
792
|
-
fliIdx--;
|
|
793
|
-
}
|
|
794
|
-
if (fliIdx === (e.action === DOWNARROW ? cul.childElementCount : -1)) {
|
|
795
|
-
fliIdx = defaultIdx;
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
const cli: Element = cul.children[fliIdx as number];
|
|
800
|
-
fliIdx = this.isValidLI(cli, fliIdx, e.action);
|
|
801
|
-
cul.children[fliIdx as number].classList.add(FOCUSED);
|
|
802
|
-
(cul.children[fliIdx as number] as HTMLElement).focus();
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
private isValidLI(cli: Element, index: number, action: string): number {
|
|
806
|
-
const cul: Element = this.getUlByNavIdx();
|
|
807
|
-
const defaultIdx: number = (action === DOWNARROW || action === HOME || action === TAB) ? 0 : cul.childElementCount - 1;
|
|
808
|
-
if (cli.classList.contains(SEPARATOR) || cli.classList.contains(DISABLED) || cli.classList.contains(HIDE)) {
|
|
809
|
-
if (action === DOWNARROW && index === cul.childElementCount - 1) {
|
|
810
|
-
index = defaultIdx;
|
|
811
|
-
} else if (action === UPARROW && index === 0) {
|
|
812
|
-
index = defaultIdx;
|
|
813
|
-
}
|
|
814
|
-
else if ((action === DOWNARROW) || (action === RIGHTARROW)) {
|
|
815
|
-
index++;
|
|
816
|
-
} else if (action === 'tab' && cli.classList.contains(SEPARATOR)) {
|
|
817
|
-
index++;
|
|
818
|
-
} else {
|
|
819
|
-
index--;
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
cli = cul.children[index as number];
|
|
823
|
-
if (cli && (cli.classList.contains(SEPARATOR) || cli.classList.contains(DISABLED) || cli.classList.contains(HIDE))) {
|
|
824
|
-
index = this.isValidLI(cli, index, action);
|
|
825
|
-
}
|
|
826
|
-
return index;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
private getUlByNavIdx(navIdxLen: number = this.navIdx.length): HTMLElement {
|
|
830
|
-
if (this.isMenu) {
|
|
831
|
-
let popup: Element = [this.getWrapper()].concat([].slice.call(selectAll('.' + POPUP)))[navIdxLen as number];
|
|
832
|
-
const popups: Element[] = [];
|
|
833
|
-
const allPopup: Element[] = selectAll('.' + POPUP);
|
|
834
|
-
allPopup.forEach((elem: Element) => {
|
|
835
|
-
if (this.element.id === elem.id.split('-')[2] || elem.id.split('-')[2] + '-' + elem.id.split('-')[3]) {
|
|
836
|
-
popups.push(elem);
|
|
837
|
-
}
|
|
838
|
-
});
|
|
839
|
-
popup = [this.getWrapper()].concat([].slice.call(popups))[navIdxLen as number];
|
|
840
|
-
return isNullOrUndefined(popup) ? null : select('.e-menu-parent', popup) as HTMLElement;
|
|
841
|
-
} else {
|
|
842
|
-
if (!document.body.contains(this.element) && navIdxLen === 0) { return null; }
|
|
843
|
-
return this.getWrapper().children[navIdxLen as number] as HTMLElement;
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
private rightEnterKeyHandler(e: KeyboardEventArgs): void {
|
|
848
|
-
let eventArgs: MenuEventArgs;
|
|
849
|
-
const cul: Element = this.getUlByNavIdx();
|
|
850
|
-
const fli: Element = this.getLIByClass(cul, FOCUSED);
|
|
851
|
-
if (fli) {
|
|
852
|
-
const fliIdx: number = this.getIdx(cul, fli);
|
|
853
|
-
const navIdx: number[] = this.navIdx.concat(fliIdx);
|
|
854
|
-
const item: MenuItemModel = this.getItem(navIdx);
|
|
855
|
-
if (item.items.length) {
|
|
856
|
-
this.navIdx.push(fliIdx);
|
|
857
|
-
this.keyType = 'right';
|
|
858
|
-
this.action = e.action;
|
|
859
|
-
this.openMenu(fli, item, -1, -1, e);
|
|
860
|
-
} else {
|
|
861
|
-
if (e.action === ENTER) {
|
|
862
|
-
if (this.isMenu && this.navIdx.length === 0) {
|
|
863
|
-
this.removeLIStateByClass([SELECTED], [this.getWrapper()]);
|
|
864
|
-
} else {
|
|
865
|
-
fli.classList.remove(FOCUSED);
|
|
866
|
-
}
|
|
867
|
-
fli.classList.add(SELECTED);
|
|
868
|
-
eventArgs = { element: fli as HTMLElement, item: item, event: e };
|
|
869
|
-
this.trigger('select', eventArgs);
|
|
870
|
-
const aEle: HTMLElement = fli.querySelector('.e-menu-url');
|
|
871
|
-
if (item.url && aEle) {
|
|
872
|
-
switch (aEle.getAttribute('target')) {
|
|
873
|
-
case '_blank':
|
|
874
|
-
window.open(item.url, '_blank');
|
|
875
|
-
break;
|
|
876
|
-
case '_parent':
|
|
877
|
-
window.parent.location.href = item.url;
|
|
878
|
-
break;
|
|
879
|
-
default:
|
|
880
|
-
window.location.href = item.url;
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
this.closeMenu(null, e);
|
|
884
|
-
const sli: Element = this.getLIByClass(this.getUlByNavIdx(), SELECTED);
|
|
885
|
-
if (sli) {
|
|
886
|
-
sli.classList.add(FOCUSED); (sli as HTMLElement).focus();
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
private leftEscKeyHandler(e: KeyboardEventArgs): void {
|
|
894
|
-
if (this.navIdx.length) {
|
|
895
|
-
this.keyType = 'left';
|
|
896
|
-
this.closeMenu(this.navIdx.length, e);
|
|
897
|
-
} else {
|
|
898
|
-
if (e.action === ESCAPE) {
|
|
899
|
-
this.closeMenu(null, e);
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
|
|
904
|
-
private scrollHandler(e: MouseEvent): void {
|
|
905
|
-
this.closeMenu(null, e);
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
private touchHandler(e: TapEventArgs): void {
|
|
909
|
-
this.isTapHold = true;
|
|
910
|
-
this.cmenuHandler(e.originalEvent);
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
private cmenuHandler(e: MouseEvent & (TouchEventArgs | MouseEventArgs)): void {
|
|
914
|
-
e.preventDefault();
|
|
915
|
-
this.currentTarget = e.target as Element;
|
|
916
|
-
this.isCMenu = true;
|
|
917
|
-
this.pageX = e.changedTouches ? e.changedTouches[0].pageX + 1 : e.pageX + 1;
|
|
918
|
-
this.pageY = e.changedTouches ? e.changedTouches[0].pageY + 1 : e.pageY + 1;
|
|
919
|
-
this.closeMenu(null, e);
|
|
920
|
-
if (this.isCMenu) {
|
|
921
|
-
if (this.canOpen(e.target as Element)) {
|
|
922
|
-
this.openMenu(null, null, this.pageY, this.pageX, e);
|
|
923
|
-
}
|
|
924
|
-
this.isCMenu = false;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
// eslint:disable-next-line:max-func-body-length
|
|
929
|
-
protected closeMenu(ulIndex: number = 0, e: MouseEvent | KeyboardEvent = null, isIterated?: boolean): void {
|
|
930
|
-
if (this.isMenuVisible()) {
|
|
931
|
-
let sli: Element; let item: MenuItemModel; const wrapper: Element = this.getWrapper();
|
|
932
|
-
let beforeCloseArgs: BeforeOpenCloseMenuEventArgs; let items: MenuItemModel[]; const popups: Element[] = this.getPopups();
|
|
933
|
-
let isClose: boolean = false; const cnt: number = this.isMenu ? popups.length + 1 : wrapper.childElementCount;
|
|
934
|
-
const ul: HTMLElement = this.isMenu && cnt !== 1 ? select('.e-ul', popups[cnt - 2]) as HTMLElement
|
|
935
|
-
: selectAll('.e-menu-parent', wrapper)[cnt - 1] as HTMLElement;
|
|
936
|
-
if (this.isMenu && ul.classList.contains('e-menu')) {
|
|
937
|
-
sli = this.getLIByClass(ul, SELECTED);
|
|
938
|
-
if (sli) {
|
|
939
|
-
sli.classList.remove(SELECTED);
|
|
940
|
-
}
|
|
941
|
-
isClose = true;
|
|
942
|
-
}
|
|
943
|
-
if (!isClose) {
|
|
944
|
-
const liElem: Element = e && e.target && this.getLI(e.target as Element);
|
|
945
|
-
if (liElem) {
|
|
946
|
-
this.cli = liElem;
|
|
947
|
-
} else {
|
|
948
|
-
this.cli = ul.children[0];
|
|
949
|
-
}
|
|
950
|
-
item = this.navIdx.length ? this.getItem(this.navIdx) : null; items = item ? item.items : this.items as objColl;
|
|
951
|
-
beforeCloseArgs = { element: ul, parentItem: item, items: items, event: e, cancel: false , isFocused: true };
|
|
952
|
-
this.trigger('beforeClose', beforeCloseArgs, (observedCloseArgs: BeforeOpenCloseMenuEventArgs) => {
|
|
953
|
-
let popupEle: HTMLElement; let closeArgs: OpenCloseMenuEventArgs; let popupId: string = '';
|
|
954
|
-
let popupObj: Popup; const isOpen: boolean = !observedCloseArgs.cancel;
|
|
955
|
-
if (isOpen || this.isCMenu) {
|
|
956
|
-
if (this.isMenu) {
|
|
957
|
-
popupEle = closest(ul, '.' + POPUP) as HTMLElement;
|
|
958
|
-
if (this.hamburgerMode) {
|
|
959
|
-
popupEle.parentElement.style.minHeight = '';
|
|
960
|
-
closest(ul, '.e-menu-item').setAttribute('aria-expanded', 'false');
|
|
961
|
-
}
|
|
962
|
-
this.unWireKeyboardEvent(popupEle);
|
|
963
|
-
destroyScroll(
|
|
964
|
-
getInstance(popupEle.children[0] as HTMLElement, VScroll) as VScroll, popupEle.children[0]);
|
|
965
|
-
popupObj = getInstance(popupEle, Popup) as Popup;
|
|
966
|
-
popupObj.hide(); popupId = popupEle.id; popupObj.destroy(); detach(popupEle);
|
|
967
|
-
} else {
|
|
968
|
-
this.isContextMenuClosed = false;
|
|
969
|
-
this.toggleAnimation(ul, false);
|
|
970
|
-
}
|
|
971
|
-
closeArgs = { element: ul, parentItem: item, items: items };
|
|
972
|
-
this.trigger('onClose', closeArgs); this.navIdx.pop();
|
|
973
|
-
if (this.navIdx.length === 0 && e && e.type === 'keyup') { this.showSubMenu = false; }
|
|
974
|
-
if (!this.isMenu) {
|
|
975
|
-
EventHandler.remove(ul, 'keydown', this.keyHandler);
|
|
976
|
-
if (this.keyType === 'right') {
|
|
977
|
-
this.keyType = '';
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
this.updateReactTemplate(); let trgtliId: string; let closedLi: Element; let trgtLi: Element;
|
|
982
|
-
const trgtpopUp: HTMLElement = this.getWrapper() && this.getUlByNavIdx();
|
|
983
|
-
if (this.isCMenu) {
|
|
984
|
-
if (this.canOpen(e.target as Element)) {
|
|
985
|
-
this.openMenu(null, null, this.pageY, this.pageX, e);
|
|
986
|
-
}
|
|
987
|
-
this.isCMenu = false;
|
|
988
|
-
}
|
|
989
|
-
if (this.isMenu && trgtpopUp && popupId.length) {
|
|
990
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
991
|
-
const regExp: any = RegExp;
|
|
992
|
-
trgtliId = new regExp('(.*)-ej2menu-' + this.element.id + '-popup').exec(popupId)[1];
|
|
993
|
-
closedLi = trgtpopUp.querySelector('[id="' + trgtliId + '"]');
|
|
994
|
-
trgtLi = (liElem && trgtpopUp.querySelector('[id="' + liElem.id + '"]'));
|
|
995
|
-
} else if (trgtpopUp) {
|
|
996
|
-
closedLi = trgtpopUp.querySelector('.e-menu-item.e-selected');
|
|
997
|
-
trgtLi = (liElem && trgtpopUp.querySelector('[id="' + liElem.id + '"]'));
|
|
998
|
-
}
|
|
999
|
-
const submenus: NodeListOf<Element> = liElem && liElem.querySelectorAll('.e-menu-item');
|
|
1000
|
-
if (isOpen && this.hamburgerMode && ulIndex && !(submenus.length)) {
|
|
1001
|
-
this.afterCloseMenu(e as MouseEvent);
|
|
1002
|
-
} else if (isOpen && !this.hamburgerMode && closedLi && !trgtLi && this.keyType !== 'left' && (this.navIdx.length || !this.isMenu && this.navIdx.length === 0) ) {
|
|
1003
|
-
let ele: HTMLElement = (e && (e.target as Element).classList && ((e.target as Element).classList.contains('e-vscroll') || (e.target as Element).classList.contains('e-scroll-nav')))
|
|
1004
|
-
? closest(e.target as Element, '.e-menu-wrapper') as HTMLElement : null;
|
|
1005
|
-
if (ele) {
|
|
1006
|
-
ele = ele.querySelector('.e-menu-item');
|
|
1007
|
-
if (this.showItemOnClick || (ele && this.getIndex(ele.id, true).length <= this.navIdx.length)) {
|
|
1008
|
-
this.closeMenu(this.navIdx[this.navIdx.length - 1], e, true);
|
|
1009
|
-
}
|
|
1010
|
-
} else {
|
|
1011
|
-
if (!(e && (e.target as Element).classList && (e.target as Element).classList.contains('e-nav-arrow'))) {
|
|
1012
|
-
this.closeMenu(this.navIdx[this.navIdx.length - 1], e);
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
} else if (isOpen && !isIterated && !ulIndex && ((this.hamburgerMode && this.navIdx.length) ||
|
|
1016
|
-
this.navIdx.length === 1 && liElem && trgtpopUp !== liElem.parentElement)) {
|
|
1017
|
-
this.closeMenu(null, e);
|
|
1018
|
-
} else if (isOpen && isNullOrUndefined(ulIndex) && this.navIdx.length) {
|
|
1019
|
-
this.closeMenu(null, e);
|
|
1020
|
-
} else if (isOpen && !this.isMenu && !ulIndex && this.navIdx.length === 0 &&
|
|
1021
|
-
!this.isMenusClosed && !this.isCmenuHover) {
|
|
1022
|
-
this.isMenusClosed = true;
|
|
1023
|
-
this.closeMenu(0, e);
|
|
1024
|
-
} else if (isOpen && this.isMenu && e && e.target &&
|
|
1025
|
-
this.navIdx.length !== 0 && closest(e.target as Element, '.e-menu-parent.e-control')) {
|
|
1026
|
-
this.closeMenu(0, e);
|
|
1027
|
-
} else if (isOpen && !this.isMenu && selectAll('.e-menu-parent', wrapper)[ulIndex - 1] && e.which === 3) {
|
|
1028
|
-
this.closeMenu(null, e);
|
|
1029
|
-
} else {
|
|
1030
|
-
if (isOpen && (this.keyType === 'right' || this.keyType === 'click')) {
|
|
1031
|
-
this.afterCloseMenu(e as MouseEvent);
|
|
1032
|
-
} else {
|
|
1033
|
-
const cul: Element = this.getUlByNavIdx(); const sli: Element = this.getLIByClass(cul, SELECTED);
|
|
1034
|
-
if (sli) {
|
|
1035
|
-
sli.setAttribute('aria-expanded', 'false'); sli.classList.remove(SELECTED);
|
|
1036
|
-
if (observedCloseArgs.isFocused && liElem || this.keyType === 'left') {
|
|
1037
|
-
sli.classList.add(FOCUSED);
|
|
1038
|
-
if ( !e.target || !(e.target as Element).classList.contains('e-edit-template')) {
|
|
1039
|
-
(sli as HTMLElement).focus();
|
|
1040
|
-
}
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
if (!isOpen && this.hamburgerMode && liElem && liElem.getAttribute('aria-expanded') === 'false' &&
|
|
1044
|
-
liElem.getAttribute('aria-haspopup') === 'true') {
|
|
1045
|
-
if (closest(liElem as Element, '.e-menu-parent.e-control')) {
|
|
1046
|
-
this.navIdx = [];
|
|
1047
|
-
} else {
|
|
1048
|
-
this.navIdx.pop();
|
|
1049
|
-
}
|
|
1050
|
-
this.navIdx.push(this.cliIdx); const item: MenuItemModel = this.getItem(this.navIdx);
|
|
1051
|
-
liElem.setAttribute('aria-expanded', 'true'); this.openMenu(liElem, item, -1, -1, e);
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
if (this.navIdx.length < 1) {
|
|
1055
|
-
if (this.showSubMenuOn === 'Hover' || this.showSubMenuOn === 'Click') {
|
|
1056
|
-
this.showItemOnClick = this.defaultOption; this.showSubMenuOn = 'Auto';
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
this.removeStateWrapper();
|
|
1061
|
-
});
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
private updateReactTemplate(): void {
|
|
1066
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1067
|
-
if ((this as any).isReact && this.template && this.navIdx.length === 0) {
|
|
1068
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1069
|
-
let portals: any;
|
|
1070
|
-
if (this.portals) {
|
|
1071
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1072
|
-
portals = (this as any).portals.splice(0, this.items.length);
|
|
1073
|
-
}
|
|
1074
|
-
this.clearTemplate(['template']);
|
|
1075
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1076
|
-
(this as any).portals = portals; this.renderReactTemplates();
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
private getMenuItemModel(item: obj, level: number): MenuItemModel {
|
|
1080
|
-
if (isNullOrUndefined(item)) { return null; }
|
|
1081
|
-
if (isNullOrUndefined(level)) { level = 0; }
|
|
1082
|
-
const fields: FieldsMap = this.getFields(level);
|
|
1083
|
-
return <MenuItemModel>{ text: item[fields.text], id: item[fields.id], items: item[fields.child], separator: item[fields.separator],
|
|
1084
|
-
iconCss: item[fields.iconCss], url: item[fields.url] };
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
private getPopups(): Element[] {
|
|
1088
|
-
const popups: Element[] = [];
|
|
1089
|
-
[].slice.call(document.querySelectorAll('.' + POPUP)).forEach((elem: Element) => {
|
|
1090
|
-
if (!isNullOrUndefined(elem.querySelector('.' + ITEM)) && this.getIndex(elem.querySelector('.' + ITEM).id, true).length) {
|
|
1091
|
-
popups.push(elem);
|
|
1092
|
-
}
|
|
1093
|
-
});
|
|
1094
|
-
return popups;
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
private isMenuVisible(): boolean {
|
|
1098
|
-
return (this.navIdx.length > 0 || (this.element.classList.contains('e-contextmenu') && isVisible(this.element).valueOf()));
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
private canOpen(target: Element): boolean {
|
|
1102
|
-
let canOpen: boolean = true;
|
|
1103
|
-
if (this.filter) {
|
|
1104
|
-
canOpen = false;
|
|
1105
|
-
const filter: string[] = this.filter.split(' ');
|
|
1106
|
-
for (let i: number = 0, len: number = filter.length; i < len; i++) {
|
|
1107
|
-
if (closest(target, '.' + filter[i as number])) {
|
|
1108
|
-
canOpen = true;
|
|
1109
|
-
break;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
return canOpen;
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
protected openMenu(
|
|
1117
|
-
li: Element, item: MenuItemModel | { [key: string]: Object }, top: number = 0, left: number = 0,
|
|
1118
|
-
e: MouseEvent | KeyboardEvent = null, target: HTMLElement = this.targetElement): void {
|
|
1119
|
-
const wrapper: Element = this.getWrapper();
|
|
1120
|
-
this.lItem = li; const elemId: string = this.element.id !== '' ? this.element.id : 'menu';
|
|
1121
|
-
this.isMenusClosed = false;
|
|
1122
|
-
if (isNullOrUndefined(top)) {
|
|
1123
|
-
top = -1;
|
|
1124
|
-
}
|
|
1125
|
-
if (isNullOrUndefined(left)) {
|
|
1126
|
-
left = -1;
|
|
1127
|
-
}
|
|
1128
|
-
if (li) {
|
|
1129
|
-
this.uList = this.createItems((<obj>item)[this.getField('children', this.navIdx.length - 1)] as objColl);
|
|
1130
|
-
if (!this.isMenu && Browser.isDevice) {
|
|
1131
|
-
(wrapper.lastChild as HTMLElement).style.display = 'none';
|
|
1132
|
-
const data: { [key: string]: string } = {
|
|
1133
|
-
text: (<obj>item)[this.getField('text')].toString(), iconCss: ICONS + ' e-previous'
|
|
1134
|
-
};
|
|
1135
|
-
if (this.template) {
|
|
1136
|
-
item.iconCss = (item.iconCss || '') + ICONS + ' e-previous';
|
|
1137
|
-
}
|
|
1138
|
-
const hdata: MenuItem = new MenuItem(this.items[0] as MenuItem, 'items', this.template ? item : data, true);
|
|
1139
|
-
const hli: Element = this.createItems([hdata] as MenuItemModel[]).children[0];
|
|
1140
|
-
hli.classList.add(HEADER); this.uList.insertBefore(hli, this.uList.children[0]);
|
|
1141
|
-
}
|
|
1142
|
-
if (this.isMenu) {
|
|
1143
|
-
this.popupWrapper = this.createElement('div', {
|
|
1144
|
-
className: 'e-' + this.getModuleName() + '-wrapper ' + POPUP, id: li.id + '-ej2menu-' + elemId + '-popup' });
|
|
1145
|
-
this.popupWrapper.setAttribute('role', 'navigation');
|
|
1146
|
-
this.popupWrapper.setAttribute('aria-label', item.text + '-menu-popup');
|
|
1147
|
-
if (this.hamburgerMode) {
|
|
1148
|
-
top = (li as HTMLElement).offsetHeight; li.appendChild(this.popupWrapper);
|
|
1149
|
-
} else {
|
|
1150
|
-
document.body.appendChild(this.popupWrapper);
|
|
1151
|
-
}
|
|
1152
|
-
this.isNestedOrVertical = this.element.classList.contains('e-vertical') || this.navIdx.length !== 1;
|
|
1153
|
-
this.popupObj = this.generatePopup(this.popupWrapper, this.uList, li as HTMLElement, this.isNestedOrVertical);
|
|
1154
|
-
if (this.template) { this.renderReactTemplates(); }
|
|
1155
|
-
if (this.hamburgerMode) {
|
|
1156
|
-
this.calculateIndentSize(this.uList, li);
|
|
1157
|
-
} else {
|
|
1158
|
-
if (this.cssClass) { addClass([this.popupWrapper], this.cssClass.replace(/\s+/g, ' ').trim().split(' ')); }
|
|
1159
|
-
this.popupObj.hide();
|
|
1160
|
-
}
|
|
1161
|
-
if (!this.hamburgerMode && !this.showItemOnClick && this.hoverDelay) {
|
|
1162
|
-
window.clearInterval(this.timer);
|
|
1163
|
-
this.timer = window.setTimeout(
|
|
1164
|
-
() => { this.triggerBeforeOpen(li, this.uList, item, e, 0, 0, 'menu'); }, this.hoverDelay );
|
|
1165
|
-
} else {
|
|
1166
|
-
this.triggerBeforeOpen(li, this.uList, item, e, 0, 0, 'menu');
|
|
1167
|
-
}
|
|
1168
|
-
} else {
|
|
1169
|
-
this.uList.style.zIndex = this.element.style.zIndex; wrapper.appendChild(this.uList);
|
|
1170
|
-
if (!this.showItemOnClick && this.hoverDelay) {
|
|
1171
|
-
window.clearInterval(this.timer);
|
|
1172
|
-
this.timer = window.setTimeout(
|
|
1173
|
-
() => { this.triggerBeforeOpen(li, this.uList, item, e, top, left, 'none'); }, this.hoverDelay );
|
|
1174
|
-
} else {
|
|
1175
|
-
this.triggerBeforeOpen(li, this.uList, item, e, top, left, 'none');
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
} else {
|
|
1179
|
-
this.uList = this.element;
|
|
1180
|
-
this.uList.style.zIndex = getZindexPartial(target ? target : this.element).toString();
|
|
1181
|
-
if (isNullOrUndefined(e)) {
|
|
1182
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1183
|
-
const ev: any = document.createEvent('MouseEvents');
|
|
1184
|
-
ev.initEvent('click', true, false);
|
|
1185
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1186
|
-
const targetEvent: any = this.copyObject(ev, {});
|
|
1187
|
-
targetEvent.target = targetEvent.srcElement = target;
|
|
1188
|
-
targetEvent.currentTarget = target;
|
|
1189
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1190
|
-
this.triggerBeforeOpen(li, this.uList, item, targetEvent as any, top, left, 'none');
|
|
1191
|
-
} else {
|
|
1192
|
-
this.triggerBeforeOpen(li, this.uList, item, e, top, left, 'none');
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1198
|
-
private copyObject(source: any, destination: any): any {
|
|
1199
|
-
// eslint-disable-next-line guard-for-in
|
|
1200
|
-
for (const prop in source) {
|
|
1201
|
-
destination[`${prop}`] = source[`${prop}`];
|
|
1202
|
-
}
|
|
1203
|
-
return destination;
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
private calculateIndentSize(ul: HTMLElement, li: Element): void {
|
|
1207
|
-
const liStyle: CSSStyleDeclaration = getComputedStyle(li);
|
|
1208
|
-
let liIndent: number = parseInt(liStyle.textIndent, 10);
|
|
1209
|
-
if (this.navIdx.length < 2 && !li.classList.contains('e-blankicon')) {
|
|
1210
|
-
liIndent *= 2;
|
|
1211
|
-
} else {
|
|
1212
|
-
liIndent += (liIndent / 4);
|
|
1213
|
-
}
|
|
1214
|
-
ul.style.textIndent = liIndent + 'px';
|
|
1215
|
-
const blankIconElem: NodeList = ul.querySelectorAll('.e-blankicon');
|
|
1216
|
-
if (blankIconElem && blankIconElem.length) {
|
|
1217
|
-
const menuIconElem: HTMLElement = ul.querySelector('.e-menu-icon');
|
|
1218
|
-
const menuIconElemStyle: CSSStyleDeclaration = getComputedStyle(menuIconElem);
|
|
1219
|
-
const blankIconIndent: number = (parseInt(menuIconElemStyle.marginRight, 10) + menuIconElem.offsetWidth + liIndent);
|
|
1220
|
-
for (let i: number = 0; i < blankIconElem.length; i++) {
|
|
1221
|
-
(blankIconElem[i as number] as HTMLElement).style.textIndent = blankIconIndent + 'px';
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
private generatePopup(
|
|
1227
|
-
popupWrapper: HTMLElement, ul: HTMLElement, li: HTMLElement, isNestedOrVertical: boolean): Popup {
|
|
1228
|
-
const popupObj: Popup = new Popup(popupWrapper, {
|
|
1229
|
-
actionOnScroll: this.hamburgerMode ? 'none' : 'reposition',
|
|
1230
|
-
relateTo: li,
|
|
1231
|
-
collision: this.hamburgerMode ? { X: 'none', Y: 'none' } : { X: isNestedOrVertical ||
|
|
1232
|
-
this.enableRtl ? 'none' : 'flip', Y: 'fit' },
|
|
1233
|
-
position: (isNestedOrVertical && !this.hamburgerMode) ? { X: 'right', Y: 'top' } : { X: 'left', Y: 'bottom' },
|
|
1234
|
-
targetType: 'relative',
|
|
1235
|
-
enableRtl: this.enableRtl,
|
|
1236
|
-
content: ul,
|
|
1237
|
-
open: (): void => {
|
|
1238
|
-
const scrollEle: HTMLElement = select('.e-menu-vscroll', popupObj.element) as HTMLElement;
|
|
1239
|
-
if (scrollEle) {
|
|
1240
|
-
scrollEle.style.height = 'inherit';
|
|
1241
|
-
scrollEle.style.maxHeight = '';
|
|
1242
|
-
}
|
|
1243
|
-
const ul: HTMLElement = select('.e-ul', popupObj.element) as HTMLElement;
|
|
1244
|
-
popupObj.element.style.maxHeight = '';
|
|
1245
|
-
ul.focus();
|
|
1246
|
-
this.triggerOpen(ul);
|
|
1247
|
-
}
|
|
1248
|
-
});
|
|
1249
|
-
return popupObj;
|
|
1250
|
-
}
|
|
1251
|
-
|
|
1252
|
-
protected createHeaderContainer(wrapper?: Element): void {
|
|
1253
|
-
wrapper = wrapper || this.getWrapper();
|
|
1254
|
-
const spanElem: HTMLElement = this.createElement('span', { className: 'e-' + this.getModuleName() + '-header' });
|
|
1255
|
-
const tempTitle: string = (this.enableHtmlSanitizer) ? SanitizeHtmlHelper.sanitize(this.title) : this.title;
|
|
1256
|
-
const spanTitle: HTMLElement = this.createElement('span', {
|
|
1257
|
-
className: 'e-' + this.getModuleName() + '-title', innerHTML: tempTitle });
|
|
1258
|
-
const spanIcon: HTMLElement = this.createElement('span', {
|
|
1259
|
-
className: 'e-icons e-' + this.getModuleName() + '-icon', attrs: { 'tabindex': '0' } });
|
|
1260
|
-
spanElem.appendChild(spanTitle);
|
|
1261
|
-
spanElem.appendChild(spanIcon);
|
|
1262
|
-
wrapper.insertBefore(spanElem, this.element);
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
protected openHamburgerMenu(e?: MouseEvent | KeyboardEvent) : void {
|
|
1266
|
-
if (this.hamburgerMode) {
|
|
1267
|
-
this.triggerBeforeOpen(null, this.element, null, e, 0, 0, 'hamburger');
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
protected closeHamburgerMenu(e?: MouseEvent | KeyboardEvent) : void {
|
|
1272
|
-
const beforeCloseArgs: BeforeOpenCloseMenuEventArgs = { element: this.element, parentItem: null, event: e,
|
|
1273
|
-
items: this.items, cancel: false };
|
|
1274
|
-
this.trigger('beforeClose', beforeCloseArgs, (observedHamburgerCloseArgs: BeforeOpenCloseMenuEventArgs) => {
|
|
1275
|
-
if (!observedHamburgerCloseArgs.cancel) {
|
|
1276
|
-
this.closeMenu(null, e);
|
|
1277
|
-
this.element.classList.add('e-hide-menu');
|
|
1278
|
-
this.trigger('onClose', { element: this.element, parentItem: null, items: this.items });
|
|
1279
|
-
}
|
|
1280
|
-
});
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
private callFit(element: HTMLElement, x: boolean, y: boolean, top: number, left: number): OffsetPosition {
|
|
1284
|
-
return fit(element, null, { X: x, Y: y }, { top: top, left: left });
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
private triggerBeforeOpen(
|
|
1288
|
-
li: Element, ul: HTMLElement, item: MenuItemModel, e: MouseEvent | KeyboardEvent,
|
|
1289
|
-
top: number, left: number, type: string ): void {
|
|
1290
|
-
const items: MenuItemModel[] = li ? (<obj>item)[this.getField('children', this.navIdx.length - 1)] as objColl : this.items as objColl;
|
|
1291
|
-
const eventArgs: BeforeOpenCloseMenuEventArgs = {
|
|
1292
|
-
element: ul, items: items, parentItem: item, event: e, cancel: false, top: top, left: left, showSubMenuOn: 'Auto' };
|
|
1293
|
-
const menuType: string = type;
|
|
1294
|
-
let observedElement: HTMLElement;
|
|
1295
|
-
this.trigger('beforeOpen', eventArgs, (observedOpenArgs: BeforeOpenCloseMenuEventArgs) => {
|
|
1296
|
-
switch (menuType) {
|
|
1297
|
-
case 'menu':
|
|
1298
|
-
if (!this.hamburgerMode) {
|
|
1299
|
-
if (observedOpenArgs.showSubMenuOn !== 'Auto') {
|
|
1300
|
-
this.showItemOnClick = !this.defaultOption; this.showSubMenuOn = observedOpenArgs.showSubMenuOn;
|
|
1301
|
-
}
|
|
1302
|
-
this.top = observedOpenArgs.top; this.left = observedOpenArgs.left;
|
|
1303
|
-
}
|
|
1304
|
-
this.popupWrapper.style.display = 'block';
|
|
1305
|
-
if (!this.hamburgerMode) {
|
|
1306
|
-
this.popupWrapper.style.maxHeight = this.popupWrapper.getBoundingClientRect().height + 'px';
|
|
1307
|
-
if (this.enableScrolling) {
|
|
1308
|
-
addScrolling(this.createElement, this.popupWrapper, this.uList, 'vscroll', this.enableRtl);
|
|
1309
|
-
}
|
|
1310
|
-
this.checkScrollOffset(e);
|
|
1311
|
-
}
|
|
1312
|
-
if (!this.hamburgerMode && !this.left && !this.top) {
|
|
1313
|
-
this.popupObj.refreshPosition(this.lItem as HTMLElement, true);
|
|
1314
|
-
this.left = parseInt(this.popupWrapper.style.left, 10); this.top = parseInt(this.popupWrapper.style.top, 10);
|
|
1315
|
-
if (this.enableRtl) {
|
|
1316
|
-
this.left =
|
|
1317
|
-
this.isNestedOrVertical ? this.left - this.popupWrapper.offsetWidth - this.lItem.parentElement.offsetWidth + 2
|
|
1318
|
-
: this.left - this.popupWrapper.offsetWidth + (this.lItem as HTMLElement).offsetWidth;
|
|
1319
|
-
}
|
|
1320
|
-
// eslint-disable-next-line
|
|
1321
|
-
if (this.template && ((this as any).isReact || (this as any).isAngular)) {
|
|
1322
|
-
requestAnimationFrame(() => {
|
|
1323
|
-
this.collision();
|
|
1324
|
-
this.popupWrapper.style.display = '';
|
|
1325
|
-
});
|
|
1326
|
-
} else {
|
|
1327
|
-
this.collision();
|
|
1328
|
-
this.popupWrapper.style.display = '';
|
|
1329
|
-
}
|
|
1330
|
-
} else {
|
|
1331
|
-
this.popupObj.collision = { X: 'none', Y: 'none' };
|
|
1332
|
-
this.popupWrapper.style.display = '';
|
|
1333
|
-
}
|
|
1334
|
-
break;
|
|
1335
|
-
case 'none':
|
|
1336
|
-
this.top = observedOpenArgs.top; this.left = observedOpenArgs.left;
|
|
1337
|
-
this.isContextMenuClosed = true;
|
|
1338
|
-
observedElement = observedOpenArgs.element;
|
|
1339
|
-
if (this.enableScrolling && this.isCMenu && observedElement && observedElement.parentElement) {
|
|
1340
|
-
observedElement.style.height = observedElement.parentElement.style.height;
|
|
1341
|
-
}
|
|
1342
|
-
break;
|
|
1343
|
-
case 'hamburger':
|
|
1344
|
-
if (!observedOpenArgs.cancel) {
|
|
1345
|
-
this.element.classList.remove('e-hide-menu'); this.triggerOpen(this.element);
|
|
1346
|
-
}
|
|
1347
|
-
break;
|
|
1348
|
-
}
|
|
1349
|
-
if (menuType !== 'hamburger') {
|
|
1350
|
-
if (observedOpenArgs.cancel) {
|
|
1351
|
-
if (this.isMenu) {
|
|
1352
|
-
this.popupObj.destroy(); detach(this.popupWrapper);
|
|
1353
|
-
} else if (ul.className.indexOf('e-ul') > -1) { detach(ul); }
|
|
1354
|
-
this.navIdx.pop();
|
|
1355
|
-
} else {
|
|
1356
|
-
if (this.isMenu) {
|
|
1357
|
-
if (this.hamburgerMode) {
|
|
1358
|
-
this.popupWrapper.style.top = this.top + 'px'; this.popupWrapper.style.left = 0 + 'px';
|
|
1359
|
-
this.toggleAnimation(this.popupWrapper);
|
|
1360
|
-
} else {
|
|
1361
|
-
this.setBlankIconStyle(this.popupWrapper);
|
|
1362
|
-
this.wireKeyboardEvent(this.popupWrapper); rippleEffect(this.popupWrapper, { selector: '.' + ITEM });
|
|
1363
|
-
this.popupWrapper.style.left = this.left + 'px';
|
|
1364
|
-
this.popupWrapper.style.top = this.top + 'px';
|
|
1365
|
-
const animationOptions: AnimationModel = this.animationSettings.effect !== 'None' ? {
|
|
1366
|
-
name: this.animationSettings.effect, duration: this.animationSettings.duration,
|
|
1367
|
-
timingFunction: this.animationSettings.easing
|
|
1368
|
-
} : null;
|
|
1369
|
-
this.popupObj.show(animationOptions, this.lItem as HTMLElement);
|
|
1370
|
-
if (Browser.isDevice) {
|
|
1371
|
-
this.popupWrapper.style.left = this.left + 'px';
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
} else {
|
|
1375
|
-
this.setBlankIconStyle(this.uList);
|
|
1376
|
-
this.setPosition(this.lItem, this.uList, this.top, this.left); this.toggleAnimation(this.uList);
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
if (this.keyType === 'right') {
|
|
1381
|
-
let cul: Element = this.getUlByNavIdx(); li.classList.remove(FOCUSED);
|
|
1382
|
-
if (this.isMenu && this.navIdx.length === 1) {
|
|
1383
|
-
this.removeLIStateByClass([SELECTED], [this.getWrapper()]);
|
|
1384
|
-
}
|
|
1385
|
-
li.classList.add(SELECTED);
|
|
1386
|
-
if (this.action === ENTER) {
|
|
1387
|
-
const eventArgs: MenuEventArgs = { element: li as HTMLElement, item: item, event: e };
|
|
1388
|
-
this.trigger('select', eventArgs);
|
|
1389
|
-
}
|
|
1390
|
-
(li as HTMLElement).focus(); cul = this.getUlByNavIdx();
|
|
1391
|
-
const index: number = this.isValidLI(cul.children[0], 0, this.action);
|
|
1392
|
-
cul.children[index as number].classList.add(FOCUSED); (cul.children[index as number] as HTMLElement).focus();
|
|
1393
|
-
}
|
|
1394
|
-
});
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
private collision(): void {
|
|
1398
|
-
let collide: string[];
|
|
1399
|
-
collide = isCollide(this.popupWrapper, null, this.left, this.top);
|
|
1400
|
-
if ((this.isNestedOrVertical || this.enableRtl) && (collide.indexOf('right') > -1
|
|
1401
|
-
|| collide.indexOf('left') > -1)) {
|
|
1402
|
-
this.popupObj.collision.X = 'none';
|
|
1403
|
-
const offWidth: number =
|
|
1404
|
-
(closest(this.lItem, '.e-' + this.getModuleName() + '-wrapper') as HTMLElement).offsetWidth;
|
|
1405
|
-
this.left =
|
|
1406
|
-
this.enableRtl ? calculatePosition(this.lItem, this.isNestedOrVertical ? 'right' : 'left', 'top').left
|
|
1407
|
-
: this.left - this.popupWrapper.offsetWidth - offWidth + 2;
|
|
1408
|
-
}
|
|
1409
|
-
collide = isCollide(this.popupWrapper, null, this.left, this.top);
|
|
1410
|
-
if (collide.indexOf('left') > -1 || collide.indexOf('right') > -1) {
|
|
1411
|
-
this.left = this.callFit(this.popupWrapper, true, false, this.top, this.left).left;
|
|
1412
|
-
}
|
|
1413
|
-
this.popupWrapper.style.left = this.left + 'px';
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
protected setBlankIconStyle(menu: HTMLElement): void {
|
|
1417
|
-
const blankIconList: HTMLElement[] = [].slice.call(menu.getElementsByClassName('e-blankicon'));
|
|
1418
|
-
if (!blankIconList.length) { return; }
|
|
1419
|
-
const iconLi: HTMLElement = menu.querySelector('.e-menu-item:not(.e-blankicon):not(.e-separator)') as HTMLElement;
|
|
1420
|
-
if (!iconLi) { return; }
|
|
1421
|
-
const icon: HTMLElement = iconLi.querySelector('.e-menu-icon') as HTMLElement;
|
|
1422
|
-
if (!icon) { return; }
|
|
1423
|
-
const cssProp: { padding: string, margin: string } = this.enableRtl ? { padding: 'paddingRight', margin: 'marginLeft' } :
|
|
1424
|
-
{ padding: 'paddingLeft', margin: 'marginRight' };
|
|
1425
|
-
const iconCssProps: CSSStyleDeclaration = getComputedStyle(icon);
|
|
1426
|
-
let iconSize: number = parseInt(iconCssProps.fontSize, 10);
|
|
1427
|
-
if (!!parseInt(iconCssProps.width, 10) && parseInt(iconCssProps.width, 10) > iconSize) {
|
|
1428
|
-
iconSize = parseInt(iconCssProps.width, 10);
|
|
1429
|
-
}
|
|
1430
|
-
// eslint:disable
|
|
1431
|
-
const size: string = `${iconSize + parseInt(
|
|
1432
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1433
|
-
(iconCssProps as any)[cssProp.margin], 10) + parseInt((getComputedStyle(iconLi) as any)[cssProp.padding], 10)}px`;
|
|
1434
|
-
blankIconList.forEach((li: HTMLElement): void => {
|
|
1435
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1436
|
-
(li.style as any)[cssProp.padding] = size;
|
|
1437
|
-
});
|
|
1438
|
-
// eslint:enable
|
|
1439
|
-
}
|
|
1440
|
-
|
|
1441
|
-
private checkScrollOffset(e: MouseEvent | KeyboardEvent): void {
|
|
1442
|
-
const wrapper: Element = this.getWrapper();
|
|
1443
|
-
if (wrapper.children[0].classList.contains('e-menu-hscroll') && this.navIdx.length === 1) {
|
|
1444
|
-
const trgt: HTMLElement = isNullOrUndefined(e) ? this.element : closest(e.target as Element, '.' + ITEM) as HTMLElement;
|
|
1445
|
-
const offsetEle: HTMLElement = (select('.e-hscroll-bar', wrapper) as HTMLElement);
|
|
1446
|
-
if (offsetEle.scrollLeft > trgt.offsetLeft) {
|
|
1447
|
-
offsetEle.scrollLeft -= (offsetEle.scrollLeft - trgt.offsetLeft);
|
|
1448
|
-
}
|
|
1449
|
-
const offsetLeft: number = offsetEle.scrollLeft + offsetEle.offsetWidth;
|
|
1450
|
-
const offsetRight: number = trgt.offsetLeft + trgt.offsetWidth;
|
|
1451
|
-
if (offsetLeft < offsetRight) {
|
|
1452
|
-
offsetEle.scrollLeft += (offsetRight - offsetLeft);
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
|
|
1457
|
-
private setPosition(li: Element, ul: HTMLElement, top: number, left: number, isOpen: boolean = false): void {
|
|
1458
|
-
const px: string = 'px';
|
|
1459
|
-
this.toggleVisiblity(ul);
|
|
1460
|
-
if (ul === this.element || (left > -1 && top > -1)) {
|
|
1461
|
-
let collide: string[] = isCollide(ul, null, left, top);
|
|
1462
|
-
if (collide.indexOf('right') > -1) {
|
|
1463
|
-
left = left - ul.offsetWidth;
|
|
1464
|
-
}
|
|
1465
|
-
if (collide.indexOf('bottom') > -1) {
|
|
1466
|
-
const offset: OffsetPosition = this.callFit(ul, false, true, top, left);
|
|
1467
|
-
top = offset.top - 20;
|
|
1468
|
-
if (top < 0) {
|
|
1469
|
-
const newTop: number = (pageYOffset + document.documentElement.clientHeight) - ul.getBoundingClientRect().height;
|
|
1470
|
-
if (newTop > -1) { top = newTop; }
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
collide = isCollide(ul, null, left, top);
|
|
1474
|
-
if (collide.indexOf('left') > -1) {
|
|
1475
|
-
const offset: OffsetPosition = this.callFit(ul, true, false, top, left);
|
|
1476
|
-
left = offset.left;
|
|
1477
|
-
}
|
|
1478
|
-
} else {
|
|
1479
|
-
if (Browser.isDevice) {
|
|
1480
|
-
if (!this.isMenu && this.enableScrolling) {
|
|
1481
|
-
const menuScrollElement: HTMLElement = document.querySelector<HTMLElement>('.e-menu-vscroll');
|
|
1482
|
-
top = Number(menuScrollElement.style.top.replace('px', ''));
|
|
1483
|
-
left = Number(menuScrollElement.style.left.replace('px', ''));
|
|
1484
|
-
} else {
|
|
1485
|
-
top = Number(this.element.style.top.replace(px, ''));
|
|
1486
|
-
left = Number(this.element.style.left.replace(px, ''));
|
|
1487
|
-
}
|
|
1488
|
-
} else {
|
|
1489
|
-
const x: string = this.enableRtl ? 'left' : 'right';
|
|
1490
|
-
let offset: OffsetPosition = calculatePosition(li, x, 'top');
|
|
1491
|
-
top = offset.top;
|
|
1492
|
-
left = offset.left;
|
|
1493
|
-
const collide: string[] = isCollide(ul, null, this.enableRtl ? left - ul.offsetWidth : left, top);
|
|
1494
|
-
const xCollision: boolean = collide.indexOf('left') > -1 || collide.indexOf('right') > -1;
|
|
1495
|
-
if (xCollision) {
|
|
1496
|
-
offset = calculatePosition(li, this.enableRtl ? 'right' : 'left', 'top');
|
|
1497
|
-
left = offset.left;
|
|
1498
|
-
}
|
|
1499
|
-
if (this.enableRtl || xCollision) {
|
|
1500
|
-
left = (this.enableRtl && xCollision) ? left : left - ul.offsetWidth;
|
|
1501
|
-
}
|
|
1502
|
-
if (collide.indexOf('bottom') > -1 && (this.isMenu || !this.enableScrolling)) {
|
|
1503
|
-
offset = this.callFit(ul, false, true, top, left);
|
|
1504
|
-
top = offset.top;
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1508
|
-
this.toggleVisiblity(ul, false);
|
|
1509
|
-
if (this.isCMenu && this.enableScrolling && ul) {
|
|
1510
|
-
ul.style.height = '';
|
|
1511
|
-
ul.style.top = '';
|
|
1512
|
-
ul.style.left = '';
|
|
1513
|
-
ul.style.width = '';
|
|
1514
|
-
ul.style.position = '';
|
|
1515
|
-
}
|
|
1516
|
-
const wrapper: HTMLElement = closest(this.element, '.e-' + this.getModuleName() + '-wrapper') as HTMLElement;
|
|
1517
|
-
if (!this.isMenu && this.enableScrolling && ul && wrapper && wrapper.offsetHeight > 0) {
|
|
1518
|
-
const menuVScroll: Element = closest(ul, '.e-menu-vscroll');
|
|
1519
|
-
ul.style.display = 'block';
|
|
1520
|
-
if (menuVScroll) {
|
|
1521
|
-
destroyScroll(getInstance(menuVScroll as HTMLElement, VScroll) as VScroll, menuVScroll);
|
|
1522
|
-
}
|
|
1523
|
-
const cmenuWidth: number = Math.ceil(this.getMenuWidth(ul, ul.offsetWidth, this.enableRtl));
|
|
1524
|
-
const cmenu: HTMLElement = addScrolling(this.createElement, wrapper, ul, 'vscroll', this.enableRtl, wrapper.offsetHeight);
|
|
1525
|
-
const newOffset: OffsetPosition = this.callFit(cmenu, false, true, top, left);
|
|
1526
|
-
top = newOffset.top;
|
|
1527
|
-
Object.assign(cmenu.style, {
|
|
1528
|
-
top: `${top}px`,
|
|
1529
|
-
left: `${left}px`,
|
|
1530
|
-
width: `${cmenuWidth}px`,
|
|
1531
|
-
position: 'absolute',
|
|
1532
|
-
display: !isOpen ? 'none' : 'block'
|
|
1533
|
-
});
|
|
1534
|
-
} else {
|
|
1535
|
-
ul.style.top = top + px;
|
|
1536
|
-
ul.style.left = left + px;
|
|
1537
|
-
}
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
public getMenuWidth(menuElement: Element, width: number, isRtl: boolean): number {
|
|
1541
|
-
const caretIcon: HTMLElement = menuElement.getElementsByClassName(CARET)[0] as HTMLElement;
|
|
1542
|
-
if (caretIcon) { width += parseInt(getComputedStyle(caretIcon)[isRtl ? 'marginRight' : 'marginLeft'], 10); }
|
|
1543
|
-
return width < 120 ? 120 : width;
|
|
1544
|
-
}
|
|
1545
|
-
|
|
1546
|
-
private toggleVisiblity(ul: HTMLElement, isVisible: boolean = true): void {
|
|
1547
|
-
ul.style.visibility = isVisible ? 'hidden' : '';
|
|
1548
|
-
ul.style.display = isVisible ? 'block' : 'none';
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
|
-
private createItems(items: MenuItemModel[] | objColl): HTMLElement {
|
|
1552
|
-
const level: number = this.navIdx ? this.navIdx.length : 0;
|
|
1553
|
-
const fields: FieldsMap = this.getFields(level);
|
|
1554
|
-
const showIcon: boolean = this.hasField(items, this.getField('iconCss', level));
|
|
1555
|
-
const listBaseOptions: ListBaseOptions = {
|
|
1556
|
-
showIcon: showIcon,
|
|
1557
|
-
moduleName: 'menu',
|
|
1558
|
-
fields: fields,
|
|
1559
|
-
template: this.template as string | Function,
|
|
1560
|
-
itemNavigable: true,
|
|
1561
|
-
itemCreating: (args: { curData: obj, fields: obj }): void => {
|
|
1562
|
-
if (!args.curData[(<obj>args.fields)[fields.id] as string]) {
|
|
1563
|
-
args.curData[(<obj>args.fields)[fields.id] as string] = getUniqueID('menuitem');
|
|
1564
|
-
}
|
|
1565
|
-
if (isNullOrUndefined(args.curData.htmlAttributes)) {
|
|
1566
|
-
Object.defineProperty(args.curData, 'htmlAttributes', {
|
|
1567
|
-
value: {},
|
|
1568
|
-
writable: true,
|
|
1569
|
-
enumerable: true,
|
|
1570
|
-
configurable: true
|
|
1571
|
-
});
|
|
1572
|
-
}
|
|
1573
|
-
if (Browser.isIE) {
|
|
1574
|
-
if (!(args.curData.htmlAttributes as obj).role) {
|
|
1575
|
-
(args.curData.htmlAttributes as obj).role = 'menuitem';
|
|
1576
|
-
}
|
|
1577
|
-
if (!(args.curData.htmlAttributes as obj).tabindex) {
|
|
1578
|
-
(args.curData.htmlAttributes as obj).tabindex = '-1';
|
|
1579
|
-
}
|
|
1580
|
-
} else {
|
|
1581
|
-
Object.assign(args.curData.htmlAttributes, {
|
|
1582
|
-
role: (args.curData.htmlAttributes as obj).role || 'menuitem',
|
|
1583
|
-
tabindex: (args.curData.htmlAttributes as obj).tabindex || '-1'
|
|
1584
|
-
});
|
|
1585
|
-
}
|
|
1586
|
-
if (this.isMenu && !(<obj>args.curData)[this.getField('separator', level)]) {
|
|
1587
|
-
if (!(<obj>args.curData.htmlAttributes)['aria-label']) {
|
|
1588
|
-
(<obj>args.curData.htmlAttributes)['aria-label'] = (<obj>args.curData)[args.fields.text as string] ?
|
|
1589
|
-
(<obj>args.curData)[args.fields.text as string] : (<obj>args.curData)[args.fields.id as string];
|
|
1590
|
-
}
|
|
1591
|
-
}
|
|
1592
|
-
if (args.curData[(<obj>args.fields)[fields.iconCss] as string] === '') {
|
|
1593
|
-
args.curData[(<obj>args.fields)[fields.iconCss] as string] = null;
|
|
1594
|
-
}
|
|
1595
|
-
},
|
|
1596
|
-
itemCreated: (args: { curData: MenuItemModel | obj, item: Element, fields: obj }): void => {
|
|
1597
|
-
if ((<obj>args.curData)[this.getField('separator', level)]) {
|
|
1598
|
-
args.item.classList.add(SEPARATOR);
|
|
1599
|
-
if (!(args.curData.htmlAttributes as obj).role) {
|
|
1600
|
-
args.item.setAttribute('role', 'separator');
|
|
1601
|
-
}
|
|
1602
|
-
if (!(args.curData.htmlAttributes as obj).ariaLabel) {
|
|
1603
|
-
args.item.setAttribute('aria-label', 'separator');
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
if (showIcon && !(<obj>args.curData)[args.fields.iconCss as string]
|
|
1607
|
-
&& !(<obj>args.curData)[this.getField('separator', level)]) {
|
|
1608
|
-
(args.item as HTMLElement).classList.add('e-blankicon');
|
|
1609
|
-
}
|
|
1610
|
-
if ((<obj>args.curData)[args.fields.child as string]
|
|
1611
|
-
&& (<objColl>(<obj>args.curData)[args.fields.child as string]).length) {
|
|
1612
|
-
const span: Element = this.createElement('span', { className: ICONS + ' ' + CARET });
|
|
1613
|
-
args.item.appendChild(span);
|
|
1614
|
-
args.item.setAttribute('aria-haspopup', 'true');
|
|
1615
|
-
args.item.setAttribute('aria-expanded', 'false');
|
|
1616
|
-
(args.item as HTMLElement).classList.add('e-menu-caret-icon');
|
|
1617
|
-
}
|
|
1618
|
-
if (this.template) {
|
|
1619
|
-
args.item.setAttribute('id', (<obj>args.curData)[args.fields.id as string].toString());
|
|
1620
|
-
args.item.removeAttribute('data-uid');
|
|
1621
|
-
if (args.item.classList.contains('e-level-1')) { args.item.classList.remove('e-level-1'); }
|
|
1622
|
-
if (args.item.classList.contains('e-has-child')) { args.item.classList.remove('e-has-child'); }
|
|
1623
|
-
args.item.removeAttribute('aria-level');
|
|
1624
|
-
}
|
|
1625
|
-
const eventArgs: MenuEventArgs = { item: args.curData, element: args.item as HTMLElement };
|
|
1626
|
-
this.trigger('beforeItemRender', eventArgs);
|
|
1627
|
-
}
|
|
1628
|
-
};
|
|
1629
|
-
this.setProperties({'items': this.items}, true);
|
|
1630
|
-
if (this.isMenu) {
|
|
1631
|
-
listBaseOptions.templateID = this.element.id + TEMPLATE_PROPERTY;
|
|
1632
|
-
}
|
|
1633
|
-
|
|
1634
|
-
const ul: HTMLElement = ListBase.createList(
|
|
1635
|
-
this.createElement, items as objColl, listBaseOptions, !this.template, this);
|
|
1636
|
-
ul.setAttribute('tabindex', '0');
|
|
1637
|
-
if (this.isMenu) {
|
|
1638
|
-
ul.setAttribute('role', 'menu');
|
|
1639
|
-
} else {
|
|
1640
|
-
ul.setAttribute('role', 'menubar');
|
|
1641
|
-
}
|
|
1642
|
-
return ul;
|
|
1643
|
-
}
|
|
1644
|
-
|
|
1645
|
-
private moverHandler(e: MouseEvent): void {
|
|
1646
|
-
const trgt: Element = e.target as Element;
|
|
1647
|
-
this.liTrgt = trgt;
|
|
1648
|
-
if (!this.isMenu) {
|
|
1649
|
-
this.isCmenuHover = true;
|
|
1650
|
-
}
|
|
1651
|
-
const cli: Element = this.getLI(trgt);
|
|
1652
|
-
const wrapper: Element = cli ? closest(cli, '.e-' + this.getModuleName() + '-wrapper') : this.getWrapper();
|
|
1653
|
-
const hdrWrapper: Element = this.getWrapper(); const regex: RegExp = new RegExp('-ej2menu-(.*)-popup'); let ulId: string;
|
|
1654
|
-
let isDifferentElem: boolean = false;
|
|
1655
|
-
if (!wrapper) {
|
|
1656
|
-
return;
|
|
1657
|
-
}
|
|
1658
|
-
if (wrapper.id !== '') {
|
|
1659
|
-
ulId = regex.exec(wrapper.id)[1];
|
|
1660
|
-
} else {
|
|
1661
|
-
ulId = wrapper.querySelector('ul').id;
|
|
1662
|
-
}
|
|
1663
|
-
if (ulId !== this.element.id) {
|
|
1664
|
-
this.removeLIStateByClass([FOCUSED, SELECTED], [this.getWrapper()]);
|
|
1665
|
-
if (this.navIdx.length) {
|
|
1666
|
-
isDifferentElem = true;
|
|
1667
|
-
} else {
|
|
1668
|
-
return;
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
if (cli && closest(cli, '.e-' + this.getModuleName() + '-wrapper') && !isDifferentElem) {
|
|
1672
|
-
this.removeLIStateByClass([FOCUSED], this.isMenu ? [wrapper].concat(this.getPopups()) : [wrapper]);
|
|
1673
|
-
this.removeLIStateByClass([FOCUSED], this.isMenu ? [hdrWrapper].concat(this.getPopups()) : [hdrWrapper]);
|
|
1674
|
-
cli.classList.add(FOCUSED);
|
|
1675
|
-
if (!this.showItemOnClick) {
|
|
1676
|
-
this.clickHandler(e);
|
|
1677
|
-
}
|
|
1678
|
-
} else if (this.isMenu && this.showItemOnClick && !isDifferentElem) {
|
|
1679
|
-
this.removeLIStateByClass([FOCUSED], [wrapper].concat(this.getPopups()));
|
|
1680
|
-
}
|
|
1681
|
-
if (this.isMenu) {
|
|
1682
|
-
if (!this.showItemOnClick && (trgt.parentElement !== wrapper && !closest(trgt, '.e-' + this.getModuleName() + '-popup'))
|
|
1683
|
-
&& (!cli || (cli && !this.getIndex(cli.id, true).length)) && this.showSubMenuOn !== 'Hover') {
|
|
1684
|
-
this.removeLIStateByClass([FOCUSED], [wrapper]);
|
|
1685
|
-
if (this.navIdx.length) {
|
|
1686
|
-
this.isClosed = true;
|
|
1687
|
-
this.closeMenu(null, e);
|
|
1688
|
-
}
|
|
1689
|
-
} else if (isDifferentElem && !this.showItemOnClick) {
|
|
1690
|
-
if (this.navIdx.length) {
|
|
1691
|
-
this.isClosed = true;
|
|
1692
|
-
this.closeMenu(null, e);
|
|
1693
|
-
}
|
|
1694
|
-
}
|
|
1695
|
-
if (!this.isClosed) {
|
|
1696
|
-
this.removeStateWrapper();
|
|
1697
|
-
}
|
|
1698
|
-
this.isClosed = false;
|
|
1699
|
-
}
|
|
1700
|
-
if (!this.isMenu) {
|
|
1701
|
-
this.isCmenuHover = false;
|
|
1702
|
-
}
|
|
1703
|
-
}
|
|
1704
|
-
private removeStateWrapper(): void {
|
|
1705
|
-
if (this.liTrgt) {
|
|
1706
|
-
const wrapper: Element = closest(this.liTrgt, '.e-menu-vscroll');
|
|
1707
|
-
if (this.liTrgt.tagName === 'DIV' && wrapper) {
|
|
1708
|
-
this.removeLIStateByClass([FOCUSED, SELECTED], [wrapper]);
|
|
1709
|
-
}
|
|
1710
|
-
}
|
|
1711
|
-
}
|
|
1712
|
-
|
|
1713
|
-
private removeLIStateByClass(classList: string[], element: Element[]): void {
|
|
1714
|
-
let li: Element;
|
|
1715
|
-
for (let i: number = 0; i < element.length; i++) {
|
|
1716
|
-
classList.forEach((className: string) => {
|
|
1717
|
-
li = select('.' + className, element[i as number]);
|
|
1718
|
-
if (li) {
|
|
1719
|
-
li.classList.remove(className);
|
|
1720
|
-
}
|
|
1721
|
-
});
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
protected getField(propName: string, level: number = 0): string {
|
|
1726
|
-
const fieldName: object = (<obj>this.fields)[`${propName}`];
|
|
1727
|
-
return typeof fieldName === 'string' ? fieldName :
|
|
1728
|
-
(!(<obj>fieldName)[level as number] ? (fieldName as obj)[(<objColl>fieldName).length - 1].toString()
|
|
1729
|
-
: (<obj>fieldName)[level as number].toString());
|
|
1730
|
-
}
|
|
1731
|
-
|
|
1732
|
-
private getFields(level: number = 0): FieldsMap {
|
|
1733
|
-
return {
|
|
1734
|
-
id: this.getField('itemId', level),
|
|
1735
|
-
iconCss: this.getField('iconCss', level),
|
|
1736
|
-
text: this.getField('text', level),
|
|
1737
|
-
url: this.getField('url', level),
|
|
1738
|
-
child: this.getField('children', level),
|
|
1739
|
-
separator: this.getField('separator', level)
|
|
1740
|
-
};
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
private hasField(items: MenuItemModel[], field: string): boolean {
|
|
1744
|
-
for (let i: number = 0, len: number = items.length; i < len; i++) {
|
|
1745
|
-
if ((<obj>items[i as number])[`${field}`]) {
|
|
1746
|
-
return true;
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
return false;
|
|
1750
|
-
}
|
|
1751
|
-
|
|
1752
|
-
private menuHeaderClickHandler(e: MouseEvent | KeyboardEvent): void {
|
|
1753
|
-
const menuWrapper: Element = closest(e.target as Element, '.e-menu-wrapper');
|
|
1754
|
-
if (menuWrapper && menuWrapper.querySelector('ul.e-menu-parent').id !== this.element.id) {
|
|
1755
|
-
return;
|
|
1756
|
-
}
|
|
1757
|
-
if (this.element.className.indexOf('e-hide-menu') > -1) {
|
|
1758
|
-
this.openHamburgerMenu(e);
|
|
1759
|
-
} else {
|
|
1760
|
-
this.closeHamburgerMenu(e);
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
|
-
private clickHandler(e: MouseEvent): void {
|
|
1765
|
-
this.isTapHold = this.isTapHold ? false : this.isTapHold;
|
|
1766
|
-
const wrapper: Element = this.getWrapper();
|
|
1767
|
-
const trgt: Element = e.target as Element;
|
|
1768
|
-
const cli: Element = this.cli = this.getLI(trgt);
|
|
1769
|
-
const regex: RegExp = new RegExp('-ej2menu-(.*)-popup');
|
|
1770
|
-
const cliWrapper: Element = cli ? closest(cli, '.e-' + this.getModuleName() + '-wrapper') : null;
|
|
1771
|
-
const isInstLI: boolean = cli && cliWrapper && (this.isMenu ? this.getIndex(cli.id, true).length > 0
|
|
1772
|
-
: wrapper.firstElementChild.id === cliWrapper.firstElementChild.id);
|
|
1773
|
-
if (Browser.isDevice && this.isMenu) {
|
|
1774
|
-
this.removeLIStateByClass([FOCUSED], [wrapper].concat(this.getPopups()));
|
|
1775
|
-
this.mouseDownHandler(e);
|
|
1776
|
-
}
|
|
1777
|
-
if (cli && cliWrapper && this.isMenu) {
|
|
1778
|
-
const cliWrapperId: string = cliWrapper.id ? regex.exec(cliWrapper.id)[1] : cliWrapper.querySelector('.e-menu-parent').id;
|
|
1779
|
-
if (this.element.id !== cliWrapperId) {
|
|
1780
|
-
return;
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
|
-
if (isInstLI && e.type === 'click' && !cli.classList.contains(HEADER)) {
|
|
1784
|
-
this.setLISelected(cli);
|
|
1785
|
-
const navIdx: number[] = this.getIndex(cli.id, true);
|
|
1786
|
-
const item: MenuItemModel = this.getItem(navIdx);
|
|
1787
|
-
const eventArgs: MenuEventArgs = { element: cli as HTMLElement, item: item, event: e };
|
|
1788
|
-
this.trigger('select', eventArgs);
|
|
1789
|
-
}
|
|
1790
|
-
if (isInstLI && (e.type === 'mouseover' || Browser.isDevice || this.showItemOnClick)) {
|
|
1791
|
-
let ul: HTMLElement;
|
|
1792
|
-
if (cli.classList.contains(HEADER)) {
|
|
1793
|
-
ul = wrapper.children[this.navIdx.length - 1] as HTMLElement;
|
|
1794
|
-
this.toggleAnimation(ul);
|
|
1795
|
-
const sli: Element = this.getLIByClass(ul, SELECTED);
|
|
1796
|
-
if (sli) {
|
|
1797
|
-
sli.classList.remove(SELECTED);
|
|
1798
|
-
}
|
|
1799
|
-
const scrollMenu: HTMLElement = this.enableScrolling && !this.isMenu ? closest(cli.parentElement, '.e-menu-vscroll') as HTMLElement : null;
|
|
1800
|
-
if (scrollMenu) {
|
|
1801
|
-
destroyScroll(getInstance(scrollMenu, VScroll) as VScroll, scrollMenu);
|
|
1802
|
-
}
|
|
1803
|
-
detach(cli.parentNode);
|
|
1804
|
-
this.navIdx.pop();
|
|
1805
|
-
} else {
|
|
1806
|
-
if (!cli.classList.contains(SEPARATOR)) {
|
|
1807
|
-
this.showSubMenu = true;
|
|
1808
|
-
const cul: Element = cli.parentNode as Element;
|
|
1809
|
-
if (isNullOrUndefined(cul)) {
|
|
1810
|
-
return;
|
|
1811
|
-
}
|
|
1812
|
-
this.cliIdx = this.getIdx(cul, cli);
|
|
1813
|
-
if (this.isMenu || !Browser.isDevice) {
|
|
1814
|
-
const culIdx: number = this.isMenu ? Array.prototype.indexOf.call(
|
|
1815
|
-
[wrapper].concat(this.getPopups()), closest(cul, '.' + 'e-' + this.getModuleName() + '-wrapper'))
|
|
1816
|
-
: this.getIdx(wrapper, cul);
|
|
1817
|
-
if (this.navIdx[culIdx as number] === this.cliIdx) {
|
|
1818
|
-
this.showSubMenu = false;
|
|
1819
|
-
}
|
|
1820
|
-
if (culIdx !== this.navIdx.length && (e.type !== 'mouseover' || this.showSubMenu)) {
|
|
1821
|
-
const sli: Element = this.getLIByClass(cul, SELECTED);
|
|
1822
|
-
if (sli) {
|
|
1823
|
-
sli.classList.remove(SELECTED);
|
|
1824
|
-
}
|
|
1825
|
-
this.isClosed = true;
|
|
1826
|
-
this.keyType = 'click';
|
|
1827
|
-
if (this.showItemOnClick) {
|
|
1828
|
-
this.setLISelected(cli);
|
|
1829
|
-
if (!this.isMenu) {
|
|
1830
|
-
this.isCmenuHover = true;
|
|
1831
|
-
}
|
|
1832
|
-
}
|
|
1833
|
-
this.closeMenu(culIdx + 1, e);
|
|
1834
|
-
if (this.showItemOnClick) {
|
|
1835
|
-
this.setLISelected(cli);
|
|
1836
|
-
if (!this.isMenu) {
|
|
1837
|
-
this.isCmenuHover = false;
|
|
1838
|
-
}
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
if (!this.isClosed) {
|
|
1843
|
-
this.afterCloseMenu(e);
|
|
1844
|
-
}
|
|
1845
|
-
this.isClosed = false;
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
1848
|
-
} else {
|
|
1849
|
-
if (trgt.tagName === 'DIV' && closest(trgt, '.e-menu-vscroll') && (this.navIdx.length || !this.isMenu && this.enableScrolling && this.navIdx.length === 0)) {
|
|
1850
|
-
const popupEle: Element = this.isMenu ? closest(trgt, '.' + POPUP) : closest(trgt, '.e-menu-vscroll');
|
|
1851
|
-
const cIdx: number = this.isMenu ? Array.prototype.indexOf.call(this.getPopups(), popupEle) + 1
|
|
1852
|
-
: this.getIdx(wrapper, select('ul.e-menu-parent', popupEle));
|
|
1853
|
-
if (cIdx < this.navIdx.length) {
|
|
1854
|
-
this.closeMenu(cIdx + 1, e);
|
|
1855
|
-
if (popupEle) { this.removeLIStateByClass([FOCUSED, SELECTED], [popupEle]); }
|
|
1856
|
-
}
|
|
1857
|
-
} else if (this.isMenu && this.hamburgerMode && trgt.tagName === 'SPAN'
|
|
1858
|
-
&& trgt.classList.contains('e-menu-icon')) {
|
|
1859
|
-
this.menuHeaderClickHandler(e);
|
|
1860
|
-
} else {
|
|
1861
|
-
if (trgt.tagName !== 'UL' || (this.isMenu ? trgt.parentElement.classList.contains('e-menu-wrapper') &&
|
|
1862
|
-
!this.getIndex(trgt.querySelector('.' + ITEM).id, true).length : trgt.parentElement !== wrapper)) {
|
|
1863
|
-
if (!cli) {
|
|
1864
|
-
this.removeLIStateByClass([SELECTED], [wrapper]);
|
|
1865
|
-
}
|
|
1866
|
-
if (!this.isAnimationNone && !cli || (cli && !cli.querySelector('.' + CARET))) {
|
|
1867
|
-
if (navigator.platform.toUpperCase().indexOf('MAC') < 0 || (navigator.platform.toUpperCase().indexOf('MAC') >= 0 && !e.ctrlKey)) {
|
|
1868
|
-
this.closeMenu(null, e);
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
private afterCloseMenu(e: MouseEvent): void {
|
|
1876
|
-
if (isNullOrUndefined(e)) {
|
|
1877
|
-
return;
|
|
1878
|
-
}
|
|
1879
|
-
let isHeader: Element;
|
|
1880
|
-
if (this.showSubMenu) {
|
|
1881
|
-
if (this.showItemOnClick && this.navIdx.length === 0) {
|
|
1882
|
-
isHeader = closest(e.target as Element, '.e-menu-parent.e-control');
|
|
1883
|
-
} else {
|
|
1884
|
-
isHeader = closest(this.element, '.e-menu-parent.e-control');
|
|
1885
|
-
}
|
|
1886
|
-
const idx: number[] = this.navIdx.concat(this.cliIdx);
|
|
1887
|
-
const item: MenuItemModel = this.getItem(idx);
|
|
1888
|
-
if (item && (<objColl>(<obj>item)[this.getField('children', idx.length - 1)]) &&
|
|
1889
|
-
(<objColl>(<obj>item)[this.getField('children', idx.length - 1)]).length) {
|
|
1890
|
-
if (e.type === 'mouseover' || (Browser.isDevice && this.isMenu)) {
|
|
1891
|
-
this.setLISelected(this.cli);
|
|
1892
|
-
}
|
|
1893
|
-
if ((!this.hamburgerMode && isHeader) || (this.hamburgerMode && this.cli.getAttribute('aria-expanded') === 'false')) {
|
|
1894
|
-
this.cli.setAttribute('aria-expanded', 'true');
|
|
1895
|
-
this.navIdx.push(this.cliIdx);
|
|
1896
|
-
this.openMenu(this.cli, item, null, null, e);
|
|
1897
|
-
}
|
|
1898
|
-
} else {
|
|
1899
|
-
if (e.type !== 'mouseover') {
|
|
1900
|
-
this.closeMenu(null, e);
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
if (!isHeader) {
|
|
1904
|
-
const cul: Element = this.getUlByNavIdx();
|
|
1905
|
-
const sli: Element = this.getLIByClass(cul, SELECTED);
|
|
1906
|
-
if (sli) {
|
|
1907
|
-
sli.setAttribute('aria-expanded', 'false');
|
|
1908
|
-
sli.classList.remove(SELECTED);
|
|
1909
|
-
}
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
this.keyType = '';
|
|
1913
|
-
}
|
|
1914
|
-
private setLISelected(li: Element): void {
|
|
1915
|
-
const sli: Element = this.getLIByClass(li.parentElement, SELECTED);
|
|
1916
|
-
if (sli) {
|
|
1917
|
-
sli.classList.remove(SELECTED);
|
|
1918
|
-
}
|
|
1919
|
-
if (!this.isMenu) {
|
|
1920
|
-
li.classList.remove(FOCUSED);
|
|
1921
|
-
}
|
|
1922
|
-
li.classList.add(SELECTED);
|
|
1923
|
-
}
|
|
1924
|
-
|
|
1925
|
-
private getLIByClass(ul: Element, classname: string): Element {
|
|
1926
|
-
if (ul && ul.children) {
|
|
1927
|
-
for (let i: number = 0, len: number = ul.children.length; i < len; i++) {
|
|
1928
|
-
if (ul.children[i as number].classList.contains(classname)) {
|
|
1929
|
-
return ul.children[i as number];
|
|
1930
|
-
}
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
|
-
return null;
|
|
1934
|
-
}
|
|
1935
|
-
|
|
1936
|
-
/**
|
|
1937
|
-
* This method is used to get the index of the menu item in the Menu based on the argument.
|
|
1938
|
-
*
|
|
1939
|
-
* @param {MenuItem | string} item - item be passed to get the index | id to be passed to get the item index.
|
|
1940
|
-
* @param {boolean} isUniqueId - Set `true` if it is a unique id.
|
|
1941
|
-
* @returns {void}
|
|
1942
|
-
*/
|
|
1943
|
-
public getItemIndex(item: MenuItem | string, isUniqueId?: boolean): number[] {
|
|
1944
|
-
let idx: string;
|
|
1945
|
-
if (typeof item === 'string') {
|
|
1946
|
-
idx = item;
|
|
1947
|
-
} else {
|
|
1948
|
-
idx = item.id;
|
|
1949
|
-
}
|
|
1950
|
-
const isText: boolean = (isUniqueId === false) ? false : true;
|
|
1951
|
-
const navIdx: number[] = this.getIndex(idx, isText);
|
|
1952
|
-
return navIdx;
|
|
1953
|
-
}
|
|
1954
|
-
|
|
1955
|
-
/**
|
|
1956
|
-
* This method is used to set the menu item in the Menu based on the argument.
|
|
1957
|
-
*
|
|
1958
|
-
* @param {MenuItem} item - item need to be updated.
|
|
1959
|
-
* @param {string} id - id / text to be passed to update the item.
|
|
1960
|
-
* @param {boolean} isUniqueId - Set `true` if it is a unique id.
|
|
1961
|
-
* @returns {void}
|
|
1962
|
-
*/
|
|
1963
|
-
public setItem(item: MenuItem, id?: string, isUniqueId?: boolean): void {
|
|
1964
|
-
let idx: string;
|
|
1965
|
-
if (isUniqueId) {
|
|
1966
|
-
idx = id ? id : item.id;
|
|
1967
|
-
} else {
|
|
1968
|
-
idx = id ? id : item.text;
|
|
1969
|
-
}
|
|
1970
|
-
const navIdx: number[] = this.getIndex(idx, isUniqueId);
|
|
1971
|
-
const newItem: MenuItemModel = this.getItem(navIdx);
|
|
1972
|
-
Object.assign(newItem, item);
|
|
1973
|
-
}
|
|
1974
|
-
|
|
1975
|
-
private getItem(navIdx: number[]): MenuItemModel {
|
|
1976
|
-
navIdx = navIdx.slice();
|
|
1977
|
-
const idx: number = navIdx.pop();
|
|
1978
|
-
const items: MenuItemModel[] = this.getItems(navIdx);
|
|
1979
|
-
return items[idx as number];
|
|
1980
|
-
}
|
|
1981
|
-
|
|
1982
|
-
private getItems(navIdx: number[]): objColl {
|
|
1983
|
-
let items: objColl = this.items as objColl;
|
|
1984
|
-
for (let i: number = 0; i < navIdx.length; i++) {
|
|
1985
|
-
items = (<obj>items[navIdx[i as number]])[this.getField('children', i)] as objColl;
|
|
1986
|
-
}
|
|
1987
|
-
return items;
|
|
1988
|
-
}
|
|
1989
|
-
|
|
1990
|
-
private setItems(newItems: objColl, navIdx: number[]): void {
|
|
1991
|
-
const items: objColl = this.getItems(navIdx);
|
|
1992
|
-
items.splice(0, items.length);
|
|
1993
|
-
for (let i: number = 0; i < newItems.length; i++) {
|
|
1994
|
-
items.splice(i, 0, newItems[i as number]);
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
|
|
1998
|
-
private getIdx(ul: Element, li: Element, skipHdr: boolean = true): number {
|
|
1999
|
-
const ulElem: HTMLElement[] = !this.isMenu && this.enableScrolling && select('.e-menu-vscroll', ul)
|
|
2000
|
-
? selectAll('.e-menu-parent', ul) as HTMLElement[] : Array.from(ul.children) as HTMLElement[];
|
|
2001
|
-
let idx: number = Array.prototype.indexOf.call(ulElem, li);
|
|
2002
|
-
if (skipHdr && ul.children[0].classList.contains(HEADER)) {
|
|
2003
|
-
idx--;
|
|
2004
|
-
}
|
|
2005
|
-
return idx;
|
|
2006
|
-
}
|
|
2007
|
-
|
|
2008
|
-
private getLI(elem: Element): Element {
|
|
2009
|
-
if (elem.tagName === 'LI' && elem.classList.contains('e-menu-item')) {
|
|
2010
|
-
return elem;
|
|
2011
|
-
}
|
|
2012
|
-
return closest(elem, 'li.e-menu-item');
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
private updateItemsByNavIdx(): void {
|
|
2016
|
-
let items: MenuItemModel[] = this.items; let count: number = 0;
|
|
2017
|
-
for (let index: number = 0; index < this.navIdx.length; index++) {
|
|
2018
|
-
items = items[index as number].items;
|
|
2019
|
-
if (!items) { break; }
|
|
2020
|
-
count++;
|
|
2021
|
-
const ul: HTMLUListElement = <HTMLUListElement>this.getUlByNavIdx(count);
|
|
2022
|
-
if (!ul) { break; }
|
|
2023
|
-
this.updateItem(ul, items);
|
|
2024
|
-
}
|
|
2025
|
-
}
|
|
2026
|
-
|
|
2027
|
-
private removeChildElement(elem: HTMLUListElement): HTMLUListElement {
|
|
2028
|
-
while (elem.firstElementChild) {
|
|
2029
|
-
elem.removeChild(elem.firstElementChild);
|
|
2030
|
-
}
|
|
2031
|
-
return elem;
|
|
2032
|
-
}
|
|
2033
|
-
/**
|
|
2034
|
-
* Called internally if any of the property value changed.
|
|
2035
|
-
*
|
|
2036
|
-
* @private
|
|
2037
|
-
* @param {MenuBaseModel} newProp - Specifies the new properties
|
|
2038
|
-
* @param {MenuBaseModel} oldProp - Specifies the old properties
|
|
2039
|
-
* @returns {void}
|
|
2040
|
-
*/
|
|
2041
|
-
public onPropertyChanged(newProp: MenuBaseModel, oldProp: MenuBaseModel): void {
|
|
2042
|
-
const wrapper: HTMLElement = this.getWrapper() as HTMLElement;
|
|
2043
|
-
for (const prop of Object.keys(newProp)) {
|
|
2044
|
-
switch (prop) {
|
|
2045
|
-
case 'cssClass':
|
|
2046
|
-
if (oldProp.cssClass) {
|
|
2047
|
-
removeClass([wrapper], oldProp.cssClass.split(' '));
|
|
2048
|
-
}
|
|
2049
|
-
if (newProp.cssClass) {
|
|
2050
|
-
addClass([wrapper], newProp.cssClass.replace(/\s+/g, ' ').trim().split(' '));
|
|
2051
|
-
}
|
|
2052
|
-
break;
|
|
2053
|
-
case 'enableRtl':
|
|
2054
|
-
if (this.enableRtl){
|
|
2055
|
-
wrapper.classList.add(RTL);
|
|
2056
|
-
} else {
|
|
2057
|
-
wrapper.classList.remove(RTL);
|
|
2058
|
-
}
|
|
2059
|
-
break;
|
|
2060
|
-
case 'showItemOnClick':
|
|
2061
|
-
this.unWireEvents();
|
|
2062
|
-
this.showItemOnClick = newProp.showItemOnClick;
|
|
2063
|
-
this.wireEvents();
|
|
2064
|
-
break;
|
|
2065
|
-
case 'enableScrolling':
|
|
2066
|
-
if (newProp.enableScrolling) {
|
|
2067
|
-
let ul: HTMLElement;
|
|
2068
|
-
if (this.element.classList.contains('e-vertical')) {
|
|
2069
|
-
addScrolling(this.createElement, wrapper, this.element, 'vscroll', this.enableRtl);
|
|
2070
|
-
} else {
|
|
2071
|
-
addScrolling(this.createElement, wrapper, this.element, 'hscroll', this.enableRtl);
|
|
2072
|
-
}
|
|
2073
|
-
(this.getPopups() as HTMLElement[]).forEach((wrapper: HTMLElement) => {
|
|
2074
|
-
ul = select('.e-ul', wrapper) as HTMLElement;
|
|
2075
|
-
addScrolling(this.createElement, wrapper, ul, 'vscroll', this.enableRtl);
|
|
2076
|
-
});
|
|
2077
|
-
} else {
|
|
2078
|
-
let ul: HTMLElement = wrapper.children[0] as HTMLElement;
|
|
2079
|
-
if (this.element.classList.contains('e-vertical') || !this.isMenu) {
|
|
2080
|
-
destroyScroll(getInstance(ul, VScroll) as VScroll, ul);
|
|
2081
|
-
} else {
|
|
2082
|
-
destroyScroll(getInstance(ul, HScroll) as HScroll, ul);
|
|
2083
|
-
}
|
|
2084
|
-
wrapper.style.overflow = '';
|
|
2085
|
-
wrapper.appendChild(this.element);
|
|
2086
|
-
(this.getPopups() as HTMLElement[]).forEach((wrapper: HTMLElement) => {
|
|
2087
|
-
ul = wrapper.children[0] as HTMLElement;
|
|
2088
|
-
destroyScroll(getInstance(ul, VScroll) as VScroll, ul);
|
|
2089
|
-
wrapper.style.overflow = '';
|
|
2090
|
-
});
|
|
2091
|
-
}
|
|
2092
|
-
break;
|
|
2093
|
-
case 'items': {
|
|
2094
|
-
let idx: number;
|
|
2095
|
-
let navIdx: number[];
|
|
2096
|
-
let item: MenuItemModel[];
|
|
2097
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2098
|
-
if ((this as any).isReact && this.template) {
|
|
2099
|
-
this.clearTemplate(['template']);
|
|
2100
|
-
}
|
|
2101
|
-
if (!Object.keys(oldProp.items).length) {
|
|
2102
|
-
this.updateItem(this.element, this.items);
|
|
2103
|
-
if (this.enableScrolling && this.element.parentElement.classList.contains('e-custom-scroll')) {
|
|
2104
|
-
if (this.element.classList.contains('e-vertical')) {
|
|
2105
|
-
addScrolling(this.createElement, wrapper, this.element, 'vscroll', this.enableRtl);
|
|
2106
|
-
} else {
|
|
2107
|
-
addScrolling(this.createElement, wrapper, this.element, 'hscroll', this.enableRtl);
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
if (this.enableScrolling && this.element.classList.contains('e-contextmenu')) {
|
|
2111
|
-
this.isCMenu = true;
|
|
2112
|
-
this.setPosition(this.lItem, this.uList, this.top, this.left, true);
|
|
2113
|
-
this.isCMenu = false;
|
|
2114
|
-
}
|
|
2115
|
-
if (!this.hamburgerMode) {
|
|
2116
|
-
for (let i: number = 1, count: number = wrapper.childElementCount; i < count; i++) {
|
|
2117
|
-
detach(wrapper.lastElementChild);
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
this.navIdx = [];
|
|
2121
|
-
} else {
|
|
2122
|
-
const keys: string[] = Object.keys(newProp.items);
|
|
2123
|
-
for (let i: number = 0; i < keys.length; i++) {
|
|
2124
|
-
navIdx = this.getChangedItemIndex(newProp, [], Number(keys[i as number]));
|
|
2125
|
-
if (navIdx.length <= this.getWrapper().children.length) {
|
|
2126
|
-
idx = navIdx.pop();
|
|
2127
|
-
item = this.getItems(navIdx);
|
|
2128
|
-
this.insertAfter([item[idx as number]], item[idx as number].text);
|
|
2129
|
-
this.removeItem(item, navIdx, idx);
|
|
2130
|
-
this.setItems(item as objColl, navIdx);
|
|
2131
|
-
}
|
|
2132
|
-
navIdx.length = 0;
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
break;
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
}
|
|
2139
|
-
}
|
|
2140
|
-
|
|
2141
|
-
private updateItem(ul: HTMLUListElement, items: MenuItemModel[]): void {
|
|
2142
|
-
if (isBlazor() && !this.isMenu) {
|
|
2143
|
-
ul = this.removeChildElement(ul);
|
|
2144
|
-
} else {
|
|
2145
|
-
if (this.enableScrolling) {
|
|
2146
|
-
const wrapper1: HTMLElement = this.getWrapper() as HTMLElement;
|
|
2147
|
-
const ul1: HTMLElement = wrapper1.children[0] as HTMLElement;
|
|
2148
|
-
if (this.element.classList.contains('e-vertical')) {
|
|
2149
|
-
destroyScroll(getInstance(ul1, VScroll) as VScroll, ul1);
|
|
2150
|
-
} else {
|
|
2151
|
-
destroyScroll(getInstance(ul1, HScroll) as HScroll, ul1);
|
|
2152
|
-
}
|
|
2153
|
-
}
|
|
2154
|
-
ul.innerHTML = '';
|
|
2155
|
-
}
|
|
2156
|
-
const lis: HTMLElement[] = [].slice.call(this.createItems(items).children);
|
|
2157
|
-
lis.forEach((li: HTMLElement): void => {
|
|
2158
|
-
ul.appendChild(li);
|
|
2159
|
-
});
|
|
2160
|
-
}
|
|
2161
|
-
|
|
2162
|
-
private getChangedItemIndex(newProp: MenuBaseModel, index: number[], idx: number): number[] {
|
|
2163
|
-
index.push(idx);
|
|
2164
|
-
const key: string = Object.keys((<objColl>newProp.items)[idx as number]).pop();
|
|
2165
|
-
if (key === 'items') {
|
|
2166
|
-
const item: MenuItemModel = (<objColl>newProp.items)[idx as number];
|
|
2167
|
-
const popStr: string = Object.keys(item.items).pop();
|
|
2168
|
-
if (popStr) {
|
|
2169
|
-
this.getChangedItemIndex(item, index, Number(popStr));
|
|
2170
|
-
}
|
|
2171
|
-
} else {
|
|
2172
|
-
if (key === 'isParentArray' && index.length > 1) {
|
|
2173
|
-
index.pop();
|
|
2174
|
-
}
|
|
2175
|
-
}
|
|
2176
|
-
return index;
|
|
2177
|
-
}
|
|
2178
|
-
|
|
2179
|
-
private removeItem(item: MenuItemModel[], navIdx: number[], idx: number): void {
|
|
2180
|
-
item.splice(idx, 1);
|
|
2181
|
-
const uls: HTMLCollection = this.getWrapper().children;
|
|
2182
|
-
if (navIdx.length < uls.length) {
|
|
2183
|
-
if (this.enableScrolling && !uls[navIdx.length].classList.contains('e-menu-parent')) {
|
|
2184
|
-
const ul: HTMLElement = uls[navIdx.length].querySelector('.e-menu-parent');
|
|
2185
|
-
detach(ul.children[idx as number]);
|
|
2186
|
-
} else {
|
|
2187
|
-
detach(uls[navIdx.length].children[idx as number]);
|
|
2188
|
-
}
|
|
2189
|
-
}
|
|
2190
|
-
}
|
|
2191
|
-
|
|
2192
|
-
/**
|
|
2193
|
-
* Used to unwire the bind events.
|
|
2194
|
-
*
|
|
2195
|
-
* @private
|
|
2196
|
-
* @param {string} targetSelctor - Specifies the target selector
|
|
2197
|
-
* @returns {void}
|
|
2198
|
-
*/
|
|
2199
|
-
protected unWireEvents(targetSelctor: string = this.target): void {
|
|
2200
|
-
const wrapper: HTMLElement = this.getWrapper() as HTMLElement;
|
|
2201
|
-
if (targetSelctor) {
|
|
2202
|
-
let target: HTMLElement;
|
|
2203
|
-
let touchModule: Touch;
|
|
2204
|
-
const targetElems: HTMLElement[] = selectAll(targetSelctor);
|
|
2205
|
-
for (let i: number = 0, len: number = targetElems.length; i < len; i++) {
|
|
2206
|
-
target = targetElems[i as number];
|
|
2207
|
-
if (this.isMenu) {
|
|
2208
|
-
EventHandler.remove(target, 'click', this.menuHeaderClickHandler);
|
|
2209
|
-
} else {
|
|
2210
|
-
if (Browser.isIos) {
|
|
2211
|
-
touchModule = getInstance(target, Touch) as Touch;
|
|
2212
|
-
if (touchModule) {
|
|
2213
|
-
touchModule.destroy();
|
|
2214
|
-
}
|
|
2215
|
-
} else {
|
|
2216
|
-
EventHandler.remove(target, 'contextmenu', this.cmenuHandler);
|
|
2217
|
-
}
|
|
2218
|
-
}
|
|
2219
|
-
}
|
|
2220
|
-
if (!this.isMenu) {
|
|
2221
|
-
EventHandler.remove(this.targetElement, 'scroll', this.scrollHandler);
|
|
2222
|
-
for (const parent of getScrollableParent(this.targetElement)) {
|
|
2223
|
-
EventHandler.remove(parent, 'scroll', this.scrollHandler);
|
|
2224
|
-
}
|
|
2225
|
-
}
|
|
2226
|
-
}
|
|
2227
|
-
if (!Browser.isDevice) {
|
|
2228
|
-
EventHandler.remove(this.isMenu ? document : wrapper, 'mouseover', this.delegateMoverHandler);
|
|
2229
|
-
EventHandler.remove(document, 'mousedown', this.delegateMouseDownHandler);
|
|
2230
|
-
EventHandler.remove(document, 'keydown', this.domKeyHandler);
|
|
2231
|
-
if (!this.isMenu && !this.target) {
|
|
2232
|
-
EventHandler.remove(document, 'scroll', this.scrollHandler);
|
|
2233
|
-
}
|
|
2234
|
-
}
|
|
2235
|
-
EventHandler.remove(document, 'click', this.delegateClickHandler);
|
|
2236
|
-
this.unWireKeyboardEvent(wrapper);
|
|
2237
|
-
this.rippleFn();
|
|
2238
|
-
if (!this.isMenu && this.enableScrolling) {
|
|
2239
|
-
wrapper.removeEventListener('touchstart', this.touchStartFn);
|
|
2240
|
-
wrapper.removeEventListener('touchmove', this.touchMoveFn);
|
|
2241
|
-
document.removeEventListener('touchstart', this.touchOutsideHandler);
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
|
|
2245
|
-
private unWireKeyboardEvent(element: HTMLElement): void {
|
|
2246
|
-
const keyboardModule: KeyboardEvents = getInstance(element, KeyboardEvents) as KeyboardEvents;
|
|
2247
|
-
if (keyboardModule) {
|
|
2248
|
-
keyboardModule.destroy();
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
|
|
2252
|
-
private toggleAnimation(ul: HTMLElement, isMenuOpen: boolean = true): void {
|
|
2253
|
-
const menuWrapper: Element = this.getWrapper();
|
|
2254
|
-
if (menuWrapper) {
|
|
2255
|
-
const activeMenuElements: NodeListOf<Element> = menuWrapper.querySelectorAll('.e-menu-parent');
|
|
2256
|
-
activeMenuElements.forEach((menuElement: Element): void => {
|
|
2257
|
-
Animation.stop(menuElement as HTMLElement);
|
|
2258
|
-
});
|
|
2259
|
-
}
|
|
2260
|
-
let pUlHeight: number;
|
|
2261
|
-
let pElement: HTMLElement;
|
|
2262
|
-
const animateElement: HTMLElement = (this.enableScrolling && !this.isMenu && closest(ul, '.e-menu-vscroll'))
|
|
2263
|
-
? closest(ul, '.e-menu-vscroll') as HTMLElement : ul;
|
|
2264
|
-
Animation.stop(animateElement);
|
|
2265
|
-
if (this.animationSettings.effect === 'None' || !isMenuOpen) {
|
|
2266
|
-
if (this.hamburgerMode && ul) {
|
|
2267
|
-
ul.style.top = '0px';
|
|
2268
|
-
}
|
|
2269
|
-
this.isAnimationNone = this.animationSettings.effect === 'None';
|
|
2270
|
-
this.end(ul, isMenuOpen);
|
|
2271
|
-
} else {
|
|
2272
|
-
animateElement.style.maxHeight = '';
|
|
2273
|
-
this.animation.animate(animateElement, {
|
|
2274
|
-
name: this.animationSettings.effect,
|
|
2275
|
-
duration: this.animationSettings.duration,
|
|
2276
|
-
timingFunction: this.animationSettings.easing,
|
|
2277
|
-
begin: (options: AnimationOptions) => {
|
|
2278
|
-
if (this.hamburgerMode) {
|
|
2279
|
-
pElement = options.element.parentElement;
|
|
2280
|
-
options.element.style.position = 'absolute';
|
|
2281
|
-
if (pElement) { pUlHeight = pElement.offsetHeight; }
|
|
2282
|
-
options.element.style.maxHeight = options.element.offsetHeight + 'px';
|
|
2283
|
-
if (pElement) { pElement.style.maxHeight = ''; }
|
|
2284
|
-
} else {
|
|
2285
|
-
options.element.style.display = 'block';
|
|
2286
|
-
options.element.style.maxHeight = options.element.getBoundingClientRect().height + 'px';
|
|
2287
|
-
}
|
|
2288
|
-
},
|
|
2289
|
-
progress: (options: AnimationOptions) => {
|
|
2290
|
-
if (this.hamburgerMode && pElement) {
|
|
2291
|
-
pElement.style.minHeight = (pUlHeight + options.element.offsetHeight) + 'px';
|
|
2292
|
-
}
|
|
2293
|
-
},
|
|
2294
|
-
end: (options: AnimationOptions) => {
|
|
2295
|
-
if (this.hamburgerMode) {
|
|
2296
|
-
options.element.style.position = '';
|
|
2297
|
-
options.element.style.maxHeight = '';
|
|
2298
|
-
if (pElement) { pElement.style.minHeight = ''; }
|
|
2299
|
-
options.element.style.top = 0 + 'px';
|
|
2300
|
-
(options.element.children[0] as HTMLElement).focus();
|
|
2301
|
-
this.triggerOpen(options.element.children[0] as HTMLElement);
|
|
2302
|
-
} else {
|
|
2303
|
-
this.end(options.element, isMenuOpen);
|
|
2304
|
-
}
|
|
2305
|
-
this.isKBDAction = false;
|
|
2306
|
-
}
|
|
2307
|
-
});
|
|
2308
|
-
}
|
|
2309
|
-
}
|
|
2310
|
-
|
|
2311
|
-
private triggerOpen(ul: HTMLElement): void {
|
|
2312
|
-
const item: MenuItemModel = this.navIdx.length ? this.getItem(this.navIdx) : null;
|
|
2313
|
-
const eventArgs: OpenCloseMenuEventArgs = {
|
|
2314
|
-
element: ul, parentItem: item, items: item ? item.items : this.items as objColl
|
|
2315
|
-
};
|
|
2316
|
-
this.trigger('onOpen', eventArgs);
|
|
2317
|
-
if (!this.isMenu) {
|
|
2318
|
-
EventHandler.add(ul, 'keydown', this.keyHandler, this);
|
|
2319
|
-
}
|
|
2320
|
-
}
|
|
2321
|
-
|
|
2322
|
-
private end(ul: HTMLElement, isMenuOpen: boolean): void {
|
|
2323
|
-
if (isMenuOpen && this.isContextMenuClosed) {
|
|
2324
|
-
if (this.isMenu || !Browser.isDevice || (!this.isMenu && this.isAnimationNone && Browser.isDevice)) {
|
|
2325
|
-
ul.style.display = 'block';
|
|
2326
|
-
}
|
|
2327
|
-
ul.style.maxHeight = '';
|
|
2328
|
-
const scrollMenu: HTMLElement = this.enableScrolling && !this.isMenu ? closest(ul, '.e-menu-vscroll') as HTMLElement : null;
|
|
2329
|
-
if (scrollMenu) {
|
|
2330
|
-
scrollMenu.style.display = 'block';
|
|
2331
|
-
}
|
|
2332
|
-
this.triggerOpen(ul);
|
|
2333
|
-
if (ul.querySelector('.' + FOCUSED) && this.isKBDAction) {
|
|
2334
|
-
(ul.querySelector('.' + FOCUSED) as HTMLElement).focus();
|
|
2335
|
-
} else {
|
|
2336
|
-
const ele: HTMLElement = this.getWrapper().children[this.getIdx(this.getWrapper(), ul) - 1] as HTMLElement;
|
|
2337
|
-
if (this.currentTarget) {
|
|
2338
|
-
if (!(this.currentTarget.classList.contains('e-numerictextbox') || this.currentTarget.classList.contains('e-textbox') || this.currentTarget.tagName === 'INPUT')) {
|
|
2339
|
-
if (ele && this.isKBDAction) {
|
|
2340
|
-
(ele.querySelector('.' + SELECTED) as HTMLElement).focus();
|
|
2341
|
-
} else {
|
|
2342
|
-
this.element.focus();
|
|
2343
|
-
}
|
|
2344
|
-
}
|
|
2345
|
-
} else {
|
|
2346
|
-
if (ele && this.isKBDAction) {
|
|
2347
|
-
(ele.querySelector('.' + SELECTED) as HTMLElement).focus();
|
|
2348
|
-
} else {
|
|
2349
|
-
this.element.focus();
|
|
2350
|
-
}
|
|
2351
|
-
}
|
|
2352
|
-
}
|
|
2353
|
-
} else {
|
|
2354
|
-
const scrollMenu: HTMLElement = this.enableScrolling && !this.isMenu ? closest(ul, '.e-menu-vscroll') as HTMLElement : null;
|
|
2355
|
-
if (scrollMenu) {
|
|
2356
|
-
destroyScroll(getInstance(scrollMenu, VScroll) as VScroll, scrollMenu);
|
|
2357
|
-
}
|
|
2358
|
-
if (ul === this.element) {
|
|
2359
|
-
const fli: Element = this.getLIByClass(this.element, FOCUSED);
|
|
2360
|
-
if (fli) {
|
|
2361
|
-
fli.classList.remove(FOCUSED);
|
|
2362
|
-
}
|
|
2363
|
-
const sli: Element = this.getLIByClass(this.element, SELECTED);
|
|
2364
|
-
if (sli) {
|
|
2365
|
-
sli.classList.remove(SELECTED);
|
|
2366
|
-
}
|
|
2367
|
-
ul.style.display = 'none';
|
|
2368
|
-
this.isAnimationNone = false;
|
|
2369
|
-
} else {
|
|
2370
|
-
detach(ul);
|
|
2371
|
-
}
|
|
2372
|
-
}
|
|
2373
|
-
}
|
|
2374
|
-
|
|
2375
|
-
/**
|
|
2376
|
-
* Get the properties to be maintained in the persisted state.
|
|
2377
|
-
*
|
|
2378
|
-
* @returns {string} - Persist data
|
|
2379
|
-
*/
|
|
2380
|
-
protected getPersistData(): string {
|
|
2381
|
-
return '';
|
|
2382
|
-
}
|
|
2383
|
-
|
|
2384
|
-
/**
|
|
2385
|
-
* Get wrapper element.
|
|
2386
|
-
*
|
|
2387
|
-
* @returns {Element} - Wrapper element
|
|
2388
|
-
* @private
|
|
2389
|
-
*/
|
|
2390
|
-
private getWrapper(): Element {
|
|
2391
|
-
return closest(this.element, '.e-' + this.getModuleName() + '-wrapper');
|
|
2392
|
-
}
|
|
2393
|
-
|
|
2394
|
-
protected getIndex(
|
|
2395
|
-
data: string, isUniqueId?: boolean, items: MenuItemModel[] | { [key: string]: Object }[] = this.items as objColl,
|
|
2396
|
-
nIndex: number[] = [], isCallBack: boolean = false, level: number = 0): number[] {
|
|
2397
|
-
let item: MenuItemModel | obj;
|
|
2398
|
-
level = isCallBack ? level + 1 : 0;
|
|
2399
|
-
for (let i: number = 0, len: number = items.length; i < len; i++) {
|
|
2400
|
-
item = items[i as number];
|
|
2401
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2402
|
-
const currentField: any = isUniqueId ? (<obj>item)[this.getField('itemId', level)] : (<obj>item)[this.getField('text', level)];
|
|
2403
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2404
|
-
const itemId: string = (item.htmlAttributes && 'id' in item.htmlAttributes) ? (item.htmlAttributes as Record<string, any>).id : currentField;
|
|
2405
|
-
if (itemId === data) {
|
|
2406
|
-
nIndex.push(i);
|
|
2407
|
-
break;
|
|
2408
|
-
} else if ((<objColl>(<obj>item)[this.getField('children', level)])
|
|
2409
|
-
&& (<objColl>(<obj>item)[this.getField('children', level)]).length) {
|
|
2410
|
-
nIndex = this.getIndex(data, isUniqueId, (<objColl>(<obj>item)[this.getField('children', level)]), nIndex, true, level);
|
|
2411
|
-
if (nIndex[nIndex.length - 1] === -1) {
|
|
2412
|
-
if (i !== len - 1) {
|
|
2413
|
-
nIndex.pop();
|
|
2414
|
-
}
|
|
2415
|
-
} else {
|
|
2416
|
-
nIndex.unshift(i);
|
|
2417
|
-
break;
|
|
2418
|
-
}
|
|
2419
|
-
} else {
|
|
2420
|
-
if (i === len - 1) {
|
|
2421
|
-
nIndex.push(-1);
|
|
2422
|
-
}
|
|
2423
|
-
}
|
|
2424
|
-
}
|
|
2425
|
-
return (!isCallBack && nIndex[0] === -1) ? [] : nIndex;
|
|
2426
|
-
}
|
|
2427
|
-
|
|
2428
|
-
/**
|
|
2429
|
-
* This method is used to enable or disable the menu items in the Menu based on the items and enable argument.
|
|
2430
|
-
*
|
|
2431
|
-
* @param {string[]} items - Text items that needs to be enabled/disabled.
|
|
2432
|
-
* @param {boolean} enable - Set `true`/`false` to enable/disable the list items.
|
|
2433
|
-
* @param {boolean} isUniqueId - Set `true` if it is a unique id.
|
|
2434
|
-
* @returns {void}
|
|
2435
|
-
*/
|
|
2436
|
-
public enableItems(items: string[], enable: boolean = true, isUniqueId?: boolean): void {
|
|
2437
|
-
let ul: Element;
|
|
2438
|
-
let idx: number;
|
|
2439
|
-
let navIdx: number[];
|
|
2440
|
-
const disabled: string = DISABLED; let skipItem: boolean;
|
|
2441
|
-
for (let i: number = 0; i < items.length; i++) {
|
|
2442
|
-
navIdx = this.getIndex(items[i as number], isUniqueId);
|
|
2443
|
-
if (this.navIdx.length) {
|
|
2444
|
-
if (navIdx.length !== 1) {
|
|
2445
|
-
skipItem = false;
|
|
2446
|
-
for (let i: number = 0, len: number = navIdx.length - 1; i < len; i++) {
|
|
2447
|
-
if (navIdx[i as number] !== this.navIdx[i as number]) {
|
|
2448
|
-
skipItem = true; break;
|
|
2449
|
-
}
|
|
2450
|
-
}
|
|
2451
|
-
if (skipItem) { continue; }
|
|
2452
|
-
}
|
|
2453
|
-
} else {
|
|
2454
|
-
if (navIdx.length !== 1) { continue; }
|
|
2455
|
-
}
|
|
2456
|
-
idx = navIdx.pop();
|
|
2457
|
-
ul = this.getUlByNavIdx(navIdx.length);
|
|
2458
|
-
if (ul && !isNullOrUndefined(idx)) {
|
|
2459
|
-
if (enable) {
|
|
2460
|
-
if (this.isMenu) {
|
|
2461
|
-
ul.children[idx as number].classList.remove(disabled);
|
|
2462
|
-
ul.children[idx as number].removeAttribute('aria-disabled');
|
|
2463
|
-
} else {
|
|
2464
|
-
if (Browser.isDevice && !ul.classList.contains('e-contextmenu')) {
|
|
2465
|
-
ul.children[idx + 1].classList.remove(disabled);
|
|
2466
|
-
} else if (this.enableScrolling && !ul.classList.contains('e-menu-parent')) {
|
|
2467
|
-
const mainUl: Element = ul.querySelector('.e-menu-parent');
|
|
2468
|
-
mainUl.children[idx as number].classList.remove(disabled);
|
|
2469
|
-
} else {
|
|
2470
|
-
ul.children[idx as number].classList.remove(disabled);
|
|
2471
|
-
}
|
|
2472
|
-
}
|
|
2473
|
-
} else {
|
|
2474
|
-
if (this.isMenu) {
|
|
2475
|
-
ul.children[idx as number].classList.add(disabled);
|
|
2476
|
-
ul.children[idx as number].setAttribute('aria-disabled', 'true');
|
|
2477
|
-
} else {
|
|
2478
|
-
if (Browser.isDevice && !ul.classList.contains('e-contextmenu')) {
|
|
2479
|
-
ul.children[idx + 1].classList.add(disabled);
|
|
2480
|
-
} else {
|
|
2481
|
-
if (this.enableScrolling && !ul.classList.contains('e-menu-parent')) {
|
|
2482
|
-
const mainUl: Element = ul.querySelector('.e-menu-parent');
|
|
2483
|
-
mainUl.children[idx as number].classList.add(disabled);
|
|
2484
|
-
} else {
|
|
2485
|
-
ul.children[idx as number].classList.add(disabled);
|
|
2486
|
-
}
|
|
2487
|
-
}
|
|
2488
|
-
}
|
|
2489
|
-
}
|
|
2490
|
-
}
|
|
2491
|
-
}
|
|
2492
|
-
}
|
|
2493
|
-
|
|
2494
|
-
/**
|
|
2495
|
-
* This method is used to show the menu items in the Menu based on the items text.
|
|
2496
|
-
*
|
|
2497
|
-
* @param {string[]} items - Text items that needs to be shown.
|
|
2498
|
-
* @param {boolean} isUniqueId - Set `true` if it is a unique id.
|
|
2499
|
-
* @returns {void}
|
|
2500
|
-
*/
|
|
2501
|
-
public showItems(items: string[], isUniqueId?: boolean): void {
|
|
2502
|
-
this.showHideItems(items, false, isUniqueId);
|
|
2503
|
-
}
|
|
2504
|
-
|
|
2505
|
-
/**
|
|
2506
|
-
* This method is used to hide the menu items in the Menu based on the items text.
|
|
2507
|
-
*
|
|
2508
|
-
* @param {string[]} items - Text items that needs to be hidden.
|
|
2509
|
-
* @param {boolean} isUniqueId - Set `true` if it is a unique id.
|
|
2510
|
-
* @returns {void}
|
|
2511
|
-
*/
|
|
2512
|
-
public hideItems(items: string[], isUniqueId?: boolean): void {
|
|
2513
|
-
this.showHideItems(items, true, isUniqueId);
|
|
2514
|
-
}
|
|
2515
|
-
|
|
2516
|
-
private showHideItems(items: string[], ishide: boolean, isUniqueId?: boolean): void {
|
|
2517
|
-
let ul: Element;
|
|
2518
|
-
let index: number;
|
|
2519
|
-
let navIdx: number[];
|
|
2520
|
-
let item: objColl;
|
|
2521
|
-
for (let i: number = 0; i < items.length; i++) {
|
|
2522
|
-
navIdx = this.getIndex(items[i as number], isUniqueId);
|
|
2523
|
-
index = navIdx.pop();
|
|
2524
|
-
ul = this.getUlByNavIdx(navIdx.length);
|
|
2525
|
-
item = this.getItems(navIdx);
|
|
2526
|
-
if (ul) {
|
|
2527
|
-
if (this.enableScrolling && !ul.classList.contains('e-menu-parent')) {
|
|
2528
|
-
ul = ul.querySelector('.e-menu-parent');
|
|
2529
|
-
}
|
|
2530
|
-
const validUl: string = isUniqueId ? ul.children[index as number].id : item[index as number].text.toString();
|
|
2531
|
-
if (ishide && validUl === items[i as number]) {
|
|
2532
|
-
ul.children[index as number].classList.add(HIDE);
|
|
2533
|
-
} else if (!ishide && validUl === items[i as number]) {
|
|
2534
|
-
ul.children[index as number].classList.remove(HIDE);
|
|
2535
|
-
}
|
|
2536
|
-
}
|
|
2537
|
-
}
|
|
2538
|
-
}
|
|
2539
|
-
|
|
2540
|
-
/**
|
|
2541
|
-
* It is used to remove the menu items from the Menu based on the items text.
|
|
2542
|
-
*
|
|
2543
|
-
* @param {string[]} items Text items that needs to be removed.
|
|
2544
|
-
* @param {boolean} isUniqueId - Set `true` if it is a unique id.
|
|
2545
|
-
* @returns {void}
|
|
2546
|
-
*/
|
|
2547
|
-
public removeItems(items: string[], isUniqueId?: boolean): void {
|
|
2548
|
-
let idx: number;
|
|
2549
|
-
let navIdx: number[];
|
|
2550
|
-
let iitems: MenuItemModel[];
|
|
2551
|
-
for (let i: number = 0; i < items.length; i++) {
|
|
2552
|
-
navIdx = this.getIndex(items[i as number], isUniqueId);
|
|
2553
|
-
idx = navIdx.pop();
|
|
2554
|
-
iitems = this.getItems(navIdx);
|
|
2555
|
-
if (!isNullOrUndefined(idx)) {
|
|
2556
|
-
this.removeItem(iitems, navIdx, idx);
|
|
2557
|
-
}
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
|
|
2561
|
-
/**
|
|
2562
|
-
* It is used to insert the menu items after the specified menu item text.
|
|
2563
|
-
*
|
|
2564
|
-
* @param {MenuItemModel[]} items - Items that needs to be inserted.
|
|
2565
|
-
* @param {string} text - Text item after that the element to be inserted.
|
|
2566
|
-
* @param {boolean} isUniqueId - Set `true` if it is a unique id.
|
|
2567
|
-
* @returns {void}
|
|
2568
|
-
*/
|
|
2569
|
-
public insertAfter(items: MenuItemModel[], text: string, isUniqueId?: boolean): void {
|
|
2570
|
-
this.insertItems(items, text, isUniqueId);
|
|
2571
|
-
}
|
|
2572
|
-
|
|
2573
|
-
/**
|
|
2574
|
-
* It is used to insert the menu items before the specified menu item text.
|
|
2575
|
-
*
|
|
2576
|
-
* @param {MenuItemModel[]} items - Items that needs to be inserted.
|
|
2577
|
-
* @param {string} text - Text item before that the element to be inserted.
|
|
2578
|
-
* @param {boolean} isUniqueId - Set `true` if it is a unique id.
|
|
2579
|
-
* @returns {void}
|
|
2580
|
-
*/
|
|
2581
|
-
public insertBefore(items: MenuItemModel[], text: string, isUniqueId?: boolean): void {
|
|
2582
|
-
this.insertItems(items, text, isUniqueId, false);
|
|
2583
|
-
}
|
|
2584
|
-
|
|
2585
|
-
private insertItems(items: MenuItemModel[] | objColl, text: string, isUniqueId?: boolean, isAfter: boolean = true): void {
|
|
2586
|
-
let li: Element;
|
|
2587
|
-
let idx: number;
|
|
2588
|
-
let navIdx: number[];
|
|
2589
|
-
let iitems: MenuItemModel[];
|
|
2590
|
-
let menuitem: MenuItem;
|
|
2591
|
-
let parentUl: HTMLElement;
|
|
2592
|
-
for (let i: number = 0; i < items.length; i++) {
|
|
2593
|
-
navIdx = this.getIndex(text, isUniqueId);
|
|
2594
|
-
idx = navIdx.pop();
|
|
2595
|
-
iitems = this.getItems(navIdx);
|
|
2596
|
-
menuitem = new MenuItem(iitems[0] as MenuItem, 'items', items[i as number], true);
|
|
2597
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
2598
|
-
(menuitem as any).parentObj = (iitems[0] as any).parentObj;
|
|
2599
|
-
iitems.splice(isAfter ? idx + 1 : idx, 0, menuitem);
|
|
2600
|
-
const uls: Element[] = this.isMenu ? [this.getWrapper()].concat(this.getPopups()) : [].slice.call(this.getWrapper().children);
|
|
2601
|
-
if (!isNullOrUndefined(idx) && navIdx.length < uls.length) {
|
|
2602
|
-
idx = isAfter ? idx + 1 : idx;
|
|
2603
|
-
li = this.createItems(iitems).children[idx as number];
|
|
2604
|
-
let ul: HTMLElement = parentUl = this.isMenu ? select('.e-menu-parent', uls[navIdx.length]) : uls[navIdx.length];
|
|
2605
|
-
if (this.enableScrolling && !ul.classList.contains('e-menu-parent')) {
|
|
2606
|
-
ul = ul.querySelector('.e-menu-parent');
|
|
2607
|
-
}
|
|
2608
|
-
ul.insertBefore(li, ul.children[idx as number]);
|
|
2609
|
-
if (i === items.length - 1 && !this.isMenu && ul.style.display === 'block') {
|
|
2610
|
-
if (this.enableScrolling) {
|
|
2611
|
-
this.setPosition(null, ul, parseFloat(parentUl.style.top), parseFloat(parentUl.style.left));
|
|
2612
|
-
const scrollElem: HTMLElement = closest(ul, '.e-vscroll') as HTMLElement;
|
|
2613
|
-
if (scrollElem) { scrollElem.style.display = 'block'; }
|
|
2614
|
-
} else {
|
|
2615
|
-
this.setPosition(null, ul, parseFloat(ul.style.top), parseFloat(ul.style.left));
|
|
2616
|
-
ul.style.display = 'block';
|
|
2617
|
-
}
|
|
2618
|
-
}
|
|
2619
|
-
}
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
|
|
2623
|
-
private removeAttributes(): void {
|
|
2624
|
-
['top', 'left', 'display', 'z-index'].forEach((key: string) => {
|
|
2625
|
-
this.element.style.removeProperty(key);
|
|
2626
|
-
});
|
|
2627
|
-
['role', 'tabindex', 'class', 'style'].forEach((key: string) => {
|
|
2628
|
-
if (key === 'class' && this.element.classList.contains('e-menu-parent')) {
|
|
2629
|
-
this.element.classList.remove('e-menu-parent');
|
|
2630
|
-
}
|
|
2631
|
-
if (['class', 'style'].indexOf(key) === -1 || !this.element.getAttribute(key)) {
|
|
2632
|
-
this.element.removeAttribute(key);
|
|
2633
|
-
}
|
|
2634
|
-
if (this.isMenu && key === 'class' && this.element.classList.contains('e-vertical')) {
|
|
2635
|
-
this.element.classList.remove('e-vertical');
|
|
2636
|
-
}
|
|
2637
|
-
});
|
|
2638
|
-
}
|
|
2639
|
-
|
|
2640
|
-
/**
|
|
2641
|
-
* Destroys the widget.
|
|
2642
|
-
*
|
|
2643
|
-
* @returns {void}
|
|
2644
|
-
*/
|
|
2645
|
-
|
|
2646
|
-
public destroy(): void {
|
|
2647
|
-
const wrapper: Element = this.getWrapper();
|
|
2648
|
-
if (wrapper) {
|
|
2649
|
-
this.unWireEvents();
|
|
2650
|
-
if (!this.isMenu) {
|
|
2651
|
-
this.clonedElement.style.display = '';
|
|
2652
|
-
if (this.clonedElement.tagName === 'EJS-CONTEXTMENU') {
|
|
2653
|
-
addClass([this.clonedElement], ['e-control', 'e-lib', 'e-' + this.getModuleName()]);
|
|
2654
|
-
this.element = this.clonedElement as HTMLUListElement;
|
|
2655
|
-
} else {
|
|
2656
|
-
if (this.refreshing && this.clonedElement.childElementCount && this.clonedElement.children[0].tagName === 'LI') {
|
|
2657
|
-
this.setProperties({ 'items': [] }, true);
|
|
2658
|
-
}
|
|
2659
|
-
if (document.getElementById(this.clonedElement.id)) {
|
|
2660
|
-
const refEle: Element = this.clonedElement.nextElementSibling;
|
|
2661
|
-
if (refEle && refEle !== wrapper) {
|
|
2662
|
-
this.clonedElement.parentElement.insertBefore(this.element, refEle);
|
|
2663
|
-
} else {
|
|
2664
|
-
this.clonedElement.parentElement.appendChild(this.element);
|
|
2665
|
-
}
|
|
2666
|
-
if (isBlazor() && !this.isMenu) {
|
|
2667
|
-
this.element = this.removeChildElement(this.element);
|
|
2668
|
-
} else {
|
|
2669
|
-
this.element.innerHTML = '';
|
|
2670
|
-
}
|
|
2671
|
-
append([].slice.call(this.clonedElement.children), this.element);
|
|
2672
|
-
detach(this.clonedElement);
|
|
2673
|
-
this.removeAttributes();
|
|
2674
|
-
}
|
|
2675
|
-
}
|
|
2676
|
-
this.clonedElement = null;
|
|
2677
|
-
} else {
|
|
2678
|
-
this.closeMenu();
|
|
2679
|
-
if (isBlazor() && !this.isMenu) {
|
|
2680
|
-
this.element = this.removeChildElement(this.element);
|
|
2681
|
-
} else {
|
|
2682
|
-
this.element.innerHTML = '';
|
|
2683
|
-
}
|
|
2684
|
-
this.removeAttributes();
|
|
2685
|
-
wrapper.parentNode.insertBefore(this.element, wrapper);
|
|
2686
|
-
this.clonedElement = null;
|
|
2687
|
-
}
|
|
2688
|
-
detach(wrapper);
|
|
2689
|
-
super.destroy();
|
|
2690
|
-
if (this.template) { this.clearTemplate(['template']); }
|
|
2691
|
-
}
|
|
2692
|
-
this.rippleFn = null;
|
|
2693
|
-
}
|
|
2694
|
-
}
|
|
2695
|
-
|
|
2696
|
-
interface FieldsMap {
|
|
2697
|
-
id: string;
|
|
2698
|
-
iconCss: string;
|
|
2699
|
-
text: string;
|
|
2700
|
-
url: string;
|
|
2701
|
-
child: string;
|
|
2702
|
-
separator: string;
|
|
2703
|
-
}
|
|
2704
|
-
|
|
2705
|
-
/**
|
|
2706
|
-
* Interface for before item render/select event.
|
|
2707
|
-
*/
|
|
2708
|
-
export interface MenuEventArgs extends BaseEventArgs {
|
|
2709
|
-
element: HTMLElement;
|
|
2710
|
-
item: MenuItemModel;
|
|
2711
|
-
event?: Event;
|
|
2712
|
-
}
|
|
2713
|
-
|
|
2714
|
-
/**
|
|
2715
|
-
* Interface for before open/close event.
|
|
2716
|
-
*/
|
|
2717
|
-
export interface BeforeOpenCloseMenuEventArgs extends BaseEventArgs {
|
|
2718
|
-
element: HTMLElement;
|
|
2719
|
-
items: MenuItemModel[];
|
|
2720
|
-
parentItem: MenuItemModel;
|
|
2721
|
-
event: Event;
|
|
2722
|
-
cancel: boolean;
|
|
2723
|
-
top?: number;
|
|
2724
|
-
left?: number;
|
|
2725
|
-
isFocused?: boolean;
|
|
2726
|
-
showSubMenuOn?: MenuOpenType;
|
|
2727
|
-
}
|
|
2728
|
-
|
|
2729
|
-
/**
|
|
2730
|
-
* Interface for open/close event.
|
|
2731
|
-
*/
|
|
2732
|
-
export interface OpenCloseMenuEventArgs extends BaseEventArgs {
|
|
2733
|
-
element: HTMLElement;
|
|
2734
|
-
items: MenuItemModel[] | { [key: string]: Object }[];
|
|
2735
|
-
parentItem: MenuItemModel;
|
|
2736
|
-
}
|