@syncfusion/ej2-navigations 17.2.55-1205479 → 17.3.14-96615
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/.eslintrc.json +244 -0
- package/CHANGELOG.md +898 -786
- package/README.md +163 -163
- package/dist/ej2-navigations.umd.min.js +1 -10
- package/dist/ej2-navigations.umd.min.js.map +1 -1
- package/dist/es6/ej2-navigations.es2015.js +512 -255
- package/dist/es6/ej2-navigations.es2015.js.map +1 -1
- package/dist/es6/ej2-navigations.es5.js +642 -385
- package/dist/es6/ej2-navigations.es5.js.map +1 -1
- package/dist/global/ej2-navigations.min.js +1 -10
- package/dist/global/ej2-navigations.min.js.map +1 -1
- package/dist/global/index.d.ts +0 -9
- package/dist/ts/accordion/accordion.ts +1312 -0
- package/dist/ts/common/h-scroll.ts +459 -0
- package/dist/ts/common/menu-base.ts +2131 -0
- package/dist/ts/common/v-scroll.ts +430 -0
- package/dist/ts/context-menu/context-menu.ts +119 -0
- package/dist/ts/menu/menu.ts +270 -0
- package/dist/ts/sidebar/sidebar.ts +817 -0
- package/dist/ts/tab/tab.ts +1761 -0
- package/dist/ts/toolbar/toolbar.ts +2076 -0
- package/dist/ts/treeview/treeview.ts +5050 -0
- package/helpers/e2e/index.js +3 -3
- package/license +10 -10
- package/package.json +135 -145
- package/src/accordion/accordion-model.d.ts +162 -143
- package/src/accordion/accordion.d.ts +35 -6
- package/src/accordion/accordion.js +193 -71
- package/src/common/h-scroll-model.d.ts +5 -5
- package/src/common/h-scroll.js +19 -20
- package/src/common/index.d.ts +1 -0
- package/src/common/index.js +1 -0
- package/src/common/menu-base-model.d.ts +157 -157
- package/src/common/menu-base.d.ts +19 -0
- package/src/common/menu-base.js +97 -24
- package/src/common/v-scroll-model.d.ts +5 -5
- package/src/common/v-scroll.js +19 -19
- package/src/context-menu/context-menu-model.d.ts +15 -15
- package/src/context-menu/context-menu.js +19 -19
- package/src/menu/menu-model.d.ts +30 -30
- package/src/menu/menu.js +19 -19
- package/src/sidebar/sidebar-model.d.ts +136 -136
- package/src/sidebar/sidebar.js +19 -19
- package/src/tab/tab-model.d.ts +215 -215
- package/src/tab/tab.d.ts +3 -0
- package/src/tab/tab.js +120 -83
- package/src/toolbar/toolbar-model.d.ts +175 -175
- package/src/toolbar/toolbar.d.ts +2 -1
- package/src/toolbar/toolbar.js +30 -24
- package/src/treeview/treeview-model.d.ts +323 -323
- package/src/treeview/treeview.d.ts +3 -1
- package/src/treeview/treeview.js +107 -87
- package/styles/accordion/_all.scss +2 -2
- package/styles/accordion/_bootstrap-dark-definition.scss +69 -69
- package/styles/accordion/_bootstrap-definition.scss +76 -76
- package/styles/accordion/_bootstrap4-definition.scss +82 -82
- package/styles/accordion/_fabric-dark-definition.scss +74 -74
- package/styles/accordion/_fabric-definition.scss +78 -78
- package/styles/accordion/_highcontrast-definition.scss +106 -106
- package/styles/accordion/_highcontrast-light-definition.scss +104 -104
- package/styles/accordion/_layout.scss +447 -447
- package/styles/accordion/_material-dark-definition.scss +75 -75
- package/styles/accordion/_material-definition.scss +72 -72
- package/styles/accordion/_theme.scss +479 -479
- package/styles/accordion/icons/_bootstrap-dark.scss +17 -17
- package/styles/accordion/icons/_bootstrap.scss +17 -17
- package/styles/accordion/icons/_bootstrap4.scss +17 -17
- package/styles/accordion/icons/_fabric-dark.scss +17 -17
- package/styles/accordion/icons/_fabric.scss +17 -17
- package/styles/accordion/icons/_highcontrast-light.scss +17 -17
- package/styles/accordion/icons/_highcontrast.scss +17 -17
- package/styles/accordion/icons/_material-dark.scss +17 -17
- package/styles/accordion/icons/_material.scss +17 -17
- package/styles/accordion/material-dark.css +2 -2
- package/styles/bootstrap-dark.css +10 -9
- package/styles/bootstrap.css +10 -9
- package/styles/bootstrap4.css +10 -9
- package/styles/bootstrap5-dark.css +0 -0
- package/styles/bootstrap5-dark.scss +0 -0
- package/styles/bootstrap5.css +0 -0
- package/styles/bootstrap5.scss +0 -0
- package/styles/context-menu/_all.scss +2 -2
- package/styles/context-menu/_bootstrap-dark-definition.scss +54 -54
- package/styles/context-menu/_bootstrap-definition.scss +52 -52
- package/styles/context-menu/_bootstrap4-definition.scss +52 -52
- package/styles/context-menu/_fabric-dark-definition.scss +54 -54
- package/styles/context-menu/_fabric-definition.scss +52 -52
- package/styles/context-menu/_highcontrast-definition.scss +52 -52
- package/styles/context-menu/_highcontrast-light-definition.scss +54 -54
- package/styles/context-menu/_layout-mixin.scss +175 -174
- package/styles/context-menu/_layout.scss +70 -70
- package/styles/context-menu/_material-dark-definition.scss +54 -54
- package/styles/context-menu/_material-definition.scss +52 -52
- package/styles/context-menu/_theme-mixin.scss +59 -59
- package/styles/context-menu/_theme.scss +36 -36
- package/styles/context-menu/bootstrap-dark.css +1 -1
- package/styles/context-menu/bootstrap.css +1 -1
- package/styles/context-menu/bootstrap4.css +1 -1
- package/styles/context-menu/fabric-dark.css +1 -1
- package/styles/context-menu/fabric.css +1 -1
- package/styles/context-menu/highcontrast-light.css +1 -1
- package/styles/context-menu/highcontrast.css +1 -1
- package/styles/context-menu/icons/_bootstrap-dark.scss +30 -30
- package/styles/context-menu/icons/_bootstrap.scss +30 -30
- package/styles/context-menu/icons/_bootstrap4.scss +30 -30
- package/styles/context-menu/icons/_fabric-dark.scss +30 -30
- package/styles/context-menu/icons/_fabric.scss +30 -30
- package/styles/context-menu/icons/_highcontrast-light.scss +30 -30
- package/styles/context-menu/icons/_highcontrast.scss +30 -30
- package/styles/context-menu/icons/_material-dark.scss +30 -30
- package/styles/context-menu/icons/_material.scss +30 -30
- package/styles/context-menu/material-dark.css +1 -1
- package/styles/context-menu/material.css +4 -4
- package/styles/fabric-dark.css +10 -9
- package/styles/fabric.css +10 -9
- package/styles/h-scroll/_all.scss +2 -2
- package/styles/h-scroll/_bootstrap-dark-definition.scss +49 -49
- package/styles/h-scroll/_bootstrap-definition.scss +50 -50
- package/styles/h-scroll/_bootstrap4-definition.scss +49 -49
- package/styles/h-scroll/_fabric-dark-definition.scss +50 -50
- package/styles/h-scroll/_fabric-definition.scss +48 -48
- package/styles/h-scroll/_highcontrast-definition.scss +52 -52
- package/styles/h-scroll/_highcontrast-light-definition.scss +54 -54
- package/styles/h-scroll/_layout.scss +198 -198
- package/styles/h-scroll/_material-dark-definition.scss +77 -77
- package/styles/h-scroll/_material-definition.scss +77 -77
- package/styles/h-scroll/_theme.scss +157 -157
- package/styles/h-scroll/icons/_bootstrap-dark.scss +49 -49
- package/styles/h-scroll/icons/_bootstrap.scss +49 -49
- package/styles/h-scroll/icons/_bootstrap4.scss +49 -49
- package/styles/h-scroll/icons/_fabric-dark.scss +49 -49
- package/styles/h-scroll/icons/_fabric.scss +49 -49
- package/styles/h-scroll/icons/_highcontrast-light.scss +49 -49
- package/styles/h-scroll/icons/_highcontrast.scss +49 -49
- package/styles/h-scroll/icons/_material-dark.scss +49 -49
- package/styles/h-scroll/icons/_material.scss +49 -49
- package/styles/highcontrast-light.css +10 -9
- package/styles/highcontrast.css +10 -9
- package/styles/material-dark.css +12 -11
- package/styles/material.css +24 -14
- package/styles/menu/_all.scss +2 -2
- package/styles/menu/_bootstrap-dark-definition.scss +63 -63
- package/styles/menu/_bootstrap-definition.scss +65 -65
- package/styles/menu/_bootstrap4-definition.scss +64 -64
- package/styles/menu/_fabric-dark-definition.scss +63 -63
- package/styles/menu/_fabric-definition.scss +64 -64
- package/styles/menu/_highcontrast-definition.scss +65 -65
- package/styles/menu/_highcontrast-light-definition.scss +61 -61
- package/styles/menu/_layout.scss +638 -637
- package/styles/menu/_material-dark-definition.scss +63 -63
- package/styles/menu/_material-definition.scss +64 -64
- package/styles/menu/_theme.scss +243 -243
- package/styles/menu/bootstrap-dark.css +2 -1
- package/styles/menu/bootstrap.css +2 -1
- package/styles/menu/bootstrap.scss +1 -0
- package/styles/menu/bootstrap4.css +2 -1
- package/styles/menu/fabric-dark.css +2 -1
- package/styles/menu/fabric.css +2 -1
- package/styles/menu/fabric.scss +1 -0
- package/styles/menu/highcontrast-light.css +2 -1
- package/styles/menu/highcontrast.css +2 -1
- package/styles/menu/highcontrast.scss +1 -0
- package/styles/menu/icons/_bootstrap-dark.scss +127 -127
- package/styles/menu/icons/_bootstrap.scss +127 -127
- package/styles/menu/icons/_bootstrap4.scss +127 -127
- package/styles/menu/icons/_fabric-dark.scss +127 -127
- package/styles/menu/icons/_fabric.scss +127 -127
- package/styles/menu/icons/_highcontrast-light.scss +127 -127
- package/styles/menu/icons/_highcontrast.scss +127 -127
- package/styles/menu/icons/_material-dark.scss +127 -127
- package/styles/menu/icons/_material.scss +127 -127
- package/styles/menu/material-dark.css +2 -1
- package/styles/menu/material.css +4 -3
- package/styles/menu/material.scss +1 -0
- package/styles/sidebar/_all.scss +3 -3
- package/styles/sidebar/_bootstrap-dark-definition.scss +4 -4
- package/styles/sidebar/_bootstrap-definition.scss +4 -4
- package/styles/sidebar/_bootstrap4-definition.scss +4 -4
- package/styles/sidebar/_fabric-dark-definition.scss +4 -4
- package/styles/sidebar/_fabric-definition.scss +6 -6
- package/styles/sidebar/_highcontrast-definition.scss +4 -4
- package/styles/sidebar/_highcontrast-light-definition.scss +4 -4
- package/styles/sidebar/_icons.scss +1 -1
- package/styles/sidebar/_material-dark-definition.scss +4 -4
- package/styles/sidebar/_material-definition.scss +6 -6
- package/styles/sidebar/_theme.scss +168 -168
- package/styles/sidebar/bootstrap-dark.css +0 -1
- package/styles/sidebar/bootstrap.css +0 -1
- package/styles/sidebar/bootstrap4.css +0 -1
- package/styles/sidebar/fabric-dark.css +0 -1
- package/styles/sidebar/fabric.css +0 -1
- package/styles/sidebar/highcontrast-light.css +0 -1
- package/styles/sidebar/highcontrast.css +0 -1
- package/styles/sidebar/material-dark.css +0 -1
- package/styles/sidebar/material.css +0 -1
- package/styles/tab/_all.scss +2 -2
- package/styles/tab/_bootstrap-dark-definition.scss +386 -386
- package/styles/tab/_bootstrap-definition.scss +396 -396
- package/styles/tab/_bootstrap4-definition.scss +401 -401
- package/styles/tab/_fabric-dark-definition.scss +394 -394
- package/styles/tab/_fabric-definition.scss +410 -410
- package/styles/tab/_highcontrast-definition.scss +434 -434
- package/styles/tab/_highcontrast-light-definition.scss +423 -423
- package/styles/tab/_icons.scss +43 -43
- package/styles/tab/_layout.scss +3528 -3521
- package/styles/tab/_material-dark-definition.scss +407 -407
- package/styles/tab/_material-definition.scss +416 -416
- package/styles/tab/_theme.scss +1751 -1751
- package/styles/tab/bootstrap-dark.css +7 -2
- package/styles/tab/bootstrap.css +7 -2
- package/styles/tab/bootstrap4.css +7 -2
- package/styles/tab/fabric-dark.css +7 -2
- package/styles/tab/fabric.css +7 -2
- package/styles/tab/highcontrast-light.css +7 -2
- package/styles/tab/highcontrast.css +7 -2
- package/styles/tab/icons/_bootstrap-dark.scss +132 -132
- package/styles/tab/icons/_bootstrap.scss +132 -132
- package/styles/tab/icons/_bootstrap4.scss +132 -132
- package/styles/tab/icons/_fabric-dark.scss +132 -132
- package/styles/tab/icons/_fabric.scss +132 -132
- package/styles/tab/icons/_highcontrast-light.scss +132 -132
- package/styles/tab/icons/_highcontrast.scss +132 -132
- package/styles/tab/icons/_material-dark.scss +132 -132
- package/styles/tab/icons/_material.scss +132 -132
- package/styles/tab/material-dark.css +7 -2
- package/styles/tab/material.css +7 -2
- package/styles/tailwind-dark.css +0 -0
- package/styles/tailwind-dark.scss +0 -0
- package/styles/tailwind.css +0 -0
- package/styles/tailwind.scss +0 -0
- package/styles/toolbar/_all.scss +2 -2
- package/styles/toolbar/_bootstrap-dark-definition.scss +135 -135
- package/styles/toolbar/_bootstrap-definition.scss +134 -134
- package/styles/toolbar/_bootstrap4-definition.scss +139 -139
- package/styles/toolbar/_fabric-dark-definition.scss +155 -155
- package/styles/toolbar/_fabric-definition.scss +139 -139
- package/styles/toolbar/_highcontrast-definition.scss +149 -149
- package/styles/toolbar/_highcontrast-light-definition.scss +164 -164
- package/styles/toolbar/_layout.scss +1460 -1460
- package/styles/toolbar/_material-dark-definition.scss +180 -180
- package/styles/toolbar/_material-definition.scss +164 -164
- package/styles/toolbar/_theme.scss +451 -451
- package/styles/toolbar/bootstrap-dark.css +0 -1
- package/styles/toolbar/bootstrap.css +0 -1
- package/styles/toolbar/bootstrap.scss +1 -0
- package/styles/toolbar/bootstrap4.css +0 -1
- package/styles/toolbar/fabric-dark.css +0 -1
- package/styles/toolbar/fabric.css +0 -1
- package/styles/toolbar/fabric.scss +1 -0
- package/styles/toolbar/highcontrast-light.css +0 -1
- package/styles/toolbar/highcontrast.css +0 -1
- package/styles/toolbar/highcontrast.scss +1 -0
- package/styles/toolbar/icons/_bootstrap-dark.scss +16 -16
- package/styles/toolbar/icons/_bootstrap.scss +16 -16
- package/styles/toolbar/icons/_bootstrap4.scss +16 -16
- package/styles/toolbar/icons/_fabric-dark.scss +16 -16
- package/styles/toolbar/icons/_fabric.scss +16 -16
- package/styles/toolbar/icons/_highcontrast-light.scss +16 -16
- package/styles/toolbar/icons/_highcontrast.scss +16 -16
- package/styles/toolbar/icons/_material-dark.scss +16 -16
- package/styles/toolbar/icons/_material.scss +16 -16
- package/styles/toolbar/material-dark.css +0 -1
- package/styles/toolbar/material.css +0 -1
- package/styles/toolbar/material.scss +1 -0
- package/styles/treeview/_all.scss +2 -2
- package/styles/treeview/_bootstrap-dark-definition.scss +131 -131
- package/styles/treeview/_bootstrap-definition.scss +127 -127
- package/styles/treeview/_bootstrap4-definition.scss +153 -153
- package/styles/treeview/_fabric-dark-definition.scss +130 -130
- package/styles/treeview/_fabric-definition.scss +126 -126
- package/styles/treeview/_highcontrast-definition.scss +132 -132
- package/styles/treeview/_highcontrast-light-definition.scss +137 -137
- package/styles/treeview/_layout.scss +551 -551
- package/styles/treeview/_material-dark-definition.scss +126 -126
- package/styles/treeview/_material-definition.scss +126 -126
- package/styles/treeview/_theme.scss +331 -331
- package/styles/treeview/bootstrap-dark.css +0 -3
- package/styles/treeview/bootstrap.css +0 -3
- package/styles/treeview/bootstrap4.css +0 -3
- package/styles/treeview/fabric-dark.css +0 -3
- package/styles/treeview/fabric.css +0 -3
- package/styles/treeview/highcontrast-light.css +0 -3
- package/styles/treeview/highcontrast.css +0 -3
- package/styles/treeview/icons/_bootstrap-dark.scss +39 -39
- package/styles/treeview/icons/_bootstrap.scss +39 -39
- package/styles/treeview/icons/_bootstrap4.scss +39 -39
- package/styles/treeview/icons/_fabric-dark.scss +43 -43
- package/styles/treeview/icons/_fabric.scss +43 -43
- package/styles/treeview/icons/_highcontrast-light.scss +43 -43
- package/styles/treeview/icons/_highcontrast.scss +43 -43
- package/styles/treeview/icons/_material-dark.scss +43 -43
- package/styles/treeview/icons/_material.scss +43 -43
- package/styles/treeview/material-dark.css +0 -3
- package/styles/treeview/material.css +9 -3
- package/styles/v-scroll/_all.scss +2 -2
- package/styles/v-scroll/_bootstrap-dark-definition.scss +50 -50
- package/styles/v-scroll/_bootstrap-definition.scss +49 -49
- package/styles/v-scroll/_bootstrap4-definition.scss +49 -49
- package/styles/v-scroll/_fabric-dark-definition.scss +51 -51
- package/styles/v-scroll/_fabric-definition.scss +50 -50
- package/styles/v-scroll/_highcontrast-definition.scss +51 -51
- package/styles/v-scroll/_highcontrast-light-definition.scss +52 -52
- package/styles/v-scroll/_layout.scss +162 -162
- package/styles/v-scroll/_material-dark-definition.scss +78 -78
- package/styles/v-scroll/_material-definition.scss +77 -77
- package/styles/v-scroll/_theme.scss +133 -133
- package/styles/v-scroll/icons/_bootstrap-dark.scss +26 -26
- package/styles/v-scroll/icons/_bootstrap.scss +26 -26
- package/styles/v-scroll/icons/_bootstrap4.scss +26 -26
- package/styles/v-scroll/icons/_fabric-dark.scss +26 -26
- package/styles/v-scroll/icons/_fabric.scss +26 -26
- package/styles/v-scroll/icons/_highcontrast-light.scss +26 -26
- package/styles/v-scroll/icons/_highcontrast.scss +26 -26
- package/styles/v-scroll/icons/_material-dark.scss +26 -26
- package/styles/v-scroll/icons/_material.scss +26 -26
- package/tslint.json +111 -0
|
@@ -0,0 +1,2131 @@
|
|
|
1
|
+
import { Component, Property, ChildProperty, NotifyPropertyChanges, INotifyPropertyChanged, AnimationModel } from '@syncfusion/ej2-base';
|
|
2
|
+
import { Event, EventHandler, EmitType, BaseEventArgs, KeyboardEvents, KeyboardEventArgs, Touch, TapEventArgs } from '@syncfusion/ej2-base';
|
|
3
|
+
import { attributes, 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, flip, fit, Popup } from '@syncfusion/ej2-popups';
|
|
8
|
+
import { updateBlazorTemplate, resetBlazorTemplate, blazorTemplates, extend } 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
|
+
|
|
14
|
+
type objColl = { [key: string]: Object }[];
|
|
15
|
+
type obj = { [key: string]: Object };
|
|
16
|
+
|
|
17
|
+
const ENTER: string = 'enter';
|
|
18
|
+
|
|
19
|
+
const ESCAPE: string = 'escape';
|
|
20
|
+
|
|
21
|
+
const FOCUSED: string = 'e-focused';
|
|
22
|
+
|
|
23
|
+
const HEADER: string = 'e-menu-header';
|
|
24
|
+
|
|
25
|
+
const SELECTED: string = 'e-selected';
|
|
26
|
+
|
|
27
|
+
const SEPARATOR: string = 'e-separator';
|
|
28
|
+
|
|
29
|
+
const UPARROW: string = 'uparrow';
|
|
30
|
+
|
|
31
|
+
const DOWNARROW: string = 'downarrow';
|
|
32
|
+
|
|
33
|
+
const LEFTARROW: string = 'leftarrow';
|
|
34
|
+
|
|
35
|
+
const RIGHTARROW: string = 'rightarrow';
|
|
36
|
+
|
|
37
|
+
const HOME: string = 'home';
|
|
38
|
+
|
|
39
|
+
const END: string = 'end';
|
|
40
|
+
|
|
41
|
+
const CARET: string = 'e-caret';
|
|
42
|
+
|
|
43
|
+
const ITEM: string = 'e-menu-item';
|
|
44
|
+
|
|
45
|
+
const DISABLED: string = 'e-disabled';
|
|
46
|
+
|
|
47
|
+
const HIDE: string = 'e-menu-hide';
|
|
48
|
+
|
|
49
|
+
const ICONS: string = 'e-icons';
|
|
50
|
+
|
|
51
|
+
const RTL: string = 'e-rtl';
|
|
52
|
+
|
|
53
|
+
const POPUP: string = 'e-menu-popup';
|
|
54
|
+
|
|
55
|
+
const TEMPLATE_PROPERTY: string = 'Template';
|
|
56
|
+
/**
|
|
57
|
+
* Menu animation effects
|
|
58
|
+
*/
|
|
59
|
+
export type MenuEffect = 'None' | 'SlideDown' | 'ZoomIn' | 'FadeIn';
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Configures the field options of the Menu.
|
|
63
|
+
*/
|
|
64
|
+
export class FieldSettings extends ChildProperty<FieldSettings> {
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Specifies the itemId field for Menu item.
|
|
68
|
+
* @default 'id'
|
|
69
|
+
*/
|
|
70
|
+
@Property('id')
|
|
71
|
+
public itemId: string | string[];
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Specifies the parentId field for Menu item.
|
|
75
|
+
* @default 'parentId'
|
|
76
|
+
*/
|
|
77
|
+
@Property('parentId')
|
|
78
|
+
public parentId: string | string[];
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Specifies the text field for Menu item.
|
|
82
|
+
* @default 'text'
|
|
83
|
+
*/
|
|
84
|
+
@Property('text')
|
|
85
|
+
public text: string | string[];
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Specifies the css icon field for Menu item.
|
|
89
|
+
* @default 'iconCss'
|
|
90
|
+
*/
|
|
91
|
+
@Property('iconCss')
|
|
92
|
+
public iconCss: string | string[];
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Specifies the Url field for Menu item.
|
|
96
|
+
* @default 'url'
|
|
97
|
+
*/
|
|
98
|
+
@Property('url')
|
|
99
|
+
public url: string | string[];
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Specifies the separator field for Menu item.
|
|
103
|
+
* @default 'separator'
|
|
104
|
+
*/
|
|
105
|
+
@Property('separator')
|
|
106
|
+
public separator: string | string[];
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Specifies the children field for Menu item.
|
|
110
|
+
* @default 'items'
|
|
111
|
+
*/
|
|
112
|
+
@Property('items')
|
|
113
|
+
public children: string | string[];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface BrowserDetails {
|
|
117
|
+
isAndroid?: boolean;
|
|
118
|
+
isDevice?: boolean;
|
|
119
|
+
isIE?: boolean;
|
|
120
|
+
isIos?: boolean;
|
|
121
|
+
isIos7?: boolean;
|
|
122
|
+
isMSPointer?: boolean;
|
|
123
|
+
isPointer?: boolean;
|
|
124
|
+
isTouch?: boolean;
|
|
125
|
+
isWebView?: boolean;
|
|
126
|
+
isWindows?: boolean;
|
|
127
|
+
touchStartEvent?: string;
|
|
128
|
+
touchMoveEvent?: string;
|
|
129
|
+
touchEndEvent?: string;
|
|
130
|
+
touchCancelEvent?: string;
|
|
131
|
+
}
|
|
132
|
+
interface MyWindow extends Window {
|
|
133
|
+
browserDetails: BrowserDetails;
|
|
134
|
+
cordova: Object;
|
|
135
|
+
PhoneGap: Object;
|
|
136
|
+
phonegap: Object;
|
|
137
|
+
forge: Object;
|
|
138
|
+
}
|
|
139
|
+
declare let window: MyWindow;
|
|
140
|
+
const REGX_IOS: RegExp = /(ipad|iphone|ipod touch)/i;
|
|
141
|
+
const REGX_BROWSER: { [key: string]: RegExp } = {
|
|
142
|
+
OPERA: /(opera|opr)(?:.*version|)[ /]([\w.]+)/i,
|
|
143
|
+
EDGE: /(edge)(?:.*version|)[ /]([\w.]+)/i,
|
|
144
|
+
CHROME: /(chrome|crios)[ /]([\w.]+)/i,
|
|
145
|
+
PANTHOMEJS: /(phantomjs)[ /]([\w.]+)/i,
|
|
146
|
+
SAFARI: /(safari)[ /]([\w.]+)/i,
|
|
147
|
+
WEBKIT: /(webkit)[ /]([\w.]+)/i,
|
|
148
|
+
MSIE: /(msie|trident) ([\w.]+)/i,
|
|
149
|
+
MOZILLA: /(mozilla)(?:.*? rv:([\w.]+)|)/i
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Specifies menu items.
|
|
154
|
+
*/
|
|
155
|
+
export class MenuItem extends ChildProperty<MenuItem> {
|
|
156
|
+
/**
|
|
157
|
+
* Defines class/multiple classes separated by a space for the menu Item that is used to include an icon.
|
|
158
|
+
* Menu Item can include font icon and sprite image.
|
|
159
|
+
* @default null
|
|
160
|
+
*/
|
|
161
|
+
@Property(null)
|
|
162
|
+
public iconCss: string;
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Specifies the id for menu item.
|
|
166
|
+
* @default ''
|
|
167
|
+
*/
|
|
168
|
+
@Property('')
|
|
169
|
+
public id: string;
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Specifies separator between the menu items. Separator are either horizontal or vertical lines used to group menu items.
|
|
173
|
+
* @default false
|
|
174
|
+
*/
|
|
175
|
+
@Property(false)
|
|
176
|
+
public separator: boolean;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Specifies the sub menu items that is the array of MenuItem model.
|
|
180
|
+
* @default []
|
|
181
|
+
*/
|
|
182
|
+
@Collection<MenuItemModel>([], MenuItem)
|
|
183
|
+
public items: MenuItemModel[];
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Specifies text for menu item.
|
|
187
|
+
* @default ''
|
|
188
|
+
*/
|
|
189
|
+
@Property('')
|
|
190
|
+
public text: string;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Specifies url for menu item that creates the anchor link to navigate to the url provided.
|
|
194
|
+
* @default ''
|
|
195
|
+
*/
|
|
196
|
+
@Property('')
|
|
197
|
+
public url: string;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Animation configuration settings.
|
|
202
|
+
*/
|
|
203
|
+
export class MenuAnimationSettings extends ChildProperty<MenuAnimationSettings> {
|
|
204
|
+
/**
|
|
205
|
+
* Specifies the effect that shown in the sub menu transform.
|
|
206
|
+
* The possible effects are:
|
|
207
|
+
* * None: Specifies the sub menu transform with no animation effect.
|
|
208
|
+
* * SlideDown: Specifies the sub menu transform with slide down effect.
|
|
209
|
+
* * ZoomIn: Specifies the sub menu transform with zoom in effect.
|
|
210
|
+
* * FadeIn: Specifies the sub menu transform with fade in effect.
|
|
211
|
+
* @default 'SlideDown'
|
|
212
|
+
* @aspType Syncfusion.EJ2.Navigations.MenuEffect
|
|
213
|
+
* @blazorType Syncfusion.EJ2.Navigations.MenuEffect
|
|
214
|
+
* @isEnumeration true
|
|
215
|
+
*/
|
|
216
|
+
@Property('SlideDown')
|
|
217
|
+
public effect: MenuEffect;
|
|
218
|
+
/**
|
|
219
|
+
* Specifies the time duration to transform object.
|
|
220
|
+
* @default 400
|
|
221
|
+
*/
|
|
222
|
+
@Property(400)
|
|
223
|
+
public duration: number;
|
|
224
|
+
/**
|
|
225
|
+
* Specifies the easing effect applied while transform.
|
|
226
|
+
* @default 'ease'
|
|
227
|
+
*/
|
|
228
|
+
@Property('ease')
|
|
229
|
+
public easing: string;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* @private
|
|
234
|
+
* Base class for Menu and ContextMenu components.
|
|
235
|
+
*/
|
|
236
|
+
@NotifyPropertyChanges
|
|
237
|
+
export abstract class MenuBase extends Component<HTMLUListElement> implements INotifyPropertyChanged {
|
|
238
|
+
private clonedElement: HTMLElement;
|
|
239
|
+
private targetElement: HTMLElement;
|
|
240
|
+
private delegateClickHandler: Function;
|
|
241
|
+
private delegateMoverHandler: Function;
|
|
242
|
+
private delegateMouseDownHandler: Function;
|
|
243
|
+
private navIdx: number[] = [];
|
|
244
|
+
private animation: Animation = new Animation({});
|
|
245
|
+
private isTapHold: boolean = false;
|
|
246
|
+
protected isMenu: boolean;
|
|
247
|
+
protected hamburgerMode: boolean;
|
|
248
|
+
protected title: string;
|
|
249
|
+
private rippleFn: Function;
|
|
250
|
+
private uList: HTMLElement;
|
|
251
|
+
private lItem: Element;
|
|
252
|
+
private popupObj: Popup;
|
|
253
|
+
private popupWrapper: HTMLElement;
|
|
254
|
+
private isNestedOrVertical: boolean;
|
|
255
|
+
private top: number;
|
|
256
|
+
private left: number;
|
|
257
|
+
private keyType: string;
|
|
258
|
+
private showSubMenu: boolean;
|
|
259
|
+
private action: string;
|
|
260
|
+
private cli: Element;
|
|
261
|
+
private cliIdx: number;
|
|
262
|
+
private isClosed: boolean;
|
|
263
|
+
private liTrgt: Element;
|
|
264
|
+
private isMenusClosed: boolean;
|
|
265
|
+
private isCMenu: boolean;
|
|
266
|
+
private pageX: number;
|
|
267
|
+
private pageY: number;
|
|
268
|
+
private tempItem: objColl = [];
|
|
269
|
+
/**
|
|
270
|
+
* Triggers while rendering each menu item.
|
|
271
|
+
* @event
|
|
272
|
+
* @blazorProperty 'OnItemRender'
|
|
273
|
+
*/
|
|
274
|
+
@Event()
|
|
275
|
+
public beforeItemRender: EmitType<MenuEventArgs>;
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Triggers before opening the menu item.
|
|
279
|
+
* @event
|
|
280
|
+
* @blazorProperty 'OnOpen'
|
|
281
|
+
*/
|
|
282
|
+
@Event()
|
|
283
|
+
public beforeOpen: EmitType<BeforeOpenCloseMenuEventArgs>;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Triggers while opening the menu item.
|
|
287
|
+
* @event
|
|
288
|
+
* @blazorProperty 'Opened'
|
|
289
|
+
*/
|
|
290
|
+
@Event()
|
|
291
|
+
public onOpen: EmitType<OpenCloseMenuEventArgs>;
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Triggers before closing the menu.
|
|
295
|
+
* @event
|
|
296
|
+
* @blazorProperty 'OnClose'
|
|
297
|
+
*/
|
|
298
|
+
@Event()
|
|
299
|
+
public beforeClose: EmitType<BeforeOpenCloseMenuEventArgs>;
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Triggers while closing the menu.
|
|
303
|
+
* @event
|
|
304
|
+
* @blazorProperty 'Closed'
|
|
305
|
+
*/
|
|
306
|
+
@Event()
|
|
307
|
+
public onClose: EmitType<OpenCloseMenuEventArgs>;
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Triggers while selecting menu item.
|
|
311
|
+
* @event
|
|
312
|
+
* @blazorProperty 'ItemSelected'
|
|
313
|
+
*/
|
|
314
|
+
@Event()
|
|
315
|
+
public select: EmitType<MenuEventArgs>;
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Triggers once the component rendering is completed.
|
|
319
|
+
* @event
|
|
320
|
+
* @blazorProperty 'Created'
|
|
321
|
+
*/
|
|
322
|
+
@Event()
|
|
323
|
+
public created: EmitType<Event>;
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Defines class/multiple classes separated by a space in the Menu wrapper.
|
|
327
|
+
* @default ''
|
|
328
|
+
*/
|
|
329
|
+
@Property('')
|
|
330
|
+
public cssClass: string;
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Specifies whether to show the sub menu or not on click.
|
|
334
|
+
* When set to true, the sub menu will open only on mouse click.
|
|
335
|
+
* @default false
|
|
336
|
+
*/
|
|
337
|
+
@Property(false)
|
|
338
|
+
public showItemOnClick: boolean;
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Specifies target element selector in which the ContextMenu should be opened.
|
|
342
|
+
* Specifies target element to open/close Menu while click in Hamburger mode.
|
|
343
|
+
* @default ''
|
|
344
|
+
* @private
|
|
345
|
+
*/
|
|
346
|
+
@Property('')
|
|
347
|
+
public target: string;
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Specifies the filter selector for elements inside the target in that the context menu will be opened.
|
|
351
|
+
* Not applicable to Menu component.
|
|
352
|
+
* @default ''
|
|
353
|
+
* @private
|
|
354
|
+
*/
|
|
355
|
+
@Property('')
|
|
356
|
+
public filter: string;
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Specifies the template for Menu item.
|
|
360
|
+
* Not applicable to ContextMenu component.
|
|
361
|
+
* @default null
|
|
362
|
+
* @private
|
|
363
|
+
*/
|
|
364
|
+
@Property(null)
|
|
365
|
+
public template: string;
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Specifies whether to enable / disable the scrollable option in Menu.
|
|
369
|
+
* Not applicable to ContextMenu component.
|
|
370
|
+
* @default false
|
|
371
|
+
* @private
|
|
372
|
+
*/
|
|
373
|
+
@Property(false)
|
|
374
|
+
public enableScrolling: boolean;
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Specifies mapping fields from the dataSource.
|
|
378
|
+
* Not applicable to ContextMenu component.
|
|
379
|
+
* @default { itemId: "id", text: "text", parentId: "parentId", iconCss: "iconCss", url: "url", separator: "separator",
|
|
380
|
+
* children: "items" }
|
|
381
|
+
* @private
|
|
382
|
+
*/
|
|
383
|
+
@Complex<FieldSettingsModel>({}, FieldSettings)
|
|
384
|
+
public fields: FieldSettingsModel;
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Specifies menu items with its properties which will be rendered as Menu.
|
|
388
|
+
* @default []
|
|
389
|
+
*/
|
|
390
|
+
@Collection<MenuItemModel>([], MenuItem)
|
|
391
|
+
public items: MenuItemModel[] | { [key: string]: Object }[];
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Specifies the animation settings for the sub menu open.
|
|
395
|
+
* @default { duration: 400, easing: 'ease', effect: 'SlideDown' }
|
|
396
|
+
*/
|
|
397
|
+
@Complex<MenuAnimationSettingsModel>({}, MenuAnimationSettings)
|
|
398
|
+
public animationSettings: MenuAnimationSettingsModel;
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Constructor for creating the widget.
|
|
402
|
+
* @private
|
|
403
|
+
*/
|
|
404
|
+
constructor(options?: MenuBaseModel, element?: string | HTMLUListElement) {
|
|
405
|
+
super(options, <HTMLUListElement | string>element);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Initialized third party configuration settings.
|
|
410
|
+
* @private
|
|
411
|
+
*/
|
|
412
|
+
protected preRender(): void {
|
|
413
|
+
if (!this.isMenu) {
|
|
414
|
+
let ul: HTMLUListElement;
|
|
415
|
+
if (this.element.tagName === 'EJS-CONTEXTMENU') {
|
|
416
|
+
ul = this.createElement('ul', {
|
|
417
|
+
id: getUniqueID(this.getModuleName()), className: 'e-control e-lib e-' + this.getModuleName() }) as HTMLUListElement;
|
|
418
|
+
let ejInst: Object = getValue('ej2_instances', this.element);
|
|
419
|
+
removeClass([this.element], ['e-control', 'e-lib', 'e-' + this.getModuleName()]);
|
|
420
|
+
this.clonedElement = this.element; this.element = ul;
|
|
421
|
+
setValue('ej2_instances', ejInst, this.element);
|
|
422
|
+
} else {
|
|
423
|
+
ul = this.createElement('ul', { id: getUniqueID(this.getModuleName()) }) as HTMLUListElement;
|
|
424
|
+
append([].slice.call((this.element.cloneNode(true) as Element).children), ul);
|
|
425
|
+
let refEle: Element = this.element.nextElementSibling;
|
|
426
|
+
refEle ? this.element.parentElement.insertBefore(ul, refEle) : this.element.parentElement.appendChild(ul);
|
|
427
|
+
this.clonedElement = ul;
|
|
428
|
+
}
|
|
429
|
+
this.clonedElement.style.display = 'none';
|
|
430
|
+
}
|
|
431
|
+
if (this.element.tagName === 'EJS-MENU') {
|
|
432
|
+
let ele: Element = this.element;
|
|
433
|
+
let ejInstance: Object = getValue('ej2_instances', ele);
|
|
434
|
+
let ul: Element = this.createElement('ul');
|
|
435
|
+
let wrapper: HTMLElement = this.createElement('EJS-MENU', { className: 'e-' + this.getModuleName() + '-wrapper' });
|
|
436
|
+
for (let idx: number = 0, len: number = ele.attributes.length; idx < len; idx++) {
|
|
437
|
+
ul.setAttribute(ele.attributes[idx].nodeName, ele.attributes[idx].nodeValue);
|
|
438
|
+
}
|
|
439
|
+
ele.parentNode.insertBefore(wrapper, ele);
|
|
440
|
+
detach(ele);
|
|
441
|
+
ele = ul;
|
|
442
|
+
wrapper.appendChild(ele);
|
|
443
|
+
setValue('ej2_instances', ejInstance, ele);
|
|
444
|
+
this.clonedElement = wrapper;
|
|
445
|
+
this.element = ele as HTMLUListElement;
|
|
446
|
+
if (!this.element.id) {
|
|
447
|
+
this.element.id = getUniqueID(this.getModuleName());
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Initialize the control rendering
|
|
454
|
+
* @private
|
|
455
|
+
*/
|
|
456
|
+
protected render(): void {
|
|
457
|
+
this.initialize();
|
|
458
|
+
this.renderItems();
|
|
459
|
+
if (this.isMenu && this.template && this.isBlazor()) {
|
|
460
|
+
let menuTemplateId: string = this.element.id + TEMPLATE_PROPERTY;
|
|
461
|
+
resetBlazorTemplate(menuTemplateId, TEMPLATE_PROPERTY);
|
|
462
|
+
if (Object.keys(blazorTemplates).length) {
|
|
463
|
+
extend(this.tempItem, (<{ [key: string]: Object }>blazorTemplates)[menuTemplateId], [], true);
|
|
464
|
+
}
|
|
465
|
+
updateBlazorTemplate(menuTemplateId, TEMPLATE_PROPERTY, this);
|
|
466
|
+
}
|
|
467
|
+
this.wireEvents();
|
|
468
|
+
this.renderComplete();
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
protected initialize(): void {
|
|
472
|
+
let wrapper: Element = this.getWrapper();
|
|
473
|
+
if (!wrapper) {
|
|
474
|
+
wrapper = this.createElement('div', { className: 'e-' + this.getModuleName() + '-wrapper' });
|
|
475
|
+
if (this.isMenu) {
|
|
476
|
+
this.element.parentElement.insertBefore(wrapper, this.element);
|
|
477
|
+
} else {
|
|
478
|
+
document.body.appendChild(wrapper);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (this.cssClass) {
|
|
482
|
+
addClass([wrapper], this.cssClass.split(' '));
|
|
483
|
+
}
|
|
484
|
+
if (this.enableRtl) {
|
|
485
|
+
wrapper.classList.add(RTL);
|
|
486
|
+
}
|
|
487
|
+
wrapper.appendChild(this.element);
|
|
488
|
+
if (this.isMenu && this.hamburgerMode) {
|
|
489
|
+
if (!this.target) {
|
|
490
|
+
this.createHeaderContainer(wrapper);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
private renderItems(): void {
|
|
496
|
+
if (!(this.items as objColl).length) {
|
|
497
|
+
let items: { [key: string]: Object; }[] = ListBase.createJsonFromElement(this.element, { fields: { child: 'items' } });
|
|
498
|
+
this.setProperties({ items: items }, true);
|
|
499
|
+
if (this.isBlazor()) {
|
|
500
|
+
this.element = this.removeChildElement(this.element);
|
|
501
|
+
} else {
|
|
502
|
+
this.element.innerHTML = '';
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
let ul: Element = this.createItems(this.items as objColl);
|
|
506
|
+
append(Array.prototype.slice.call(ul.children), this.element);
|
|
507
|
+
this.element.classList.add('e-menu-parent');
|
|
508
|
+
let wrapper: HTMLElement = this.getWrapper() as HTMLElement;
|
|
509
|
+
this.element.classList.contains('e-vertical') ?
|
|
510
|
+
this.addScrolling(wrapper, this.element, 'vscroll', wrapper.offsetHeight, this.element.offsetHeight)
|
|
511
|
+
: this.addScrolling(wrapper, this.element, 'hscroll', wrapper.offsetWidth, this.element.offsetWidth);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
protected wireEvents(): void {
|
|
515
|
+
let wrapper: HTMLElement = this.getWrapper() as HTMLElement;
|
|
516
|
+
if (this.target) {
|
|
517
|
+
let target: HTMLElement;
|
|
518
|
+
let targetElems: HTMLElement[] = selectAll(this.target);
|
|
519
|
+
for (let i: number = 0, len: number = targetElems.length; i < len; i++) {
|
|
520
|
+
target = targetElems[i];
|
|
521
|
+
if (this.isMenu) {
|
|
522
|
+
EventHandler.add(target, 'click', this.menuHeaderClickHandler, this);
|
|
523
|
+
} else {
|
|
524
|
+
if (this.menuIos()) {
|
|
525
|
+
new Touch(target, { tapHold: this.touchHandler.bind(this) });
|
|
526
|
+
} else {
|
|
527
|
+
EventHandler.add(target, 'contextmenu', this.cmenuHandler, this);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
this.targetElement = target;
|
|
532
|
+
if (!this.isMenu) {
|
|
533
|
+
EventHandler.add(this.targetElement, 'scroll', this.scrollHandler, this);
|
|
534
|
+
for (let parent of getScrollableParent(this.targetElement)) {
|
|
535
|
+
EventHandler.add(parent, 'scroll', this.scrollHandler, this);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
if (!Browser.isDevice) {
|
|
540
|
+
this.delegateMoverHandler = this.moverHandler.bind(this);
|
|
541
|
+
this.delegateMouseDownHandler = this.mouseDownHandler.bind(this);
|
|
542
|
+
EventHandler.add(this.isMenu ? document : wrapper, 'mouseover', this.delegateMoverHandler, this);
|
|
543
|
+
EventHandler.add(document, 'mousedown', this.delegateMouseDownHandler, this);
|
|
544
|
+
}
|
|
545
|
+
this.delegateClickHandler = this.clickHandler.bind(this);
|
|
546
|
+
EventHandler.add(document, 'click', this.delegateClickHandler, this);
|
|
547
|
+
this.wireKeyboardEvent(wrapper);
|
|
548
|
+
this.rippleFn = rippleEffect(wrapper, { selector: '.' + ITEM });
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
private menuIos(): boolean {
|
|
552
|
+
return <boolean>this.getValue('isIos', REGX_IOS);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
private getValue(key: string, regX: RegExp): Object {
|
|
556
|
+
const browserDetails: any = typeof window !== 'undefined' ? window.browserDetails : {};
|
|
557
|
+
if (typeof navigator !== 'undefined' && navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1 && Browser.isTouch === true && !REGX_BROWSER.CHROME.test(navigator.userAgent)) {
|
|
558
|
+
browserDetails['isIos'] = true;
|
|
559
|
+
browserDetails['isDevice'] = true;
|
|
560
|
+
browserDetails['isTouch'] = true;
|
|
561
|
+
browserDetails['isPointer'] = true;
|
|
562
|
+
}
|
|
563
|
+
if ('undefined' === typeof (<{ [key: string]: Object }>browserDetails)[`${key}`]) {
|
|
564
|
+
return (<{ [key: string]: Object }>browserDetails)[`${key}`] = regX.test(Browser.userAgent);
|
|
565
|
+
}
|
|
566
|
+
return (<{ [key: string]: Object }>browserDetails)[`${key}`];
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
private wireKeyboardEvent(element: HTMLElement): void {
|
|
570
|
+
let keyConfigs: { [key: string]: string; } = {
|
|
571
|
+
downarrow: DOWNARROW,
|
|
572
|
+
uparrow: UPARROW,
|
|
573
|
+
enter: ENTER,
|
|
574
|
+
leftarrow: LEFTARROW,
|
|
575
|
+
rightarrow: RIGHTARROW,
|
|
576
|
+
escape: ESCAPE
|
|
577
|
+
};
|
|
578
|
+
if (this.isMenu) {
|
|
579
|
+
keyConfigs.home = HOME;
|
|
580
|
+
keyConfigs.end = END;
|
|
581
|
+
}
|
|
582
|
+
new KeyboardEvents(element, {
|
|
583
|
+
keyAction: this.keyBoardHandler.bind(this),
|
|
584
|
+
keyConfigs: keyConfigs
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
private mouseDownHandler(e: MouseEvent): void {
|
|
589
|
+
if (closest(e.target as Element, '.e-' + this.getModuleName() + '-wrapper') !== this.getWrapper()
|
|
590
|
+
&& (!closest(e.target as Element, '.e-' + this.getModuleName() + '-popup'))) {
|
|
591
|
+
this.closeMenu(this.isMenu ? null : this.navIdx.length, e);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
private keyBoardHandler(e: KeyboardEventArgs): void {
|
|
596
|
+
let actionName: string = '';
|
|
597
|
+
let trgt: Element = e.target as Element;
|
|
598
|
+
let actionNeeded: boolean = this.isMenu && !this.hamburgerMode && !this.element.classList.contains('e-vertical')
|
|
599
|
+
&& this.navIdx.length < 1;
|
|
600
|
+
e.preventDefault();
|
|
601
|
+
if (this.enableScrolling && e.keyCode === 13 && trgt.classList.contains('e-scroll-nav')) {
|
|
602
|
+
this.removeLIStateByClass([FOCUSED, SELECTED], [closest(trgt, '.e-' + this.getModuleName() + '-wrapper')]);
|
|
603
|
+
}
|
|
604
|
+
if (actionNeeded) {
|
|
605
|
+
switch (e.action) {
|
|
606
|
+
case RIGHTARROW:
|
|
607
|
+
actionName = RIGHTARROW;
|
|
608
|
+
e.action = DOWNARROW;
|
|
609
|
+
break;
|
|
610
|
+
case LEFTARROW:
|
|
611
|
+
actionName = LEFTARROW;
|
|
612
|
+
e.action = UPARROW;
|
|
613
|
+
break;
|
|
614
|
+
case DOWNARROW:
|
|
615
|
+
actionName = DOWNARROW;
|
|
616
|
+
e.action = RIGHTARROW;
|
|
617
|
+
break;
|
|
618
|
+
case UPARROW:
|
|
619
|
+
actionName = UPARROW;
|
|
620
|
+
e.action = '';
|
|
621
|
+
break;
|
|
622
|
+
}
|
|
623
|
+
} else if (this.enableRtl) {
|
|
624
|
+
switch (e.action) {
|
|
625
|
+
case LEFTARROW:
|
|
626
|
+
actionNeeded = true;
|
|
627
|
+
actionName = LEFTARROW;
|
|
628
|
+
e.action = RIGHTARROW;
|
|
629
|
+
break;
|
|
630
|
+
case RIGHTARROW:
|
|
631
|
+
actionNeeded = true;
|
|
632
|
+
actionName = RIGHTARROW;
|
|
633
|
+
e.action = LEFTARROW;
|
|
634
|
+
break;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
switch (e.action) {
|
|
638
|
+
case DOWNARROW:
|
|
639
|
+
case UPARROW:
|
|
640
|
+
case END:
|
|
641
|
+
case HOME:
|
|
642
|
+
this.upDownKeyHandler(e);
|
|
643
|
+
break;
|
|
644
|
+
case RIGHTARROW:
|
|
645
|
+
this.rightEnterKeyHandler(e);
|
|
646
|
+
break;
|
|
647
|
+
case LEFTARROW:
|
|
648
|
+
this.leftEscKeyHandler(e);
|
|
649
|
+
break;
|
|
650
|
+
case ENTER:
|
|
651
|
+
if (this.hamburgerMode && trgt.tagName === 'SPAN' && trgt.classList.contains('e-menu-icon')) {
|
|
652
|
+
this.menuHeaderClickHandler(e);
|
|
653
|
+
} else {
|
|
654
|
+
this.rightEnterKeyHandler(e);
|
|
655
|
+
}
|
|
656
|
+
break;
|
|
657
|
+
case ESCAPE:
|
|
658
|
+
this.leftEscKeyHandler(e);
|
|
659
|
+
break;
|
|
660
|
+
}
|
|
661
|
+
if (actionNeeded) {
|
|
662
|
+
e.action = actionName;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
private upDownKeyHandler(e: KeyboardEventArgs): void {
|
|
667
|
+
let cul: Element = this.getUlByNavIdx();
|
|
668
|
+
let defaultIdx: number = (e.action === DOWNARROW || e.action === HOME) ? 0 : cul.childElementCount - 1;
|
|
669
|
+
let fliIdx: number = defaultIdx;
|
|
670
|
+
let fli: Element = this.getLIByClass(cul, FOCUSED);
|
|
671
|
+
if (fli) {
|
|
672
|
+
if (e.action !== END && e.action !== HOME) {
|
|
673
|
+
fliIdx = this.getIdx(cul, fli);
|
|
674
|
+
}
|
|
675
|
+
fli.classList.remove(FOCUSED);
|
|
676
|
+
if (e.action !== END && e.action !== HOME) {
|
|
677
|
+
e.action === DOWNARROW ? fliIdx++ : fliIdx--;
|
|
678
|
+
if (fliIdx === (e.action === DOWNARROW ? cul.childElementCount : -1)) {
|
|
679
|
+
fliIdx = defaultIdx;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
let cli: Element = cul.children[fliIdx];
|
|
684
|
+
fliIdx = this.isValidLI(cli, fliIdx, e.action);
|
|
685
|
+
cul.children[fliIdx].classList.add(FOCUSED);
|
|
686
|
+
(cul.children[fliIdx] as HTMLElement).focus();
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
private isValidLI(cli: Element, index: number, action: string): number {
|
|
690
|
+
let wrapper: Element = this.getWrapper();
|
|
691
|
+
let cul: Element = this.getUlByNavIdx();
|
|
692
|
+
if (cli.classList.contains(SEPARATOR) || cli.classList.contains(DISABLED) || cli.classList.contains(HIDE)) {
|
|
693
|
+
((action === DOWNARROW) || (action === RIGHTARROW)) ? index++ : index--;
|
|
694
|
+
}
|
|
695
|
+
cli = cul.children[index];
|
|
696
|
+
if (cli.classList.contains(SEPARATOR) || cli.classList.contains(DISABLED) || cli.classList.contains(HIDE)) {
|
|
697
|
+
index = this.isValidLI(cli, index, action);
|
|
698
|
+
}
|
|
699
|
+
return index;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
private getUlByNavIdx(navIdxLen: number = this.navIdx.length): HTMLElement {
|
|
703
|
+
if (this.isMenu) {
|
|
704
|
+
let popup: Element = [this.getWrapper()].concat([].slice.call(selectAll('.' + POPUP)))[navIdxLen];
|
|
705
|
+
return isNullOrUndefined(popup) ? null : select('.e-menu-parent', popup) as HTMLElement;
|
|
706
|
+
} else {
|
|
707
|
+
return this.getWrapper().children[navIdxLen] as HTMLElement;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
private rightEnterKeyHandler(e: KeyboardEventArgs): void {
|
|
712
|
+
let eventArgs: MenuEventArgs;
|
|
713
|
+
let cul: Element = this.getUlByNavIdx();
|
|
714
|
+
let fli: Element = this.getLIByClass(cul, FOCUSED);
|
|
715
|
+
if (fli) {
|
|
716
|
+
let fliIdx: number = this.getIdx(cul, fli);
|
|
717
|
+
let navIdx: number[] = this.navIdx.concat(fliIdx);
|
|
718
|
+
let index: number;
|
|
719
|
+
let item: MenuItemModel = this.getItem(navIdx);
|
|
720
|
+
if (item.items.length) {
|
|
721
|
+
this.navIdx.push(fliIdx);
|
|
722
|
+
this.keyType = 'right';
|
|
723
|
+
this.action = e.action;
|
|
724
|
+
this.openMenu(fli, item, null, null, e);
|
|
725
|
+
} else {
|
|
726
|
+
if (e.action === ENTER) {
|
|
727
|
+
if (this.isMenu && this.navIdx.length === 0) {
|
|
728
|
+
this.removeLIStateByClass([SELECTED], [this.getWrapper()]);
|
|
729
|
+
} else {
|
|
730
|
+
fli.classList.remove(FOCUSED);
|
|
731
|
+
}
|
|
732
|
+
fli.classList.add(SELECTED);
|
|
733
|
+
eventArgs = { element: fli as HTMLElement, item: item, event: e };
|
|
734
|
+
this.trigger('select', eventArgs);
|
|
735
|
+
this.closeMenu(null, e);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
private leftEscKeyHandler(e: KeyboardEventArgs): void {
|
|
742
|
+
if (this.navIdx.length) {
|
|
743
|
+
this.keyType = 'left';
|
|
744
|
+
this.closeMenu(this.navIdx.length, e);
|
|
745
|
+
} else {
|
|
746
|
+
if (e.action === ESCAPE) {
|
|
747
|
+
this.closeMenu(null, e);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
private scrollHandler(e: MouseEvent): void {
|
|
753
|
+
this.closeMenu(null, e);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
private touchHandler(e: TapEventArgs): void {
|
|
757
|
+
this.isTapHold = true;
|
|
758
|
+
this.cmenuHandler(e.originalEvent);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
private cmenuHandler(e: MouseEvent & (TouchEventArgs | MouseEventArgs)): void {
|
|
762
|
+
e.preventDefault();
|
|
763
|
+
this.isCMenu = true;
|
|
764
|
+
this.pageX = e.changedTouches ? e.changedTouches[0].pageX + 1 : e.pageX + 1;
|
|
765
|
+
this.pageY = e.changedTouches ? e.changedTouches[0].pageY + 1 : e.pageY + 1;
|
|
766
|
+
this.closeMenu(null, e);
|
|
767
|
+
if (this.isCMenu) {
|
|
768
|
+
if (this.canOpen(e.target as Element)) {
|
|
769
|
+
this.openMenu(null, null, this.pageY, this.pageX, e);
|
|
770
|
+
}
|
|
771
|
+
this.isCMenu = false;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
protected closeMenu(ulIndex: number = 0, e: MouseEvent | KeyboardEvent = null): void {
|
|
776
|
+
if (this.isMenuVisible()) {
|
|
777
|
+
let sli: Element;
|
|
778
|
+
let ul: HTMLElement;
|
|
779
|
+
let item: MenuItemModel;
|
|
780
|
+
let items: MenuItemModel[];
|
|
781
|
+
let beforeCloseArgs: BeforeOpenCloseMenuEventArgs;
|
|
782
|
+
let wrapper: Element = this.getWrapper();
|
|
783
|
+
let popups: Element[] = this.getPopups();
|
|
784
|
+
let isClose: boolean = false;
|
|
785
|
+
let cnt: number = this.isMenu ? popups.length + 1 : wrapper.childElementCount;
|
|
786
|
+
ul = this.isMenu && cnt !== 1 ? select('.e-ul', popups[cnt - 2]) as HTMLElement
|
|
787
|
+
: selectAll('.e-menu-parent', wrapper)[cnt - 1] as HTMLElement;
|
|
788
|
+
if (this.isMenu && ul.classList.contains('e-menu')) {
|
|
789
|
+
sli = this.getLIByClass(ul, SELECTED);
|
|
790
|
+
if (sli) {
|
|
791
|
+
sli.classList.remove(SELECTED);
|
|
792
|
+
}
|
|
793
|
+
isClose = true;
|
|
794
|
+
}
|
|
795
|
+
if (!isClose) {
|
|
796
|
+
item = this.navIdx.length ? this.getItem(this.navIdx) : null;
|
|
797
|
+
items = item ? item.items : this.items as objColl;
|
|
798
|
+
beforeCloseArgs = { element: ul, parentItem: item, items: items, event: e, cancel: false };
|
|
799
|
+
this.trigger('beforeClose', beforeCloseArgs, (observedCloseArgs: BeforeOpenCloseMenuEventArgs) => {
|
|
800
|
+
let popupEle: HTMLElement; let closeArgs: OpenCloseMenuEventArgs;
|
|
801
|
+
let popupObj: Popup; let isOpen: boolean = !observedCloseArgs.cancel;
|
|
802
|
+
if (isOpen || this.isCMenu) {
|
|
803
|
+
if (this.isMenu) {
|
|
804
|
+
popupEle = closest(ul, '.' + POPUP) as HTMLElement;
|
|
805
|
+
if (this.hamburgerMode) {
|
|
806
|
+
popupEle.parentElement.style.minHeight = '';
|
|
807
|
+
}
|
|
808
|
+
this.unWireKeyboardEvent(popupEle);
|
|
809
|
+
this.destroyScrollObj(
|
|
810
|
+
getInstance(popupEle.children[0] as HTMLElement, VScroll) as VScroll, popupEle.children[0]);
|
|
811
|
+
popupObj = getInstance(popupEle, Popup) as Popup;
|
|
812
|
+
popupObj.hide();
|
|
813
|
+
popupObj.destroy();
|
|
814
|
+
detach(popupEle);
|
|
815
|
+
} else {
|
|
816
|
+
this.toggleAnimation(ul, false);
|
|
817
|
+
}
|
|
818
|
+
closeArgs = { element: ul, parentItem: item, items: items };
|
|
819
|
+
this.trigger('onClose', closeArgs);
|
|
820
|
+
this.navIdx.pop();
|
|
821
|
+
}
|
|
822
|
+
if (this.isCMenu) {
|
|
823
|
+
if (this.canOpen(e.target as Element)) {
|
|
824
|
+
this.openMenu(null, null, this.pageY, this.pageX, e);
|
|
825
|
+
}
|
|
826
|
+
this.isCMenu = false;
|
|
827
|
+
} else if (isOpen && this.hamburgerMode && ulIndex !== null) {
|
|
828
|
+
this.afterCloseMenu(e as MouseEvent);
|
|
829
|
+
} else if (isOpen && !ulIndex && this.navIdx.length) {
|
|
830
|
+
this.closeMenu(null, e);
|
|
831
|
+
} else if (isOpen && !this.isMenu && !ulIndex && this.navIdx.length === 0 && !this.isMenusClosed) {
|
|
832
|
+
this.isMenusClosed = true;
|
|
833
|
+
this.closeMenu(0, e);
|
|
834
|
+
} else if (isOpen && this.isMenu && e && e.target &&
|
|
835
|
+
this.navIdx.length !== 0 && closest(e.target as Element, '.e-menu-parent.e-control')) {
|
|
836
|
+
this.closeMenu(0, e);
|
|
837
|
+
} else {
|
|
838
|
+
if (isOpen && (this.keyType === 'right' || this.keyType === 'click')) {
|
|
839
|
+
this.afterCloseMenu(e as MouseEvent);
|
|
840
|
+
} else {
|
|
841
|
+
let cul: Element = this.getUlByNavIdx();
|
|
842
|
+
let sli: Element = this.getLIByClass(cul, SELECTED);
|
|
843
|
+
if (sli) {
|
|
844
|
+
sli.setAttribute('aria-expanded', 'false');
|
|
845
|
+
sli.classList.remove(SELECTED);
|
|
846
|
+
sli.classList.add(FOCUSED);
|
|
847
|
+
(sli as HTMLElement).focus();
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
this.removeStateWrapper();
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
private destroyScrollObj(scrollObj: VScroll | HScroll, scrollEle: Element): void {
|
|
857
|
+
if (scrollObj) {
|
|
858
|
+
scrollObj.destroy();
|
|
859
|
+
scrollEle.parentElement.appendChild(select('.e-menu-parent', scrollEle));
|
|
860
|
+
detach(scrollEle);
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
private getPopups(): Element[] {
|
|
865
|
+
let popups: Element[] = [];
|
|
866
|
+
[].slice.call(document.querySelectorAll('.' + POPUP)).forEach((elem: Element) => {
|
|
867
|
+
if (this.getIndex(elem.querySelector('.' + ITEM).id, true).length) {
|
|
868
|
+
popups.push(elem);
|
|
869
|
+
}
|
|
870
|
+
});
|
|
871
|
+
return popups;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
private isMenuVisible(): boolean {
|
|
875
|
+
return (this.navIdx.length > 0 || (this.element.classList.contains('e-contextmenu') && isVisible(this.element).valueOf()));
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
private canOpen(target: Element): boolean {
|
|
879
|
+
let canOpen: boolean = true;
|
|
880
|
+
if (this.filter) {
|
|
881
|
+
canOpen = false;
|
|
882
|
+
let filter: string[] = this.filter.split(' ');
|
|
883
|
+
for (let i: number = 0, len: number = filter.length; i < len; i++) {
|
|
884
|
+
if (closest(target, '.' + filter[i])) {
|
|
885
|
+
canOpen = true;
|
|
886
|
+
break;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
return canOpen;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
protected openMenu(
|
|
894
|
+
li: Element, item: MenuItemModel | { [key: string]: Object }, top: number = 0, left: number = 0,
|
|
895
|
+
e: MouseEvent | KeyboardEvent = null, target: HTMLElement = this.targetElement): void {
|
|
896
|
+
let eventArgs: BeforeOpenCloseMenuEventArgs; let wrapper: Element = this.getWrapper();
|
|
897
|
+
this.lItem = li; let elemId: string = this.element.id !== '' ? this.element.id : 'menu';
|
|
898
|
+
this.isMenusClosed = false;
|
|
899
|
+
if (li) {
|
|
900
|
+
this.uList = this.createItems((<obj>item)[this.getField('children', this.navIdx.length - 1)] as objColl);
|
|
901
|
+
if (!this.isMenu && Browser.isDevice) {
|
|
902
|
+
(wrapper.lastChild as HTMLElement).style.display = 'none';
|
|
903
|
+
let data: { [key: string]: string } = {
|
|
904
|
+
text: (<obj>item)[this.getField('text')].toString(), iconCss: ICONS + ' e-previous'
|
|
905
|
+
};
|
|
906
|
+
let hdata: MenuItem = new MenuItem(this.items[0] as MenuItem, 'items', data, true);
|
|
907
|
+
let hli: Element = this.createItems([hdata] as MenuItemModel[]).children[0];
|
|
908
|
+
hli.classList.add(HEADER);
|
|
909
|
+
this.uList.insertBefore(hli, this.uList.children[0]);
|
|
910
|
+
}
|
|
911
|
+
if (this.isMenu) {
|
|
912
|
+
this.popupWrapper = this.createElement('div', {
|
|
913
|
+
className: 'e-' + this.getModuleName() + '-wrapper ' + POPUP, id: li.id + '-ej2menu-' + elemId + '-popup' });
|
|
914
|
+
if (this.hamburgerMode) {
|
|
915
|
+
top = (li as HTMLElement).offsetHeight;
|
|
916
|
+
li.appendChild(this.popupWrapper);
|
|
917
|
+
} else {
|
|
918
|
+
document.body.appendChild(this.popupWrapper);
|
|
919
|
+
}
|
|
920
|
+
this.isNestedOrVertical = this.element.classList.contains('e-vertical') || this.navIdx.length !== 1;
|
|
921
|
+
this.popupObj = this.generatePopup(this.popupWrapper, this.uList, li as HTMLElement, this.isNestedOrVertical);
|
|
922
|
+
if (this.hamburgerMode) {
|
|
923
|
+
this.calculateIndentSize(this.uList, li);
|
|
924
|
+
} else {
|
|
925
|
+
if (this.cssClass) {
|
|
926
|
+
addClass([this.popupWrapper], this.cssClass.split(' '));
|
|
927
|
+
}
|
|
928
|
+
this.popupObj.hide();
|
|
929
|
+
}
|
|
930
|
+
this.triggerBeforeOpen(li, this.uList, item, e, 0, 0, 'menu');
|
|
931
|
+
} else {
|
|
932
|
+
this.uList.style.zIndex = this.element.style.zIndex; wrapper.appendChild(this.uList);
|
|
933
|
+
this.triggerBeforeOpen(li, this.uList, item, e, top, left, 'none');
|
|
934
|
+
}
|
|
935
|
+
} else {
|
|
936
|
+
this.uList = this.element;
|
|
937
|
+
this.uList.style.zIndex = getZindexPartial(target ? target : this.element).toString();
|
|
938
|
+
this.triggerBeforeOpen(li, this.uList, item, e, top, left, 'none');
|
|
939
|
+
}
|
|
940
|
+
if (this.isMenu && this.template && this.isBlazor()) {
|
|
941
|
+
let menuTemplateId: string = this.element.id + TEMPLATE_PROPERTY;
|
|
942
|
+
if (Object.keys(blazorTemplates).length) {
|
|
943
|
+
let itemFromBlazorTemplate: objColl = (<obj>blazorTemplates)[menuTemplateId] as objColl;
|
|
944
|
+
this.tempItem = this.tempItem.concat(itemFromBlazorTemplate);
|
|
945
|
+
(<{ [key: string]: Object }>blazorTemplates)[menuTemplateId] = this.tempItem;
|
|
946
|
+
}
|
|
947
|
+
updateBlazorTemplate(menuTemplateId, TEMPLATE_PROPERTY, this);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
private calculateIndentSize(ul: HTMLElement, li: Element): void {
|
|
952
|
+
let liStyle: CSSStyleDeclaration = getComputedStyle(li);
|
|
953
|
+
let liIndent: number = parseInt(liStyle.textIndent, 10);
|
|
954
|
+
if (this.navIdx.length < 2 && !li.classList.contains('e-blankicon')) {
|
|
955
|
+
liIndent *= 2;
|
|
956
|
+
} else {
|
|
957
|
+
liIndent += (liIndent / 4);
|
|
958
|
+
}
|
|
959
|
+
ul.style.textIndent = liIndent + 'px';
|
|
960
|
+
let blankIconElem: NodeList = ul.querySelectorAll('.e-blankicon');
|
|
961
|
+
if (blankIconElem && blankIconElem.length) {
|
|
962
|
+
let menuIconElem: HTMLElement = ul.querySelector('.e-menu-icon');
|
|
963
|
+
let menuIconElemStyle: CSSStyleDeclaration = getComputedStyle(menuIconElem);
|
|
964
|
+
let blankIconIndent: number = (parseInt(menuIconElemStyle.marginRight, 10) + menuIconElem.offsetWidth + liIndent);
|
|
965
|
+
blankIconElem.forEach((element: HTMLElement) => element.style.textIndent = blankIconIndent + 'px');
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
private generatePopup(
|
|
970
|
+
popupWrapper: HTMLElement, ul: HTMLElement, li: HTMLElement, isNestedOrVertical: boolean): Popup {
|
|
971
|
+
let popupObj: Popup = new Popup(popupWrapper, {
|
|
972
|
+
actionOnScroll: this.hamburgerMode ? 'none' : 'reposition',
|
|
973
|
+
relateTo: li,
|
|
974
|
+
collision: this.hamburgerMode ? { X: 'none', Y: 'none' } : { X: isNestedOrVertical ||
|
|
975
|
+
this.enableRtl ? 'none' : 'flip', Y: 'fit' },
|
|
976
|
+
position: (isNestedOrVertical && !this.hamburgerMode) ? { X: 'right', Y: 'top' } : { X: 'left', Y: 'bottom' },
|
|
977
|
+
targetType: 'relative',
|
|
978
|
+
enableRtl: this.enableRtl,
|
|
979
|
+
content: ul,
|
|
980
|
+
open: (): void => {
|
|
981
|
+
let scrollEle: HTMLElement = select('.e-menu-vscroll', popupObj.element) as HTMLElement;
|
|
982
|
+
if (scrollEle) {
|
|
983
|
+
scrollEle.style.height = 'inherit';
|
|
984
|
+
scrollEle.style.maxHeight = '';
|
|
985
|
+
}
|
|
986
|
+
let ul: HTMLElement = select('.e-ul', popupObj.element) as HTMLElement;
|
|
987
|
+
popupObj.element.style.maxHeight = '';
|
|
988
|
+
ul.focus();
|
|
989
|
+
this.triggerOpen(ul);
|
|
990
|
+
}
|
|
991
|
+
});
|
|
992
|
+
return popupObj;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
protected createHeaderContainer(wrapper?: Element): void {
|
|
996
|
+
wrapper = wrapper || this.getWrapper();
|
|
997
|
+
let spanElem: HTMLElement = this.createElement('span', { className: 'e-' + this.getModuleName() + '-header' });
|
|
998
|
+
let spanTitle: HTMLElement = this.createElement('span', {
|
|
999
|
+
className: 'e-' + this.getModuleName() + '-title', innerHTML: this.title });
|
|
1000
|
+
let spanIcon: HTMLElement = this.createElement('span', {
|
|
1001
|
+
className: 'e-icons e-' + this.getModuleName() + '-icon', attrs: { 'tabindex': '0' } });
|
|
1002
|
+
spanElem.appendChild(spanTitle);
|
|
1003
|
+
spanElem.appendChild(spanIcon);
|
|
1004
|
+
wrapper.insertBefore(spanElem, this.element);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
protected openHamburgerMenu(e?: MouseEvent | KeyboardEvent) : void {
|
|
1008
|
+
if (this.hamburgerMode) {
|
|
1009
|
+
let eventArgs: BeforeOpenCloseMenuEventArgs;
|
|
1010
|
+
this.triggerBeforeOpen(null, this.element, null, e, 0, 0, 'hamburger');
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
protected closeHamburgerMenu(e?: MouseEvent | KeyboardEvent) : void {
|
|
1015
|
+
if (this.hamburgerMode) {
|
|
1016
|
+
let beforeCloseArgs: BeforeOpenCloseMenuEventArgs;
|
|
1017
|
+
beforeCloseArgs = { element: this.element, parentItem: null, event: e, items: this.items, cancel: false };
|
|
1018
|
+
this.trigger('beforeClose', beforeCloseArgs, (observedHamburgerCloseArgs: BeforeOpenCloseMenuEventArgs) => {
|
|
1019
|
+
if (!observedHamburgerCloseArgs.cancel) {
|
|
1020
|
+
this.closeMenu(null, e);
|
|
1021
|
+
this.element.classList.add('e-hide-menu');
|
|
1022
|
+
this.trigger('onClose', { element: this.element, parentItem: null, items: this.items });
|
|
1023
|
+
}
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
private callFit(element: HTMLElement, x: boolean, y: boolean, top: number, left: number): OffsetPosition {
|
|
1029
|
+
return fit(element, null, { X: x, Y: y }, { top: top, left: left });
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
private triggerBeforeOpen(
|
|
1033
|
+
li: Element, ul: HTMLElement, item: MenuItemModel, e: MouseEvent | KeyboardEvent,
|
|
1034
|
+
top: number, left: number, type: string): void {
|
|
1035
|
+
let navIdx: number[] = this.getIndex(li ? li.id : null, true);
|
|
1036
|
+
let items: MenuItemModel[] = li ? (<obj>item)[this.getField('children', this.navIdx.length - 1)] as objColl : this.items as objColl;
|
|
1037
|
+
let eventArgs: BeforeOpenCloseMenuEventArgs = {
|
|
1038
|
+
element: ul, items: items, parentItem: item, event: e, cancel: false, top: top, left: left
|
|
1039
|
+
};
|
|
1040
|
+
let menuType: string = type;
|
|
1041
|
+
this.trigger('beforeOpen', eventArgs, (observedOpenArgs: BeforeOpenCloseMenuEventArgs) => {
|
|
1042
|
+
switch (menuType) {
|
|
1043
|
+
case 'menu':
|
|
1044
|
+
if (!this.hamburgerMode) {
|
|
1045
|
+
this.top = observedOpenArgs.top; this.left = observedOpenArgs.left;
|
|
1046
|
+
}
|
|
1047
|
+
this.popupWrapper.style.display = 'block';
|
|
1048
|
+
if (!this.hamburgerMode) {
|
|
1049
|
+
this.popupWrapper.style.maxHeight = this.popupWrapper.getBoundingClientRect().height + 'px';
|
|
1050
|
+
this.addScrolling(
|
|
1051
|
+
this.popupWrapper, this.uList, 'vscroll', this.popupWrapper.offsetHeight, this.uList.offsetHeight);
|
|
1052
|
+
this.checkScrollOffset(e);
|
|
1053
|
+
}
|
|
1054
|
+
let collide: string[];
|
|
1055
|
+
if (!this.hamburgerMode && !this.left && !this.top) {
|
|
1056
|
+
this.popupObj.refreshPosition(this.lItem as HTMLElement, true);
|
|
1057
|
+
this.left = parseInt(this.popupWrapper.style.left, 10); this.top = parseInt(this.popupWrapper.style.top, 10);
|
|
1058
|
+
if (this.enableRtl) {
|
|
1059
|
+
this.left =
|
|
1060
|
+
this.isNestedOrVertical ? this.left - this.popupWrapper.offsetWidth - this.lItem.parentElement.offsetWidth
|
|
1061
|
+
: this.left - this.popupWrapper.offsetWidth + (this.lItem as HTMLElement).offsetWidth;
|
|
1062
|
+
}
|
|
1063
|
+
collide = isCollide(this.popupWrapper, null, this.left, this.top);
|
|
1064
|
+
if ((this.isNestedOrVertical || this.enableRtl) && (collide.indexOf('right') > -1
|
|
1065
|
+
|| collide.indexOf('left') > -1)) {
|
|
1066
|
+
this.popupObj.collision.X = 'none';
|
|
1067
|
+
let offWidth: number =
|
|
1068
|
+
(closest(this.lItem, '.e-' + this.getModuleName() + '-wrapper') as HTMLElement).offsetWidth;
|
|
1069
|
+
this.left =
|
|
1070
|
+
this.enableRtl ? calculatePosition(this.lItem, this.isNestedOrVertical ? 'right' : 'left', 'top').left
|
|
1071
|
+
: this.left - this.popupWrapper.offsetWidth - offWidth;
|
|
1072
|
+
}
|
|
1073
|
+
collide = isCollide(this.popupWrapper, null, this.left, this.top);
|
|
1074
|
+
if (collide.indexOf('left') > -1 || collide.indexOf('right') > -1) {
|
|
1075
|
+
this.left = this.callFit(this.popupWrapper, true, false, this.top, this.left).left;
|
|
1076
|
+
}
|
|
1077
|
+
this.popupWrapper.style.left = this.left + 'px';
|
|
1078
|
+
} else {
|
|
1079
|
+
this.popupObj.collision = { X: 'none', Y: 'none' };
|
|
1080
|
+
}
|
|
1081
|
+
this.popupWrapper.style.display = '';
|
|
1082
|
+
break;
|
|
1083
|
+
case 'none':
|
|
1084
|
+
this.top = observedOpenArgs.top; this.left = observedOpenArgs.left;
|
|
1085
|
+
break;
|
|
1086
|
+
case 'hamburger':
|
|
1087
|
+
if (!observedOpenArgs.cancel) {
|
|
1088
|
+
this.element.classList.remove('e-hide-menu');
|
|
1089
|
+
this.triggerOpen(this.element);
|
|
1090
|
+
}
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1093
|
+
if (menuType !== 'hamburger') {
|
|
1094
|
+
if (observedOpenArgs.cancel) {
|
|
1095
|
+
if (this.isMenu) { this.popupObj.destroy(); detach(this.popupWrapper); }
|
|
1096
|
+
this.navIdx.pop();
|
|
1097
|
+
} else {
|
|
1098
|
+
if (this.isMenu) {
|
|
1099
|
+
if (this.hamburgerMode) {
|
|
1100
|
+
this.popupWrapper.style.top = this.top + 'px'; this.popupWrapper.style.left = 0 + 'px';
|
|
1101
|
+
this.toggleAnimation(this.popupWrapper);
|
|
1102
|
+
} else {
|
|
1103
|
+
this.wireKeyboardEvent(this.popupWrapper);
|
|
1104
|
+
rippleEffect(this.popupWrapper, { selector: '.' + ITEM });
|
|
1105
|
+
this.popupWrapper.style.left = this.left + 'px'; this.popupWrapper.style.top = this.top + 'px';
|
|
1106
|
+
let animationOptions: AnimationModel = this.animationSettings.effect !== 'None' ? {
|
|
1107
|
+
name: this.animationSettings.effect, duration: this.animationSettings.duration,
|
|
1108
|
+
timingFunction: this.animationSettings.easing
|
|
1109
|
+
} : null;
|
|
1110
|
+
this.popupObj.show(animationOptions, this.lItem as HTMLElement);
|
|
1111
|
+
}
|
|
1112
|
+
} else {
|
|
1113
|
+
this.setPosition(this.lItem, this.uList, this.top, this.left); this.toggleAnimation(this.uList);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
if (this.keyType === 'right') {
|
|
1118
|
+
let cul: Element = this.getUlByNavIdx(); li.classList.remove(FOCUSED);
|
|
1119
|
+
if (this.isMenu && this.navIdx.length === 1) {
|
|
1120
|
+
this.removeLIStateByClass([SELECTED], [this.getWrapper()]);
|
|
1121
|
+
}
|
|
1122
|
+
li.classList.add(SELECTED);
|
|
1123
|
+
if (this.action === ENTER) {
|
|
1124
|
+
let eventArgs: MenuEventArgs = { element: li as HTMLElement, item: item, event: e };
|
|
1125
|
+
this.trigger('select', eventArgs);
|
|
1126
|
+
}
|
|
1127
|
+
(li as HTMLElement).focus(); cul = this.getUlByNavIdx();
|
|
1128
|
+
let index: number = this.isValidLI(cul.children[0], 0, this.action);
|
|
1129
|
+
cul.children[index].classList.add(FOCUSED);
|
|
1130
|
+
(cul.children[index] as HTMLElement).focus();
|
|
1131
|
+
}
|
|
1132
|
+
});
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
private checkScrollOffset(e: MouseEvent | KeyboardEvent): void {
|
|
1136
|
+
let wrapper: Element = this.getWrapper();
|
|
1137
|
+
if (wrapper.children[0].classList.contains('e-menu-hscroll') && this.navIdx.length === 1) {
|
|
1138
|
+
let trgt: HTMLElement = isNullOrUndefined(e) ? this.element : closest(e.target as Element, '.' + ITEM) as HTMLElement;
|
|
1139
|
+
let offsetEle: HTMLElement = (select('.e-hscroll-bar', wrapper) as HTMLElement);
|
|
1140
|
+
let offsetLeft: number; let offsetRight: number;
|
|
1141
|
+
if (offsetEle.scrollLeft > trgt.offsetLeft) {
|
|
1142
|
+
offsetEle.scrollLeft -= (offsetEle.scrollLeft - trgt.offsetLeft);
|
|
1143
|
+
}
|
|
1144
|
+
offsetLeft = offsetEle.scrollLeft + offsetEle.offsetWidth;
|
|
1145
|
+
offsetRight = trgt.offsetLeft + trgt.offsetWidth;
|
|
1146
|
+
if (offsetLeft < offsetRight) {
|
|
1147
|
+
offsetEle.scrollLeft += (offsetRight - offsetLeft);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
private addScrolling(wrapper: HTMLElement, ul: HTMLElement, scrollType: string, wrapperOffset: number, contentOffset: number): void {
|
|
1153
|
+
if (this.enableScrolling && wrapperOffset < contentOffset) {
|
|
1154
|
+
let scrollEle: HTMLElement = this.createElement('div', { className: 'e-menu-' + scrollType });
|
|
1155
|
+
wrapper.appendChild(scrollEle);
|
|
1156
|
+
scrollEle.appendChild(ul);
|
|
1157
|
+
scrollEle.style.maxHeight = wrapper.style.maxHeight;
|
|
1158
|
+
let scrollObj: VScroll | HScroll;
|
|
1159
|
+
wrapper.style.overflow = 'hidden';
|
|
1160
|
+
if (scrollType === 'vscroll') {
|
|
1161
|
+
scrollObj = new VScroll({ enableRtl: this.enableRtl }, scrollEle);
|
|
1162
|
+
scrollObj.scrollStep = (select('.e-' + scrollType + '-bar', wrapper) as HTMLElement).offsetHeight / 2;
|
|
1163
|
+
} else {
|
|
1164
|
+
scrollObj = new HScroll({ enableRtl: this.enableRtl }, scrollEle);
|
|
1165
|
+
scrollObj.scrollStep = (select('.e-' + scrollType + '-bar', wrapper) as HTMLElement).offsetWidth;
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
private setPosition(li: Element, ul: HTMLElement, top: number, left: number): void {
|
|
1171
|
+
let px: string = 'px';
|
|
1172
|
+
this.toggleVisiblity(ul);
|
|
1173
|
+
if (ul === this.element || (!isNullOrUndefined(left) && !isNullOrUndefined(top))) {
|
|
1174
|
+
let collide: string[] = isCollide(ul, null, left, top);
|
|
1175
|
+
if (collide.indexOf('right') > -1) {
|
|
1176
|
+
left = left - ul.offsetWidth;
|
|
1177
|
+
}
|
|
1178
|
+
if (collide.indexOf('bottom') > -1) {
|
|
1179
|
+
let offset: OffsetPosition = this.callFit(ul, false, true, top, left);
|
|
1180
|
+
top = offset.top - 20;
|
|
1181
|
+
}
|
|
1182
|
+
collide = isCollide(ul, null, left, top);
|
|
1183
|
+
if (collide.indexOf('left') > -1) {
|
|
1184
|
+
let offset: OffsetPosition = this.callFit(ul, true, false, top, left);
|
|
1185
|
+
left = offset.left;
|
|
1186
|
+
}
|
|
1187
|
+
} else {
|
|
1188
|
+
if (Browser.isDevice) {
|
|
1189
|
+
top = Number(this.element.style.top.replace(px, ''));
|
|
1190
|
+
left = Number(this.element.style.left.replace(px, ''));
|
|
1191
|
+
} else {
|
|
1192
|
+
let x: string = this.enableRtl ? 'left' : 'right';
|
|
1193
|
+
let offset: OffsetPosition = calculatePosition(li, x, 'top');
|
|
1194
|
+
top = offset.top;
|
|
1195
|
+
left = offset.left;
|
|
1196
|
+
let collide: string[] = isCollide(ul, null, this.enableRtl ? left - ul.offsetWidth : left, top);
|
|
1197
|
+
let xCollision: boolean = collide.indexOf('left') > -1 || collide.indexOf('right') > -1;
|
|
1198
|
+
if (xCollision) {
|
|
1199
|
+
offset = calculatePosition(li, this.enableRtl ? 'right' : 'left', 'top');
|
|
1200
|
+
left = offset.left;
|
|
1201
|
+
}
|
|
1202
|
+
if (this.enableRtl || xCollision) {
|
|
1203
|
+
left = (this.enableRtl && xCollision) ? left : left - ul.offsetWidth;
|
|
1204
|
+
}
|
|
1205
|
+
if (collide.indexOf('bottom') > -1) {
|
|
1206
|
+
offset = this.callFit(ul, false, true, top, left);
|
|
1207
|
+
top = offset.top;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
this.toggleVisiblity(ul, false);
|
|
1212
|
+
ul.style.top = top + px;
|
|
1213
|
+
ul.style.left = left + px;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
private toggleVisiblity(ul: HTMLElement, isVisible: boolean = true): void {
|
|
1217
|
+
ul.style.visibility = isVisible ? 'hidden' : '';
|
|
1218
|
+
ul.style.display = isVisible ? 'block' : 'none';
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
private createItems(items: MenuItemModel[] | objColl): HTMLElement {
|
|
1222
|
+
let level: number = this.navIdx ? this.navIdx.length : 0;
|
|
1223
|
+
let showIcon: boolean = this.hasField(items, this.getField('iconCss', level));
|
|
1224
|
+
let id: string = 'id'; let iconCss: string = 'iconCss';
|
|
1225
|
+
let listBaseOptions: ListBaseOptions = {
|
|
1226
|
+
showIcon: showIcon,
|
|
1227
|
+
moduleName: 'menu',
|
|
1228
|
+
fields: this.getFields(level),
|
|
1229
|
+
template: this.template,
|
|
1230
|
+
itemCreating: (args: { curData: obj, fields: obj }): void => {
|
|
1231
|
+
if (!args.curData[(<obj>args.fields)[id] as string]) {
|
|
1232
|
+
args.curData[(<obj>args.fields)[id] as string] = getUniqueID('menuitem');
|
|
1233
|
+
}
|
|
1234
|
+
args.curData.htmlAttributes = {
|
|
1235
|
+
role: 'menuitem',
|
|
1236
|
+
tabindex: '-1'
|
|
1237
|
+
};
|
|
1238
|
+
if (this.isMenu && !(<obj>args.curData)[this.getField('separator', level)]) {
|
|
1239
|
+
(<obj>args.curData.htmlAttributes)['aria-label'] = (<obj>args.curData)[args.fields.text as string];
|
|
1240
|
+
}
|
|
1241
|
+
if (args.curData[(<obj>args.fields)[iconCss] as string] === '') {
|
|
1242
|
+
args.curData[(<obj>args.fields)[iconCss] as string] = null;
|
|
1243
|
+
}
|
|
1244
|
+
},
|
|
1245
|
+
itemCreated: (args: { curData: MenuItemModel | obj, item: Element, fields: obj }): void => {
|
|
1246
|
+
if ((<obj>args.curData)[this.getField('separator', level)]) {
|
|
1247
|
+
args.item.classList.add(SEPARATOR);
|
|
1248
|
+
args.item.removeAttribute('role');
|
|
1249
|
+
}
|
|
1250
|
+
if (showIcon && !(<obj>args.curData)[args.fields.iconCss as string]
|
|
1251
|
+
&& !(<obj>args.curData)[this.getField('separator', level)]) {
|
|
1252
|
+
(args.item as HTMLElement).classList.add('e-blankicon');
|
|
1253
|
+
}
|
|
1254
|
+
if ((<obj>args.curData)[args.fields.child as string]
|
|
1255
|
+
&& (<objColl>(<obj>args.curData)[args.fields.child as string]).length) {
|
|
1256
|
+
let span: Element = this.createElement('span', { className: ICONS + ' ' + CARET });
|
|
1257
|
+
args.item.appendChild(span);
|
|
1258
|
+
args.item.setAttribute('aria-haspopup', 'true');
|
|
1259
|
+
args.item.setAttribute('aria-expanded', 'false');
|
|
1260
|
+
if (!this.isMenu) {
|
|
1261
|
+
args.item.removeAttribute('role');
|
|
1262
|
+
}
|
|
1263
|
+
(args.item as HTMLElement).classList.add('e-menu-caret-icon');
|
|
1264
|
+
}
|
|
1265
|
+
if (this.isMenu && this.template) {
|
|
1266
|
+
args.item.setAttribute('id', (<obj>args.curData)[args.fields.id as string].toString());
|
|
1267
|
+
args.item.removeAttribute('data-uid');
|
|
1268
|
+
}
|
|
1269
|
+
let eventArgs: MenuEventArgs = { item: args.curData, element: args.item as HTMLElement };
|
|
1270
|
+
this.trigger('beforeItemRender', eventArgs);
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
this.setProperties({'items': this.items}, true);
|
|
1274
|
+
if (this.isMenu) {
|
|
1275
|
+
listBaseOptions.templateID = this.element.id + TEMPLATE_PROPERTY;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
let ul: HTMLElement = ListBase.createList(
|
|
1279
|
+
this.createElement, items as objColl, listBaseOptions, !this.template);
|
|
1280
|
+
ul.setAttribute('tabindex', '0');
|
|
1281
|
+
if (this.isMenu) {
|
|
1282
|
+
ul.setAttribute('role', 'menu');
|
|
1283
|
+
}
|
|
1284
|
+
return ul;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
private moverHandler(e: MouseEvent): void {
|
|
1288
|
+
let trgt: Element = e.target as Element;
|
|
1289
|
+
this.liTrgt = trgt;
|
|
1290
|
+
let cli: Element = this.getLI(trgt);
|
|
1291
|
+
let wrapper: Element = cli ? closest(cli, '.e-' + this.getModuleName() + '-wrapper') : this.getWrapper();
|
|
1292
|
+
let hdrWrapper: Element = this.getWrapper(); let regex: RegExp = new RegExp('-ej2menu-(.*)-popup'); let ulId: string;
|
|
1293
|
+
let isDifferentElem: boolean = false;
|
|
1294
|
+
if (!wrapper) {
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
if (wrapper.id !== '') {
|
|
1298
|
+
ulId = regex.exec(wrapper.id)[1];
|
|
1299
|
+
} else {
|
|
1300
|
+
ulId = wrapper.querySelector('ul').id;
|
|
1301
|
+
}
|
|
1302
|
+
if (ulId !== this.element.id) {
|
|
1303
|
+
this.removeLIStateByClass([FOCUSED, SELECTED], [this.getWrapper()]);
|
|
1304
|
+
if (this.navIdx.length) {
|
|
1305
|
+
isDifferentElem = true;
|
|
1306
|
+
} else {
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
if (cli && closest(cli, '.e-' + this.getModuleName() + '-wrapper') && !isDifferentElem) {
|
|
1311
|
+
this.removeLIStateByClass([FOCUSED], this.isMenu ? [wrapper].concat(this.getPopups()) : [wrapper]);
|
|
1312
|
+
this.removeLIStateByClass([FOCUSED], this.isMenu ? [hdrWrapper].concat(this.getPopups()) : [hdrWrapper]);
|
|
1313
|
+
cli.classList.add(FOCUSED);
|
|
1314
|
+
if (!this.showItemOnClick) {
|
|
1315
|
+
this.clickHandler(e);
|
|
1316
|
+
}
|
|
1317
|
+
} else if (this.isMenu && this.showItemOnClick) {
|
|
1318
|
+
this.removeLIStateByClass([FOCUSED], [wrapper].concat(this.getPopups()));
|
|
1319
|
+
}
|
|
1320
|
+
if (this.isMenu) {
|
|
1321
|
+
if (!this.showItemOnClick && (trgt.parentElement !== wrapper && !closest(trgt, '.e-' + this.getModuleName() + '-popup'))
|
|
1322
|
+
&& (!cli || (cli && !this.getIndex(cli.id, true).length))) {
|
|
1323
|
+
this.removeLIStateByClass([FOCUSED], [wrapper]);
|
|
1324
|
+
if (this.navIdx.length) {
|
|
1325
|
+
this.isClosed = true;
|
|
1326
|
+
this.closeMenu(null, e);
|
|
1327
|
+
}
|
|
1328
|
+
} else if (isDifferentElem) {
|
|
1329
|
+
if (this.navIdx.length) {
|
|
1330
|
+
this.isClosed = true;
|
|
1331
|
+
this.closeMenu(null, e);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
if (!this.isClosed) {
|
|
1335
|
+
this.removeStateWrapper();
|
|
1336
|
+
}
|
|
1337
|
+
this.isClosed = false;
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
private removeStateWrapper(): void {
|
|
1341
|
+
if (this.liTrgt) {
|
|
1342
|
+
let wrapper: Element = closest(this.liTrgt, '.e-menu-vscroll');
|
|
1343
|
+
if (this.liTrgt.tagName === 'DIV' && wrapper) {
|
|
1344
|
+
this.removeLIStateByClass([FOCUSED, SELECTED], [wrapper]);
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
private removeLIStateByClass(classList: string[], element: Element[]): void {
|
|
1350
|
+
let li: Element;
|
|
1351
|
+
for (let i: number = 0; i < element.length; i++) {
|
|
1352
|
+
classList.forEach((className: string) => {
|
|
1353
|
+
li = select('.' + className, element[i]);
|
|
1354
|
+
if (li) {
|
|
1355
|
+
li.classList.remove(className);
|
|
1356
|
+
}
|
|
1357
|
+
});
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
protected getField(propName: string, level: number = 0): string {
|
|
1362
|
+
let fieldName: object = (<obj>this.fields)[propName];
|
|
1363
|
+
return typeof fieldName === 'string' ? fieldName :
|
|
1364
|
+
(!(<obj>fieldName)[level] ? (fieldName as obj)[(<objColl>fieldName).length - 1].toString()
|
|
1365
|
+
: (<obj>fieldName)[level].toString());
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
private getFields(level: number = 0): obj {
|
|
1369
|
+
return {
|
|
1370
|
+
id: this.getField('itemId', level),
|
|
1371
|
+
iconCss: this.getField('iconCss', level),
|
|
1372
|
+
text: this.getField('text', level),
|
|
1373
|
+
url: this.getField('url', level),
|
|
1374
|
+
child: this.getField('children', level),
|
|
1375
|
+
separator: this.getField('separator', level)
|
|
1376
|
+
};
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
private hasField(items: MenuItemModel[], field: string): boolean {
|
|
1380
|
+
for (let i: number = 0, len: number = items.length; i < len; i++) {
|
|
1381
|
+
if ((<obj>items[i])[field]) {
|
|
1382
|
+
return true;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
return false;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
private menuHeaderClickHandler(e: MouseEvent | KeyboardEvent): void {
|
|
1389
|
+
if (closest(e.target as Element, '.e-menu-wrapper').querySelector('ul.e-menu-parent').id !== this.element.id) {
|
|
1390
|
+
return;
|
|
1391
|
+
}
|
|
1392
|
+
this.element.classList.contains('e-hide-menu') ? this.openHamburgerMenu(e) : this.closeHamburgerMenu(e);
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
private clickHandler(e: MouseEvent): void {
|
|
1396
|
+
if (this.isTapHold) {
|
|
1397
|
+
this.isTapHold = false;
|
|
1398
|
+
} else {
|
|
1399
|
+
let wrapper: Element = this.getWrapper();
|
|
1400
|
+
let trgt: Element = e.target as Element;
|
|
1401
|
+
let cli: Element = this.cli = this.getLI(trgt);
|
|
1402
|
+
let regex: RegExp = new RegExp('-ej2menu-(.*)-popup');
|
|
1403
|
+
let cliWrapper: Element = cli ? closest(cli, '.e-' + this.getModuleName() + '-wrapper') : null;
|
|
1404
|
+
let isInstLI: boolean = cli && cliWrapper && (this.isMenu ? this.getIndex(cli.id, true).length > 0
|
|
1405
|
+
: wrapper.firstElementChild.id === cliWrapper.firstElementChild.id);
|
|
1406
|
+
if (cli && cliWrapper && this.isMenu) {
|
|
1407
|
+
let cliWrapperId: string = cliWrapper.id ? regex.exec(cliWrapper.id)[1] : cliWrapper.querySelector('.e-menu-parent').id;
|
|
1408
|
+
if (this.element.id !== cliWrapperId) {
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
if (isInstLI && e.type === 'click' && !cli.classList.contains(HEADER)) {
|
|
1413
|
+
this.setLISelected(cli);
|
|
1414
|
+
let navIdx: number[] = this.getIndex(cli.id, true);
|
|
1415
|
+
let item: MenuItemModel = this.getItem(navIdx);
|
|
1416
|
+
let eventArgs: MenuEventArgs = { element: cli as HTMLElement, item: item, event: e };
|
|
1417
|
+
this.trigger('select', eventArgs);
|
|
1418
|
+
}
|
|
1419
|
+
if (isInstLI && (e.type === 'mouseover' || Browser.isDevice || this.showItemOnClick)) {
|
|
1420
|
+
let ul: HTMLElement;
|
|
1421
|
+
if (cli.classList.contains(HEADER)) {
|
|
1422
|
+
ul = wrapper.children[this.navIdx.length - 1] as HTMLElement;
|
|
1423
|
+
this.toggleAnimation(ul);
|
|
1424
|
+
let sli: Element = this.getLIByClass(ul, SELECTED);
|
|
1425
|
+
if (sli) {
|
|
1426
|
+
sli.classList.remove(SELECTED);
|
|
1427
|
+
}
|
|
1428
|
+
detach(cli.parentNode);
|
|
1429
|
+
this.navIdx.pop();
|
|
1430
|
+
} else {
|
|
1431
|
+
if (!cli.classList.contains(SEPARATOR)) {
|
|
1432
|
+
this.showSubMenu = true;
|
|
1433
|
+
let cul: Element = cli.parentNode as Element;
|
|
1434
|
+
this.cliIdx = this.getIdx(cul, cli);
|
|
1435
|
+
if (this.isMenu || !Browser.isDevice) {
|
|
1436
|
+
let culIdx: number = this.isMenu ? Array.prototype.indexOf.call(
|
|
1437
|
+
[wrapper].concat(this.getPopups()), closest(cul, '.' + 'e-' + this.getModuleName() + '-wrapper'))
|
|
1438
|
+
: this.getIdx(wrapper, cul);
|
|
1439
|
+
if (this.navIdx[culIdx] === this.cliIdx) {
|
|
1440
|
+
this.showSubMenu = false;
|
|
1441
|
+
}
|
|
1442
|
+
if (culIdx !== this.navIdx.length && (e.type !== 'mouseover' || this.showSubMenu)) {
|
|
1443
|
+
let sli: Element = this.getLIByClass(cul, SELECTED);
|
|
1444
|
+
if (sli) {
|
|
1445
|
+
sli.classList.remove(SELECTED);
|
|
1446
|
+
}
|
|
1447
|
+
this.isClosed = true;
|
|
1448
|
+
this.keyType = 'click';
|
|
1449
|
+
this.closeMenu(culIdx + 1, e);
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
if (!this.isClosed) {
|
|
1453
|
+
this.afterCloseMenu(e);
|
|
1454
|
+
}
|
|
1455
|
+
this.isClosed = false;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
} else {
|
|
1459
|
+
if (this.isMenu && trgt.tagName === 'DIV' && this.navIdx.length && closest(trgt, '.e-menu-vscroll')) {
|
|
1460
|
+
let popupEle: Element = closest(trgt, '.' + POPUP);
|
|
1461
|
+
let cIdx: number = Array.prototype.indexOf.call(this.getPopups(), popupEle) + 1;
|
|
1462
|
+
if (cIdx < this.navIdx.length) {
|
|
1463
|
+
this.closeMenu(cIdx + 1, e);
|
|
1464
|
+
this.removeLIStateByClass([FOCUSED, SELECTED], [popupEle]);
|
|
1465
|
+
}
|
|
1466
|
+
} else if (this.isMenu && this.hamburgerMode && trgt.tagName === 'SPAN'
|
|
1467
|
+
&& trgt.classList.contains('e-menu-icon')) {
|
|
1468
|
+
this.menuHeaderClickHandler(e);
|
|
1469
|
+
} else {
|
|
1470
|
+
if (trgt.tagName !== 'UL' || (this.isMenu ? trgt.parentElement.classList.contains('e-menu-wrapper') &&
|
|
1471
|
+
!this.getIndex(trgt.querySelector('.' + ITEM).id, true).length : trgt.parentElement !== wrapper)) {
|
|
1472
|
+
if (!cli) {
|
|
1473
|
+
this.removeLIStateByClass([SELECTED], [wrapper]);
|
|
1474
|
+
}
|
|
1475
|
+
if (!cli || !cli.querySelector('.' + CARET)) {
|
|
1476
|
+
this.closeMenu(null, e);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
private afterCloseMenu(e: MouseEvent): void {
|
|
1484
|
+
if (this.showSubMenu) {
|
|
1485
|
+
let idx: number[] = this.navIdx.concat(this.cliIdx);
|
|
1486
|
+
let item: MenuItemModel = this.getItem(idx);
|
|
1487
|
+
if (item && (<objColl>(<obj>item)[this.getField('children', idx.length - 1)]) &&
|
|
1488
|
+
(<objColl>(<obj>item)[this.getField('children', idx.length - 1)]).length) {
|
|
1489
|
+
if (e.type === 'mouseover' || (Browser.isDevice && this.isMenu)) {
|
|
1490
|
+
this.setLISelected(this.cli);
|
|
1491
|
+
}
|
|
1492
|
+
this.cli.setAttribute('aria-expanded', 'true');
|
|
1493
|
+
this.navIdx.push(this.cliIdx);
|
|
1494
|
+
this.openMenu(this.cli, item, null, null, e);
|
|
1495
|
+
} else {
|
|
1496
|
+
if (e.type !== 'mouseover') {
|
|
1497
|
+
this.closeMenu(null, e);
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
this.keyType = '';
|
|
1502
|
+
}
|
|
1503
|
+
private setLISelected(li: Element): void {
|
|
1504
|
+
let sli: Element = this.getLIByClass(li.parentElement, SELECTED);
|
|
1505
|
+
if (sli) {
|
|
1506
|
+
sli.classList.remove(SELECTED);
|
|
1507
|
+
}
|
|
1508
|
+
if (!this.isMenu) {
|
|
1509
|
+
li.classList.remove(FOCUSED);
|
|
1510
|
+
}
|
|
1511
|
+
li.classList.add(SELECTED);
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
private getLIByClass(ul: Element, classname: string): Element {
|
|
1515
|
+
for (let i: number = 0, len: number = ul.children.length; i < len; i++) {
|
|
1516
|
+
if (ul.children[i].classList.contains(classname)) {
|
|
1517
|
+
return ul.children[i];
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
private getItem(navIdx: number[]): MenuItemModel {
|
|
1524
|
+
navIdx = navIdx.slice();
|
|
1525
|
+
let idx: number = navIdx.pop();
|
|
1526
|
+
let items: MenuItemModel[] = this.getItems(navIdx);
|
|
1527
|
+
return items[idx];
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
private getItems(navIdx: number[]): objColl {
|
|
1531
|
+
let items: objColl = this.items as objColl;
|
|
1532
|
+
for (let i: number = 0; i < navIdx.length; i++) {
|
|
1533
|
+
items = (<obj>items[navIdx[i]])[this.getField('children', i)] as objColl;
|
|
1534
|
+
}
|
|
1535
|
+
return items;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
private setItems(newItems: objColl, navIdx: number[]): void {
|
|
1539
|
+
let items: objColl = this.getItems(navIdx);
|
|
1540
|
+
items.splice(0, items.length);
|
|
1541
|
+
for (let i: number = 0; i < newItems.length; i++) {
|
|
1542
|
+
items.splice(i, 0, newItems[i]);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
private getIdx(ul: Element, li: Element, skipHdr: boolean = true): number {
|
|
1547
|
+
let idx: number = Array.prototype.indexOf.call(ul.querySelectorAll('li'), li);
|
|
1548
|
+
if (this.isMenu && this.template && this.isBlazor()) {
|
|
1549
|
+
idx = Array.prototype.indexOf.call(ul.querySelectorAll(li.tagName), li);
|
|
1550
|
+
} else {
|
|
1551
|
+
idx = Array.prototype.indexOf.call(ul.children, li);
|
|
1552
|
+
}
|
|
1553
|
+
if (skipHdr && ul.children[0].classList.contains(HEADER)) {
|
|
1554
|
+
idx--;
|
|
1555
|
+
}
|
|
1556
|
+
return idx;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
private getLI(elem: Element): Element {
|
|
1560
|
+
if (elem.tagName === 'LI' && elem.classList.contains('e-menu-item')) {
|
|
1561
|
+
return elem;
|
|
1562
|
+
}
|
|
1563
|
+
return closest(elem, 'li.e-menu-item');
|
|
1564
|
+
}
|
|
1565
|
+
|
|
1566
|
+
private isBlazor(): boolean {
|
|
1567
|
+
return ((Object.keys(window).indexOf('ejsInterop') === -1) ? false : true);
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
private removeChildElement(elem: HTMLUListElement): HTMLUListElement {
|
|
1571
|
+
while (elem.firstElementChild) {
|
|
1572
|
+
elem.removeChild(elem.firstElementChild);
|
|
1573
|
+
}
|
|
1574
|
+
return elem;
|
|
1575
|
+
}
|
|
1576
|
+
/**
|
|
1577
|
+
* Called internally if any of the property value changed
|
|
1578
|
+
* @private
|
|
1579
|
+
* @param {MenuBaseModel} newProp
|
|
1580
|
+
* @param {MenuBaseModel} oldProp
|
|
1581
|
+
* @returns void
|
|
1582
|
+
*/
|
|
1583
|
+
public onPropertyChanged(newProp: MenuBaseModel, oldProp: MenuBaseModel): void {
|
|
1584
|
+
let wrapper: HTMLElement = this.getWrapper() as HTMLElement;
|
|
1585
|
+
for (let prop of Object.keys(newProp)) {
|
|
1586
|
+
switch (prop) {
|
|
1587
|
+
case 'cssClass':
|
|
1588
|
+
if (oldProp.cssClass) {
|
|
1589
|
+
removeClass([wrapper], oldProp.cssClass.split(' '));
|
|
1590
|
+
}
|
|
1591
|
+
if (newProp.cssClass) {
|
|
1592
|
+
addClass([wrapper], newProp.cssClass.split(' '));
|
|
1593
|
+
}
|
|
1594
|
+
break;
|
|
1595
|
+
case 'enableRtl':
|
|
1596
|
+
wrapper.classList.toggle(RTL);
|
|
1597
|
+
break;
|
|
1598
|
+
case 'showItemOnClick':
|
|
1599
|
+
this.unWireEvents();
|
|
1600
|
+
this.showItemOnClick = newProp.showItemOnClick;
|
|
1601
|
+
this.wireEvents();
|
|
1602
|
+
break;
|
|
1603
|
+
case 'enableScrolling':
|
|
1604
|
+
if (newProp.enableScrolling) {
|
|
1605
|
+
let ul: HTMLElement;
|
|
1606
|
+
this.element.classList.contains('e-vertical') ?
|
|
1607
|
+
this.addScrolling(wrapper, this.element, 'vscroll', wrapper.offsetHeight, this.element.offsetHeight)
|
|
1608
|
+
: this.addScrolling(wrapper, this.element, 'hscroll', wrapper.offsetWidth, this.element.offsetWidth);
|
|
1609
|
+
(this.getPopups() as HTMLElement[]).forEach((wrapper: HTMLElement) => {
|
|
1610
|
+
ul = select('.e-ul', wrapper) as HTMLElement;
|
|
1611
|
+
this.addScrolling(wrapper, ul, 'vscroll', wrapper.offsetHeight, ul.offsetHeight);
|
|
1612
|
+
});
|
|
1613
|
+
} else {
|
|
1614
|
+
let ul: HTMLElement = wrapper.children[0] as HTMLElement;
|
|
1615
|
+
this.element.classList.contains('e-vertical') ? this.destroyScrollObj(getInstance(ul, VScroll) as VScroll, ul)
|
|
1616
|
+
: this.destroyScrollObj(getInstance(ul, HScroll) as HScroll, ul);
|
|
1617
|
+
wrapper.style.overflow = '';
|
|
1618
|
+
wrapper.appendChild(this.element);
|
|
1619
|
+
(this.getPopups() as HTMLElement[]).forEach((wrapper: HTMLElement) => {
|
|
1620
|
+
ul = wrapper.children[0] as HTMLElement;
|
|
1621
|
+
this.destroyScrollObj(getInstance(ul, VScroll) as VScroll, ul);
|
|
1622
|
+
wrapper.style.overflow = '';
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1625
|
+
break;
|
|
1626
|
+
case 'items':
|
|
1627
|
+
let idx: number;
|
|
1628
|
+
let navIdx: number[];
|
|
1629
|
+
let item: MenuItemModel[];
|
|
1630
|
+
if (!Object.keys(oldProp.items).length) {
|
|
1631
|
+
let ul: HTMLElement = this.element;
|
|
1632
|
+
if (this.isBlazor()) {
|
|
1633
|
+
ul = this.removeChildElement(this.element);
|
|
1634
|
+
} else {
|
|
1635
|
+
ul.innerHTML = '';
|
|
1636
|
+
}
|
|
1637
|
+
let lis: HTMLElement[] = [].slice.call(this.createItems(this.items).children);
|
|
1638
|
+
lis.forEach((li: HTMLElement): void => {
|
|
1639
|
+
ul.appendChild(li);
|
|
1640
|
+
});
|
|
1641
|
+
for (let i: number = 1, count: number = wrapper.childElementCount; i < count; i++) {
|
|
1642
|
+
detach(wrapper.lastElementChild);
|
|
1643
|
+
}
|
|
1644
|
+
this.navIdx = [];
|
|
1645
|
+
} else {
|
|
1646
|
+
let keys: string[] = Object.keys(newProp.items);
|
|
1647
|
+
for (let i: number = 0; i < keys.length; i++) {
|
|
1648
|
+
navIdx = this.getChangedItemIndex(newProp, [], Number(keys[i]));
|
|
1649
|
+
if (navIdx.length <= this.getWrapper().children.length) {
|
|
1650
|
+
idx = navIdx.pop();
|
|
1651
|
+
item = this.getItems(navIdx);
|
|
1652
|
+
this.insertAfter([item[idx]], item[idx].text);
|
|
1653
|
+
this.removeItem(item, navIdx, idx);
|
|
1654
|
+
this.setItems(item as objColl, navIdx);
|
|
1655
|
+
}
|
|
1656
|
+
navIdx.length = 0;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
break;
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
private getChangedItemIndex(newProp: MenuBaseModel, index: number[], idx: number): number[] {
|
|
1665
|
+
index.push(idx);
|
|
1666
|
+
let key: string = Object.keys((<objColl>newProp.items)[idx]).pop();
|
|
1667
|
+
if (key === 'items') {
|
|
1668
|
+
let item: MenuItemModel = (<objColl>newProp.items)[idx];
|
|
1669
|
+
this.getChangedItemIndex(item, index, Number(Object.keys(item.items).pop()));
|
|
1670
|
+
} else {
|
|
1671
|
+
if (key === 'isParentArray' && index.length > 1) {
|
|
1672
|
+
index.pop();
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
return index;
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
private removeItem(item: MenuItemModel[], navIdx: number[], idx: number): void {
|
|
1679
|
+
item.splice(idx, 1);
|
|
1680
|
+
let uls: HTMLCollection = this.getWrapper().children;
|
|
1681
|
+
if (navIdx.length < uls.length) {
|
|
1682
|
+
detach(uls[navIdx.length].children[idx]);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
/**
|
|
1687
|
+
* Used to unwire the bind events.
|
|
1688
|
+
* @private
|
|
1689
|
+
*/
|
|
1690
|
+
protected unWireEvents(targetSelctor: string = this.target): void {
|
|
1691
|
+
let wrapper: HTMLElement = this.getWrapper() as HTMLElement;
|
|
1692
|
+
if (targetSelctor) {
|
|
1693
|
+
let target: HTMLElement;
|
|
1694
|
+
let touchModule: Touch;
|
|
1695
|
+
let targetElems: HTMLElement[] = selectAll(targetSelctor);
|
|
1696
|
+
for (let i: number = 0, len: number = targetElems.length; i < len; i++) {
|
|
1697
|
+
target = targetElems[i];
|
|
1698
|
+
if (this.isMenu) {
|
|
1699
|
+
EventHandler.remove(target, 'click', this.menuHeaderClickHandler);
|
|
1700
|
+
} else {
|
|
1701
|
+
if (Browser.isIos) {
|
|
1702
|
+
touchModule = getInstance(target, Touch) as Touch;
|
|
1703
|
+
if (touchModule) {
|
|
1704
|
+
touchModule.destroy();
|
|
1705
|
+
}
|
|
1706
|
+
} else {
|
|
1707
|
+
EventHandler.remove(target, 'contextmenu', this.cmenuHandler);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
if (!this.isMenu) {
|
|
1712
|
+
EventHandler.remove(this.targetElement, 'scroll', this.scrollHandler);
|
|
1713
|
+
for (let parent of getScrollableParent(this.targetElement)) {
|
|
1714
|
+
EventHandler.remove(parent, 'scroll', this.scrollHandler);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
if (!Browser.isDevice) {
|
|
1719
|
+
EventHandler.remove(this.isMenu ? document : wrapper, 'mouseover', this.delegateMoverHandler);
|
|
1720
|
+
EventHandler.remove(document, 'mousedown', this.delegateMouseDownHandler);
|
|
1721
|
+
}
|
|
1722
|
+
EventHandler.remove(document, 'click', this.delegateClickHandler);
|
|
1723
|
+
this.unWireKeyboardEvent(wrapper);
|
|
1724
|
+
this.rippleFn();
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
private unWireKeyboardEvent(element: HTMLElement): void {
|
|
1728
|
+
let keyboardModule: KeyboardEvents = getInstance(element, KeyboardEvents) as KeyboardEvents;
|
|
1729
|
+
if (keyboardModule) {
|
|
1730
|
+
keyboardModule.destroy();
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
private toggleAnimation(ul: HTMLElement, isMenuOpen: boolean = true): void {
|
|
1735
|
+
let pUlHeight: number;
|
|
1736
|
+
let pElement: HTMLElement;
|
|
1737
|
+
if (this.animationSettings.effect === 'None' || !isMenuOpen) {
|
|
1738
|
+
this.end(ul, isMenuOpen);
|
|
1739
|
+
} else {
|
|
1740
|
+
this.animation.animate(ul, {
|
|
1741
|
+
name: this.animationSettings.effect,
|
|
1742
|
+
duration: this.animationSettings.duration,
|
|
1743
|
+
timingFunction: this.animationSettings.easing,
|
|
1744
|
+
begin: (options: AnimationOptions) => {
|
|
1745
|
+
if (this.hamburgerMode) {
|
|
1746
|
+
pElement = options.element.parentElement;
|
|
1747
|
+
options.element.style.position = 'absolute';
|
|
1748
|
+
pUlHeight = pElement.offsetHeight;
|
|
1749
|
+
options.element.style.maxHeight = options.element.offsetHeight + 'px';
|
|
1750
|
+
pElement.style.maxHeight = '';
|
|
1751
|
+
} else {
|
|
1752
|
+
options.element.style.display = 'block';
|
|
1753
|
+
options.element.style.maxHeight = options.element.getBoundingClientRect().height + 'px';
|
|
1754
|
+
}
|
|
1755
|
+
},
|
|
1756
|
+
progress: (options: AnimationOptions) => {
|
|
1757
|
+
if (this.hamburgerMode) {
|
|
1758
|
+
pElement.style.minHeight = (pUlHeight + options.element.offsetHeight) + 'px';
|
|
1759
|
+
}
|
|
1760
|
+
},
|
|
1761
|
+
end: (options: AnimationOptions) => {
|
|
1762
|
+
if (this.hamburgerMode) {
|
|
1763
|
+
options.element.style.position = '';
|
|
1764
|
+
options.element.style.maxHeight = '';
|
|
1765
|
+
pElement.style.minHeight = '';
|
|
1766
|
+
options.element.style.top = 0 + 'px';
|
|
1767
|
+
(options.element.children[0] as HTMLElement).focus();
|
|
1768
|
+
this.triggerOpen(options.element.children[0] as HTMLElement);
|
|
1769
|
+
} else {
|
|
1770
|
+
this.end(options.element, isMenuOpen);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
});
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1777
|
+
private triggerOpen(ul: HTMLElement): void {
|
|
1778
|
+
let item: MenuItemModel = this.navIdx.length ? this.getItem(this.navIdx) : null;
|
|
1779
|
+
let eventArgs: OpenCloseMenuEventArgs = {
|
|
1780
|
+
element: ul, parentItem: item, items: item ? item.items : this.items as objColl
|
|
1781
|
+
};
|
|
1782
|
+
this.trigger('onOpen', eventArgs);
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
private end(ul: HTMLElement, isMenuOpen: boolean): void {
|
|
1786
|
+
if (isMenuOpen) {
|
|
1787
|
+
ul.style.display = 'block';
|
|
1788
|
+
ul.style.maxHeight = '';
|
|
1789
|
+
this.triggerOpen(ul);
|
|
1790
|
+
if (ul.querySelector('.' + FOCUSED)) {
|
|
1791
|
+
(ul.querySelector('.' + FOCUSED) as HTMLElement).focus();
|
|
1792
|
+
} else {
|
|
1793
|
+
let ele: HTMLElement;
|
|
1794
|
+
ele = this.getWrapper().children[this.getIdx(this.getWrapper(), ul) - 1] as HTMLElement;
|
|
1795
|
+
if (ele) {
|
|
1796
|
+
(ele.querySelector('.' + SELECTED) as HTMLElement).focus();
|
|
1797
|
+
} else {
|
|
1798
|
+
this.element.focus();
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
} else {
|
|
1802
|
+
if (ul === this.element) {
|
|
1803
|
+
let fli: Element = this.getLIByClass(this.element, FOCUSED);
|
|
1804
|
+
if (fli) {
|
|
1805
|
+
fli.classList.remove(FOCUSED);
|
|
1806
|
+
}
|
|
1807
|
+
let sli: Element = this.getLIByClass(this.element, SELECTED);
|
|
1808
|
+
if (sli) {
|
|
1809
|
+
sli.classList.remove(SELECTED);
|
|
1810
|
+
}
|
|
1811
|
+
ul.style.display = 'none';
|
|
1812
|
+
} else {
|
|
1813
|
+
detach(ul);
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
/**
|
|
1819
|
+
* Get the properties to be maintained in the persisted state.
|
|
1820
|
+
* @returns string
|
|
1821
|
+
*/
|
|
1822
|
+
protected getPersistData(): string {
|
|
1823
|
+
return '';
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
/**
|
|
1827
|
+
* Get wrapper element.
|
|
1828
|
+
* @returns Element
|
|
1829
|
+
* @private
|
|
1830
|
+
*/
|
|
1831
|
+
private getWrapper(): Element {
|
|
1832
|
+
return closest(this.element, '.e-' + this.getModuleName() + '-wrapper');
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
protected getIndex(
|
|
1836
|
+
data: string, isUniqueId?: boolean, items: MenuItemModel[] | { [key: string]: Object }[] = this.items as objColl,
|
|
1837
|
+
nIndex: number[] = [], isCallBack: boolean = false, level: number = 0): number[] {
|
|
1838
|
+
let item: MenuItemModel | obj;
|
|
1839
|
+
level = isCallBack ? level + 1 : 0;
|
|
1840
|
+
for (let i: number = 0, len: number = items.length; i < len; i++) {
|
|
1841
|
+
item = items[i];
|
|
1842
|
+
if ((isUniqueId ? (<obj>item)[this.getField('itemId', level)] : (<obj>item)[this.getField('text', level)]) === data) {
|
|
1843
|
+
nIndex.push(i);
|
|
1844
|
+
break;
|
|
1845
|
+
} else if ((<objColl>(<obj>item)[this.getField('children', level)])
|
|
1846
|
+
&& (<objColl>(<obj>item)[this.getField('children', level)]).length) {
|
|
1847
|
+
nIndex = this.getIndex(data, isUniqueId, (<objColl>(<obj>item)[this.getField('children', level)]), nIndex, true, level);
|
|
1848
|
+
if (nIndex[nIndex.length - 1] === -1) {
|
|
1849
|
+
if (i !== len - 1) {
|
|
1850
|
+
nIndex.pop();
|
|
1851
|
+
}
|
|
1852
|
+
} else {
|
|
1853
|
+
nIndex.unshift(i);
|
|
1854
|
+
break;
|
|
1855
|
+
}
|
|
1856
|
+
} else {
|
|
1857
|
+
if (i === len - 1) {
|
|
1858
|
+
nIndex.push(-1);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
return (!isCallBack && nIndex[0] === -1) ? [] : nIndex;
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
/**
|
|
1866
|
+
* This method is used to enable or disable the menu items in the Menu based on the items and enable argument.
|
|
1867
|
+
* @param items Text items that needs to be enabled/disabled.
|
|
1868
|
+
* @param enable Set `true`/`false` to enable/disable the list items.
|
|
1869
|
+
* @param isUniqueId - Set `true` if it is a unique id.
|
|
1870
|
+
* @returns void
|
|
1871
|
+
*/
|
|
1872
|
+
public enableItems(items: string[], enable: boolean = true, isUniqueId?: boolean): void {
|
|
1873
|
+
let ul: Element;
|
|
1874
|
+
let idx: number;
|
|
1875
|
+
let navIdx: number[];
|
|
1876
|
+
let disabled: string = DISABLED; let skipItem: boolean;
|
|
1877
|
+
for (let i: number = 0; i < items.length; i++) {
|
|
1878
|
+
navIdx = this.getIndex(items[i], isUniqueId);
|
|
1879
|
+
if (this.navIdx.length) {
|
|
1880
|
+
if (navIdx.length !== 1) {
|
|
1881
|
+
skipItem = false;
|
|
1882
|
+
for (let i: number = 0, len: number = navIdx.length - 1; i < len; i++) {
|
|
1883
|
+
if (navIdx[i] !== this.navIdx[i]) {
|
|
1884
|
+
skipItem = true; break;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
if (skipItem) { continue; }
|
|
1888
|
+
}
|
|
1889
|
+
} else {
|
|
1890
|
+
if (navIdx.length !== 1) { continue; }
|
|
1891
|
+
}
|
|
1892
|
+
idx = navIdx.pop();
|
|
1893
|
+
ul = this.getUlByNavIdx(navIdx.length);
|
|
1894
|
+
if (ul) {
|
|
1895
|
+
if (enable) {
|
|
1896
|
+
if (this.isMenu) {
|
|
1897
|
+
ul.children[idx].classList.remove(disabled);
|
|
1898
|
+
ul.children[idx].removeAttribute('aria-disabled');
|
|
1899
|
+
} else {
|
|
1900
|
+
if (Browser.isDevice && !ul.classList.contains('e-contextmenu')) {
|
|
1901
|
+
ul.children[idx + 1].classList.remove(disabled);
|
|
1902
|
+
} else {
|
|
1903
|
+
ul.children[idx].classList.remove(disabled);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
} else {
|
|
1907
|
+
if (this.isMenu) {
|
|
1908
|
+
ul.children[idx].classList.add(disabled);
|
|
1909
|
+
ul.children[idx].setAttribute('aria-disabled', 'true');
|
|
1910
|
+
} else {
|
|
1911
|
+
if (Browser.isDevice && !ul.classList.contains('e-contextmenu')) {
|
|
1912
|
+
ul.children[idx + 1].classList.add(disabled);
|
|
1913
|
+
} else {
|
|
1914
|
+
ul.children[idx].classList.add(disabled);
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
/**
|
|
1923
|
+
* This method is used to show the menu items in the Menu based on the items text.
|
|
1924
|
+
* @param items Text items that needs to be shown.
|
|
1925
|
+
* @param isUniqueId - Set `true` if it is a unique id.
|
|
1926
|
+
* @returns void
|
|
1927
|
+
*/
|
|
1928
|
+
public showItems(items: string[], isUniqueId?: boolean): void {
|
|
1929
|
+
this.showHideItems(items, false, isUniqueId);
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
/**
|
|
1933
|
+
* This method is used to hide the menu items in the Menu based on the items text.
|
|
1934
|
+
* @param items Text items that needs to be hidden.
|
|
1935
|
+
* @returns void
|
|
1936
|
+
*/
|
|
1937
|
+
public hideItems(items: string[], isUniqueId?: boolean): void {
|
|
1938
|
+
this.showHideItems(items, true, isUniqueId);
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
private showHideItems(items: string[], ishide: boolean, isUniqueId?: boolean): void {
|
|
1942
|
+
let ul: Element;
|
|
1943
|
+
let index: number;
|
|
1944
|
+
let navIdx: number[];
|
|
1945
|
+
for (let i: number = 0; i < items.length; i++) {
|
|
1946
|
+
navIdx = this.getIndex(items[i], isUniqueId);
|
|
1947
|
+
index = navIdx.pop();
|
|
1948
|
+
ul = this.getUlByNavIdx(navIdx.length);
|
|
1949
|
+
if (ul) {
|
|
1950
|
+
if (ishide) {
|
|
1951
|
+
if (Browser.isDevice && !ul.classList.contains('e-contextmenu')) {
|
|
1952
|
+
ul.children[index + 1].classList.add(HIDE);
|
|
1953
|
+
} else {
|
|
1954
|
+
ul.children[index].classList.add(HIDE);
|
|
1955
|
+
}
|
|
1956
|
+
} else {
|
|
1957
|
+
if (Browser.isDevice && !ul.classList.contains('e-contextmenu')) {
|
|
1958
|
+
ul.children[index + 1].classList.remove(HIDE);
|
|
1959
|
+
} else {
|
|
1960
|
+
ul.children[index].classList.remove(HIDE);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1967
|
+
/**
|
|
1968
|
+
* It is used to remove the menu items from the Menu based on the items text.
|
|
1969
|
+
* @param items Text items that needs to be removed.
|
|
1970
|
+
* @returns void
|
|
1971
|
+
*/
|
|
1972
|
+
public removeItems(items: string[], isUniqueId?: boolean): void {
|
|
1973
|
+
let idx: number;
|
|
1974
|
+
let navIdx: number[];
|
|
1975
|
+
let iitems: MenuItemModel[];
|
|
1976
|
+
for (let i: number = 0; i < items.length; i++) {
|
|
1977
|
+
navIdx = this.getIndex(items[i], isUniqueId);
|
|
1978
|
+
idx = navIdx.pop();
|
|
1979
|
+
iitems = this.getItems(navIdx);
|
|
1980
|
+
this.removeItem(iitems, navIdx, idx);
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
/**
|
|
1985
|
+
* It is used to insert the menu items after the specified menu item text.
|
|
1986
|
+
* @param items Items that needs to be inserted.
|
|
1987
|
+
* @param text Text item after that the element to be inserted.
|
|
1988
|
+
* @returns void
|
|
1989
|
+
*/
|
|
1990
|
+
public insertAfter(items: MenuItemModel[], text: string, isUniqueId?: boolean): void {
|
|
1991
|
+
this.insertItems(items, text, isUniqueId);
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
/**
|
|
1995
|
+
* It is used to insert the menu items before the specified menu item text.
|
|
1996
|
+
* @param items Items that needs to be inserted.
|
|
1997
|
+
* @param text Text item before that the element to be inserted.
|
|
1998
|
+
* @param isUniqueId - Set `true` if it is a unique id.
|
|
1999
|
+
* @returns void
|
|
2000
|
+
*/
|
|
2001
|
+
public insertBefore(items: MenuItemModel[], text: string, isUniqueId?: boolean): void {
|
|
2002
|
+
this.insertItems(items, text, isUniqueId, false);
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
private insertItems(items: MenuItemModel[] | objColl, text: string, isUniqueId?: boolean, isAfter: boolean = true): void {
|
|
2006
|
+
let li: Element;
|
|
2007
|
+
let idx: number;
|
|
2008
|
+
let navIdx: number[];
|
|
2009
|
+
let iitems: MenuItemModel[];
|
|
2010
|
+
let menuitem: MenuItem;
|
|
2011
|
+
let showIcon: boolean;
|
|
2012
|
+
for (let i: number = 0; i < items.length; i++) {
|
|
2013
|
+
navIdx = this.getIndex(text, isUniqueId);
|
|
2014
|
+
idx = navIdx.pop();
|
|
2015
|
+
iitems = this.getItems(navIdx);
|
|
2016
|
+
menuitem = new MenuItem(iitems[0] as MenuItem, 'items', items[i], true);
|
|
2017
|
+
iitems.splice(isAfter ? idx + 1 : idx, 0, menuitem);
|
|
2018
|
+
let uls: Element[] = this.isMenu ? [this.getWrapper()].concat(this.getPopups()) : [].slice.call(this.getWrapper().children);
|
|
2019
|
+
if (navIdx.length < uls.length) {
|
|
2020
|
+
idx = isAfter ? idx + 1 : idx;
|
|
2021
|
+
showIcon = this.hasField(iitems, this.getField('iconCss', navIdx.length - 1));
|
|
2022
|
+
li = this.createItems(iitems).children[idx];
|
|
2023
|
+
let ul: Element = this.isMenu ? select('.e-menu-parent', uls[navIdx.length]) : uls[navIdx.length];
|
|
2024
|
+
ul.insertBefore(li, ul.children[idx]);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
|
|
2029
|
+
private removeAttributes(): void {
|
|
2030
|
+
['top', 'left', 'display', 'z-index'].forEach((key: string) => {
|
|
2031
|
+
this.element.style.removeProperty(key);
|
|
2032
|
+
});
|
|
2033
|
+
['role', 'tabindex', 'class', 'style'].forEach((key: string) => {
|
|
2034
|
+
if (key === 'class' && this.element.classList.contains('e-menu-parent')) {
|
|
2035
|
+
this.element.classList.remove('e-menu-parent');
|
|
2036
|
+
}
|
|
2037
|
+
if (['class', 'style'].indexOf(key) === -1 || !this.element.getAttribute(key)) {
|
|
2038
|
+
this.element.removeAttribute(key);
|
|
2039
|
+
}
|
|
2040
|
+
if (this.isMenu && key === 'class' && this.element.classList.contains('e-vertical')) {
|
|
2041
|
+
this.element.classList.remove('e-vertical');
|
|
2042
|
+
}
|
|
2043
|
+
});
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
/**
|
|
2047
|
+
* Destroys the widget.
|
|
2048
|
+
* @returns void
|
|
2049
|
+
*/
|
|
2050
|
+
|
|
2051
|
+
public destroy(): void {
|
|
2052
|
+
let wrapper: Element = this.getWrapper();
|
|
2053
|
+
if (wrapper) {
|
|
2054
|
+
this.unWireEvents();
|
|
2055
|
+
if (!this.isMenu) {
|
|
2056
|
+
this.clonedElement.style.display = '';
|
|
2057
|
+
if (this.clonedElement.tagName === 'EJS-CONTEXTMENU') {
|
|
2058
|
+
addClass([this.clonedElement], ['e-control', 'e-lib', 'e-' + this.getModuleName()]);
|
|
2059
|
+
this.element = this.clonedElement as HTMLUListElement;
|
|
2060
|
+
} else {
|
|
2061
|
+
if (this.refreshing && this.clonedElement.childElementCount && this.clonedElement.children[0].tagName === 'LI') {
|
|
2062
|
+
this.setProperties({ 'items': [] }, true);
|
|
2063
|
+
}
|
|
2064
|
+
if (document.getElementById(this.clonedElement.id)) {
|
|
2065
|
+
let refEle: Element = this.clonedElement.nextElementSibling;
|
|
2066
|
+
refEle && refEle !== wrapper ? this.clonedElement.parentElement.insertBefore(this.element, refEle) :
|
|
2067
|
+
this.clonedElement.parentElement.appendChild(this.element);
|
|
2068
|
+
if (this.isBlazor()) {
|
|
2069
|
+
this.element = this.removeChildElement(this.element);
|
|
2070
|
+
} else {
|
|
2071
|
+
this.element.innerHTML = '';
|
|
2072
|
+
}
|
|
2073
|
+
append([].slice.call(this.clonedElement.children), this.element);
|
|
2074
|
+
detach(this.clonedElement);
|
|
2075
|
+
this.removeAttributes();
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
this.clonedElement = null;
|
|
2079
|
+
} else {
|
|
2080
|
+
this.closeMenu();
|
|
2081
|
+
if (this.isBlazor()) {
|
|
2082
|
+
this.element = this.removeChildElement(this.element);
|
|
2083
|
+
} else {
|
|
2084
|
+
this.element.innerHTML = '';
|
|
2085
|
+
}
|
|
2086
|
+
this.removeAttributes();
|
|
2087
|
+
wrapper.parentNode.insertBefore(this.element, wrapper);
|
|
2088
|
+
}
|
|
2089
|
+
if (this.isMenu && this.clonedElement) {
|
|
2090
|
+
detach(this.element);
|
|
2091
|
+
(wrapper as HTMLElement).style.display = '';
|
|
2092
|
+
wrapper.classList.remove('e-' + this.getModuleName() + '-wrapper');
|
|
2093
|
+
wrapper.removeAttribute('data-ripple');
|
|
2094
|
+
} else {
|
|
2095
|
+
detach(wrapper);
|
|
2096
|
+
}
|
|
2097
|
+
super.destroy();
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
/**
|
|
2103
|
+
* Interface for before item render/select event.
|
|
2104
|
+
*/
|
|
2105
|
+
export interface MenuEventArgs extends BaseEventArgs {
|
|
2106
|
+
element: HTMLElement;
|
|
2107
|
+
item: MenuItemModel;
|
|
2108
|
+
event?: Event;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
/**
|
|
2112
|
+
* Interface for before open/close event.
|
|
2113
|
+
*/
|
|
2114
|
+
export interface BeforeOpenCloseMenuEventArgs extends BaseEventArgs {
|
|
2115
|
+
element: HTMLElement;
|
|
2116
|
+
items: MenuItemModel[];
|
|
2117
|
+
parentItem: MenuItemModel;
|
|
2118
|
+
event: Event;
|
|
2119
|
+
cancel: boolean;
|
|
2120
|
+
top?: number;
|
|
2121
|
+
left?: number;
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
/**
|
|
2125
|
+
* Interface for open/close event.
|
|
2126
|
+
*/
|
|
2127
|
+
export interface OpenCloseMenuEventArgs extends BaseEventArgs {
|
|
2128
|
+
element: HTMLElement;
|
|
2129
|
+
items: MenuItemModel[] | { [key: string]: Object }[];
|
|
2130
|
+
parentItem: MenuItemModel;
|
|
2131
|
+
}
|