@syncfusion/ej2-dropdowns 18.1.57 → 18.2.44-4569

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/.eslintrc.json +244 -0
  2. package/CHANGELOG.md +1524 -1514
  3. package/README.md +118 -118
  4. package/dist/ej2-dropdowns.umd.min.js +1 -10
  5. package/dist/ej2-dropdowns.umd.min.js.map +1 -1
  6. package/dist/es6/ej2-dropdowns.es2015.js +198 -126
  7. package/dist/es6/ej2-dropdowns.es2015.js.map +1 -1
  8. package/dist/es6/ej2-dropdowns.es5.js +290 -217
  9. package/dist/es6/ej2-dropdowns.es5.js.map +1 -1
  10. package/dist/global/ej2-dropdowns.min.js +1 -10
  11. package/dist/global/ej2-dropdowns.min.js.map +1 -1
  12. package/dist/global/index.d.ts +0 -9
  13. package/dist/ts/auto-complete/auto-complete.ts +527 -0
  14. package/dist/ts/combo-box/combo-box.ts +957 -0
  15. package/dist/ts/common/highlight-search.ts +47 -0
  16. package/dist/ts/common/incremental-search.ts +81 -0
  17. package/dist/ts/drop-down-base/drop-down-base.ts +1572 -0
  18. package/dist/ts/drop-down-list/drop-down-list.ts +2993 -0
  19. package/dist/ts/drop-down-tree/drop-down-tree.ts +3066 -0
  20. package/dist/ts/list-box/list-box.ts +2317 -0
  21. package/dist/ts/multi-select/checkbox-selection.ts +528 -0
  22. package/dist/ts/multi-select/float-label.ts +155 -0
  23. package/dist/ts/multi-select/interface.ts +66 -0
  24. package/dist/ts/multi-select/multi-select.ts +4216 -0
  25. package/helpers/e2e/index.js +3 -3
  26. package/license +2 -2
  27. package/package.json +77 -77
  28. package/src/auto-complete/auto-complete-model.d.ts +179 -179
  29. package/src/auto-complete/auto-complete.d.ts +12 -12
  30. package/src/auto-complete/auto-complete.js +21 -21
  31. package/src/combo-box/combo-box-model.d.ts +212 -212
  32. package/src/combo-box/combo-box.d.ts +27 -27
  33. package/src/combo-box/combo-box.js +29 -29
  34. package/src/common/incremental-search.d.ts +1 -1
  35. package/src/common/incremental-search.js +4 -2
  36. package/src/drop-down-base/drop-down-base-model.d.ts +191 -191
  37. package/src/drop-down-base/drop-down-base.d.ts +17 -17
  38. package/src/drop-down-base/drop-down-base.js +20 -20
  39. package/src/drop-down-list/drop-down-list-model.d.ts +222 -222
  40. package/src/drop-down-list/drop-down-list.d.ts +3 -2
  41. package/src/drop-down-list/drop-down-list.js +43 -30
  42. package/src/drop-down-tree/drop-down-tree-model.d.ts +344 -344
  43. package/src/drop-down-tree/drop-down-tree.js +32 -26
  44. package/src/list-box/index.d.ts +1 -0
  45. package/src/list-box/index.js +1 -0
  46. package/src/list-box/list-box-model.d.ts +156 -156
  47. package/src/list-box/list-box.d.ts +2 -2
  48. package/src/list-box/list-box.js +57 -59
  49. package/src/multi-select/index.d.ts +1 -0
  50. package/src/multi-select/index.js +1 -0
  51. package/src/multi-select/multi-select-model.d.ts +452 -452
  52. package/src/multi-select/multi-select.d.ts +2 -0
  53. package/src/multi-select/multi-select.js +98 -43
  54. package/styles/_all.scss +3 -3
  55. package/styles/auto-complete/_bootstrap-dark-definition.scss +3 -3
  56. package/styles/auto-complete/_bootstrap4-definition.scss +11 -11
  57. package/styles/auto-complete/_fabric-dark-definition.scss +2 -2
  58. package/styles/auto-complete/_highcontrast-light-definition.scss +2 -2
  59. package/styles/auto-complete/_material-dark-definition.scss +2 -2
  60. package/styles/bootstrap-dark.css +67 -61
  61. package/styles/bootstrap.css +69 -63
  62. package/styles/bootstrap4.css +81 -61
  63. package/styles/combo-box/_bootstrap-dark-definition.scss +2 -2
  64. package/styles/combo-box/_bootstrap4-definition.scss +11 -11
  65. package/styles/combo-box/_fabric-dark-definition.scss +2 -2
  66. package/styles/combo-box/_highcontrast-light-definition.scss +3 -3
  67. package/styles/combo-box/_material-dark-definition.scss +2 -2
  68. package/styles/drop-down-base/_all.scss +2 -2
  69. package/styles/drop-down-base/_bootstrap-dark-definition.scss +64 -64
  70. package/styles/drop-down-base/_bootstrap-definition.scss +64 -64
  71. package/styles/drop-down-base/_bootstrap4-definition.scss +78 -78
  72. package/styles/drop-down-base/_definition.scss +23 -23
  73. package/styles/drop-down-base/_fabric-dark-definition.scss +68 -68
  74. package/styles/drop-down-base/_fabric-definition.scss +66 -66
  75. package/styles/drop-down-base/_highcontrast-definition.scss +82 -82
  76. package/styles/drop-down-base/_highcontrast-light-definition.scss +81 -81
  77. package/styles/drop-down-base/_layout.scss +108 -108
  78. package/styles/drop-down-base/_material-dark-definition.scss +67 -67
  79. package/styles/drop-down-base/_material-definition.scss +65 -65
  80. package/styles/drop-down-base/_theme.scss +242 -242
  81. package/styles/drop-down-list/_all.scss +2 -2
  82. package/styles/drop-down-list/_bootstrap-dark-definition.scss +157 -157
  83. package/styles/drop-down-list/_bootstrap-definition.scss +156 -156
  84. package/styles/drop-down-list/_bootstrap4-definition.scss +184 -184
  85. package/styles/drop-down-list/_fabric-dark-definition.scss +127 -127
  86. package/styles/drop-down-list/_fabric-definition.scss +122 -122
  87. package/styles/drop-down-list/_highcontrast-definition.scss +131 -131
  88. package/styles/drop-down-list/_highcontrast-light-definition.scss +133 -133
  89. package/styles/drop-down-list/_layout.scss +218 -218
  90. package/styles/drop-down-list/_material-dark-definition.scss +143 -143
  91. package/styles/drop-down-list/_material-definition.scss +166 -166
  92. package/styles/drop-down-list/_theme.scss +10 -10
  93. package/styles/drop-down-list/icons/_bootstrap-dark.scss +14 -14
  94. package/styles/drop-down-list/icons/_bootstrap.scss +14 -14
  95. package/styles/drop-down-list/icons/_bootstrap4.scss +14 -14
  96. package/styles/drop-down-list/icons/_fabric-dark.scss +14 -14
  97. package/styles/drop-down-list/icons/_fabric.scss +14 -14
  98. package/styles/drop-down-list/icons/_highcontrast-light.scss +14 -14
  99. package/styles/drop-down-list/icons/_highcontrast.scss +14 -14
  100. package/styles/drop-down-list/icons/_material-dark.scss +14 -14
  101. package/styles/drop-down-list/icons/_material.scss +14 -14
  102. package/styles/drop-down-list/material.css +9 -0
  103. package/styles/drop-down-tree/_all.scss +2 -2
  104. package/styles/drop-down-tree/_bootstrap-dark-definition.scss +62 -49
  105. package/styles/drop-down-tree/_bootstrap-definition.scss +62 -49
  106. package/styles/drop-down-tree/_bootstrap4-definition.scss +63 -50
  107. package/styles/drop-down-tree/_fabric-dark-definition.scss +63 -49
  108. package/styles/drop-down-tree/_fabric-definition.scss +63 -49
  109. package/styles/drop-down-tree/_highcontrast-definition.scss +63 -49
  110. package/styles/drop-down-tree/_highcontrast-light-definition.scss +63 -49
  111. package/styles/drop-down-tree/_layout.scss +437 -398
  112. package/styles/drop-down-tree/_material-dark-definition.scss +61 -54
  113. package/styles/drop-down-tree/_material-definition.scss +61 -54
  114. package/styles/drop-down-tree/_theme.scss +68 -63
  115. package/styles/drop-down-tree/bootstrap-dark.css +67 -61
  116. package/styles/drop-down-tree/bootstrap.css +69 -63
  117. package/styles/drop-down-tree/bootstrap4.css +81 -61
  118. package/styles/drop-down-tree/fabric-dark.css +71 -63
  119. package/styles/drop-down-tree/fabric.css +71 -63
  120. package/styles/drop-down-tree/highcontrast-light.css +71 -63
  121. package/styles/drop-down-tree/highcontrast.css +75 -63
  122. package/styles/drop-down-tree/icons/_bootstrap-dark.scss +11 -11
  123. package/styles/drop-down-tree/icons/_bootstrap.scss +11 -11
  124. package/styles/drop-down-tree/icons/_bootstrap4.scss +11 -11
  125. package/styles/drop-down-tree/icons/_fabric-dark.scss +11 -11
  126. package/styles/drop-down-tree/icons/_fabric.scss +11 -11
  127. package/styles/drop-down-tree/icons/_highcontrast-light.scss +11 -11
  128. package/styles/drop-down-tree/icons/_highcontrast.scss +11 -11
  129. package/styles/drop-down-tree/icons/_material-dark.scss +11 -11
  130. package/styles/drop-down-tree/icons/_material.scss +11 -11
  131. package/styles/drop-down-tree/material-dark.css +76 -85
  132. package/styles/drop-down-tree/material.css +93 -85
  133. package/styles/fabric-dark.css +71 -63
  134. package/styles/fabric.css +71 -63
  135. package/styles/highcontrast-light.css +71 -63
  136. package/styles/highcontrast.css +75 -63
  137. package/styles/list-box/_all.scss +2 -2
  138. package/styles/list-box/_bootstrap-dark-definition.scss +118 -118
  139. package/styles/list-box/_bootstrap-definition.scss +112 -112
  140. package/styles/list-box/_bootstrap4-definition.scss +118 -118
  141. package/styles/list-box/_fabric-dark-definition.scss +118 -118
  142. package/styles/list-box/_fabric-definition.scss +112 -112
  143. package/styles/list-box/_highcontrast-definition.scss +112 -112
  144. package/styles/list-box/_highcontrast-light-definition.scss +118 -118
  145. package/styles/list-box/_layout.scss +458 -458
  146. package/styles/list-box/_material-dark-definition.scss +118 -118
  147. package/styles/list-box/_material-definition.scss +112 -112
  148. package/styles/list-box/_theme.scss +273 -273
  149. package/styles/list-box/icons/_bootstrap-dark.scss +25 -25
  150. package/styles/list-box/icons/_bootstrap.scss +25 -25
  151. package/styles/list-box/icons/_bootstrap4.scss +25 -25
  152. package/styles/list-box/icons/_fabric-dark.scss +25 -25
  153. package/styles/list-box/icons/_fabric.scss +25 -25
  154. package/styles/list-box/icons/_highcontrast-light.scss +25 -25
  155. package/styles/list-box/icons/_highcontrast.scss +25 -25
  156. package/styles/list-box/icons/_material-dark.scss +25 -25
  157. package/styles/list-box/icons/_material.scss +25 -25
  158. package/styles/list-box/material-dark.css +4 -4
  159. package/styles/list-box/material.css +4 -4
  160. package/styles/material-dark.css +80 -89
  161. package/styles/material.css +115 -89
  162. package/styles/multi-select/_all.scss +2 -2
  163. package/styles/multi-select/_bootstrap-dark-definition.scss +171 -171
  164. package/styles/multi-select/_bootstrap-definition.scss +166 -166
  165. package/styles/multi-select/_bootstrap4-definition.scss +233 -233
  166. package/styles/multi-select/_fabric-dark-definition.scss +170 -170
  167. package/styles/multi-select/_fabric-definition.scss +167 -167
  168. package/styles/multi-select/_highcontrast-definition.scss +257 -257
  169. package/styles/multi-select/_highcontrast-light-definition.scss +258 -258
  170. package/styles/multi-select/_layout.scss +1153 -1153
  171. package/styles/multi-select/_material-dark-definition.scss +186 -186
  172. package/styles/multi-select/_material-definition.scss +191 -191
  173. package/styles/multi-select/_theme.scss +384 -384
  174. package/styles/multi-select/icons/_bootstrap-dark.scss +26 -26
  175. package/styles/multi-select/icons/_bootstrap.scss +26 -26
  176. package/styles/multi-select/icons/_bootstrap4.scss +37 -37
  177. package/styles/multi-select/icons/_fabric-dark.scss +26 -26
  178. package/styles/multi-select/icons/_fabric.scss +26 -26
  179. package/styles/multi-select/icons/_highcontrast-light.scss +26 -26
  180. package/styles/multi-select/icons/_highcontrast.scss +26 -26
  181. package/styles/multi-select/icons/_material-dark.scss +26 -26
  182. package/styles/multi-select/icons/_material.scss +324 -324
  183. package/styles/multi-select/material.css +9 -0
@@ -0,0 +1,2993 @@
1
+ /// <reference path='../drop-down-base/drop-down-base-model.d.ts'/>
2
+ import { EventHandler, Property, Event, compile, EmitType, KeyboardEvents, append } from '@syncfusion/ej2-base';
3
+ import { attributes, isNullOrUndefined, getUniqueID, formatUnit, isUndefined, getValue } from '@syncfusion/ej2-base';
4
+ import { Animation, AnimationModel, Browser, KeyboardEventArgs, NotifyPropertyChanges } from '@syncfusion/ej2-base';
5
+ import { addClass, removeClass, closest, prepend, detach, classList, isBlazor } from '@syncfusion/ej2-base';
6
+ import { Popup, isCollide, createSpinner, showSpinner, hideSpinner } from '@syncfusion/ej2-popups';
7
+ import { IInput, Input, InputObject, FloatLabelType } from '@syncfusion/ej2-inputs';
8
+ import { incrementalSearch } from '../common/incremental-search';
9
+ import { DropDownBase, dropDownBaseClasses, SelectEventArgs, FilteringEventArgs, PopupEventArgs } from '../drop-down-base/drop-down-base';
10
+ import { FocusEventArgs, ResultData, BeforeOpenEventArgs } from '../drop-down-base/drop-down-base';
11
+ import { FieldSettingsModel } from '../drop-down-base/drop-down-base-model';
12
+ import { DropDownListModel } from '../drop-down-list';
13
+ /* tslint:disable */
14
+ import { DataManager, Query, Predicate } from '@syncfusion/ej2-data';
15
+ import { SortOrder } from '@syncfusion/ej2-lists';
16
+ /* tslint:enable */
17
+ export interface ChangeEventArgs extends SelectEventArgs {
18
+ /**
19
+ * Returns the selected value
20
+ * @isGenericType true
21
+ */
22
+ value: number | string | boolean;
23
+ /**
24
+ * Returns the previous selected list item
25
+ */
26
+ previousItem: HTMLLIElement;
27
+ /**
28
+ * Returns the previous selected item as JSON Object from the data source.
29
+ * @blazorType object
30
+ */
31
+ previousItemData: FieldSettingsModel;
32
+ /**
33
+ * Returns the root element of the component.
34
+ */
35
+ element: HTMLElement;
36
+ }
37
+ // don't use space in classnames
38
+ export const dropDownListClasses: DropDownListClassList = {
39
+ root: 'e-dropdownlist',
40
+ hover: dropDownBaseClasses.hover,
41
+ selected: dropDownBaseClasses.selected,
42
+ rtl: dropDownBaseClasses.rtl,
43
+ li: dropDownBaseClasses.li,
44
+ disable: dropDownBaseClasses.disabled,
45
+ base: dropDownBaseClasses.root,
46
+ focus: dropDownBaseClasses.focus,
47
+ input: 'e-input-group',
48
+ inputFocus: 'e-input-focus',
49
+ icon: 'e-input-group-icon e-ddl-icon',
50
+ iconAnimation: 'e-icon-anim',
51
+ value: 'e-input-value',
52
+ device: 'e-ddl-device',
53
+ backIcon: 'e-input-group-icon e-back-icon e-icons',
54
+ filterBarClearIcon: 'e-input-group-icon e-clear-icon e-icons',
55
+ filterInput: 'e-input-filter',
56
+ filterParent: 'e-filter-parent',
57
+ mobileFilter: 'e-ddl-device-filter',
58
+ footer: 'e-ddl-footer',
59
+ header: 'e-ddl-header',
60
+ clearIcon: 'e-clear-icon',
61
+ clearIconHide: 'e-clear-icon-hide',
62
+ popupFullScreen: 'e-popup-full-page',
63
+ disableIcon: 'e-ddl-disable-icon',
64
+ hiddenElement: 'e-ddl-hidden'
65
+ };
66
+
67
+
68
+ let inputObject: InputObject = {
69
+ container: null,
70
+ buttons: []
71
+ };
72
+
73
+ /**
74
+ * The DropDownList component contains a list of predefined values from which you can
75
+ * choose a single value.
76
+ * ```html
77
+ * <input type="text" tabindex="1" id="list"> </input>
78
+ * ```
79
+ * ```typescript
80
+ * let dropDownListObj:DropDownList = new DropDownList();
81
+ * dropDownListObj.appendTo("#list");
82
+ * ```
83
+ */
84
+
85
+ @NotifyPropertyChanges
86
+ export class DropDownList extends DropDownBase implements IInput {
87
+ protected inputWrapper: InputObject;
88
+ protected inputElement: HTMLInputElement;
89
+ private valueTempElement: HTMLSpanElement;
90
+ private listObject: HTMLElement;
91
+ private header: HTMLElement;
92
+ private footer: HTMLElement;
93
+ protected selectedLI: HTMLElement;
94
+ protected previousSelectedLI: HTMLElement;
95
+ protected previousItemData: { [key: string]: Object } | string | number | boolean;
96
+ private listHeight: string;
97
+ protected hiddenElement: HTMLSelectElement;
98
+ protected isPopupOpen: boolean;
99
+ private isDocumentClick: boolean;
100
+ protected isInteracted: boolean;
101
+ private isFilterFocus: boolean;
102
+ protected beforePopupOpen: boolean;
103
+ protected initial: boolean;
104
+ private initRemoteRender: boolean;
105
+ private searchBoxHeight: number;
106
+ private popupObj: Popup;
107
+ private backIconElement: Element;
108
+ private clearIconElement: Element;
109
+ private containerStyle: ClientRect;
110
+ protected previousValue: string | number | boolean = null;
111
+ protected activeIndex: number;
112
+ protected filterInput: HTMLInputElement;
113
+ private searchKeyModule: KeyboardEvents;
114
+ private tabIndex: string;
115
+ private isNotSearchList: boolean;
116
+ protected isTyped: boolean;
117
+ protected isSelected: boolean;
118
+ protected preventFocus: boolean;
119
+ protected preventAutoFill: boolean;
120
+ protected queryString: string;
121
+ protected isValidKey: boolean;
122
+ protected typedString: string;
123
+ protected isEscapeKey: boolean;
124
+ private isPreventBlur: boolean;
125
+ protected isTabKey: boolean;
126
+ private actionCompleteData: ActionCompleteData;
127
+ protected prevSelectPoints: { [key: string]: number };
128
+ protected isSelectCustom: boolean;
129
+ protected isDropDownClick: boolean;
130
+ protected preventAltUp: boolean;
131
+ private searchKeyEvent: KeyboardEventArgs;
132
+ private filterInputObj: InputObject;
133
+ protected spinnerElement: HTMLElement;
134
+ protected keyConfigure: { [key: string]: string };
135
+ protected isCustomFilter: boolean;
136
+ private isSecondClick: boolean;
137
+ private serverPopupEle: HTMLElement;
138
+ protected isServerBlazor: boolean;
139
+ private isServerIncrementalSearch: boolean;
140
+ private isServerNavigation: boolean;
141
+
142
+ /**
143
+ * Sets CSS classes to the root element of the component that allows customization of appearance.
144
+ * @default null
145
+ */
146
+ @Property(null)
147
+ public cssClass: string;
148
+ /**
149
+ * Specifies the width of the component. By default, the component width sets based on the width of
150
+ * its parent container. You can also set the width in pixel values.
151
+ * @default '100%'
152
+ * @aspType string
153
+ * @blazorType string
154
+ */
155
+ @Property('100%')
156
+ public width: string | number;
157
+ /**
158
+ * Specifies the height of the popup list.
159
+ * > For more details about the popup configuration refer to
160
+ * [`Popup Configuration`](../../drop-down-list/getting-started#configure-the-popup-list) documentation.
161
+ * @default '300px'
162
+ * @aspType string
163
+ * @blazorType string
164
+ */
165
+ @Property('300px')
166
+ public popupHeight: string | number;
167
+ /**
168
+ * Specifies the width of the popup list. By default, the popup width sets based on the width of
169
+ * the component.
170
+ * > For more details about the popup configuration refer to
171
+ * [`Popup Configuration`](../../drop-down-list/getting-started#configure-the-popup-list) documentation.
172
+ * @default '100%'
173
+ * @aspType string
174
+ * @blazorType string
175
+ */
176
+ @Property('100%')
177
+ public popupWidth: string | number;
178
+ /**
179
+ * Specifies a short hint that describes the expected value of the DropDownList component.
180
+ * @default null
181
+ */
182
+ @Property(null)
183
+ public placeholder: string;
184
+ /**
185
+ * Accepts the value to be displayed as a watermark text on the filter bar.
186
+ * @default null
187
+ */
188
+ @Property(null)
189
+ public filterBarPlaceholder: string;
190
+ /**
191
+ * Allows additional HTML attributes such as title, name, etc., and
192
+ * accepts n number of attributes in a key-value pair format.
193
+ *
194
+ * {% codeBlock src='dropdownlist/htmlAttributes/index.md' %}{% endcodeBlock %}
195
+ *
196
+ * @default {}
197
+ */
198
+ @Property({})
199
+ public htmlAttributes: { [key: string]: string; };
200
+ /**
201
+ * Accepts the external `Query`
202
+ * that execute along with data processing.
203
+ *
204
+ * {% codeBlock src='dropdownlist/query/index.md' %}{% endcodeBlock %}
205
+ *
206
+ * @default null
207
+ * @deprecated
208
+ */
209
+ @Property(null)
210
+ public query: Query;
211
+ /**
212
+ * Accepts the template design and assigns it to the selected list item in the input element of the component.
213
+ * For more details about the available template options refer to
214
+ * [`Template`](../../drop-down-list/templates) documentation.
215
+ *
216
+ * We have built-in `template engine`
217
+ * which provides options to compile template string into a executable function.
218
+ * For EX: We have expression evolution as like ES6 expression string literals.
219
+ * @default null
220
+ */
221
+ @Property(null)
222
+ public valueTemplate: string;
223
+ /**
224
+ * Accepts the template design and assigns it to the header container of the popup list.
225
+ * > For more details about the available template options refer to [`Template`](../../drop-down-list/templates) documentation.
226
+ * @default null
227
+ */
228
+ @Property(null)
229
+ public headerTemplate: string;
230
+ /**
231
+ * Accepts the template design and assigns it to the footer container of the popup list.
232
+ * > For more details about the available template options refer to [`Template`](../../drop-down-list/templates) documentation.
233
+ * @default null
234
+ */
235
+ @Property(null)
236
+ public footerTemplate: string;
237
+ /**
238
+ * When allowFiltering is set to true, show the filter bar (search box) of the component.
239
+ * The filter action retrieves matched items through the `filtering` event based on
240
+ * the characters typed in the search TextBox.
241
+ *
242
+ * If no match is found, the value of the `noRecordsTemplate` property will be displayed.
243
+ * > For more details about the filtering refer to [`Filtering`](../../drop-down-list/filtering) documentation.
244
+ *
245
+ * {% codeBlock src="dropdownlist/allow-filtering-api/index.ts" %}{% endcodeBlock %}
246
+ *
247
+ * {% codeBlock src="dropdownlist/allow-filtering-api/index.html" %}{% endcodeBlock %}
248
+ * @default false
249
+ */
250
+ @Property(false)
251
+ public allowFiltering: boolean;
252
+ /**
253
+ * When set to true, the user interactions on the component are disabled.
254
+ * @default false
255
+ */
256
+ @Property(false)
257
+ public readonly: boolean;
258
+ /**
259
+ * Gets or sets the display text of the selected item in the component.
260
+ * @default null
261
+ */
262
+ @Property(null)
263
+ public text: string;
264
+ /**
265
+ * Gets or sets the value of the selected item in the component.
266
+ * @default null
267
+ * @isGenericType true
268
+ */
269
+ @Property(null)
270
+ public value: number | string | boolean;
271
+ /**
272
+ * Gets or sets the index of the selected item in the component.
273
+ *
274
+ * {% codeBlock src="dropdownlist/index-api/index.ts" %}{% endcodeBlock %}
275
+ *
276
+ * {% codeBlock src="dropdownlist/index-api/index.html" %}{% endcodeBlock %}
277
+ *
278
+ * @default null
279
+ * @blazorType int
280
+ * @isBlazorNullableType true
281
+ * @blazorDefaultValue
282
+ */
283
+ @Property(null)
284
+ public index: number;
285
+ /**
286
+ * Specifies whether to display the floating label above the input element.
287
+ * Possible values are:
288
+ * * Never: The label will never float in the input when the placeholder is available.
289
+ * * Always: The floating label will always float above the input.
290
+ * * Auto: The floating label will float above the input after focusing or entering a value in the input.
291
+ *
292
+ * {% codeBlock src="dropdownlist/float-label-type-api/index.ts" %}{% endcodeBlock %}
293
+ *
294
+ * {% codeBlock src="dropdownlist/float-label-type-api/index.html" %}{% endcodeBlock %}
295
+ *
296
+ * @default Syncfusion.EJ2.Inputs.FloatLabelType.Never
297
+ * @aspType Syncfusion.EJ2.Inputs.FloatLabelType
298
+ * @isEnumeration true
299
+ * @blazorType Syncfusion.Blazor.Inputs.FloatLabelType
300
+ */
301
+ @Property('Never')
302
+ public floatLabelType: FloatLabelType;
303
+ /**
304
+ * Specifies whether to show or hide the clear button.
305
+ * When the clear button is clicked, `value`, `text`, and `index` properties are reset to null.
306
+ * @default false
307
+ * @blazorOverrideType virtual
308
+ */
309
+ @Property(false)
310
+ public showClearButton: boolean;
311
+ /**
312
+ * Triggers on typing a character in the filter bar when the
313
+ * [`allowFiltering`](./#allowfiltering)
314
+ * is enabled.
315
+ * > For more details about the filtering refer to [`Filtering`](../../drop-down-list/filtering) documentation.
316
+ *
317
+ * @event
318
+ * @blazorProperty 'Filtering'
319
+ */
320
+ @Event()
321
+ public filtering: EmitType<FilteringEventArgs>;
322
+
323
+ /**
324
+ * Triggers when an item in a popup is selected or when the model value is changed by user.
325
+ * Use change event to
326
+ * [`Configure the Cascading DropDownList`](../../drop-down-list/how-to/cascading)
327
+ * @event
328
+ * @blazorProperty 'ValueChange'
329
+ */
330
+ @Event()
331
+ public change: EmitType<ChangeEventArgs>;
332
+ /**
333
+ * Triggers when the popup before opens.
334
+ * @event
335
+ * @blazorProperty 'OnOpen'
336
+ * @blazorType BeforeOpenEventArgs
337
+ */
338
+ @Event()
339
+ public beforeOpen: EmitType<Object>;
340
+ /**
341
+ * Triggers when the popup opens.
342
+ * @event
343
+ * @blazorProperty 'Opened'
344
+ */
345
+ @Event()
346
+ public open: EmitType<PopupEventArgs>;
347
+ /**
348
+ * Triggers when the popup is closed.
349
+ * @event
350
+ * @blazorProperty 'OnClose'
351
+ */
352
+ @Event()
353
+ public close: EmitType<PopupEventArgs>;
354
+ /**
355
+ * Triggers when focus moves out from the component.
356
+ * @event
357
+ */
358
+ @Event()
359
+ public blur: EmitType<Object>;
360
+ /**
361
+ * Triggers when the component is focused.
362
+ * @event
363
+ */
364
+ @Event()
365
+ public focus: EmitType<Object>;
366
+
367
+ /**
368
+ * * Constructor for creating the DropDownList component.
369
+ */
370
+ constructor(options?: DropDownListModel, element?: string | HTMLElement) {
371
+ super(options, element);
372
+ };
373
+
374
+ /**
375
+ * Initialize the event handler.
376
+ * @private
377
+ */
378
+ protected preRender(): void {
379
+ let checkBlazor: boolean = isBlazor() && this.isServerRendered;
380
+ this.isServerBlazor = (checkBlazor) ? true : false;
381
+ if (this.isServerBlazor) {
382
+ this.initializeData();
383
+ } else {
384
+ this.element.style.opacity = '0';
385
+ this.initializeData();
386
+ super.preRender();
387
+ }
388
+ this.activeIndex = this.index;
389
+ this.queryString = '';
390
+ }
391
+
392
+ private initializeData(): void {
393
+ this.isPopupOpen = false;
394
+ this.isDocumentClick = false;
395
+ this.isInteracted = false;
396
+ this.isFilterFocus = false;
397
+ this.beforePopupOpen = false;
398
+ this.initial = true;
399
+ this.initRemoteRender = false;
400
+ this.isNotSearchList = false;
401
+ this.isTyped = false;
402
+ this.isSelected = false;
403
+ this.preventFocus = false;
404
+ this.preventAutoFill = false;
405
+ this.isValidKey = false;
406
+ this.typedString = '';
407
+ this.isEscapeKey = false;
408
+ this.isPreventBlur = false;
409
+ this.isTabKey = false;
410
+ this.actionCompleteData = { isUpdated: false };
411
+ this.prevSelectPoints = {};
412
+ this.isSelectCustom = false;
413
+ this.isDropDownClick = false;
414
+ this.preventAltUp = false;
415
+ this.isCustomFilter = false;
416
+ this.isSecondClick = false;
417
+ this.keyConfigure = {
418
+ tab: 'tab',
419
+ enter: '13',
420
+ escape: '27',
421
+ end: '35',
422
+ home: '36',
423
+ down: '40',
424
+ up: '38',
425
+ pageUp: '33',
426
+ pageDown: '34',
427
+ open: 'alt+40',
428
+ close: 'shift+tab',
429
+ hide: 'alt+38',
430
+ space: '32'
431
+ };
432
+ }
433
+
434
+ protected setZIndex(): void {
435
+ if (this.popupObj) {
436
+ this.popupObj.setProperties({ 'zIndex': this.zIndex });
437
+ }
438
+ }
439
+
440
+ protected renderList(isEmptyData?: boolean): void {
441
+ if (!this.isServerBlazor) {
442
+ super.render(isEmptyData);
443
+ this.wireListEvents();
444
+ } else {
445
+ // tslint:disable-next-line
446
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerRenderList', this.beforePopupOpen, false);
447
+ }
448
+ }
449
+
450
+ private floatLabelChange(): void {
451
+ if (this.getModuleName() === 'dropdownlist' && this.floatLabelType === 'Auto') {
452
+ let floatElement: HTMLElement = <HTMLElement>this.inputWrapper.container.querySelector('.e-float-text');
453
+ if (this.inputElement.value !== '' || this.isInteracted) {
454
+ classList(floatElement, ['e-label-top'], ['e-label-bottom']);
455
+ } else {
456
+ classList(floatElement, ['e-label-bottom'], ['e-label-top']);
457
+ }
458
+ }
459
+ }
460
+
461
+ protected resetHandler(e: MouseEvent): void {
462
+ e.preventDefault();
463
+ this.clearAll(e);
464
+ }
465
+
466
+ protected resetFocusElement(): void {
467
+ this.removeHover();
468
+ this.removeSelection();
469
+ this.removeFocus();
470
+ this.list.scrollTop = 0;
471
+ if (this.getModuleName() !== 'autocomplete' && !isNullOrUndefined(this.ulElement)) {
472
+ let li: Element = this.ulElement.querySelector('.' + dropDownListClasses.li);
473
+ if (li) { li.classList.add(dropDownListClasses.focus); }
474
+ }
475
+ }
476
+
477
+ protected clearAll(e?: MouseEvent | KeyboardEventArgs, properties?: DropDownListModel): void {
478
+ if (isNullOrUndefined(properties) || (!isNullOrUndefined(properties) &&
479
+ (isNullOrUndefined(properties.dataSource) ||
480
+ (!(properties.dataSource instanceof DataManager) && properties.dataSource.length === 0)))) {
481
+ this.isActive = true;
482
+ this.resetSelection(properties);
483
+ }
484
+ let dataItem: { [key: string]: string } = this.getItemData();
485
+ if (this.previousValue === dataItem.value) { return; }
486
+ this.onChangeEvent(e);
487
+ }
488
+
489
+ private resetSelection(properties?: DropDownListModel): void {
490
+ if (this.list) {
491
+ if ((!isNullOrUndefined(properties) &&
492
+ (isNullOrUndefined(properties.dataSource) ||
493
+ (!(properties.dataSource instanceof DataManager) && properties.dataSource.length === 0)))) {
494
+ this.selectedLI = null;
495
+ this.actionCompleteData.isUpdated = false;
496
+ this.actionCompleteData.ulElement = null;
497
+ this.actionCompleteData.list = null;
498
+ this.resetList(properties.dataSource);
499
+ } else {
500
+ if (this.allowFiltering && this.getModuleName() !== 'autocomplete'
501
+ && !isNullOrUndefined(this.actionCompleteData.ulElement) && !isNullOrUndefined(this.actionCompleteData.list)) {
502
+ let actionList: HTMLElement = this.actionCompleteData.ulElement.querySelector('li');
503
+ let ulElement: HTMLElement = this.ulElement && this.ulElement.querySelector('li');
504
+ if (this.element.tagName === 'EJS-COMBOBOX' && actionList && ulElement &&
505
+ actionList.childElementCount > 0 && ulElement.childElementCount > 0 &&
506
+ actionList.textContent !== ulElement.textContent && this.itemTemplate) {
507
+ this.cloneElements();
508
+ }
509
+ this.onActionComplete(this.actionCompleteData.ulElement.cloneNode(true) as HTMLElement, this.actionCompleteData.list);
510
+ }
511
+ this.resetFocusElement();
512
+ }
513
+ }
514
+ if (!this.isServerBlazor) { this.hiddenElement.innerHTML = ''; }
515
+ this.inputElement.value = '';
516
+ this.value = null;
517
+ this.itemData = null;
518
+ this.text = null;
519
+ this.index = null;
520
+ this.activeIndex = null;
521
+ this.item = null;
522
+ this.queryString = '';
523
+ if (this.valueTempElement) {
524
+ detach(this.valueTempElement);
525
+ this.inputElement.style.display = 'block';
526
+ this.valueTempElement = null;
527
+ }
528
+ this.setSelection(null, null);
529
+ this.isSelectCustom = false;
530
+ this.updateIconState();
531
+ this.cloneElements();
532
+ }
533
+ private setHTMLAttributes(): void {
534
+ if (Object.keys(this.htmlAttributes).length) {
535
+ for (let htmlAttr of Object.keys(this.htmlAttributes)) {
536
+ if (htmlAttr === 'class') {
537
+ let updatedClassValue : string = (this.htmlAttributes[htmlAttr].replace(/\s+/g, ' ')).trim();
538
+ if (updatedClassValue !== '') {
539
+ addClass([this.inputWrapper.container], updatedClassValue.split(' '));
540
+ }
541
+ } else if (htmlAttr === 'disabled' && this.htmlAttributes[htmlAttr] === 'disabled') {
542
+ this.enabled = false;
543
+ this.setEnable();
544
+ } else if (htmlAttr === 'readonly' && !isNullOrUndefined(this.htmlAttributes[htmlAttr])) {
545
+ this.readonly = true;
546
+ this.dataBind();
547
+ } else if (htmlAttr === 'style') {
548
+ this.inputWrapper.container.setAttribute('style', this.htmlAttributes[htmlAttr]);
549
+ } else {
550
+ let defaultAttr: string[] = ['title', 'id', 'placeholder', 'aria-placeholder',
551
+ 'role', 'autocorrect', 'autocomplete', 'autocapitalize', 'spellcheck', 'minlength', 'maxlength'];
552
+ let validateAttr: string[] = ['name', 'required'];
553
+ if (this.getModuleName() === 'autocomplete' || this.getModuleName() === 'combobox') {
554
+ defaultAttr.push('tabindex');
555
+ }
556
+ if (htmlAttr.indexOf('data') === 0 || validateAttr.indexOf(htmlAttr) > -1) {
557
+ this.hiddenElement.setAttribute(htmlAttr, this.htmlAttributes[htmlAttr]);
558
+ } else if (defaultAttr.indexOf(htmlAttr) > -1) {
559
+ htmlAttr === 'placeholder' ? Input.setPlaceholder(this.htmlAttributes[htmlAttr], this.inputElement) :
560
+ this.inputElement.setAttribute(htmlAttr, this.htmlAttributes[htmlAttr]);
561
+ } else {
562
+ this.inputWrapper.container.setAttribute(htmlAttr, this.htmlAttributes[htmlAttr]);
563
+ }
564
+ }
565
+ }
566
+ }
567
+ if (this.getModuleName() === 'autocomplete' || this.getModuleName() === 'combobox') {
568
+ this.inputWrapper.container.removeAttribute('tabindex');
569
+ }
570
+ }
571
+
572
+ protected getAriaAttributes(): { [key: string]: string } {
573
+ return {
574
+ 'aria-disabled': 'false',
575
+ 'aria-owns': this.element.id + '_options',
576
+ 'role': 'listbox',
577
+ 'aria-haspopup': 'true',
578
+ 'aria-expanded': 'false',
579
+ 'aria-activedescendant': 'null',
580
+ 'aria-live': 'polite',
581
+ 'aria-labelledby': this.hiddenElement.id
582
+ };
583
+ }
584
+
585
+ protected setEnableRtl(): void {
586
+ Input.setEnableRtl(this.enableRtl, [this.inputElement.parentElement]);
587
+ if (this.popupObj) {
588
+ this.popupObj.enableRtl = this.enableRtl;
589
+ this.popupObj.dataBind();
590
+ }
591
+ }
592
+
593
+ private setEnable(): void {
594
+ Input.setEnabled(this.enabled, this.inputElement);
595
+ if (this.enabled) {
596
+ removeClass([this.inputWrapper.container], dropDownListClasses.disable);
597
+ this.inputElement.setAttribute('aria-disabled', 'false');
598
+ this.targetElement().setAttribute('tabindex', this.tabIndex);
599
+ } else {
600
+ this.hidePopup();
601
+ addClass([this.inputWrapper.container], dropDownListClasses.disable);
602
+ this.inputElement.setAttribute('aria-disabled', 'true');
603
+ this.targetElement().tabIndex = -1;
604
+ }
605
+ }
606
+ /**
607
+ * Get the properties to be maintained in the persisted state.
608
+ */
609
+ protected getPersistData(): string {
610
+ return this.addOnPersist(['value']);
611
+ };
612
+
613
+ protected getLocaleName(): string {
614
+ return 'drop-down-list';
615
+ };
616
+
617
+ private preventTabIndex(element: HTMLElement): void {
618
+ if (this.getModuleName() === 'dropdownlist') {
619
+ element.tabIndex = -1;
620
+ }
621
+ }
622
+
623
+ protected targetElement(): HTMLElement | HTMLInputElement {
624
+ return this.inputWrapper.container;
625
+ }
626
+
627
+ protected getNgDirective(): string {
628
+ return 'EJS-DROPDOWNLIST';
629
+ }
630
+
631
+ protected getElementByText(text: string): Element {
632
+ return this.getElementByValue(this.getValueByText(text));
633
+ }
634
+
635
+ protected getElementByValue(value: string | number | boolean): Element {
636
+ let item: Element;
637
+ let listItems: Element[] = this.getItems();
638
+ for (let liItem of listItems) {
639
+ if (this.getFormattedValue(liItem.getAttribute('data-value')) === value) {
640
+ item = liItem;
641
+ break;
642
+ }
643
+ }
644
+ return item;
645
+ };
646
+
647
+ private initValue(): void {
648
+ this.renderList();
649
+ if (this.dataSource instanceof DataManager) {
650
+ this.initRemoteRender = true;
651
+ } else {
652
+ this.updateValues();
653
+ }
654
+ }
655
+
656
+ protected updateValues(): void {
657
+ if (!isNullOrUndefined(this.value)) {
658
+ this.setSelection(this.getElementByValue(this.value), null);
659
+ } else if (this.text && isNullOrUndefined(this.value)) {
660
+ let element: Element = this.getElementByText(this.text);
661
+ if (isNullOrUndefined(element)) {
662
+ this.setProperties({ text: null });
663
+ return;
664
+ } else {
665
+ this.setSelection(element, null);
666
+ }
667
+ } else {
668
+ this.setSelection(this.liCollections[this.activeIndex], null);
669
+ }
670
+ this.setHiddenValue();
671
+ Input.setValue(this.text, this.inputElement, this.floatLabelType, this.showClearButton);
672
+ }
673
+
674
+ protected onBlur(e: MouseEvent): void {
675
+ if (!this.enabled) {
676
+ return;
677
+ }
678
+ let target: HTMLElement = <HTMLElement>e.relatedTarget;
679
+ let currentTarget: HTMLElement = <HTMLElement>e.target;
680
+ let isPreventBlur: boolean = this.isPreventBlur;
681
+ this.isPreventBlur = false;
682
+ //IE 11 - issue
683
+ if (isPreventBlur && !this.isDocumentClick && this.isPopupOpen && (!isNullOrUndefined(currentTarget) ||
684
+ !this.isFilterLayout() && isNullOrUndefined(target))) {
685
+ if (this.getModuleName() === 'dropdownlist' && this.allowFiltering && this.isPopupOpen) {
686
+ this.filterInput.focus();
687
+ } else {
688
+ this.targetElement().focus();
689
+ }
690
+ return;
691
+ }
692
+ if (this.isDocumentClick || (!isNullOrUndefined(this.popupObj)
693
+ && document.body.contains(this.popupObj.element) &&
694
+ this.popupObj.element.classList.contains(dropDownListClasses.mobileFilter))) {
695
+ if (!this.beforePopupOpen) {
696
+ this.isDocumentClick = false;
697
+ }
698
+ return;
699
+ }
700
+ if (((this.getModuleName() === 'dropdownlist' && !this.isFilterFocus && target !== this.inputElement)
701
+ && (document.activeElement !== target || (document.activeElement === target &&
702
+ currentTarget.classList.contains(dropDownListClasses.inputFocus)))) ||
703
+ (isNullOrUndefined(target) && this.getModuleName() === 'dropdownlist' && this.allowFiltering &&
704
+ currentTarget !== this.inputWrapper.container) || this.getModuleName() !== 'dropdownlist' &&
705
+ !this.inputWrapper.container.contains(target) || this.isTabKey) {
706
+ this.isDocumentClick = this.isPopupOpen ? true : false;
707
+ this.focusOutAction(e);
708
+ this.isTabKey = false;
709
+ }
710
+ if (this.isRequested && !this.isPopupOpen && !this.isPreventBlur) {
711
+ this.isActive = false;
712
+ this.beforePopupOpen = false;
713
+ }
714
+ }
715
+
716
+ protected focusOutAction(e?: MouseEvent | KeyboardEventArgs): void {
717
+ this.isInteracted = false;
718
+ this.focusOut(e);
719
+ this.onFocusOut();
720
+ }
721
+
722
+ protected onFocusOut(): void {
723
+ if (!this.enabled) {
724
+ return;
725
+ }
726
+ if (this.isSelected) {
727
+ this.isSelectCustom = false;
728
+ this.onChangeEvent(null);
729
+ }
730
+ this.floatLabelChange();
731
+ this.dispatchEvent(this.hiddenElement as HTMLElement, 'change');
732
+ if (this.getModuleName() === 'dropdownlist' && this.element.tagName !== 'INPUT') {
733
+ this.dispatchEvent(this.inputElement as HTMLElement, 'blur');
734
+ }
735
+ if (this.inputWrapper.clearButton) {
736
+ addClass([this.inputWrapper.clearButton], dropDownListClasses.clearIconHide);
737
+ }
738
+ this.trigger('blur');
739
+ }
740
+
741
+ protected onFocus(e?: FocusEvent | MouseEvent | KeyboardEvent | TouchEvent): void {
742
+ if (!this.isInteracted) {
743
+ this.isInteracted = true;
744
+ let args: FocusEventArgs = { isInteracted: e ? true : false, event: e };
745
+ this.trigger('focus', args);
746
+ }
747
+ this.updateIconState();
748
+ }
749
+
750
+ private resetValueHandler(e: Event): void {
751
+ let formElement: HTMLFormElement = closest(this.inputElement, 'form') as HTMLFormElement;
752
+ if (formElement && e.target === formElement) {
753
+ let val: string = (this.element.tagName === this.getNgDirective()) ? null : this.inputElement.getAttribute('value');
754
+ this.text = val;
755
+ }
756
+ }
757
+
758
+ protected wireEvent(): void {
759
+ EventHandler.add(this.inputWrapper.container, 'mousedown', this.dropDownClick, this);
760
+ EventHandler.add(this.inputWrapper.container, 'focus', this.focusIn, this);
761
+ EventHandler.add(this.inputWrapper.container, 'keypress', this.onSearch, this);
762
+ this.bindCommonEvent();
763
+ }
764
+
765
+ protected bindCommonEvent(): void {
766
+ EventHandler.add(this.targetElement(), 'blur', this.onBlur, this);
767
+ let formElement: HTMLFormElement = closest(this.inputElement, 'form') as HTMLFormElement;
768
+ if (formElement) {
769
+ EventHandler.add(formElement, 'reset', this.resetValueHandler, this);
770
+ }
771
+ if (!Browser.isDevice) {
772
+ this.keyboardModule = new KeyboardEvents(
773
+ this.targetElement(), {
774
+ keyAction: this.keyActionHandler.bind(this), keyConfigs: this.keyConfigure, eventName: 'keydown'
775
+ });
776
+ } else {
777
+ this.keyboardModule = new KeyboardEvents(
778
+ this.targetElement(), {
779
+ keyAction: this.mobileKeyActionHandler.bind(this), keyConfigs: this.keyConfigure, eventName: 'keydown'
780
+ });
781
+ }
782
+ this.bindClearEvent();
783
+ }
784
+
785
+ private bindClearEvent(): void {
786
+ if (this.showClearButton) {
787
+ EventHandler.add(this.inputWrapper.clearButton, 'mousedown', this.resetHandler, this);
788
+ }
789
+ }
790
+
791
+ protected unBindCommonEvent(): void {
792
+ EventHandler.remove(this.targetElement(), 'blur', this.onBlur);
793
+ let formElement: HTMLFormElement = closest(this.inputElement, 'form') as HTMLFormElement;
794
+ if (formElement) {
795
+ EventHandler.remove(formElement, 'reset', this.resetValueHandler);
796
+ }
797
+ if (!Browser.isDevice) {
798
+ this.keyboardModule.destroy();
799
+ }
800
+ if (this.showClearButton) {
801
+ EventHandler.remove(this.inputWrapper.clearButton, 'mousedown', this.resetHandler);
802
+ }
803
+ }
804
+
805
+ protected updateIconState(): void {
806
+ if (this.showClearButton) {
807
+ if (this.inputElement.value !== '' && !this.readonly) {
808
+ removeClass([this.inputWrapper.clearButton], dropDownListClasses.clearIconHide);
809
+ } else {
810
+ addClass([this.inputWrapper.clearButton], dropDownListClasses.clearIconHide);
811
+ }
812
+ }
813
+ }
814
+ /**
815
+ * Event binding for list
816
+ */
817
+ private wireListEvents(): void {
818
+ EventHandler.add(this.list, 'click', this.onMouseClick, this);
819
+ EventHandler.add(this.list, 'mouseover', this.onMouseOver, this);
820
+ EventHandler.add(this.list, 'mouseout', this.onMouseLeave, this);
821
+ };
822
+
823
+ private onSearch(e: KeyboardEventArgs): void {
824
+ if (e.charCode !== 32 && e.charCode !== 13) {
825
+ if (this.list === undefined) {
826
+ if (!this.isServerBlazor) {
827
+ this.renderList();
828
+ } else {
829
+ this.isServerIncrementalSearch = true;
830
+ // tslint:disable-next-line
831
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerRenderList', true, false);
832
+ }
833
+ }
834
+ this.searchKeyEvent = e;
835
+ this.onServerIncrementalSearch(e);
836
+ }
837
+ }
838
+
839
+ private onServerIncrementalSearch(e: KeyboardEventArgs): void {
840
+ if (!this.isRequested && !isNullOrUndefined(this.list) &&
841
+ !isNullOrUndefined(this.list.querySelector('li')) && this.enabled && !this.readonly) {
842
+ this.incrementalSearch(e);
843
+ }
844
+ }
845
+
846
+ protected onMouseClick(e: MouseEvent): void {
847
+ let target: Element = <Element>e.target;
848
+ let classList: DOMTokenList = target.classList;
849
+ let li: HTMLElement = <HTMLElement>closest(target, '.' + dropDownBaseClasses.li);
850
+ if (!this.isValidLI(li)) {
851
+ return;
852
+ }
853
+ this.setSelection(li, e);
854
+ if (Browser.isDevice && this.isFilterLayout()) {
855
+ history.back();
856
+ } else {
857
+ let delay: number = 100;
858
+ this.closePopup(delay);
859
+ }
860
+ }
861
+
862
+ private onMouseOver(e: MouseEvent): void {
863
+ let currentLi: HTMLElement = <HTMLElement>closest(<Element>e.target, '.' + dropDownBaseClasses.li);
864
+ this.setHover(currentLi);
865
+ };
866
+
867
+ private setHover(li: HTMLElement): void {
868
+ if (this.enabled && this.isValidLI(li) && !li.classList.contains(dropDownBaseClasses.hover)) {
869
+ this.removeHover();
870
+ addClass([li], dropDownBaseClasses.hover);
871
+ }
872
+ };
873
+
874
+ private onMouseLeave(e: MouseEvent): void {
875
+ this.removeHover();
876
+ };
877
+
878
+ protected removeHover(): void {
879
+ if (this.list) {
880
+ let hoveredItem: Element[] = (this.isServerBlazor && this.popupObj && this.popupObj.element) ?
881
+ <NodeListOf<Element> & Element[]>this.popupObj.element.querySelectorAll('.' + dropDownBaseClasses.hover) :
882
+ <NodeListOf<Element> & Element[]>this.list.querySelectorAll('.' + dropDownBaseClasses.hover);
883
+ if (hoveredItem && hoveredItem.length) {
884
+ removeClass(hoveredItem, dropDownBaseClasses.hover);
885
+ }
886
+ }
887
+ };
888
+
889
+ protected isValidLI(li: Element | HTMLElement): boolean {
890
+ return (li && li.hasAttribute('role') && li.getAttribute('role') === 'option');
891
+ };
892
+
893
+ protected incrementalSearch(e: KeyboardEventArgs): void {
894
+ if (this.liCollections.length > 0) {
895
+ let li: Element =
896
+ incrementalSearch(e.charCode, this.liCollections, this.activeIndex, true, this.element.id, this.isServerBlazor);
897
+ if (!isNullOrUndefined(li)) {
898
+ this.setSelection(li, e);
899
+ this.setScrollPosition();
900
+ }
901
+ }
902
+ };
903
+ /**
904
+ * Hides the spinner loader.
905
+ * @returns void.
906
+ */
907
+ public hideSpinner(): void {
908
+ if (!isNullOrUndefined(this.spinnerElement)) {
909
+ hideSpinner(this.spinnerElement);
910
+ removeClass([this.spinnerElement], dropDownListClasses.disableIcon);
911
+ this.spinnerElement.innerHTML = '';
912
+ this.spinnerElement = null;
913
+ }
914
+ }
915
+ /**
916
+ * Shows the spinner loader.
917
+ * @returns void.
918
+ */
919
+ public showSpinner(): void {
920
+ if (isNullOrUndefined(this.spinnerElement)) {
921
+ this.spinnerElement = Browser.isDevice && !isNullOrUndefined(this.filterInputObj) && this.filterInputObj.buttons[1] ||
922
+ !isNullOrUndefined(this.filterInputObj) && this.filterInputObj.buttons[0] || this.inputWrapper.buttons[0];
923
+ addClass([this.spinnerElement], dropDownListClasses.disableIcon);
924
+ createSpinner(
925
+ {
926
+ target: this.spinnerElement,
927
+ width: Browser.isDevice ? '16px' : '14px'
928
+ },
929
+ this.createElement);
930
+ showSpinner(this.spinnerElement);
931
+ }
932
+ }
933
+ protected keyActionHandler(e: KeyboardEventArgs): void {
934
+ if (!this.enabled) {
935
+ return;
936
+ }
937
+ let preventAction: boolean = e.action === 'pageUp' || e.action === 'pageDown';
938
+ let preventHomeEnd: boolean = this.getModuleName() !== 'dropdownlist' && (e.action === 'home' || e.action === 'end');
939
+ this.isEscapeKey = e.action === 'escape';
940
+ this.isTabKey = !this.isPopupOpen && e.action === 'tab';
941
+ let isNavAction: boolean = e.action === 'down' || e.action === 'up' || e.action === 'home' || e.action === 'end';
942
+ let isNavigation: boolean = (e.action === 'down' || e.action === 'up' || e.action === 'pageUp' || e.action === 'pageDown'
943
+ || e.action === 'home' || e.action === 'end');
944
+ if ((this.isEditTextBox() || preventAction || preventHomeEnd) && !this.isPopupOpen) {
945
+ return;
946
+ }
947
+ if (!this.readonly) {
948
+ let isTabAction: boolean = e.action === 'tab' || e.action === 'close';
949
+ if (this.list === undefined && !this.isRequested && !isTabAction && e.action !== 'escape') {
950
+ this.searchKeyEvent = e;
951
+ this.renderList();
952
+ }
953
+ if (!(this.isServerBlazor && (e.action === 'open' || e.action === 'space')) && isNullOrUndefined(this.list) ||
954
+ (!isNullOrUndefined(this.liCollections) && isNavigation && this.liCollections.length === 0) || this.isRequested) {
955
+ if (!(this.isServerBlazor && isNavAction)) {
956
+ return;
957
+ }
958
+ }
959
+ if ((isTabAction && this.getModuleName() !== 'autocomplete') && this.isPopupOpen
960
+ || e.action === 'escape') { e.preventDefault(); }
961
+ this.isSelected = e.action === 'escape' ? false : this.isSelected;
962
+ this.isTyped = (isNavigation || e.action === 'escape') ? false : this.isTyped;
963
+ switch (e.action) {
964
+ case 'down':
965
+ case 'up':
966
+ this.updateUpDownAction(e);
967
+ break;
968
+ case 'pageUp':
969
+ this.pageUpSelection(this.activeIndex - this.getPageCount(), e);
970
+ e.preventDefault();
971
+ break;
972
+ case 'pageDown':
973
+ this.pageDownSelection(this.activeIndex + this.getPageCount(), e);
974
+ e.preventDefault();
975
+ break;
976
+ case 'home':
977
+ this.updateHomeEndAction(e);
978
+ break;
979
+ case 'end':
980
+ this.updateHomeEndAction(e);
981
+ break;
982
+ case 'space':
983
+ if (this.getModuleName() === 'dropdownlist') {
984
+ if (!this.beforePopupOpen) {
985
+ this.showPopup();
986
+ }
987
+ }
988
+ break;
989
+ case 'open':
990
+ this.showPopup();
991
+ break;
992
+ case 'hide':
993
+ this.preventAltUp = this.isPopupOpen;
994
+ this.hidePopup(e);
995
+ this.focusDropDown(e);
996
+ break;
997
+ case 'enter':
998
+ this.selectCurrentItem(e);
999
+ break;
1000
+ case 'tab':
1001
+ this.selectCurrentValueOnTab(e);
1002
+ break;
1003
+ case 'escape':
1004
+ case 'close':
1005
+ if (this.isPopupOpen) {
1006
+ this.hidePopup(e);
1007
+ this.focusDropDown(e);
1008
+ }
1009
+ break;
1010
+ }
1011
+ }
1012
+ }
1013
+
1014
+ private updateUpDownAction(e: KeyboardEventArgs): void {
1015
+ if (this.isServerBlazor && isNullOrUndefined(this.list)) {
1016
+ this.isServerNavigation = true;
1017
+ // tslint:disable-next-line
1018
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerRenderList', true, false);
1019
+ } else {
1020
+ this.isServerNavigation = false;
1021
+ let focusEle: Element = this.list.querySelector('.' + dropDownListClasses.focus);
1022
+ if (this.isSelectFocusItem(focusEle)) {
1023
+ this.setSelection(focusEle, e);
1024
+ } else {
1025
+ let nextItem: Element;
1026
+ let index: number = e.action === 'down' ? this.activeIndex + 1 : this.activeIndex - 1;
1027
+ let startIndex: number = 0;
1028
+ if (this.getModuleName() === 'autocomplete') {
1029
+ startIndex = e.action === 'down' && isNullOrUndefined(this.activeIndex) ? 0 : this.liCollections.length - 1;
1030
+ index = index < 0 ? this.liCollections.length - 1 : index === this.liCollections.length ? 0 : index;
1031
+ }
1032
+ nextItem = isNullOrUndefined(this.activeIndex) ? this.liCollections[startIndex] : this.liCollections[index];
1033
+ if (!isNullOrUndefined(nextItem)) { this.setSelection(nextItem, e); }
1034
+ }
1035
+ e.preventDefault();
1036
+ }
1037
+ }
1038
+
1039
+ private updateHomeEndAction(e: KeyboardEventArgs): void {
1040
+ if (this.getModuleName() === 'dropdownlist') {
1041
+ if (this.isServerBlazor && isNullOrUndefined(this.list)) {
1042
+ this.isServerNavigation = true;
1043
+ // tslint:disable-next-line
1044
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerRenderList', true, false);
1045
+ } else {
1046
+ this.isServerNavigation = false;
1047
+ let findLi: number = 0;
1048
+ if (e.action === 'home') {
1049
+ findLi = 0;
1050
+ } else {
1051
+ findLi = this.getItems().length - 1;
1052
+ }
1053
+ e.preventDefault();
1054
+ if (this.activeIndex === findLi) { return; }
1055
+ this.setSelection(this.liCollections[findLi], e);
1056
+ }
1057
+ }
1058
+ }
1059
+
1060
+ protected selectCurrentValueOnTab(e: KeyboardEventArgs): void {
1061
+ if (this.getModuleName() === 'autocomplete') {
1062
+ this.selectCurrentItem(e);
1063
+ } else {
1064
+ if (this.isPopupOpen) {
1065
+ this.hidePopup(e);
1066
+ this.focusDropDown(e);
1067
+ }
1068
+ }
1069
+ }
1070
+
1071
+ protected mobileKeyActionHandler(e: KeyboardEventArgs): void {
1072
+ if (!this.enabled) {
1073
+ return;
1074
+ }
1075
+ if ((this.isEditTextBox()) && !this.isPopupOpen) {
1076
+ return;
1077
+ }
1078
+ if (!this.readonly) {
1079
+ if (this.list === undefined && !this.isRequested) {
1080
+ this.searchKeyEvent = e;
1081
+ this.renderList();
1082
+ }
1083
+ if (isNullOrUndefined(this.list) || (!isNullOrUndefined(this.liCollections) &&
1084
+ this.liCollections.length === 0) || this.isRequested) {
1085
+ return;
1086
+ }
1087
+ if (e.action === 'enter') {
1088
+ this.selectCurrentItem(e);
1089
+ }
1090
+ }
1091
+ }
1092
+
1093
+ protected selectCurrentItem(e: KeyboardEventArgs): void {
1094
+ if (this.isPopupOpen) {
1095
+ let li: Element = this.list.querySelector('.' + dropDownListClasses.focus);
1096
+ if (li) {
1097
+ this.setSelection(li, e);
1098
+ this.isTyped = false;
1099
+ }
1100
+ if (this.isSelected) {
1101
+ this.isSelectCustom = false;
1102
+ this.onChangeEvent(e);
1103
+ }
1104
+ this.hidePopup();
1105
+ this.focusDropDown(e);
1106
+ } else {
1107
+ this.showPopup();
1108
+ }
1109
+ }
1110
+
1111
+ protected isSelectFocusItem(element: Element): boolean {
1112
+ return !isNullOrUndefined(element);
1113
+ }
1114
+
1115
+ private getPageCount(): number {
1116
+ let liHeight: string = this.list.classList.contains(dropDownBaseClasses.noData) ? null :
1117
+ getComputedStyle(this.getItems()[0], null).getPropertyValue('height');
1118
+ return Math.round(this.list.getBoundingClientRect().height / parseInt(liHeight, 10));
1119
+ }
1120
+
1121
+ private pageUpSelection(steps: number, event: KeyboardEventArgs): void {
1122
+ let previousItem: Element = steps >= 0 ? this.liCollections[steps + 1] : this.liCollections[0];
1123
+ this.setSelection(previousItem, event);
1124
+ };
1125
+
1126
+ private pageDownSelection(steps: number, event: KeyboardEventArgs): void {
1127
+ let list: Element[] = this.getItems();
1128
+ let previousItem: Element = steps <= list.length ? this.liCollections[steps - 1] : this.liCollections[list.length - 1];
1129
+ this.setSelection(previousItem, event);
1130
+ };
1131
+
1132
+ protected unWireEvent(): void {
1133
+ EventHandler.remove(this.inputWrapper.container, 'mousedown', this.dropDownClick);
1134
+ EventHandler.remove(this.inputWrapper.container, 'keypress', this.onSearch);
1135
+ EventHandler.remove(this.inputWrapper.container, 'focus', this.focusIn);
1136
+ this.unBindCommonEvent();
1137
+ }
1138
+ /**
1139
+ * Event un binding for list items.
1140
+ */
1141
+ private unWireListEvents(): void {
1142
+ EventHandler.remove(this.list, 'click', this.onMouseClick);
1143
+ EventHandler.remove(this.list, 'mouseover', this.onMouseOver);
1144
+ EventHandler.remove(this.list, 'mouseout', this.onMouseLeave);
1145
+ };
1146
+
1147
+ protected checkSelector(id: string): string {
1148
+ return '#' + id.replace(/(:|\.|\[|\]|,|=|@|\\|\/|#)/g, '\\$1');
1149
+ }
1150
+ protected onDocumentClick(e: MouseEvent): void {
1151
+ let target: HTMLElement = <HTMLElement>e.target;
1152
+ if (!(!isNullOrUndefined(this.popupObj) && closest(target, this.checkSelector(this.popupObj.element.id))) &&
1153
+ !this.inputWrapper.container.contains(e.target as Node)) {
1154
+ if (this.inputWrapper.container.classList.contains(dropDownListClasses.inputFocus) || this.isPopupOpen) {
1155
+ this.isDocumentClick = true;
1156
+ let isActive: boolean = this.isRequested;
1157
+ this.isInteracted = false;
1158
+ this.hidePopup(e);
1159
+ if (!isActive) {
1160
+ this.onFocusOut();
1161
+ this.inputWrapper.container.classList.remove(dropDownListClasses.inputFocus);
1162
+ }
1163
+ }
1164
+ } else if (target !== this.inputElement && !(this.allowFiltering && target === this.filterInput)
1165
+ && !(this.getModuleName() === 'combobox' &&
1166
+ !this.allowFiltering && Browser.isDevice && target === this.inputWrapper.buttons[0])) {
1167
+ this.isPreventBlur = (Browser.isIE || Browser.info.name === 'edge') && (document.activeElement === this.targetElement() ||
1168
+ document.activeElement === this.filterInput);
1169
+ e.preventDefault();
1170
+ }
1171
+ }
1172
+
1173
+ private activeStateChange(): void {
1174
+ if (this.isDocumentClick) {
1175
+ this.hidePopup();
1176
+ this.onFocusOut();
1177
+ this.inputWrapper.container.classList.remove(dropDownListClasses.inputFocus);
1178
+ }
1179
+ }
1180
+
1181
+ private focusDropDown(e?: MouseEvent | KeyboardEventArgs | TouchEvent): void {
1182
+ if (!this.initial && this.isFilterLayout()) {
1183
+ this.focusIn(e);
1184
+ }
1185
+ }
1186
+
1187
+ protected dropDownClick(e: MouseEvent): void {
1188
+ if (e.which === 3 || e.button === 2) { return; }
1189
+ if (this.targetElement().classList.contains(dropDownListClasses.disable) || this.inputWrapper.clearButton === e.target) { return; }
1190
+ let target: HTMLElement = <HTMLElement>e.target;
1191
+ if (target !== this.inputElement && !(this.allowFiltering && target === this.filterInput) && this.getModuleName() !== 'combobox') {
1192
+ e.preventDefault();
1193
+ }
1194
+ if (!this.readonly) {
1195
+ if (this.isPopupOpen) {
1196
+ this.hidePopup();
1197
+ if (this.isFilterLayout()) { this.focusDropDown(e); }
1198
+ } else {
1199
+ this.focusIn(e);
1200
+ this.floatLabelChange();
1201
+ this.queryString = this.inputElement.value.trim() === '' ? null : this.inputElement.value;
1202
+ this.isDropDownClick = true;
1203
+ this.showPopup();
1204
+ }
1205
+ let proxy: this = this;
1206
+ let duration: number = (isBlazor()) ? 1000 : (this.element.tagName === this.getNgDirective() && this.itemTemplate) ? 500 : 100;
1207
+ if (!this.isSecondClick) {
1208
+ setTimeout(() => { proxy.cloneElements(); proxy.isSecondClick = true; }, duration);
1209
+ }
1210
+ } else {
1211
+ this.focusIn(e);
1212
+ }
1213
+ }
1214
+ protected cloneElements(): void {
1215
+ if (this.list) {
1216
+ let ulElement: HTMLElement = this.list.querySelector('ul');
1217
+ if (ulElement) {
1218
+ ulElement = ulElement.cloneNode ? (ulElement.cloneNode(true) as HTMLElement) : ulElement;
1219
+ this.actionCompleteData.ulElement = ulElement;
1220
+ }
1221
+ }
1222
+ }
1223
+ protected updateSelectedItem(
1224
+ li: Element,
1225
+ e: MouseEvent | KeyboardEvent | TouchEvent,
1226
+ preventSelect?: boolean,
1227
+ isSelection?: boolean): void {
1228
+ this.removeSelection();
1229
+ li.classList.add(dropDownBaseClasses.selected);
1230
+ this.removeHover();
1231
+ let value: string | number | boolean = this.getFormattedValue(li.getAttribute('data-value'));
1232
+ let selectedData: string | number | boolean | {
1233
+ [key: string]: Object;
1234
+ } = this.getDataByValue(value);
1235
+ if (!this.initial && !preventSelect && !isNullOrUndefined(e)) {
1236
+ let items: FieldSettingsModel = this.detachChanges(selectedData);
1237
+ this.isSelected = true;
1238
+ let eventArgs: SelectEventArgs = {
1239
+ e: e,
1240
+ item: li as HTMLLIElement,
1241
+ itemData: items,
1242
+ isInteracted: e ? true : false,
1243
+ cancel: false
1244
+ };
1245
+ this.trigger('select', eventArgs, (eventArgs: SelectEventArgs) => {
1246
+ if (eventArgs.cancel) {
1247
+ li.classList.remove(dropDownBaseClasses.selected);
1248
+ } else {
1249
+ this.selectEventCallback(li, e, preventSelect, selectedData, value);
1250
+ if (this.isServerBlazor) {
1251
+ // tslint:disable-next-line
1252
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerItemData', this.itemData);
1253
+ }
1254
+ if (isSelection) { this.setSelectOptions(li, e); }
1255
+ }
1256
+ });
1257
+ } else {
1258
+ this.selectEventCallback(li, e, preventSelect, selectedData, value);
1259
+ if (this.isServerBlazor) {
1260
+ // tslint:disable-next-line
1261
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerItemData', this.itemData);
1262
+ }
1263
+ if (isSelection) { this.setSelectOptions(li, e); }
1264
+ }
1265
+ }
1266
+
1267
+ private selectEventCallback(
1268
+ li: Element,
1269
+ e: MouseEvent | KeyboardEvent | TouchEvent,
1270
+ preventSelect?: boolean,
1271
+ selectedData?: string | number | boolean | { [key: string]: Object },
1272
+ value?: string | number | boolean): void {
1273
+ this.previousItemData = (!isNullOrUndefined(this.itemData)) ? this.itemData : null;
1274
+ this.item = li as HTMLLIElement;
1275
+ this.itemData = selectedData;
1276
+ let focusedItem: Element = this.list.querySelector('.' + dropDownBaseClasses.focus);
1277
+ if (focusedItem) { removeClass([focusedItem], dropDownBaseClasses.focus); }
1278
+ li.setAttribute('aria-selected', 'true');
1279
+ this.activeIndex = this.getIndexByValue(value);
1280
+ }
1281
+
1282
+ protected activeItem(li: Element): void {
1283
+ if (this.isValidLI(li) && !li.classList.contains(dropDownBaseClasses.selected)) {
1284
+ this.removeSelection();
1285
+ li.classList.add(dropDownBaseClasses.selected);
1286
+ this.removeHover();
1287
+ li.setAttribute('aria-selected', 'true');
1288
+ }
1289
+ }
1290
+
1291
+ protected setValue(e?: KeyboardEventArgs): boolean {
1292
+ let dataItem: { [key: string]: string } = this.getItemData();
1293
+ if (dataItem.value === null) {
1294
+ if (isBlazor() && dataItem.text !== null || dataItem.text !== '') {
1295
+ Input.setValue(dataItem.text, this.inputElement, this.floatLabelType, this.showClearButton);
1296
+ } else {
1297
+ Input.setValue(null, this.inputElement, this.floatLabelType, this.showClearButton);
1298
+ }
1299
+ } else {
1300
+ Input.setValue(dataItem.text, this.inputElement, this.floatLabelType, this.showClearButton);
1301
+ }
1302
+ if (this.isServerBlazor) {
1303
+ // tslint:disable-next-line
1304
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerValueTemplate', dataItem);
1305
+ }
1306
+ if (this.valueTemplate && this.itemData !== null && !this.isServerBlazor) {
1307
+ this.DropDownBaseresetBlazorTemplates(false, false, false, false, true);
1308
+ this.setValueTemplate();
1309
+ } else if (this.inputElement.previousSibling === this.valueTempElement) {
1310
+ detach(this.valueTempElement);
1311
+ this.inputElement.style.display = 'block';
1312
+ }
1313
+ if (this.previousValue === dataItem.value) {
1314
+ this.isSelected = false;
1315
+ return true;
1316
+ } else {
1317
+ this.isSelected = !this.initial ? true : false;
1318
+ this.isSelectCustom = false;
1319
+ if (this.getModuleName() === 'dropdownlist') {
1320
+ this.updateIconState();
1321
+ }
1322
+ return false;
1323
+ }
1324
+ }
1325
+
1326
+ protected setSelection(li: Element, e: MouseEvent | KeyboardEventArgs | TouchEvent): void {
1327
+ if (this.isValidLI(li) && (!li.classList.contains(dropDownBaseClasses.selected) || (this.isPopupOpen && this.isSelected
1328
+ && li.classList.contains(dropDownBaseClasses.selected)))) {
1329
+ this.updateSelectedItem(li, e, false, true);
1330
+ } else {
1331
+ this.setSelectOptions(li, e);
1332
+ }
1333
+ }
1334
+ private setSelectOptions(li: Element, e?: MouseEvent | KeyboardEventArgs | KeyboardEvent | TouchEvent): void {
1335
+ if (this.list) {
1336
+ this.removeHover();
1337
+ }
1338
+ this.previousSelectedLI = (!isNullOrUndefined(this.selectedLI)) ? this.selectedLI : null;
1339
+ this.selectedLI = li as HTMLElement;
1340
+ if (this.setValue(e as KeyboardEventArgs)) {
1341
+ return;
1342
+ }
1343
+ if (this.isPopupOpen) {
1344
+ attributes(this.targetElement(), { 'aria-activedescendant': this.selectedLI ? this.selectedLI.id : null });
1345
+ if (this.isFilterLayout() && this.filterInput) {
1346
+ attributes(this.filterInput, { 'aria-activedescendant': this.selectedLI ? this.selectedLI.id : null });
1347
+ }
1348
+ }
1349
+ if ((!this.isPopupOpen && !isNullOrUndefined(li)) || (this.isPopupOpen && !isNullOrUndefined(e) &&
1350
+ (e.type !== 'keydown' || e.type === 'keydown' && (e as KeyboardEventArgs).action === 'enter'))) {
1351
+ this.isSelectCustom = false;
1352
+ this.onChangeEvent(e);
1353
+ }
1354
+ if (this.isPopupOpen && !isNullOrUndefined(this.selectedLI) && this.itemData !== null && (!e || e.type !== 'click')) {
1355
+ this.setScrollPosition(e as KeyboardEventArgs);
1356
+ }
1357
+ if (Browser.info.name !== 'mozilla') {
1358
+ attributes(this.inputElement, { 'aria-label': this.inputElement.value });
1359
+ attributes(this.targetElement(), { 'aria-describedby': this.inputElement.id });
1360
+ this.targetElement().removeAttribute('aria-live');
1361
+ }
1362
+ }
1363
+
1364
+ private dropdownCompiler(dropdownTemplate: string): boolean {
1365
+ let checkTemplate: boolean = false;
1366
+ if (dropdownTemplate) {
1367
+ let exception: Object;
1368
+ try {
1369
+ checkTemplate = (document.querySelectorAll(dropdownTemplate).length) ? true : false;
1370
+
1371
+ } catch (exception) {
1372
+ checkTemplate = false;
1373
+ }
1374
+ }
1375
+ return checkTemplate;
1376
+ }
1377
+
1378
+ private setValueTemplate(): void {
1379
+ let compiledString: Function;
1380
+ if (!this.valueTempElement) {
1381
+ this.valueTempElement = this.createElement('span', { className: dropDownListClasses.value });
1382
+ this.inputElement.parentElement.insertBefore(this.valueTempElement, this.inputElement);
1383
+ this.inputElement.style.display = 'none';
1384
+ }
1385
+ this.valueTempElement.innerHTML = '';
1386
+ let templateData: FieldSettingsModel = (isBlazor()) ? JSON.parse(JSON.stringify(this.itemData)) : this.itemData;
1387
+ let valuecheck: boolean = this.dropdownCompiler(this.valueTemplate);
1388
+ if (valuecheck) {
1389
+ compiledString = compile(document.querySelector(this.valueTemplate).innerHTML.trim());
1390
+ } else {
1391
+ compiledString = compile(this.valueTemplate);
1392
+ }
1393
+ for (let item of compiledString(templateData, null, null, this.valueTemplateId, this.isStringTemplate)) {
1394
+ this.valueTempElement.appendChild(item);
1395
+ }
1396
+ this.DropDownBaseupdateBlazorTemplates(false, false, false, false, true, true, true);
1397
+ }
1398
+
1399
+ protected removeSelection(): void {
1400
+ if (this.list) {
1401
+ let selectedItems: Element[] = <NodeListOf<Element> & Element[]>this.list.querySelectorAll('.' + dropDownBaseClasses.selected);
1402
+ if (selectedItems.length) {
1403
+ removeClass(selectedItems, dropDownBaseClasses.selected);
1404
+ selectedItems[0].removeAttribute('aria-selected');
1405
+ }
1406
+ }
1407
+ };
1408
+
1409
+ protected getItemData(): { [key: string]: string } {
1410
+ let fields: FieldSettingsModel = this.fields;
1411
+ let dataItem: { [key: string]: string | Object } | string | boolean | number = null;
1412
+ dataItem = this.itemData;
1413
+ let dataValue: string;
1414
+ let dataText: string;
1415
+ if (!isNullOrUndefined(dataItem)) {
1416
+ dataValue = getValue(fields.value, dataItem);
1417
+ dataText = getValue(fields.text, dataItem);
1418
+ }
1419
+ let value: string = <string>(!isNullOrUndefined(dataItem) &&
1420
+ !isUndefined(dataValue) ? dataValue : dataItem);
1421
+ let text: string = <string>(!isNullOrUndefined(dataItem) &&
1422
+ !isUndefined(dataValue) ? dataText : dataItem);
1423
+ return { value: value, text: text };
1424
+ }
1425
+ /**
1426
+ * To trigger the change event for list.
1427
+ */
1428
+ protected onChangeEvent(eve: MouseEvent | KeyboardEvent | TouchEvent): void {
1429
+ let dataItem: { [key: string]: string } = this.getItemData();
1430
+ let index: number = this.isSelectCustom ? null : this.activeIndex;
1431
+ this.setProperties({ 'index': index, 'text': dataItem.text, 'value': dataItem.value }, true);
1432
+ this.detachChangeEvent(eve);
1433
+ };
1434
+
1435
+ private detachChanges(value: string | number | boolean | {
1436
+ [key: string]: Object;
1437
+ }): FieldSettingsModel {
1438
+ let items: FieldSettingsModel;
1439
+ if (typeof value === 'string' ||
1440
+ typeof value === 'boolean' ||
1441
+ typeof value === 'number') {
1442
+ items = Object.defineProperties({}, {
1443
+ value: {
1444
+ value: value,
1445
+ enumerable: true
1446
+ },
1447
+ text: {
1448
+ value: value,
1449
+ enumerable: true
1450
+ }
1451
+ });
1452
+ } else {
1453
+ items = value;
1454
+ }
1455
+ return items;
1456
+ }
1457
+
1458
+ protected detachChangeEvent(eve: MouseEvent | KeyboardEvent | TouchEvent): void {
1459
+ this.isSelected = false;
1460
+ this.previousValue = this.value;
1461
+ this.activeIndex = this.index;
1462
+ this.typedString = !isNullOrUndefined(this.text) ? this.text : '';
1463
+ if (!this.initial) {
1464
+ let items: FieldSettingsModel = this.detachChanges(this.itemData);
1465
+ let preItems: FieldSettingsModel;
1466
+ if (typeof this.previousItemData === 'string' ||
1467
+ typeof this.previousItemData === 'boolean' ||
1468
+ typeof this.previousItemData === 'number') {
1469
+ preItems = Object.defineProperties({}, {
1470
+ value: {
1471
+ value: this.previousItemData,
1472
+ enumerable: true
1473
+ },
1474
+ text: {
1475
+ value: this.previousItemData,
1476
+ enumerable: true
1477
+ }
1478
+ });
1479
+ } else {
1480
+ preItems = this.previousItemData;
1481
+ }
1482
+ this.setHiddenValue();
1483
+ let eventArgs: ChangeEventArgs = {
1484
+ e: eve,
1485
+ item: this.item,
1486
+ itemData: items,
1487
+ previousItem: this.previousSelectedLI as HTMLLIElement,
1488
+ previousItemData: preItems,
1489
+ isInteracted: eve ? true : false,
1490
+ value: this.value,
1491
+ element: this.element
1492
+ };
1493
+ this.trigger('change', eventArgs);
1494
+ }
1495
+ if ((isNullOrUndefined(this.value) || this.value === '') && this.floatLabelType !== 'Always') {
1496
+ removeClass([this.inputWrapper.container], 'e-valid-input');
1497
+ }
1498
+ }
1499
+
1500
+ protected setHiddenValue(): void {
1501
+ if (!isNullOrUndefined(this.value)) {
1502
+ if (this.isServerBlazor && this.hiddenElement.querySelector('option')) {
1503
+ let selectedElement: HTMLElement = this.hiddenElement.querySelector('option');
1504
+ selectedElement.textContent = this.text;
1505
+ selectedElement.setAttribute('value', this.value.toString());
1506
+ } else if (!this.isServerBlazor) {
1507
+ this.hiddenElement.innerHTML = '<option selected>' + this.text + '</option>';
1508
+ let selectedElement: HTMLElement = this.hiddenElement.querySelector('option');
1509
+ selectedElement.setAttribute('value', this.value.toString());
1510
+ }
1511
+ } else if (!this.isServerBlazor) {
1512
+ this.hiddenElement.innerHTML = '';
1513
+ }
1514
+ }
1515
+ /**
1516
+ * Filter bar implementation
1517
+ */
1518
+ protected onFilterUp(e: KeyboardEventArgs): void {
1519
+ if (!(e.ctrlKey && e.keyCode === 86) && (this.isValidKey || e.keyCode === 40 || e.keyCode === 38)) {
1520
+ this.isValidKey = false;
1521
+ switch (e.keyCode) {
1522
+ case 38: //up arrow
1523
+ case 40: //down arrow
1524
+ if (this.getModuleName() === 'autocomplete' && !this.isPopupOpen && !this.preventAltUp && !this.isRequested) {
1525
+ this.preventAutoFill = true;
1526
+ this.searchLists(e);
1527
+ } else {
1528
+ this.preventAutoFill = false;
1529
+ }
1530
+ this.preventAltUp = false;
1531
+ e.preventDefault();
1532
+ break;
1533
+ case 46: //delete
1534
+ case 8: //backspace
1535
+ this.typedString = this.filterInput.value;
1536
+ if (!this.isPopupOpen && this.typedString !== '' || this.isPopupOpen && this.queryString.length > 0) {
1537
+ this.preventAutoFill = true;
1538
+ this.searchLists(e);
1539
+ } else if (this.typedString === '' && this.queryString === '' && this.getModuleName() !== 'autocomplete') {
1540
+ this.preventAutoFill = true;
1541
+ this.searchLists(e);
1542
+ } else if (this.typedString === '') {
1543
+ if (this.list) { this.resetFocusElement(); }
1544
+ this.activeIndex = null;
1545
+ if (this.getModuleName() === 'autocomplete') {
1546
+ this.hidePopup();
1547
+ }
1548
+ }
1549
+ e.preventDefault();
1550
+ break;
1551
+ default:
1552
+ this.typedString = this.filterInput.value;
1553
+ this.preventAutoFill = false;
1554
+ this.searchLists(e);
1555
+ break;
1556
+ }
1557
+ } else {
1558
+ this.isValidKey = false;
1559
+ }
1560
+ }
1561
+
1562
+ protected onFilterDown(e: KeyboardEventArgs): void {
1563
+ switch (e.keyCode) {
1564
+ case 13: //enter
1565
+ break;
1566
+ case 40: //down arrow
1567
+ case 38: //up arrow
1568
+ this.queryString = this.filterInput.value;
1569
+ e.preventDefault();
1570
+ break;
1571
+ case 9: //tab
1572
+ if (this.isPopupOpen && this.getModuleName() !== 'autocomplete') {
1573
+ e.preventDefault();
1574
+ }
1575
+ break;
1576
+ default:
1577
+ this.prevSelectPoints = this.getSelectionPoints();
1578
+ this.queryString = this.filterInput.value;
1579
+ break;
1580
+ }
1581
+ }
1582
+
1583
+ protected removeFillSelection(): void {
1584
+ if (this.isInteracted) {
1585
+ let selection: { [key: string]: number } = this.getSelectionPoints();
1586
+ this.inputElement.setSelectionRange(selection.end, selection.end);
1587
+ }
1588
+ }
1589
+ protected getQuery(query: Query): Query {
1590
+ let filterQuery: Query;
1591
+ if (!this.isCustomFilter && this.allowFiltering && this.filterInput) {
1592
+ filterQuery = query ? query.clone() : this.query ? this.query.clone() : new Query();
1593
+ let filterType: string = this.typedString === '' ? 'contains' : this.filterType;
1594
+ let dataType: string = <string>this.typeOfData(this.dataSource as { [key: string]: Object; }[]).typeof;
1595
+ if (!(this.dataSource instanceof DataManager) && dataType === 'string' || dataType === 'number') {
1596
+ filterQuery.where('', filterType, this.typedString, this.ignoreCase, this.ignoreAccent);
1597
+ } else {
1598
+ let fields: string = (this.fields.text) ? this.fields.text : '';
1599
+ filterQuery.where(fields, filterType, this.typedString, this.ignoreCase, this.ignoreAccent);
1600
+ }
1601
+ } else {
1602
+ filterQuery = query ? query : this.query ? this.query : new Query();
1603
+ }
1604
+ return filterQuery;
1605
+ }
1606
+
1607
+ protected getSelectionPoints(): { [key: string]: number } {
1608
+ let input: HTMLInputElement = <HTMLInputElement>this.inputElement;
1609
+ return { start: Math.abs(input.selectionStart), end: Math.abs(input.selectionEnd) };
1610
+ }
1611
+
1612
+ protected searchLists(e: KeyboardEventArgs): void {
1613
+ this.isTyped = true;
1614
+ this.activeIndex = null;
1615
+ if (this.filterInput.parentElement.querySelector('.' + dropDownListClasses.clearIcon)) {
1616
+ let clearElement: HTMLElement = <HTMLElement>this.filterInput.parentElement.querySelector('.' + dropDownListClasses.clearIcon);
1617
+ clearElement.style.visibility = this.filterInput.value === '' ? 'hidden' : 'visible';
1618
+ }
1619
+ this.isDataFetched = false;
1620
+ if (this.isFiltering()) {
1621
+ if (this.isServerBlazor) {
1622
+ this.beforePopupOpen = (this.getModuleName() === 'combobox' && this.isFiltering() && !this.beforePopupOpen)
1623
+ ? !this.beforePopupOpen : this.beforePopupOpen;
1624
+ if (this.filterInput.value === '' && this.getModuleName() !== 'dropdownlist') {
1625
+ // tslint:disable-next-line
1626
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerRenderList', this.beforePopupOpen, false);
1627
+ } else {
1628
+ // tslint:disable-next-line
1629
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerFilter', this.filterInput.value);
1630
+ }
1631
+ } else {
1632
+ let eventArgs: FilteringEventArgs = {
1633
+ preventDefaultAction: false,
1634
+ text: this.filterInput.value,
1635
+ updateData: (
1636
+ dataSource: { [key: string]: Object }[] | DataManager | string[] | number[], query?: Query,
1637
+ fields?: FieldSettingsModel) => {
1638
+ if (eventArgs.cancel) { return; }
1639
+ this.isCustomFilter = true;
1640
+ this.filteringAction(dataSource, query, fields);
1641
+ },
1642
+ baseEventArgs: e,
1643
+ cancel: false
1644
+ };
1645
+ this.trigger('filtering', eventArgs, (eventArgs: FilteringEventArgs) => {
1646
+ if (!eventArgs.cancel && !this.isCustomFilter && !eventArgs.preventDefaultAction) {
1647
+ this.filteringAction(this.dataSource, null, this.fields);
1648
+ }
1649
+ });
1650
+ }
1651
+ }
1652
+ }
1653
+ /**
1654
+ * To filter the data from given data source by using query
1655
+ * @param {Object[] | DataManager } dataSource - Set the data source to filter.
1656
+ * @param {Query} query - Specify the query to filter the data.
1657
+ * @param {FieldSettingsModel} fields - Specify the fields to map the column in the data table.
1658
+ * @return {void}.
1659
+ * @deprecated
1660
+ */
1661
+ public filter(
1662
+ dataSource: { [key: string]: Object }[] | DataManager | string[] | number[] | boolean[],
1663
+ query?: Query, fields?: FieldSettingsModel): void {
1664
+ this.isCustomFilter = true;
1665
+ this.filteringAction(dataSource, query, fields);
1666
+ }
1667
+ private filteringAction(
1668
+ dataSource: { [key: string]: Object }[] | DataManager | string[] | number[] | boolean[],
1669
+ query?: Query, fields?: FieldSettingsModel): void {
1670
+ if (!isNullOrUndefined(this.filterInput)) {
1671
+ this.beforePopupOpen = true;
1672
+ if (this.filterInput.value.trim() === '' && !this.itemTemplate) {
1673
+ this.actionCompleteData.isUpdated = false;
1674
+ this.isTyped = false;
1675
+ if (!isNullOrUndefined(this.actionCompleteData.ulElement) && !isNullOrUndefined(this.actionCompleteData.list)) {
1676
+ this.onActionComplete(this.actionCompleteData.ulElement, this.actionCompleteData.list);
1677
+ }
1678
+ this.isTyped = true;
1679
+ if (!isNullOrUndefined(this.itemData) && this.getModuleName() === 'dropdownlist') {
1680
+ this.focusIndexItem();
1681
+ this.setScrollPosition();
1682
+ }
1683
+ this.isNotSearchList = true;
1684
+ } else {
1685
+ this.isNotSearchList = false;
1686
+ query = (this.filterInput.value.trim() === '') ? null : query;
1687
+ this.resetList(dataSource, fields, query);
1688
+ }
1689
+ }
1690
+
1691
+ }
1692
+ protected setSearchBox(popupElement: HTMLElement): InputObject {
1693
+ if (this.isFiltering()) {
1694
+ let parentElement: HTMLElement = popupElement.querySelector('.' + dropDownListClasses.filterParent) ?
1695
+ popupElement.querySelector('.' + dropDownListClasses.filterParent) : this.createElement('span', {
1696
+ className: dropDownListClasses.filterParent
1697
+ });
1698
+ if (this.isServerBlazor) {
1699
+ parentElement.innerHTML = '';
1700
+ }
1701
+ this.filterInput = <HTMLInputElement>this.createElement('input', {
1702
+ attrs: { type: 'text' },
1703
+ className: dropDownListClasses.filterInput
1704
+ });
1705
+ this.element.parentNode.insertBefore(this.filterInput, this.element);
1706
+ let backIcon: boolean = false;
1707
+ if (Browser.isDevice) {
1708
+ backIcon = true;
1709
+ }
1710
+ this.filterInputObj = Input.createInput(
1711
+ {
1712
+ element: this.filterInput,
1713
+ buttons: backIcon ?
1714
+ [dropDownListClasses.backIcon, dropDownListClasses.filterBarClearIcon] : [dropDownListClasses.filterBarClearIcon],
1715
+ properties: { placeholder: this.filterBarPlaceholder }
1716
+ },
1717
+ this.createElement
1718
+ );
1719
+ if (!isNullOrUndefined(this.cssClass)) {
1720
+ if (this.cssClass.split(' ').indexOf('e-outline') !== -1) {
1721
+ addClass([this.filterInputObj.container], 'e-outline');
1722
+ } else if (this.cssClass.split(' ').indexOf('e-filled') !== -1) {
1723
+ addClass([this.filterInputObj.container], 'e-filled');
1724
+ }
1725
+ }
1726
+ append([this.filterInputObj.container], parentElement);
1727
+ prepend([parentElement], popupElement);
1728
+ attributes(this.filterInput, {
1729
+ 'aria-disabled': 'false',
1730
+ 'aria-owns': this.element.id + '_options',
1731
+ 'role': 'listbox',
1732
+ 'aria-activedescendant': this.selectedLI ? this.selectedLI.id : null,
1733
+ 'autocomplete': 'off',
1734
+ 'autocorrect': 'off',
1735
+ 'autocapitalize': 'off',
1736
+ 'spellcheck': 'false'
1737
+ });
1738
+ this.clearIconElement = this.filterInput.parentElement.querySelector('.' + dropDownListClasses.clearIcon);
1739
+ if (!Browser.isDevice && this.clearIconElement) {
1740
+ EventHandler.add(this.clearIconElement, 'click', this.clearText, this);
1741
+ (this.clearIconElement as HTMLElement).style.visibility = 'hidden';
1742
+ }
1743
+ if (!Browser.isDevice) {
1744
+ this.searchKeyModule = new KeyboardEvents(this.filterInput, {
1745
+ keyAction: this.keyActionHandler.bind(this),
1746
+ keyConfigs: this.keyConfigure,
1747
+ eventName: 'keydown'
1748
+ });
1749
+ } else {
1750
+ this.searchKeyModule = new KeyboardEvents(this.filterInput, {
1751
+ keyAction: this.mobileKeyActionHandler.bind(this),
1752
+ keyConfigs: this.keyConfigure,
1753
+ eventName: 'keydown'
1754
+ });
1755
+ }
1756
+ EventHandler.add(this.filterInput, 'input', this.onInput, this);
1757
+ EventHandler.add(this.filterInput, 'keyup', this.onFilterUp, this);
1758
+ EventHandler.add(this.filterInput, 'keydown', this.onFilterDown, this);
1759
+ EventHandler.add(this.filterInput, 'blur', this.onBlur, this);
1760
+ EventHandler.add(this.filterInput, 'paste', this.pasteHandler, this);
1761
+ return this.filterInputObj;
1762
+ } else {
1763
+ return inputObject;
1764
+ }
1765
+ };
1766
+
1767
+ protected onInput(e: KeyboardEventArgs): void {
1768
+ this.isValidKey = true;
1769
+ // For filtering works in mobile firefox.
1770
+ if (Browser.isDevice && Browser.info.name === 'mozilla') {
1771
+ this.typedString = this.filterInput.value;
1772
+ this.preventAutoFill = true;
1773
+ this.searchLists(e as KeyboardEventArgs);
1774
+ }
1775
+ }
1776
+
1777
+ protected pasteHandler (e: KeyboardEventArgs): void {
1778
+ setTimeout((): void => {
1779
+ this.typedString = this.filterInput.value;
1780
+ this.searchLists(e);
1781
+ });
1782
+ }
1783
+
1784
+ protected onActionFailure(e: Object): void {
1785
+ super.onActionFailure(e);
1786
+ if (this.beforePopupOpen) {
1787
+ this.renderPopup();
1788
+ }
1789
+ }
1790
+
1791
+ protected onActionComplete(ulElement: HTMLElement, list: { [key: string]: Object }[], e?: Object, isUpdated?: boolean): void {
1792
+ if (this.isNotSearchList) {
1793
+ this.isNotSearchList = false;
1794
+ return;
1795
+ }
1796
+ if (this.isActive) {
1797
+ let selectedItem: HTMLElement = this.selectedLI ? <HTMLElement>this.selectedLI.cloneNode(true) : null;
1798
+ super.onActionComplete(ulElement, list, e);
1799
+ this.updateSelectElementData(this.allowFiltering);
1800
+ if (this.isRequested && !isNullOrUndefined(this.searchKeyEvent) && this.searchKeyEvent.type === 'keydown') {
1801
+ this.isRequested = false;
1802
+ this.keyActionHandler(this.searchKeyEvent);
1803
+ this.searchKeyEvent = null;
1804
+ }
1805
+ if (this.isRequested && !isNullOrUndefined(this.searchKeyEvent)) {
1806
+ this.incrementalSearch(this.searchKeyEvent);
1807
+ this.searchKeyEvent = null;
1808
+ }
1809
+ this.list.scrollTop = 0;
1810
+ if (!isNullOrUndefined(ulElement)) {
1811
+ attributes(ulElement, { 'id': this.element.id + '_options', 'role': 'listbox', 'aria-hidden': 'false' });
1812
+ }
1813
+ if (this.initRemoteRender) {
1814
+ this.initial = true;
1815
+ this.activeIndex = this.index;
1816
+ this.updateValues();
1817
+ this.initRemoteRender = false;
1818
+ this.initial = false;
1819
+ if (this.value && this.dataSource instanceof DataManager) {
1820
+ let checkField: string = isNullOrUndefined(this.fields.value) ? this.fields.text : this.fields.value;
1821
+ let checkVal: boolean = list.some((x: {[key: string]: boolean | string | number}) => x[checkField] === this.value);
1822
+ if (!checkVal) {
1823
+ this.dataSource.executeQuery(this.getQuery(this.query).where(new Predicate(checkField, 'equal', this.value)))
1824
+ .then((e: Object) => {
1825
+ if ((e as ResultData).result.length > 0) {
1826
+ this.addItem((e as ResultData).result, list.length);
1827
+ this.updateValues();
1828
+ }
1829
+ });
1830
+ }
1831
+ }
1832
+ }
1833
+ if (this.getModuleName() !== 'autocomplete' && this.isFiltering() && !this.isTyped) {
1834
+ if (!this.actionCompleteData.isUpdated || ((!this.isCustomFilter
1835
+ && !this.isFilterFocus)
1836
+ && ((this.dataSource instanceof DataManager)
1837
+ || (!isNullOrUndefined(this.dataSource) && !isNullOrUndefined(this.dataSource.length) &&
1838
+ this.dataSource.length !== 0)))) {
1839
+ this.actionCompleteData = { ulElement: ulElement.cloneNode(true) as HTMLElement, list: list, isUpdated: true };
1840
+ }
1841
+ this.addNewItem(list, selectedItem);
1842
+ if (!isNullOrUndefined(this.itemData)) {
1843
+ this.focusIndexItem();
1844
+ }
1845
+ }
1846
+ if (this.beforePopupOpen) {
1847
+ this.renderPopup();
1848
+ }
1849
+ }
1850
+ }
1851
+
1852
+ private addNewItem(listData: { [key: string]: Object }[], newElement: HTMLElement): void {
1853
+ if (!isNullOrUndefined(this.itemData) && !isNullOrUndefined(newElement)) {
1854
+ let value: string | number = this.getItemData().value;
1855
+ let isExist: boolean = listData.some((data: { [key: string]: Object }) => {
1856
+ return (((typeof data === 'string' || typeof data === 'number') && data === value) ||
1857
+ (getValue(this.fields.value, data) === value));
1858
+ });
1859
+ if (!isExist) {
1860
+ this.addItem(this.itemData);
1861
+ }
1862
+ }
1863
+ }
1864
+
1865
+ protected updateActionCompleteData(li: HTMLElement, item: { [key: string]: Object }): void {
1866
+ if (this.getModuleName() !== 'autocomplete' && this.actionCompleteData.ulElement) {
1867
+ this.actionCompleteData.ulElement.appendChild(li.cloneNode(true));
1868
+ if (this.isFiltering() && this.actionCompleteData.list.indexOf(item) < 0) {
1869
+ this.actionCompleteData.list.push(item);
1870
+ }
1871
+ }
1872
+ }
1873
+
1874
+ private focusIndexItem(): void {
1875
+ let value: string | number = this.getItemData().value;
1876
+ this.activeIndex = this.getIndexByValue(value);
1877
+ let element: HTMLElement = this.findListElement(this.list, 'li', 'data-value', value);
1878
+ this.selectedLI = element;
1879
+ this.activeItem(element);
1880
+ this.removeFocus();
1881
+ }
1882
+
1883
+ protected updateSelection(): void {
1884
+ let selectedItem: Element = this.list.querySelector('.' + dropDownBaseClasses.selected);
1885
+ if (selectedItem) {
1886
+ this.setProperties({ 'index': this.getIndexByValue(selectedItem.getAttribute('data-value')) });
1887
+ this.activeIndex = this.index;
1888
+ } else {
1889
+ this.removeFocus();
1890
+ this.list.querySelector('.' + dropDownBaseClasses.li).classList.add(dropDownListClasses.focus);
1891
+ }
1892
+ }
1893
+
1894
+ protected removeFocus(): void {
1895
+ let highlightedItem: Element[] = <NodeListOf<Element> & Element[]>this.list.querySelectorAll('.' + dropDownListClasses.focus);
1896
+ if (highlightedItem && highlightedItem.length) {
1897
+ removeClass(highlightedItem, dropDownListClasses.focus);
1898
+ }
1899
+ };
1900
+
1901
+ protected renderPopup(): void {
1902
+ if (this.popupObj && document.body.contains(this.popupObj.element)) {
1903
+ this.refreshPopup();
1904
+ return;
1905
+ }
1906
+ let args: BeforeOpenEventArgs = { cancel: false };
1907
+ this.trigger('beforeOpen', args, (args: BeforeOpenEventArgs) => {
1908
+ if (!args.cancel) {
1909
+ let popupEle: HTMLElement = (this.serverPopupEle) ? this.serverPopupEle : this.createElement('div', {
1910
+ id: this.element.id + '_popup', className: 'e-ddl e-popup ' + (this.cssClass != null ? this.cssClass : '')
1911
+ });
1912
+ let searchBox: InputObject = this.setSearchBox(popupEle);
1913
+ this.listHeight = formatUnit(this.popupHeight);
1914
+ if (this.headerTemplate && !this.isServerBlazor) { this.setHeaderTemplate(popupEle); }
1915
+ append([this.list], popupEle);
1916
+ if (this.footerTemplate && !this.isServerBlazor) { this.setFooterTemplate(popupEle); }
1917
+ if (this.isServerRendered && popupEle && popupEle.querySelector('.e-ddl-footer')) {
1918
+ popupEle.appendChild(popupEle.querySelector('.e-ddl-footer'));
1919
+ }
1920
+ document.body.appendChild(popupEle);
1921
+ this.updateServerPopup(popupEle);
1922
+ popupEle.style.visibility = 'hidden';
1923
+ if (this.popupHeight !== 'auto') {
1924
+ this.searchBoxHeight = 0;
1925
+ if (!isNullOrUndefined(searchBox.container)) {
1926
+ this.searchBoxHeight = (searchBox.container.parentElement).getBoundingClientRect().height;
1927
+ this.listHeight = (parseInt(this.listHeight, 10) - (this.searchBoxHeight)).toString() + 'px';
1928
+ }
1929
+ if (this.headerTemplate || (this.isServerRendered && popupEle && popupEle.querySelector('.e-ddl-header'))) {
1930
+ this.header = this.header ? this.header : popupEle.querySelector('.e-ddl-header');
1931
+ let height: number = Math.round(this.header.getBoundingClientRect().height);
1932
+ this.listHeight = (parseInt(this.listHeight, 10) - (height + this.searchBoxHeight)).toString() + 'px';
1933
+ }
1934
+ if (this.footerTemplate || (this.isServerRendered && popupEle && popupEle.querySelector('.e-ddl-footer'))) {
1935
+ this.footer = this.footer ? this.footer : popupEle.querySelector('.e-ddl-footer');
1936
+ let height: number = Math.round(this.footer.getBoundingClientRect().height);
1937
+ this.listHeight = (parseInt(this.listHeight, 10) - (height + this.searchBoxHeight)).toString() + 'px';
1938
+ }
1939
+ this.list.style.maxHeight = (parseInt(this.listHeight, 10) - 2).toString() + 'px'; // due to box-sizing property
1940
+ popupEle.style.maxHeight = formatUnit(this.popupHeight);
1941
+ } else { popupEle.style.height = 'auto'; }
1942
+ let offsetValue: number = 0;
1943
+ let left: number;
1944
+ if (!isNullOrUndefined(this.selectedLI) && (!isNullOrUndefined(this.activeIndex) && this.activeIndex >= 0)) {
1945
+ this.setScrollPosition();
1946
+ } else { this.list.scrollTop = 0; }
1947
+ if (Browser.isDevice && (!this.allowFiltering && (this.getModuleName() === 'dropdownlist' ||
1948
+ (this.isDropDownClick && this.getModuleName() === 'combobox')))) {
1949
+ offsetValue = this.getOffsetValue(popupEle);
1950
+ let firstItem: HTMLElement = this.isEmptyList() ? this.list : this.liCollections[0];
1951
+ left = -(parseInt(getComputedStyle(firstItem).textIndent, 10) -
1952
+ parseInt(getComputedStyle(this.inputElement).paddingLeft, 10) +
1953
+ parseInt(getComputedStyle(this.inputElement.parentElement).borderLeftWidth, 10));
1954
+ }
1955
+ this.getFocusElement();
1956
+ this.createPopup(popupEle, offsetValue, left);
1957
+ this.checkCollision(popupEle);
1958
+ if (Browser.isDevice) {
1959
+ this.popupObj.element.classList.add(dropDownListClasses.device);
1960
+ if (this.getModuleName() === 'dropdownlist' || (this.getModuleName() === 'combobox'
1961
+ && !this.allowFiltering && this.isDropDownClick)) {
1962
+ this.popupObj.collision = { X: 'fit', Y: 'fit' };
1963
+ }
1964
+ if (this.isFilterLayout()) {
1965
+ this.popupObj.element.classList.add(dropDownListClasses.mobileFilter);
1966
+ this.popupObj.position = { X: 0, Y: 0 };
1967
+ this.popupObj.dataBind();
1968
+ attributes(this.popupObj.element, { style: 'left:0px;right:0px;top:0px;bottom:0px;' });
1969
+ addClass([document.body, this.popupObj.element], dropDownListClasses.popupFullScreen);
1970
+ this.setSearchBoxPosition();
1971
+ this.backIconElement = searchBox.container.querySelector('.e-back-icon');
1972
+ this.clearIconElement = searchBox.container.querySelector('.' + dropDownListClasses.clearIcon);
1973
+ EventHandler.add(this.backIconElement, 'click', this.clickOnBackIcon, this);
1974
+ EventHandler.add(this.clearIconElement, 'click', this.clearText, this);
1975
+ }
1976
+ }
1977
+ popupEle.style.visibility = 'visible';
1978
+ addClass([popupEle], 'e-popup-close');
1979
+ let scrollParentElements: HTMLElement[] = this.popupObj.getScrollableParent(this.inputWrapper.container);
1980
+ for (let element of scrollParentElements) { EventHandler.add(element, 'scroll', this.scrollHandler, this); }
1981
+ if (Browser.isDevice && this.isFilterLayout()) { EventHandler.add(this.list, 'scroll', this.listScroll, this); }
1982
+ attributes(this.targetElement(), { 'aria-expanded': 'true' });
1983
+ let inputParent: HTMLElement = this.isFiltering() ? this.filterInput.parentElement : this.inputWrapper.container;
1984
+ addClass([inputParent], [dropDownListClasses.inputFocus]);
1985
+ let animModel: AnimationModel = { name: 'FadeIn', duration: 100 };
1986
+ this.beforePopupOpen = true;
1987
+ let popupInstance: Popup = (isBlazor() && this.isServerRendered) ? null : this.popupObj;
1988
+ let eventArgs: PopupEventArgs = { popup: popupInstance, cancel: false, animation: animModel };
1989
+ this.trigger('open', eventArgs, (eventArgs: PopupEventArgs) => {
1990
+ if (!eventArgs.cancel) {
1991
+ this.serverBlazorUpdateSelection();
1992
+ this.bindServerScrollEvent();
1993
+ addClass([this.inputWrapper.container], [dropDownListClasses.iconAnimation]);
1994
+ this.popupObj.show(new Animation(eventArgs.animation), (this.zIndex === 1000) ? this.element : null);
1995
+ } else { this.beforePopupOpen = false;
1996
+ this.destroyPopup(); }
1997
+ });
1998
+ } else { this.beforePopupOpen = false; }
1999
+ });
2000
+ }
2001
+ private checkCollision(popupEle: HTMLElement): void {
2002
+ if (!Browser.isDevice || (Browser.isDevice && !(this.getModuleName() === 'dropdownlist' || this.isDropDownClick))) {
2003
+ let collision: string[] = isCollide(popupEle);
2004
+ if (collision.length > 0) {
2005
+ popupEle.style.marginTop = -parseInt(getComputedStyle(popupEle).marginTop, 10) + 'px';
2006
+ }
2007
+ }
2008
+ }
2009
+ private serverBlazorUpdateSelection(): void {
2010
+ if (this.isServerBlazor && (this.value !== null || this.index !== null || this.text !== null) ||
2011
+ (this.getModuleName() !== 'dropdownlist' && !this.isTyped)) {
2012
+ if (this.getModuleName() === 'dropdownlist') {
2013
+ this.removeSelection();
2014
+ this.removeFocus();
2015
+ this.removeHover();
2016
+ this.updateValues();
2017
+ }
2018
+ if (this.getModuleName() === 'combobox' && this.ulElement &&
2019
+ this.findListElement(this.ulElement, 'li', 'data-value', this.value) && !this.isTyped) {
2020
+ this.updateValues();
2021
+ }
2022
+ if (this.isServerBlazor && this.getModuleName() !== 'dropdownlist' &&
2023
+ (this.text === '' || this.text === null ) && this.ulElement) {
2024
+ if (!this.ulElement.querySelector('li').classList.contains(dropDownBaseClasses.hover)) {
2025
+ addClass([this.ulElement.querySelector('li')], dropDownBaseClasses.hover);
2026
+ }
2027
+ }
2028
+ }
2029
+ }
2030
+ private bindServerScrollEvent(): void {
2031
+ if (this.isServerBlazor && this.list) {
2032
+ if ((this.fields.groupBy) && !this.isGroupChecking) {
2033
+ EventHandler.remove(this.list, 'scroll', this.setFloatingHeader);
2034
+ EventHandler.add(this.list, 'scroll', this.setFloatingHeader, this);
2035
+ }
2036
+ }
2037
+ }
2038
+ private updateServerPopup(popupEle : HTMLElement): void {
2039
+ if (this.isServerBlazor) {
2040
+ if (popupEle && popupEle.querySelector('li')) { removeClass([popupEle.querySelector('.e-content')], ['e-nodata']); }
2041
+ this.initial = false;
2042
+ popupEle.removeAttribute('style');
2043
+ }
2044
+ }
2045
+ private getOffsetValue(popupEle: HTMLElement): number {
2046
+ let popupStyles: CSSStyleDeclaration = getComputedStyle(popupEle);
2047
+ let borderTop: number = parseInt(popupStyles.borderTopWidth, 10);
2048
+ let borderBottom: number = parseInt(popupStyles.borderBottomWidth, 10);
2049
+ return this.setPopupPosition(borderTop + borderBottom);
2050
+ }
2051
+ private createPopup(element: HTMLElement, offsetValue: number, left: number): void {
2052
+ this.popupObj = new Popup(element, {
2053
+ width: this.setWidth(), targetType: 'relative',
2054
+ relateTo: this.inputWrapper.container, collision: { X: 'flip', Y: 'flip' }, offsetY: offsetValue,
2055
+ enableRtl: this.enableRtl, offsetX: left, position: { X: 'left', Y: 'bottom' },
2056
+ zIndex: this.zIndex,
2057
+ close: () => {
2058
+ if (!this.isDocumentClick) {
2059
+ this.focusDropDown();
2060
+ }
2061
+ let isResetItem: boolean = (this.getModuleName() === 'autocomplete') ? true : false;
2062
+ this.DropDownBaseresetBlazorTemplates(isResetItem, isResetItem, true, true, false, true, true);
2063
+ this.isNotSearchList = false;
2064
+ this.isDocumentClick = false;
2065
+ this.destroyPopup();
2066
+ let formElement: HTMLFormElement = closest(this.inputElement, 'form') as HTMLFormElement;
2067
+ if (this.isFiltering() && this.actionCompleteData.list && this.actionCompleteData.list[0]) {
2068
+ this.isActive = true;
2069
+ this.onActionComplete(this.actionCompleteData.ulElement, this.actionCompleteData.list, null, true);
2070
+ }
2071
+ },
2072
+ open: () => {
2073
+ EventHandler.add(document, 'mousedown', this.onDocumentClick, this);
2074
+ this.isPopupOpen = true;
2075
+ let actionList: HTMLElement = this.actionCompleteData && this.actionCompleteData.ulElement &&
2076
+ this.actionCompleteData.ulElement.querySelector('li');
2077
+ let ulElement: HTMLElement = this.list.querySelector('ul li');
2078
+ if (this.isFiltering() && this.itemTemplate && (this.element.tagName === this.getNgDirective()) &&
2079
+ (actionList && ulElement && actionList.textContent !== ulElement.textContent)) {
2080
+ this.cloneElements();
2081
+ }
2082
+ if (this.isFilterLayout()) {
2083
+ removeClass([this.inputWrapper.container], [dropDownListClasses.inputFocus]);
2084
+ this.isFilterFocus = true;
2085
+ this.filterInput.focus();
2086
+ if (this.inputWrapper.clearButton) {
2087
+ addClass([this.inputWrapper.clearButton], dropDownListClasses.clearIconHide);
2088
+ }
2089
+ }
2090
+ this.activeStateChange();
2091
+ },
2092
+ targetExitViewport: () => {
2093
+ if (!Browser.isDevice) { this.hidePopup(); }
2094
+ }
2095
+ });
2096
+ }
2097
+ private isEmptyList(): boolean {
2098
+ return !isNullOrUndefined(this.liCollections) && this.liCollections.length === 0;
2099
+ }
2100
+
2101
+ protected getFocusElement(): void {
2102
+ // combo-box used this method
2103
+ }
2104
+
2105
+ private isFilterLayout(): boolean {
2106
+ return this.getModuleName() === 'dropdownlist' && this.allowFiltering;
2107
+ }
2108
+
2109
+ private scrollHandler(): void {
2110
+ if (Browser.isDevice && ((this.getModuleName() === 'dropdownlist' &&
2111
+ !this.isFilterLayout()) || (this.getModuleName() === 'combobox' && !this.allowFiltering && this.isDropDownClick))) {
2112
+ this.hidePopup();
2113
+ }
2114
+ }
2115
+
2116
+ private setSearchBoxPosition(): void {
2117
+ let searchBoxHeight: number = this.filterInput.parentElement.getBoundingClientRect().height;
2118
+ this.popupObj.element.style.maxHeight = '100%';
2119
+ this.popupObj.element.style.width = '100%';
2120
+ this.list.style.maxHeight = (window.innerHeight - searchBoxHeight) + 'px';
2121
+ this.list.style.height = (window.innerHeight - searchBoxHeight) + 'px';
2122
+ let clearElement: Element = this.filterInput.parentElement.querySelector('.' + dropDownListClasses.clearIcon);
2123
+ detach(this.filterInput);
2124
+ clearElement.parentElement.insertBefore(this.filterInput, clearElement);
2125
+ }
2126
+
2127
+ private setPopupPosition(border?: number): number {
2128
+ let offsetValue: number;
2129
+ let popupOffset: number = border;
2130
+ let selectedLI: HTMLElement = <HTMLElement>this.list.querySelector('.' + dropDownListClasses.focus) || this.selectedLI;
2131
+ let firstItem: HTMLElement = this.isEmptyList() ? this.list : this.liCollections[0];
2132
+ let lastItem: HTMLElement = this.isEmptyList() ? this.list : this.liCollections[this.getItems().length - 1];
2133
+ let liHeight: number = firstItem.getBoundingClientRect().height;
2134
+ let listHeight: number = this.list.offsetHeight / 2;
2135
+ let height: number = isNullOrUndefined(selectedLI) ? firstItem.offsetTop : selectedLI.offsetTop;
2136
+ let lastItemOffsetValue: number = lastItem.offsetTop;
2137
+ if (lastItemOffsetValue - listHeight < height && !isNullOrUndefined(this.liCollections) &&
2138
+ this.liCollections.length > 0 && !isNullOrUndefined(selectedLI)) {
2139
+ let count: number = this.list.offsetHeight / liHeight;
2140
+ let paddingBottom: number = parseInt(getComputedStyle(this.list).paddingBottom, 10);
2141
+ offsetValue = (count - (this.liCollections.length - this.activeIndex)) * liHeight - popupOffset + paddingBottom;
2142
+ this.list.scrollTop = selectedLI.offsetTop;
2143
+ } else if (height > listHeight) {
2144
+ offsetValue = listHeight - liHeight / 2;
2145
+ this.list.scrollTop = height - listHeight + liHeight / 2;
2146
+ } else {
2147
+ offsetValue = height;
2148
+ }
2149
+ let inputHeight: number = this.inputWrapper.container.offsetHeight;
2150
+ offsetValue = offsetValue + liHeight + popupOffset - ((liHeight - inputHeight) / 2);
2151
+ return -offsetValue;
2152
+ }
2153
+
2154
+ private setWidth(): string {
2155
+ let width: string = formatUnit(this.popupWidth);
2156
+ if (width.indexOf('%') > -1) {
2157
+ let inputWidth: number = this.inputWrapper.container.offsetWidth * parseFloat(width) / 100;
2158
+ width = inputWidth.toString() + 'px';
2159
+ }
2160
+ if (Browser.isDevice && (!this.allowFiltering && (this.getModuleName() === 'dropdownlist' ||
2161
+ (this.isDropDownClick && this.getModuleName() === 'combobox')))) {
2162
+ let firstItem: HTMLElement = this.isEmptyList() ? this.list : this.liCollections[0];
2163
+ width = (parseInt(width, 10) + (parseInt(getComputedStyle(firstItem).textIndent, 10) -
2164
+ parseInt(getComputedStyle(this.inputElement).paddingLeft, 10) +
2165
+ parseInt(getComputedStyle(this.inputElement.parentElement).borderLeftWidth, 10)) * 2) + 'px';
2166
+ }
2167
+ return width;
2168
+ }
2169
+
2170
+ private scrollBottom(isInitial?: boolean): void {
2171
+ if (!isNullOrUndefined(this.selectedLI)) {
2172
+ let currentOffset: number = this.list.offsetHeight;
2173
+ let nextBottom: number = this.selectedLI.offsetTop + this.selectedLI.offsetHeight - this.list.scrollTop;
2174
+ let nextOffset: number = this.list.scrollTop + nextBottom - currentOffset;
2175
+ nextOffset = isInitial ? nextOffset + parseInt(getComputedStyle(this.list).paddingTop, 10) * 2 : nextOffset;
2176
+ let boxRange: number = this.selectedLI.offsetTop + this.selectedLI.offsetHeight - this.list.scrollTop;
2177
+ boxRange = this.fields.groupBy && !isNullOrUndefined(this.fixedHeaderElement) ?
2178
+ boxRange - this.fixedHeaderElement.offsetHeight : boxRange;
2179
+ if (this.activeIndex === 0) {
2180
+ this.list.scrollTop = 0;
2181
+ } else if (nextBottom > currentOffset || !(boxRange > 0 && this.list.offsetHeight > boxRange)) {
2182
+ this.list.scrollTop = nextOffset;
2183
+ }
2184
+ }
2185
+ }
2186
+
2187
+ private scrollTop(): void {
2188
+ if (!isNullOrUndefined(this.selectedLI)) {
2189
+ let nextOffset: number = this.selectedLI.offsetTop - this.list.scrollTop;
2190
+ let nextBottom: number = this.selectedLI.offsetTop + this.selectedLI.offsetHeight - this.list.scrollTop;
2191
+ nextOffset = this.fields.groupBy && !isNullOrUndefined(this.fixedHeaderElement) ?
2192
+ nextOffset - this.fixedHeaderElement.offsetHeight : nextOffset;
2193
+ let boxRange: number = (this.selectedLI.offsetTop + this.selectedLI.offsetHeight - this.list.scrollTop);
2194
+ if (this.activeIndex === 0) {
2195
+ this.list.scrollTop = 0;
2196
+ } else if (nextOffset < 0) {
2197
+ this.list.scrollTop = this.list.scrollTop + nextOffset;
2198
+ } else if (!(boxRange > 0 && this.list.offsetHeight > boxRange)) {
2199
+ this.list.scrollTop = this.selectedLI.offsetTop - (this.fields.groupBy && !isNullOrUndefined(this.fixedHeaderElement) ?
2200
+ this.fixedHeaderElement.offsetHeight : 0);
2201
+ }
2202
+ }
2203
+ }
2204
+ protected isEditTextBox(): boolean {
2205
+ return false;
2206
+ }
2207
+
2208
+ protected isFiltering(): boolean {
2209
+ return this.allowFiltering;
2210
+ }
2211
+
2212
+ protected isPopupButton(): boolean {
2213
+ return true;
2214
+ }
2215
+
2216
+ protected setScrollPosition(e?: KeyboardEventArgs): void {
2217
+ if (!isNullOrUndefined(e)) {
2218
+ switch (e.action) {
2219
+ case 'pageDown':
2220
+ case 'down':
2221
+ case 'end':
2222
+ this.scrollBottom();
2223
+ break;
2224
+ default:
2225
+ this.scrollTop();
2226
+ break;
2227
+ }
2228
+ } else {
2229
+ this.scrollBottom(true);
2230
+ }
2231
+ }
2232
+
2233
+ private clearText(): void {
2234
+ this.filterInput.value = '';
2235
+ this.searchLists(null);
2236
+ }
2237
+
2238
+ private listScroll(): void {
2239
+ this.filterInput.blur();
2240
+ }
2241
+
2242
+ private setEleWidth(width: string | number): void {
2243
+ if (!isNullOrUndefined(width)) {
2244
+ if (typeof width === 'number') {
2245
+ this.inputWrapper.container.style.width = formatUnit(width);
2246
+ } else if (typeof width === 'string') {
2247
+ this.inputWrapper.container.style.width = (width.match(/px|%|em/)) ? <string>(width) : <string>(formatUnit(width));
2248
+ }
2249
+ }
2250
+ }
2251
+
2252
+ private closePopup(delay?: number): void {
2253
+ this.isTyped = false;
2254
+ if (!(this.popupObj && document.body.contains(this.popupObj.element) && this.beforePopupOpen)) {
2255
+ return;
2256
+ }
2257
+ EventHandler.remove(document, 'mousedown', this.onDocumentClick);
2258
+ this.isActive = false;
2259
+ this.filterInputObj = null;
2260
+ this.isDropDownClick = false;
2261
+ this.preventAutoFill = false;
2262
+ let scrollableParentElements: HTMLElement[] = this.popupObj.getScrollableParent(this.inputWrapper.container);
2263
+ for (let element of scrollableParentElements) {
2264
+ EventHandler.remove(element, 'scroll', this.scrollHandler);
2265
+ }
2266
+ if (Browser.isDevice && this.isFilterLayout()) {
2267
+ removeClass([document.body, this.popupObj.element], dropDownListClasses.popupFullScreen);
2268
+ EventHandler.remove(this.list, 'scroll', this.listScroll);
2269
+ }
2270
+ if (this.isFilterLayout()) {
2271
+ if (!Browser.isDevice) {
2272
+ this.searchKeyModule.destroy();
2273
+ if (this.clearIconElement) { EventHandler.remove(this.clearIconElement, 'click', this.clearText); }
2274
+ }
2275
+ if (this.backIconElement) {
2276
+ EventHandler.remove(this.backIconElement, 'click', this.clickOnBackIcon);
2277
+ EventHandler.remove(this.clearIconElement, 'click', this.clearText);
2278
+ }
2279
+ EventHandler.remove(this.filterInput, 'input', this.onInput);
2280
+ EventHandler.remove(this.filterInput, 'keyup', this.onFilterUp);
2281
+ EventHandler.remove(this.filterInput, 'keydown', this.onFilterDown);
2282
+ EventHandler.remove(this.filterInput, 'blur', this.onBlur);
2283
+ EventHandler.remove(this.filterInput, 'paste', this.pasteHandler);
2284
+ this.filterInput = null;
2285
+ }
2286
+ attributes(this.targetElement(), { 'aria-expanded': 'false', 'aria-activedescendant': null });
2287
+ this.inputWrapper.container.classList.remove(dropDownListClasses.iconAnimation);
2288
+ if (this.isFiltering()) {
2289
+ this.actionCompleteData.isUpdated = false;
2290
+ }
2291
+ this.beforePopupOpen = false;
2292
+ let animModel: AnimationModel = {
2293
+ name: 'FadeOut',
2294
+ duration: 100,
2295
+ delay: delay ? delay : 0
2296
+ };
2297
+ let popupInstance: Popup = (isBlazor() && this.isServerRendered) ? null : this.popupObj;
2298
+ let eventArgs: PopupEventArgs = { popup: popupInstance, cancel: false, animation: animModel };
2299
+ this.trigger('close', eventArgs, (eventArgs: PopupEventArgs) => {
2300
+ if (!isNullOrUndefined(this.popupObj) &&
2301
+ !isNullOrUndefined(this.popupObj.element.querySelector('.e-fixed-head'))) {
2302
+ let fixedHeader: HTMLElement = this.popupObj.element.querySelector('.e-fixed-head');
2303
+ fixedHeader.parentNode.removeChild(fixedHeader);
2304
+ this.fixedHeaderElement = null;
2305
+ }
2306
+ if (!eventArgs.cancel) {
2307
+ if (this.getModuleName() === 'autocomplete' && !this.isServerBlazor) {
2308
+ this.rippleFun();
2309
+ }
2310
+ if (this.isPopupOpen) {
2311
+ this.popupObj.hide(new Animation(eventArgs.animation));
2312
+ } else {
2313
+ this.destroyPopup();
2314
+ }
2315
+ }
2316
+ });
2317
+ }
2318
+
2319
+ private destroyPopup(): void {
2320
+ let popupHolderEle: HTMLElement = document.querySelector('#' + this.element.id + '_popup_holder');
2321
+ if (this.isServerBlazor && this.serverPopupEle && popupHolderEle) {
2322
+ popupHolderEle.appendChild(this.serverPopupEle);
2323
+ }
2324
+ if (this.isServerBlazor) {
2325
+ // tslint:disable-next-line
2326
+ (this as any).interopAdaptor.invokeMethodAsync('OnServerClosePopup');
2327
+ }
2328
+ this.isPopupOpen = false;
2329
+ this.isFilterFocus = false;
2330
+ this.popupObj.destroy();
2331
+ detach(this.popupObj.element);
2332
+ }
2333
+
2334
+ private clickOnBackIcon(): void {
2335
+ this.hidePopup();
2336
+ this.focusIn();
2337
+ }
2338
+ /**
2339
+ * To Initialize the control rendering
2340
+ * @private
2341
+ */
2342
+ // tslint:disable-next-line
2343
+ public render(): void {
2344
+ if (this.isServerBlazor) {
2345
+ this.inputElement = this.element as HTMLInputElement;
2346
+ this.inputWrapper = { container: this.element.parentElement };
2347
+ this.hiddenElement = this.inputWrapper.container.querySelector('select');
2348
+ this.inputWrapper.buttons = [this.inputWrapper.container.querySelector('.e-input-group-icon.e-ddl-icon')];
2349
+ if (this.showClearButton) {
2350
+ this.inputWrapper.clearButton = this.inputWrapper.container.querySelector('.e-clear-icon');
2351
+ Input.wireClearBtnEvents(this.element as HTMLInputElement, this.inputWrapper.clearButton, this.inputWrapper.container);
2352
+ }
2353
+ if (this.floatLabelType === 'Auto') {
2354
+ Input.wireFloatingEvents(this.element as HTMLInputElement);
2355
+ }
2356
+ Input.bindInitialEvent({
2357
+ element: this.element as HTMLInputElement,
2358
+ buttons: null, customTag: null,
2359
+ floatLabelType: this.floatLabelType,
2360
+ properties: this.properties
2361
+ });
2362
+ this.setFields();
2363
+ this.wireEvent();
2364
+ this.tabIndex = this.element.hasAttribute('tabindex') ? this.element.getAttribute('tabindex') : '0';
2365
+ if (!this.enabled) {
2366
+ this.targetElement().tabIndex = -1;
2367
+ }
2368
+ if (this.element.hasAttribute('autofocus')) {
2369
+ this.focusIn();
2370
+ }
2371
+ } else {
2372
+ if (this.element.tagName === 'INPUT') {
2373
+ this.inputElement = this.element as HTMLInputElement;
2374
+ if (isNullOrUndefined(this.inputElement.getAttribute('role'))) {
2375
+ this.inputElement.setAttribute('role', 'textbox');
2376
+ }
2377
+ if (isNullOrUndefined(this.inputElement.getAttribute('type'))) {
2378
+ this.inputElement.setAttribute('type', 'text');
2379
+ }
2380
+ } else {
2381
+ this.inputElement = this.createElement('input', { attrs: { role: 'textbox', type: 'text' } }) as HTMLInputElement;
2382
+ if (this.element.tagName !== this.getNgDirective()) {
2383
+ this.element.style.display = 'none';
2384
+ }
2385
+ this.element.parentElement.insertBefore(this.inputElement, this.element);
2386
+ this.preventTabIndex(this.inputElement);
2387
+ }
2388
+ let updatedCssClassValues: string = this.cssClass;
2389
+ if (!isNullOrUndefined(this.cssClass) && this.cssClass !== '') {
2390
+ updatedCssClassValues = (this.cssClass.replace(/\s+/g, ' ')).trim();
2391
+ }
2392
+ this.inputWrapper = Input.createInput(
2393
+ {
2394
+ element: <HTMLInputElement>this.inputElement,
2395
+ buttons: this.isPopupButton() ? [dropDownListClasses.icon] : null,
2396
+ floatLabelType: this.floatLabelType,
2397
+ properties: {
2398
+ readonly: this.getModuleName() === 'dropdownlist' ? true : this.readonly,
2399
+ placeholder: this.placeholder,
2400
+ cssClass: updatedCssClassValues,
2401
+ enabled: this.enabled,
2402
+ enableRtl: this.enableRtl,
2403
+ showClearButton: this.showClearButton
2404
+ },
2405
+ },
2406
+ this.createElement
2407
+ );
2408
+ if (this.element.tagName === this.getNgDirective()) {
2409
+ this.element.appendChild(this.inputWrapper.container);
2410
+ } else {
2411
+ this.inputElement.parentElement.insertBefore(this.element, this.inputElement);
2412
+ }
2413
+ this.hiddenElement = this.createElement('select', {
2414
+ attrs: { 'aria-hidden': 'true', 'tabindex': '-1', 'class': dropDownListClasses.hiddenElement }
2415
+ }) as HTMLSelectElement;
2416
+ prepend([this.hiddenElement], this.inputWrapper.container);
2417
+ this.validationAttribute(this.element, this.hiddenElement);
2418
+ this.setFields();
2419
+ this.inputWrapper.container.style.width = formatUnit(this.width);
2420
+ this.inputWrapper.container.classList.add('e-ddl');
2421
+ this.wireEvent();
2422
+ this.tabIndex = this.element.hasAttribute('tabindex') ? this.element.getAttribute('tabindex') : '0';
2423
+ this.element.removeAttribute('tabindex');
2424
+ let id: string = this.element.getAttribute('id') ? this.element.getAttribute('id') : getUniqueID('ej2_dropdownlist');
2425
+ this.element.id = id;
2426
+ this.hiddenElement.id = id + '_hidden';
2427
+ this.targetElement().setAttribute('tabindex', this.tabIndex);
2428
+ attributes(this.targetElement(), this.getAriaAttributes());
2429
+ this.updateDataAttribute(this.htmlAttributes);
2430
+ this.setHTMLAttributes();
2431
+ if (this.value !== null || this.activeIndex !== null || this.text !== null) {
2432
+ this.initValue();
2433
+ } else if (this.element.tagName === 'SELECT' && (<HTMLSelectElement>this.element).options[0]) {
2434
+ let selectElement: HTMLSelectElement = <HTMLSelectElement>this.element;
2435
+ this.value = selectElement.options[selectElement.selectedIndex].value;
2436
+ this.text = isNullOrUndefined(this.value) ? null : selectElement.options[selectElement.selectedIndex].textContent;
2437
+ this.initValue();
2438
+ }
2439
+ this.preventTabIndex(this.element);
2440
+ if (!this.enabled) {
2441
+ this.targetElement().tabIndex = -1;
2442
+ }
2443
+ this.initial = false;
2444
+ this.element.style.opacity = '';
2445
+ this.inputElement.onselect = (e: UIEvent) => { e.stopImmediatePropagation(); };
2446
+ this.inputElement.onchange = (e: UIEvent) => { e.stopImmediatePropagation(); };
2447
+ if (this.element.hasAttribute('autofocus')) {
2448
+ this.focusIn();
2449
+ }
2450
+ if (!isNullOrUndefined(this.text)) {
2451
+ this.inputElement.setAttribute('value', this.text);
2452
+ }
2453
+ }
2454
+ this.renderComplete();
2455
+ };
2456
+
2457
+ private setFooterTemplate(popupEle: HTMLElement): void {
2458
+ let compiledString: Function;
2459
+ if (this.footer) {
2460
+ this.footer.innerHTML = '';
2461
+ } else {
2462
+ this.footer = this.createElement('div');
2463
+ addClass([this.footer], dropDownListClasses.footer);
2464
+ }
2465
+ let footercheck: boolean = this.dropdownCompiler(this.footerTemplate);
2466
+ if (footercheck) {
2467
+ compiledString = compile(document.querySelector(this.footerTemplate).innerHTML.trim());
2468
+ } else {
2469
+ compiledString = compile(this.footerTemplate);
2470
+ }
2471
+ for (let item of compiledString({}, null, null, this.footerTemplateId, this.isStringTemplate)) {
2472
+ this.footer.appendChild(item);
2473
+ }
2474
+ this.DropDownBaseupdateBlazorTemplates(false, false, false, false, false, false, true);
2475
+ append([this.footer], popupEle);
2476
+ }
2477
+
2478
+ private setHeaderTemplate(popupEle: HTMLElement): void {
2479
+ let compiledString: Function;
2480
+ if (this.header) {
2481
+ this.header.innerHTML = '';
2482
+ } else {
2483
+ this.header = this.createElement('div');
2484
+ addClass([this.header], dropDownListClasses.header);
2485
+ }
2486
+ let headercheck: boolean = this.dropdownCompiler(this.headerTemplate);
2487
+ if (headercheck) {
2488
+ compiledString = compile(document.querySelector(this.headerTemplate).innerHTML.trim());
2489
+ } else {
2490
+ compiledString = compile(this.headerTemplate);
2491
+ }
2492
+ for (let item of compiledString({}, null, null, this.headerTemplateId, this.isStringTemplate)) {
2493
+ this.header.appendChild(item);
2494
+ }
2495
+ this.DropDownBaseupdateBlazorTemplates(false, false, false, false, false, true, false);
2496
+ let contentEle: Element = popupEle.querySelector('div.e-content');
2497
+ popupEle.insertBefore(this.header, contentEle);
2498
+ }
2499
+
2500
+ protected setOldText(text: string): void {
2501
+ this.text = text;
2502
+ }
2503
+
2504
+ protected setOldValue(value: string | number | boolean): void {
2505
+ this.value = value;
2506
+ }
2507
+
2508
+ protected refreshPopup(): void {
2509
+ if (!isNullOrUndefined(this.popupObj) && document.body.contains(this.popupObj.element) &&
2510
+ ((this.allowFiltering && !(Browser.isDevice && this.isFilterLayout())) || this.getModuleName() === 'autocomplete')) {
2511
+ removeClass([this.popupObj.element], 'e-popup-close');
2512
+ this.popupObj.refreshPosition(this.inputWrapper.container);
2513
+ }
2514
+ }
2515
+ private checkDatasource(newProp?: DropDownListModel): void {
2516
+ if (newProp.dataSource && !isNullOrUndefined(Object.keys(newProp.dataSource)) && this.itemTemplate && this.allowFiltering) {
2517
+ this.list = null;
2518
+ this.actionCompleteData = { ulElement: null, list: null, isUpdated: false };
2519
+ }
2520
+ let isChangeValue: boolean = Object.keys(newProp).indexOf('value') !== -1 && isNullOrUndefined(newProp.value);
2521
+ let isChangeText: boolean = Object.keys(newProp).indexOf('text') !== -1 && isNullOrUndefined(newProp.text);
2522
+ if (this.getModuleName() !== 'autocomplete' && this.allowFiltering && (isChangeValue || isChangeText)) {
2523
+ this.itemData = null;
2524
+ }
2525
+ if (this.allowFiltering && newProp.dataSource && !isNullOrUndefined(Object.keys(newProp.dataSource))) {
2526
+ this.actionCompleteData = { ulElement: null, list: null, isUpdated: false };
2527
+ }
2528
+ }
2529
+ protected updateDataSource(props?: DropDownListModel): void {
2530
+ if (this.inputElement.value !== '' || (!isNullOrUndefined(props) && (isNullOrUndefined(props.dataSource)
2531
+ || (!(props.dataSource instanceof DataManager) && props.dataSource.length === 0)))) {
2532
+ this.clearAll(null, props);
2533
+ }
2534
+ if (!(!isNullOrUndefined(props) && (isNullOrUndefined(props.dataSource)
2535
+ || (!(props.dataSource instanceof DataManager) && props.dataSource.length === 0))) || !(props.dataSource === [])) {
2536
+ this.resetList(this.dataSource);
2537
+ }
2538
+ if (!this.isCustomFilter && !this.isFilterFocus && document.activeElement !== this.filterInput) {
2539
+ this.checkCustomValue();
2540
+ }
2541
+ }
2542
+ protected checkCustomValue(): void {
2543
+ this.itemData = this.getDataByValue(this.value);
2544
+ let dataItem: { [key: string]: string } = this.getItemData();
2545
+ this.setProperties({ 'value': dataItem.value, 'text': dataItem.text });
2546
+ }
2547
+ private updateInputFields(): void {
2548
+ if (this.getModuleName() === 'dropdownlist') {
2549
+ Input.setValue(this.text, this.inputElement, this.floatLabelType, this.showClearButton);
2550
+ }
2551
+ }
2552
+ /**
2553
+ * Dynamically change the value of properties.
2554
+ * @private
2555
+ */
2556
+ public onPropertyChanged(newProp: DropDownListModel, oldProp: DropDownListModel): void {
2557
+ if (this.getModuleName() === 'dropdownlist') {
2558
+ if (!this.isServerBlazor) {
2559
+ this.checkDatasource(newProp);
2560
+ this.setUpdateInitial(['fields', 'query', 'dataSource'], newProp as { [key: string]: string; });
2561
+ }
2562
+ }
2563
+ for (let prop of Object.keys(newProp)) {
2564
+ switch (prop) {
2565
+ case 'query':
2566
+ case 'dataSource':
2567
+ break;
2568
+ case 'htmlAttributes': this.setHTMLAttributes();
2569
+ break;
2570
+ case 'width': this.setEleWidth(newProp.width); break;
2571
+ case 'placeholder': Input.setPlaceholder(newProp.placeholder, this.inputElement as HTMLInputElement); break;
2572
+ case 'filterBarPlaceholder':
2573
+ if (this.filterInput) { Input.setPlaceholder(newProp.filterBarPlaceholder, this.filterInput as HTMLInputElement); }
2574
+ break;
2575
+ case 'readonly':
2576
+ if (this.getModuleName() !== 'dropdownlist') {
2577
+ Input.setReadonly(newProp.readonly, this.inputElement as HTMLInputElement); }
2578
+ break;
2579
+ case 'cssClass': this.setCssClass(newProp.cssClass, oldProp.cssClass); break;
2580
+ case 'enableRtl': this.setEnableRtl(); break;
2581
+ case 'enabled': this.setEnable(); break;
2582
+ case 'text': if (newProp.text === null) { this.clearAll(); break; }
2583
+ if (!this.list) {
2584
+ if (this.dataSource instanceof DataManager) { this.initRemoteRender = true; }
2585
+ this.renderList();
2586
+ }
2587
+ if (!this.initRemoteRender) {
2588
+ let li: Element = this.getElementByText(newProp.text);
2589
+ if (!this.checkValidLi(li)) {
2590
+ if (this.liCollections && this.liCollections.length === 100 &&
2591
+ this.getModuleName() === 'autocomplete' && this.listData.length > 100) {
2592
+ this.setSelectionData(newProp.text, oldProp.text, 'text');
2593
+ } else if (!this.isServerBlazor) { this.setOldText(oldProp.text); }
2594
+ }
2595
+ this.updateInputFields();
2596
+ }
2597
+ break;
2598
+ case 'value': if (newProp.value === null) { this.clearAll(); break; }
2599
+ this.notify('beforeValueChange', { newProp: newProp }); // gird component value type change
2600
+ if (!this.list) {
2601
+ if (this.dataSource instanceof DataManager) { this.initRemoteRender = true; }
2602
+ this.renderList();
2603
+ }
2604
+ if (!this.initRemoteRender) {
2605
+ let item: Element = this.getElementByValue(newProp.value);
2606
+ if (!this.checkValidLi(item)) {
2607
+ if (this.liCollections && this.liCollections.length === 100 &&
2608
+ this.getModuleName() === 'autocomplete' && this.listData.length > 100) {
2609
+ this.setSelectionData(newProp.value, oldProp.value, 'value');
2610
+ } else if (!this.isServerBlazor) { this.setOldValue(oldProp.value); }
2611
+ }
2612
+ this.updateInputFields();
2613
+ }
2614
+ break;
2615
+ case 'index': if (newProp.index === null) { this.clearAll(); break; }
2616
+ if (!this.list) {
2617
+ if (this.dataSource instanceof DataManager) { this.initRemoteRender = true; }
2618
+ this.renderList();
2619
+ }
2620
+ if (!this.initRemoteRender && this.liCollections) {
2621
+ let element: Element = this.liCollections[newProp.index] as Element;
2622
+ if (!this.checkValidLi(element)) {
2623
+ if (this.liCollections && this.liCollections.length === 100 &&
2624
+ this.getModuleName() === 'autocomplete' && this.listData.length > 100) {
2625
+ this.setSelectionData(newProp.index, oldProp.index, 'index');
2626
+ } else if (!this.isServerBlazor) { this.index = oldProp.index; }
2627
+ }
2628
+ this.updateInputFields();
2629
+ }
2630
+ break;
2631
+ case 'footerTemplate': if (this.popupObj) { this.setFooterTemplate(this.popupObj.element); } break;
2632
+ case 'headerTemplate': if (this.popupObj) { this.setHeaderTemplate(this.popupObj.element); } break;
2633
+ case 'valueTemplate':
2634
+ if (!isNullOrUndefined(this.itemData) && this.valueTemplate != null) { this.setValueTemplate(); } break;
2635
+ case 'allowFiltering':
2636
+ if (this.allowFiltering) {
2637
+ this.actionCompleteData = { ulElement: this.ulElement,
2638
+ list: this.listData as { [key: string]: Object }[], isUpdated: true };
2639
+ this.updateSelectElementData(this.allowFiltering); }
2640
+ break;
2641
+ case 'floatLabelType':
2642
+ Input.removeFloating(this.inputWrapper);
2643
+ Input.addFloating(this.inputElement, newProp.floatLabelType, this.placeholder, this.createElement);
2644
+ break;
2645
+ case 'showClearButton':
2646
+ Input.setClearButton(newProp.showClearButton, this.inputElement, this.inputWrapper, null, this.createElement);
2647
+ this.bindClearEvent();
2648
+ break;
2649
+ default:
2650
+ let ddlProps: { [key: string]: Object };
2651
+ ddlProps = this.getPropObject(prop, <{ [key: string]: string; }>newProp, <{ [key: string]: string; }>oldProp);
2652
+ super.onPropertyChanged(ddlProps.newProperty, ddlProps.oldProperty);
2653
+ break;
2654
+ }
2655
+ }
2656
+ }
2657
+
2658
+ private checkValidLi(element: Element): boolean {
2659
+ if (this.isValidLI(element)) {
2660
+ this.setSelection(element, null);
2661
+ return true;
2662
+ }
2663
+ return false;
2664
+ }
2665
+
2666
+ private setSelectionData(
2667
+ newProp: number | string | boolean,
2668
+ oldProp: number | string | boolean,
2669
+ prop: string,
2670
+ ): void {
2671
+ let li: Element;
2672
+ this.updateListValues = (): void => {
2673
+ if (prop === 'text') {
2674
+ li = this.getElementByText(newProp as string);
2675
+ if (!this.checkValidLi(li)) {
2676
+ this.setOldText(oldProp as string);
2677
+ }
2678
+ } else if (prop === 'value') {
2679
+ li = this.getElementByValue(newProp);
2680
+ if (!this.checkValidLi(li)) {
2681
+ this.setOldValue(oldProp);
2682
+ }
2683
+ } else if (prop === 'index') {
2684
+ li = this.liCollections[newProp as number] as Element;
2685
+ if (!this.checkValidLi(li)) {
2686
+ this.index = oldProp as number;
2687
+ }
2688
+ }
2689
+ };
2690
+ }
2691
+
2692
+ private setCssClass(newClass: string, oldClass: string): void {
2693
+ if (!isNullOrUndefined(oldClass)) {
2694
+ oldClass = (oldClass.replace(/\s+/g, ' ')).trim();
2695
+ }
2696
+ if (!isNullOrUndefined(newClass)) {
2697
+ newClass = (newClass.replace(/\s+/g, ' ')).trim();
2698
+ }
2699
+ Input.setCssClass(newClass, [this.inputWrapper.container], oldClass);
2700
+ if (this.popupObj) {
2701
+ Input.setCssClass(newClass, [this.popupObj.element], oldClass);
2702
+ }
2703
+ }
2704
+ /**
2705
+ * Return the module name.
2706
+ * @private
2707
+ */
2708
+ public getModuleName(): string {
2709
+ return 'dropdownlist';
2710
+ }
2711
+ /**
2712
+ * Opens the popup that displays the list of items.
2713
+ * @returns void.
2714
+ */
2715
+ public showPopup(): void {
2716
+ if (!this.enabled) {
2717
+ return;
2718
+ }
2719
+ if (isBlazor() && this.itemTemplate) {
2720
+ this.DropDownBaseupdateBlazorTemplates(true, false, false, false);
2721
+ }
2722
+ if (this.beforePopupOpen) {
2723
+ this.refreshPopup();
2724
+ return;
2725
+ }
2726
+ this.beforePopupOpen = true;
2727
+ if (this.isFiltering() && !this.isActive && this.actionCompleteData.list && this.actionCompleteData.list[0]) {
2728
+ this.isActive = true;
2729
+ this.onActionComplete(this.actionCompleteData.ulElement, this.actionCompleteData.list, null, true);
2730
+ } else if (isNullOrUndefined(this.list) || !isUndefined(this.list) && this.list.classList.contains(dropDownBaseClasses.noData)) {
2731
+ this.renderList();
2732
+ } else if (this.isFiltering() && this.isServerBlazor) {
2733
+ this.renderList();
2734
+ }
2735
+ if (!this.isServerBlazor) {
2736
+ this.invokeRenderPopup();
2737
+ }
2738
+ let popupHolderEle: Element | boolean = !this.isFiltering() || document.querySelector('#' + this.element.id + '_popup_holder');
2739
+ let isDropdownComp: boolean = this.getModuleName() === 'dropdownlist' || !this.isFiltering();
2740
+ if (this.isServerBlazor && popupHolderEle && !isNullOrUndefined(this.list) && isDropdownComp) {
2741
+ this.invokeRenderPopup();
2742
+ }
2743
+ }
2744
+
2745
+ private invokeRenderPopup(): void {
2746
+ if (Browser.isDevice && this.isFilterLayout()) {
2747
+ let proxy: this = this;
2748
+ window.onpopstate = () => {
2749
+ proxy.hidePopup();
2750
+ };
2751
+ history.pushState({}, '');
2752
+ }
2753
+
2754
+ if (!isNullOrUndefined(this.list.children[0]) || this.list.classList.contains(dropDownBaseClasses.noData)) {
2755
+ this.renderPopup();
2756
+ }
2757
+ attributes(this.targetElement(), { 'aria-activedescendant': this.selectedLI ? this.selectedLI.id : null });
2758
+ }
2759
+ private clientRenderPopup(data: { [key: string]: Object }[] | string[] | boolean[] | number[], popupEle: HTMLElement): void {
2760
+ if (popupEle) {
2761
+ this.serverPopupEle = popupEle;
2762
+ this.list = popupEle.querySelector('.e-dropdownbase.e-content') ?
2763
+ popupEle.querySelector('.e-dropdownbase.e-content') : this.list;
2764
+ this.ulElement = this.list.querySelector('ul');
2765
+ if (isNullOrUndefined(this.ulElement) && !this.list.classList.contains(dropDownBaseClasses.noData)) {
2766
+ addClass([this.list], [dropDownBaseClasses.noData]);
2767
+ }
2768
+ this.liCollections = this.ulElement ?
2769
+ <NodeListOf<Element> & HTMLElement[]>this.ulElement.querySelectorAll('.' + dropDownBaseClasses.li) : [];
2770
+ this.listData = data;
2771
+ if (this.getModuleName() === 'autocomplete' && this.liCollections.length > 0 ) {
2772
+ this.renderHightSearch();
2773
+ }
2774
+ this.initRemoteRender = false;
2775
+ if (!this.isPopupOpen) { this.serverBlazorUpdateSelection(); }
2776
+ this.unWireListEvents();
2777
+ this.wireListEvents();
2778
+ if (this.isServerIncrementalSearch && this.searchKeyEvent) {
2779
+ this.isServerIncrementalSearch = false;
2780
+ this.initial = false;
2781
+ this.onServerIncrementalSearch(this.searchKeyEvent);
2782
+ }
2783
+ if (this.isServerNavigation && this.searchKeyEvent) {
2784
+ if (this.searchKeyEvent.action === 'down' || this.searchKeyEvent.action === 'up') {
2785
+ this.isServerNavigation = false;
2786
+ this.updateUpDownAction(this.searchKeyEvent);
2787
+ } else if (this.searchKeyEvent.action === 'home' || this.searchKeyEvent.action === 'end') {
2788
+ this.isServerNavigation = false;
2789
+ this.updateHomeEndAction(this.searchKeyEvent);
2790
+ }
2791
+ }
2792
+ if (this.beforePopupOpen) {
2793
+ this.invokeRenderPopup();
2794
+ }
2795
+ if (this.getModuleName() !== 'dropdownlist') {
2796
+ this.onActionComplete(this.ulElement, this.listData as { [key: string]: Object }[]);
2797
+ }
2798
+ } else if (data != null && this.listData !== data) {
2799
+ this.listData = data;
2800
+ this.initRemoteRender = false;
2801
+ }
2802
+ }
2803
+
2804
+ protected renderHightSearch(): void {
2805
+ // update high light search
2806
+ }
2807
+ private updateclientItemData(data: { [key: string]: Object }[] | string[] | boolean[] | number[]): void {
2808
+ this.listData = data;
2809
+ }
2810
+ private initValueItemData(selectData: string | number | boolean | { [key: string]: Object }): void {
2811
+ this.itemData = selectData;
2812
+ this.previousValue = this.value;
2813
+ this.initial = false;
2814
+ }
2815
+ private serverUpdateListElement(data: { [key: string]: Object }[] | string[] | boolean[] | number[], popupEle: HTMLElement): void {
2816
+ this.listData = data;
2817
+ if (this.ulElement) {
2818
+ this.liCollections = <NodeListOf<Element> & HTMLElement[]>this.ulElement.querySelectorAll('.' + dropDownBaseClasses.li);
2819
+ }
2820
+ }
2821
+ /**
2822
+ * Hides the popup if it is in an open state.
2823
+ * @returns void.
2824
+ */
2825
+ public hidePopup(e?: MouseEvent | KeyboardEventArgs): void {
2826
+ let isHeader: boolean = (this.headerTemplate) ? true : false;
2827
+ let isFooter: boolean = (this.headerTemplate) ? true : false;
2828
+ this.DropDownBaseresetBlazorTemplates(false, false, false, false, false, isHeader, isFooter);
2829
+ if (this.isEscapeKey && this.getModuleName() === 'dropdownlist') {
2830
+ Input.setValue(this.text, this.inputElement, this.floatLabelType, this.showClearButton);
2831
+ this.isEscapeKey = false;
2832
+ if (!isNullOrUndefined(this.index)) {
2833
+ let element: HTMLElement = this.findListElement(this.ulElement, 'li', 'data-value', this.value);
2834
+ this.selectedLI = this.liCollections[this.index] || element;
2835
+ if (this.selectedLI) {
2836
+ this.updateSelectedItem(this.selectedLI, null, true);
2837
+ if (this.valueTemplate && this.itemData !== null) {
2838
+ this.setValueTemplate();
2839
+ }
2840
+ }
2841
+ } else {
2842
+ this.resetSelection();
2843
+ }
2844
+ }
2845
+ this.closePopup();
2846
+ let dataItem: { [key: string]: string } = this.getItemData();
2847
+ let isSelectVal: boolean = this.isServerBlazor ? !isNullOrUndefined(this.value) : !isNullOrUndefined(this.selectedLI);
2848
+ if (this.inputElement.value.trim() === '' && !this.isInteracted && (this.isSelectCustom ||
2849
+ isSelectVal && this.inputElement.value !== dataItem.text)) {
2850
+ this.isSelectCustom = false;
2851
+ this.clearAll(e);
2852
+ }
2853
+ }
2854
+ /**
2855
+ * Sets the focus on the component for interaction.
2856
+ * @returns void.
2857
+ */
2858
+ public focusIn(e?: FocusEvent | MouseEvent | KeyboardEvent | TouchEvent): void {
2859
+ if (!this.enabled) {
2860
+ return;
2861
+ }
2862
+ if (this.targetElement().classList.contains(dropDownListClasses.disable)) { return; }
2863
+ let isFocused: boolean = false;
2864
+ if (this.preventFocus && Browser.isDevice) {
2865
+ this.inputWrapper.container.tabIndex = 1;
2866
+ this.inputWrapper.container.focus();
2867
+ this.preventFocus = false;
2868
+ isFocused = true;
2869
+ }
2870
+ if (!isFocused) {
2871
+ this.targetElement().focus();
2872
+ }
2873
+ addClass([this.inputWrapper.container], [dropDownListClasses.inputFocus]);
2874
+ this.onFocus(e);
2875
+ }
2876
+ /**
2877
+ * Moves the focus from the component if the component is already focused.
2878
+ * @returns void.
2879
+ */
2880
+ public focusOut(e?: MouseEvent | KeyboardEventArgs): void {
2881
+ if (!this.enabled) {
2882
+ return;
2883
+ }
2884
+ this.isTyped = true;
2885
+ this.hidePopup(e);
2886
+ this.targetElement().blur();
2887
+ removeClass([this.inputWrapper.container], [dropDownListClasses.inputFocus]);
2888
+ }
2889
+ /**
2890
+ * Removes the component from the DOM and detaches all its related event handlers. Also it removes the attributes and classes.
2891
+ * @method destroy
2892
+ * @return {void}.
2893
+ */
2894
+ public destroy(): void {
2895
+ this.isActive = false;
2896
+ if (!this.isServerBlazor || (this.popupObj && document.body.contains(this.popupObj.element))) {
2897
+ this.hidePopup();
2898
+ }
2899
+ this.unWireEvent();
2900
+ if (this.list) {
2901
+ this.unWireListEvents();
2902
+ if (this.isServerBlazor) {
2903
+ if ((this.fields.groupBy) && !this.isGroupChecking) {
2904
+ EventHandler.remove(this.list, 'scroll', this.setFloatingHeader);
2905
+ }
2906
+ }
2907
+ }
2908
+ if (!this.isServerBlazor) {
2909
+ if (this.element && !this.element.classList.contains('e-' + this.getModuleName())) {
2910
+ return;
2911
+ }
2912
+ let attrArray: string[] = ['readonly', 'aria-disabled', 'aria-placeholder',
2913
+ 'placeholder', 'aria-owns', 'aria-labelledby', 'aria-haspopup', 'aria-expanded',
2914
+ 'aria-activedescendant', 'autocomplete', 'aria-readonly', 'autocorrect',
2915
+ 'autocapitalize', 'spellcheck', 'aria-autocomplete', 'aria-live', 'aria-describedby', 'aria-label'];
2916
+ for (let i: number = 0; i < attrArray.length; i++) {
2917
+ this.inputElement.removeAttribute(attrArray[i]);
2918
+ }
2919
+ this.inputElement.setAttribute('tabindex', this.tabIndex);
2920
+ this.inputElement.classList.remove('e-input');
2921
+ Input.setValue('', this.inputElement, this.floatLabelType, this.showClearButton);
2922
+ this.element.style.display = 'block';
2923
+ if (this.inputWrapper.container.parentElement.tagName === this.getNgDirective()) {
2924
+ detach(this.inputWrapper.container);
2925
+ } else {
2926
+ this.inputWrapper.container.parentElement.insertBefore(this.element, this.inputWrapper.container);
2927
+ detach(this.inputWrapper.container);
2928
+ }
2929
+ super.destroy();
2930
+ }
2931
+ };
2932
+ /**
2933
+ * Gets all the list items bound on this component.
2934
+ * @returns Element[].
2935
+ */
2936
+ public getItems(): Element[] {
2937
+ if (!this.list) {
2938
+ if (this.dataSource instanceof DataManager) { this.initRemoteRender = true; }
2939
+ this.renderList();
2940
+ }
2941
+ return this.ulElement ? super.getItems() : [];
2942
+ }
2943
+ /**
2944
+ * Gets the data Object that matches the given value.
2945
+ * @param { string | number } value - Specifies the value of the list item.
2946
+ * @returns Object.
2947
+ * @blazorType object
2948
+ */
2949
+ public getDataByValue(value: string | number | boolean)
2950
+ : { [key: string]: Object } | string | number | boolean {
2951
+ return super.getDataByValue(value);
2952
+ }
2953
+ /**
2954
+ * Allows you to clear the selected values from the component.
2955
+ * @returns void.
2956
+ */
2957
+ public clear(): void {
2958
+ this.value = null;
2959
+ }
2960
+ }
2961
+ export interface DropDownListClassList {
2962
+ root: string;
2963
+ hover: string;
2964
+ selected: string;
2965
+ rtl: string;
2966
+ base: string;
2967
+ disable: string;
2968
+ input: string;
2969
+ inputFocus: string;
2970
+ li: string;
2971
+ icon: string;
2972
+ iconAnimation: string;
2973
+ value: string;
2974
+ focus: string;
2975
+ device: string;
2976
+ backIcon: string;
2977
+ filterBarClearIcon: string;
2978
+ filterInput: string;
2979
+ filterParent: string;
2980
+ mobileFilter: string;
2981
+ footer: string;
2982
+ header: string;
2983
+ clearIcon: string;
2984
+ clearIconHide: string;
2985
+ popupFullScreen: string;
2986
+ disableIcon: string;
2987
+ hiddenElement: string;
2988
+ }
2989
+ interface ActionCompleteData {
2990
+ ulElement?: HTMLElement;
2991
+ list?: { [key: string]: Object }[];
2992
+ isUpdated: boolean;
2993
+ }