@syncfusion/ej2-dropdowns 23.1.43 → 23.2.4-13895

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 (288) hide show
  1. package/CHANGELOG.md +2114 -2084
  2. package/{README.md → ReadMe.md} +217 -217
  3. package/dist/ej2-dropdowns.min.js +1 -10
  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 +83 -71
  7. package/dist/es6/ej2-dropdowns.es2015.js.map +1 -1
  8. package/dist/es6/ej2-dropdowns.es5.js +225 -212
  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 +615 -0
  14. package/dist/ts/combo-box/combo-box.ts +1028 -0
  15. package/dist/ts/common/highlight-search.ts +57 -0
  16. package/dist/ts/common/incremental-search.ts +131 -0
  17. package/dist/ts/common/interface.ts +72 -0
  18. package/dist/ts/common/virtual-scroll.ts +354 -0
  19. package/dist/ts/drop-down-base/drop-down-base.ts +1864 -0
  20. package/dist/ts/drop-down-list/drop-down-list.ts +3954 -0
  21. package/dist/ts/drop-down-tree/drop-down-tree.ts +3741 -0
  22. package/dist/ts/list-box/list-box.ts +2753 -0
  23. package/dist/ts/mention/mention.ts +1857 -0
  24. package/dist/ts/multi-select/checkbox-selection.ts +547 -0
  25. package/dist/ts/multi-select/float-label.ts +176 -0
  26. package/dist/ts/multi-select/interface.ts +70 -0
  27. package/dist/ts/multi-select/multi-select.ts +4880 -0
  28. package/helpers/e2e/autocomplete.js +13 -13
  29. package/helpers/e2e/combobox.js +13 -13
  30. package/helpers/e2e/dropdownlist.js +13 -13
  31. package/helpers/e2e/index.js +3 -3
  32. package/helpers/e2e/listboxHelper.js +13 -13
  33. package/helpers/e2e/multiselect.js +13 -13
  34. package/license +2 -2
  35. package/package.json +80 -80
  36. package/src/auto-complete/auto-complete-model.d.ts +188 -188
  37. package/src/auto-complete/auto-complete.d.ts +12 -12
  38. package/src/auto-complete/auto-complete.js +21 -21
  39. package/src/combo-box/combo-box-model.d.ts +224 -224
  40. package/src/combo-box/combo-box.d.ts +27 -27
  41. package/src/combo-box/combo-box.js +29 -29
  42. package/src/common/virtual-scroll.js +46 -46
  43. package/src/drop-down-base/drop-down-base-model.d.ts +200 -200
  44. package/src/drop-down-base/drop-down-base.d.ts +15 -15
  45. package/src/drop-down-base/drop-down-base.js +23 -21
  46. package/src/drop-down-list/drop-down-list-model.d.ts +202 -202
  47. package/src/drop-down-list/drop-down-list.d.ts +4 -4
  48. package/src/drop-down-list/drop-down-list.js +24 -21
  49. package/src/drop-down-tree/drop-down-tree-model.d.ts +468 -468
  50. package/src/drop-down-tree/drop-down-tree.d.ts +0 -1
  51. package/src/drop-down-tree/drop-down-tree.js +19 -27
  52. package/src/list-box/list-box-model.d.ts +193 -193
  53. package/src/list-box/list-box.d.ts +5 -2
  54. package/src/list-box/list-box.js +38 -21
  55. package/src/mention/mention-model.d.ts +261 -261
  56. package/src/mention/mention.js +20 -21
  57. package/src/multi-select/multi-select-model.d.ts +512 -512
  58. package/src/multi-select/multi-select.js +19 -19
  59. package/styles/auto-complete/_all.scss +1 -1
  60. package/styles/auto-complete/_bootstrap-dark-definition.scss +3 -3
  61. package/styles/auto-complete/_bootstrap-definition.scss +2 -2
  62. package/styles/auto-complete/_bootstrap4-definition.scss +11 -11
  63. package/styles/auto-complete/_bootstrap5-definition.scss +2 -2
  64. package/styles/auto-complete/_fabric-dark-definition.scss +2 -2
  65. package/styles/auto-complete/_fabric-definition.scss +2 -2
  66. package/styles/auto-complete/_fluent-definition.scss +2 -2
  67. package/styles/auto-complete/_fusionnew-definition.scss +2 -2
  68. package/styles/auto-complete/_highcontrast-definition.scss +2 -2
  69. package/styles/auto-complete/_highcontrast-light-definition.scss +2 -2
  70. package/styles/auto-complete/_material-dark-definition.scss +2 -2
  71. package/styles/auto-complete/_material-definition.scss +2 -2
  72. package/styles/auto-complete/_material3-definition.scss +2 -2
  73. package/styles/auto-complete/_tailwind-definition.scss +2 -2
  74. package/styles/auto-complete/material3-dark.scss +1 -1
  75. package/styles/auto-complete/material3.scss +1 -1
  76. package/styles/bootstrap-dark.css +5 -0
  77. package/styles/bootstrap5-dark.css +2 -1
  78. package/styles/bootstrap5.css +2 -1
  79. package/styles/combo-box/_all.scss +1 -1
  80. package/styles/combo-box/_bootstrap-dark-definition.scss +2 -2
  81. package/styles/combo-box/_bootstrap-definition.scss +2 -2
  82. package/styles/combo-box/_bootstrap4-definition.scss +11 -11
  83. package/styles/combo-box/_bootstrap5-definition.scss +2 -2
  84. package/styles/combo-box/_fabric-dark-definition.scss +2 -2
  85. package/styles/combo-box/_fabric-definition.scss +2 -2
  86. package/styles/combo-box/_fluent-definition.scss +2 -2
  87. package/styles/combo-box/_fusionnew-definition.scss +2 -2
  88. package/styles/combo-box/_highcontrast-definition.scss +2 -2
  89. package/styles/combo-box/_highcontrast-light-definition.scss +3 -3
  90. package/styles/combo-box/_material-dark-definition.scss +2 -2
  91. package/styles/combo-box/_material-definition.scss +2 -2
  92. package/styles/combo-box/_material3-definition.scss +2 -2
  93. package/styles/combo-box/_tailwind-definition.scss +2 -2
  94. package/styles/combo-box/material3-dark.scss +1 -1
  95. package/styles/combo-box/material3.scss +1 -1
  96. package/styles/drop-down-base/_all.scss +2 -2
  97. package/styles/drop-down-base/_bootstrap-dark-definition.scss +83 -83
  98. package/styles/drop-down-base/_bootstrap-definition.scss +83 -83
  99. package/styles/drop-down-base/_bootstrap4-definition.scss +90 -90
  100. package/styles/drop-down-base/_bootstrap5-definition.scss +117 -117
  101. package/styles/drop-down-base/_definition.scss +23 -23
  102. package/styles/drop-down-base/_fabric-dark-definition.scss +86 -86
  103. package/styles/drop-down-base/_fabric-definition.scss +84 -84
  104. package/styles/drop-down-base/_fluent-definition.scss +121 -121
  105. package/styles/drop-down-base/_fusionnew-definition.scss +117 -117
  106. package/styles/drop-down-base/_highcontrast-definition.scss +105 -105
  107. package/styles/drop-down-base/_highcontrast-light-definition.scss +105 -105
  108. package/styles/drop-down-base/_layout.scss +195 -195
  109. package/styles/drop-down-base/_material-dark-definition.scss +86 -86
  110. package/styles/drop-down-base/_material-definition.scss +85 -85
  111. package/styles/drop-down-base/_material3-definition.scss +87 -87
  112. package/styles/drop-down-base/_tailwind-definition.scss +129 -129
  113. package/styles/drop-down-base/_theme.scss +391 -391
  114. package/styles/drop-down-base/material3-dark.scss +1 -1
  115. package/styles/drop-down-base/material3.scss +1 -1
  116. package/styles/drop-down-list/_all.scss +3 -3
  117. package/styles/drop-down-list/_bootstrap-dark-definition.scss +157 -157
  118. package/styles/drop-down-list/_bootstrap-definition.scss +156 -156
  119. package/styles/drop-down-list/_bootstrap4-definition.scss +202 -202
  120. package/styles/drop-down-list/_bootstrap5-definition.scss +201 -201
  121. package/styles/drop-down-list/_fabric-dark-definition.scss +128 -128
  122. package/styles/drop-down-list/_fabric-definition.scss +124 -124
  123. package/styles/drop-down-list/_fluent-definition.scss +185 -185
  124. package/styles/drop-down-list/_fusionnew-definition.scss +201 -201
  125. package/styles/drop-down-list/_highcontrast-definition.scss +142 -142
  126. package/styles/drop-down-list/_highcontrast-light-definition.scss +144 -144
  127. package/styles/drop-down-list/_layout.scss +310 -310
  128. package/styles/drop-down-list/_material-dark-definition.scss +143 -143
  129. package/styles/drop-down-list/_material-definition.scss +167 -167
  130. package/styles/drop-down-list/_material3-definition.scss +180 -180
  131. package/styles/drop-down-list/_tailwind-definition.scss +134 -134
  132. package/styles/drop-down-list/_theme.scss +10 -10
  133. package/styles/drop-down-list/icons/_bootstrap-dark.scss +14 -14
  134. package/styles/drop-down-list/icons/_bootstrap.scss +14 -14
  135. package/styles/drop-down-list/icons/_bootstrap4.scss +14 -14
  136. package/styles/drop-down-list/icons/_bootstrap5.scss +14 -14
  137. package/styles/drop-down-list/icons/_fabric-dark.scss +14 -14
  138. package/styles/drop-down-list/icons/_fabric.scss +14 -14
  139. package/styles/drop-down-list/icons/_fluent.scss +14 -14
  140. package/styles/drop-down-list/icons/_fusionnew.scss +14 -14
  141. package/styles/drop-down-list/icons/_highcontrast-light.scss +14 -14
  142. package/styles/drop-down-list/icons/_highcontrast.scss +14 -14
  143. package/styles/drop-down-list/icons/_material-dark.scss +14 -14
  144. package/styles/drop-down-list/icons/_material.scss +14 -14
  145. package/styles/drop-down-list/icons/_material3.scss +14 -14
  146. package/styles/drop-down-list/icons/_tailwind.scss +14 -14
  147. package/styles/drop-down-list/material3-dark.scss +1 -1
  148. package/styles/drop-down-list/material3.scss +1 -1
  149. package/styles/drop-down-tree/_all.scss +2 -2
  150. package/styles/drop-down-tree/_bootstrap-dark-definition.scss +71 -71
  151. package/styles/drop-down-tree/_bootstrap-definition.scss +70 -70
  152. package/styles/drop-down-tree/_bootstrap4-definition.scss +71 -71
  153. package/styles/drop-down-tree/_bootstrap5-definition.scss +59 -59
  154. package/styles/drop-down-tree/_fabric-dark-definition.scss +71 -71
  155. package/styles/drop-down-tree/_fabric-definition.scss +71 -71
  156. package/styles/drop-down-tree/_fluent-definition.scss +65 -65
  157. package/styles/drop-down-tree/_fusionnew-definition.scss +59 -59
  158. package/styles/drop-down-tree/_highcontrast-definition.scss +71 -71
  159. package/styles/drop-down-tree/_highcontrast-light-definition.scss +71 -71
  160. package/styles/drop-down-tree/_layout.scss +1418 -1412
  161. package/styles/drop-down-tree/_material-dark-definition.scss +72 -72
  162. package/styles/drop-down-tree/_material-definition.scss +72 -72
  163. package/styles/drop-down-tree/_material3-definition.scss +76 -76
  164. package/styles/drop-down-tree/_tailwind-definition.scss +61 -61
  165. package/styles/drop-down-tree/_theme.scss +132 -132
  166. package/styles/drop-down-tree/fluent-dark.css +2 -0
  167. package/styles/drop-down-tree/fluent.css +2 -0
  168. package/styles/drop-down-tree/icons/_bootstrap-dark.scss +11 -11
  169. package/styles/drop-down-tree/icons/_bootstrap.scss +11 -11
  170. package/styles/drop-down-tree/icons/_bootstrap4.scss +11 -11
  171. package/styles/drop-down-tree/icons/_bootstrap5.scss +11 -11
  172. package/styles/drop-down-tree/icons/_fabric-dark.scss +11 -11
  173. package/styles/drop-down-tree/icons/_fabric.scss +11 -11
  174. package/styles/drop-down-tree/icons/_fluent.scss +11 -11
  175. package/styles/drop-down-tree/icons/_fusionnew.scss +11 -11
  176. package/styles/drop-down-tree/icons/_highcontrast-light.scss +11 -11
  177. package/styles/drop-down-tree/icons/_highcontrast.scss +11 -11
  178. package/styles/drop-down-tree/icons/_material-dark.scss +11 -11
  179. package/styles/drop-down-tree/icons/_material.scss +11 -11
  180. package/styles/drop-down-tree/icons/_material3.scss +11 -11
  181. package/styles/drop-down-tree/icons/_tailwind-dark.scss +11 -11
  182. package/styles/drop-down-tree/icons/_tailwind.scss +11 -11
  183. package/styles/drop-down-tree/material3-dark.scss +1 -1
  184. package/styles/drop-down-tree/material3.scss +1 -1
  185. package/styles/fabric-dark.css +5 -0
  186. package/styles/fluent-dark.css +4 -1
  187. package/styles/fluent.css +4 -1
  188. package/styles/highcontrast.css +5 -0
  189. package/styles/list-box/_all.scss +2 -2
  190. package/styles/list-box/_bootstrap-dark-definition.scss +126 -126
  191. package/styles/list-box/_bootstrap-definition.scss +119 -119
  192. package/styles/list-box/_bootstrap4-definition.scss +124 -124
  193. package/styles/list-box/_bootstrap5-definition.scss +120 -120
  194. package/styles/list-box/_fabric-dark-definition.scss +126 -126
  195. package/styles/list-box/_fabric-definition.scss +119 -119
  196. package/styles/list-box/_fluent-definition.scss +120 -120
  197. package/styles/list-box/_fusionnew-definition.scss +111 -111
  198. package/styles/list-box/_highcontrast-definition.scss +119 -119
  199. package/styles/list-box/_highcontrast-light-definition.scss +126 -126
  200. package/styles/list-box/_layout.scss +542 -542
  201. package/styles/list-box/_material-dark-definition.scss +126 -126
  202. package/styles/list-box/_material-definition.scss +119 -119
  203. package/styles/list-box/_material3-definition.scss +119 -119
  204. package/styles/list-box/_tailwind-definition.scss +119 -119
  205. package/styles/list-box/_theme.scss +382 -382
  206. package/styles/list-box/icons/_bootstrap-dark.scss +25 -25
  207. package/styles/list-box/icons/_bootstrap.scss +25 -25
  208. package/styles/list-box/icons/_bootstrap4.scss +25 -25
  209. package/styles/list-box/icons/_bootstrap5.scss +25 -25
  210. package/styles/list-box/icons/_fabric-dark.scss +25 -25
  211. package/styles/list-box/icons/_fabric.scss +25 -25
  212. package/styles/list-box/icons/_fluent.scss +25 -25
  213. package/styles/list-box/icons/_fusionnew.scss +25 -25
  214. package/styles/list-box/icons/_highcontrast-light.scss +25 -25
  215. package/styles/list-box/icons/_highcontrast.scss +25 -25
  216. package/styles/list-box/icons/_material-dark.scss +25 -25
  217. package/styles/list-box/icons/_material.scss +25 -25
  218. package/styles/list-box/icons/_material3.scss +25 -25
  219. package/styles/list-box/icons/_tailwind-dark.scss +25 -25
  220. package/styles/list-box/icons/_tailwind.scss +25 -25
  221. package/styles/list-box/material3-dark.scss +1 -1
  222. package/styles/list-box/material3.scss +1 -1
  223. package/styles/material3-dark.scss +1 -1
  224. package/styles/material3.scss +1 -1
  225. package/styles/mention/_all.scss +1 -1
  226. package/styles/mention/_bootstrap-dark-definition.scss +3 -3
  227. package/styles/mention/_bootstrap-definition.scss +3 -3
  228. package/styles/mention/_bootstrap4-definition.scss +3 -3
  229. package/styles/mention/_bootstrap5-definition.scss +1 -1
  230. package/styles/mention/_fabric-dark-definition.scss +2 -2
  231. package/styles/mention/_fabric-definition.scss +3 -3
  232. package/styles/mention/_fluent-definition.scss +1 -1
  233. package/styles/mention/_fusionnew-definition.scss +1 -1
  234. package/styles/mention/_highcontrast-definition.scss +3 -3
  235. package/styles/mention/_highcontrast-light-definition.scss +3 -3
  236. package/styles/mention/_layout.scss +6 -6
  237. package/styles/mention/_material-dark-definition.scss +3 -3
  238. package/styles/mention/_material-definition.scss +3 -3
  239. package/styles/mention/_material3-definition.scss +1 -1
  240. package/styles/mention/_tailwind-definition.scss +1 -1
  241. package/styles/mention/material3-dark.scss +1 -1
  242. package/styles/mention/material3.scss +1 -1
  243. package/styles/multi-select/_all.scss +2 -2
  244. package/styles/multi-select/_bootstrap-dark-definition.scss +203 -198
  245. package/styles/multi-select/_bootstrap-definition.scss +192 -192
  246. package/styles/multi-select/_bootstrap4-definition.scss +278 -278
  247. package/styles/multi-select/_bootstrap5-definition.scss +230 -229
  248. package/styles/multi-select/_fabric-dark-definition.scss +192 -187
  249. package/styles/multi-select/_fabric-definition.scss +183 -183
  250. package/styles/multi-select/_fluent-definition.scss +241 -240
  251. package/styles/multi-select/_fusionnew-definition.scss +227 -227
  252. package/styles/multi-select/_highcontrast-definition.scss +303 -298
  253. package/styles/multi-select/_highcontrast-light-definition.scss +297 -297
  254. package/styles/multi-select/_layout.scss +2199 -2199
  255. package/styles/multi-select/_material-dark-definition.scss +230 -230
  256. package/styles/multi-select/_material-definition.scss +223 -223
  257. package/styles/multi-select/_material3-definition.scss +246 -246
  258. package/styles/multi-select/_tailwind-definition.scss +235 -234
  259. package/styles/multi-select/_theme.scss +586 -586
  260. package/styles/multi-select/bootstrap-dark.css +5 -0
  261. package/styles/multi-select/bootstrap5-dark.css +2 -1
  262. package/styles/multi-select/bootstrap5.css +2 -1
  263. package/styles/multi-select/fabric-dark.css +5 -0
  264. package/styles/multi-select/fluent-dark.css +2 -1
  265. package/styles/multi-select/fluent.css +2 -1
  266. package/styles/multi-select/highcontrast.css +5 -0
  267. package/styles/multi-select/icons/_bootstrap-dark.scss +26 -26
  268. package/styles/multi-select/icons/_bootstrap.scss +26 -26
  269. package/styles/multi-select/icons/_bootstrap4.scss +37 -37
  270. package/styles/multi-select/icons/_bootstrap5.scss +26 -26
  271. package/styles/multi-select/icons/_fabric-dark.scss +26 -26
  272. package/styles/multi-select/icons/_fabric.scss +26 -26
  273. package/styles/multi-select/icons/_fluent.scss +55 -55
  274. package/styles/multi-select/icons/_fusionnew.scss +26 -26
  275. package/styles/multi-select/icons/_highcontrast-light.scss +26 -26
  276. package/styles/multi-select/icons/_highcontrast.scss +26 -26
  277. package/styles/multi-select/icons/_material-dark.scss +693 -693
  278. package/styles/multi-select/icons/_material.scss +693 -693
  279. package/styles/multi-select/icons/_material3.scss +692 -692
  280. package/styles/multi-select/icons/_tailwind.scss +26 -26
  281. package/styles/multi-select/material3-dark.scss +1 -1
  282. package/styles/multi-select/material3.scss +1 -1
  283. package/styles/multi-select/tailwind-dark.css +2 -1
  284. package/styles/multi-select/tailwind.css +2 -1
  285. package/styles/tailwind-dark.css +2 -1
  286. package/styles/tailwind.css +2 -1
  287. package/.eslintrc.json +0 -260
  288. package/tslint.json +0 -111
@@ -0,0 +1,3954 @@
1
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
+ /// <reference path='../drop-down-base/drop-down-base-model.d.ts'/>
3
+ import { EventHandler, Property, Event, compile, EmitType, KeyboardEvents, append, select, ModuleDeclaration } from '@syncfusion/ej2-base';
4
+ import { attributes, isNullOrUndefined, getUniqueID, formatUnit, isUndefined, getValue } from '@syncfusion/ej2-base';
5
+ import { Animation, AnimationModel, Browser, KeyboardEventArgs, NotifyPropertyChanges } from '@syncfusion/ej2-base';
6
+ import { addClass, removeClass, closest, prepend, detach, classList } from '@syncfusion/ej2-base';
7
+ import { Popup, isCollide, createSpinner, showSpinner, hideSpinner } from '@syncfusion/ej2-popups';
8
+ import { IInput, Input, InputObject, FloatLabelType } from '@syncfusion/ej2-inputs';
9
+ import { incrementalSearch, resetIncrementalSearchValues } from '../common/incremental-search';
10
+ import { DropDownBase, dropDownBaseClasses, SelectEventArgs, FilteringEventArgs, PopupEventArgs } from '../drop-down-base/drop-down-base';
11
+ import { FocusEventArgs, ResultData, BeforeOpenEventArgs } from '../drop-down-base/drop-down-base';
12
+ import { FieldSettingsModel } from '../drop-down-base/drop-down-base-model';
13
+ import { DropDownListModel } from '../drop-down-list';
14
+ import { DataManager, Query, Predicate, DataOptions } from '@syncfusion/ej2-data';
15
+ import {VirtualScroll, Offsets, ScrollDirection, SentinelType, VirtualInfo} from '../common/virtual-scroll';
16
+ import { Skeleton } from '@syncfusion/ej2-notifications';
17
+
18
+ export interface ChangeEventArgs extends SelectEventArgs {
19
+ /**
20
+ * Returns the selected value
21
+ *
22
+ * @isGenericType true
23
+ */
24
+ value: number | string | boolean
25
+ /**
26
+ * Returns the previous selected list item
27
+ */
28
+ previousItem: HTMLLIElement
29
+ /**
30
+ * Returns the previous selected item as JSON Object from the data source.
31
+ *
32
+ */
33
+ previousItemData: FieldSettingsModel
34
+ /**
35
+ * Returns the root element of the component.
36
+ */
37
+ element: HTMLElement
38
+ /**
39
+ * Specifies the original event arguments.
40
+ */
41
+ event: MouseEvent | KeyboardEvent | TouchEvent
42
+ }
43
+
44
+ export interface GeneratedData {
45
+ [key: string]: Object
46
+ }[];
47
+ // don't use space in classnames
48
+ export const dropDownListClasses: DropDownListClassList = {
49
+ root: 'e-dropdownlist',
50
+ hover: dropDownBaseClasses.hover,
51
+ selected: dropDownBaseClasses.selected,
52
+ rtl: dropDownBaseClasses.rtl,
53
+ li: dropDownBaseClasses.li,
54
+ disable: dropDownBaseClasses.disabled,
55
+ base: dropDownBaseClasses.root,
56
+ focus: dropDownBaseClasses.focus,
57
+ content: dropDownBaseClasses.content,
58
+ input: 'e-input-group',
59
+ inputFocus: 'e-input-focus',
60
+ icon: 'e-input-group-icon e-ddl-icon',
61
+ iconAnimation: 'e-icon-anim',
62
+ value: 'e-input-value',
63
+ device: 'e-ddl-device',
64
+ backIcon: 'e-input-group-icon e-back-icon e-icons',
65
+ filterBarClearIcon: 'e-input-group-icon e-clear-icon e-icons',
66
+ filterInput: 'e-input-filter',
67
+ filterParent: 'e-filter-parent',
68
+ mobileFilter: 'e-ddl-device-filter',
69
+ footer: 'e-ddl-footer',
70
+ header: 'e-ddl-header',
71
+ clearIcon: 'e-clear-icon',
72
+ clearIconHide: 'e-clear-icon-hide',
73
+ popupFullScreen: 'e-popup-full-page',
74
+ disableIcon: 'e-ddl-disable-icon',
75
+ hiddenElement: 'e-ddl-hidden',
76
+ virtualList: 'e-list-item e-virtual-list',
77
+ };
78
+
79
+
80
+ const inputObject: InputObject = {
81
+ container: null,
82
+ buttons: []
83
+ };
84
+
85
+ /**
86
+ * The DropDownList component contains a list of predefined values from which you can
87
+ * choose a single value.
88
+ * ```html
89
+ * <input type="text" tabindex="1" id="list"> </input>
90
+ * ```
91
+ * ```typescript
92
+ * let dropDownListObj:DropDownList = new DropDownList();
93
+ * dropDownListObj.appendTo("#list");
94
+ * ```
95
+ */
96
+
97
+ @NotifyPropertyChanges
98
+ export class DropDownList extends DropDownBase implements IInput {
99
+ protected inputWrapper: InputObject;
100
+ protected inputElement: HTMLInputElement;
101
+ private valueTempElement: HTMLSpanElement;
102
+ private listObject: HTMLElement;
103
+ private header: HTMLElement;
104
+ private footer: HTMLElement;
105
+ protected selectedLI: HTMLElement;
106
+ protected previousSelectedLI: HTMLElement;
107
+ protected previousItemData: { [key: string]: Object } | string | number | boolean;
108
+ private listHeight: string;
109
+ private listItemHeight: number;
110
+ private skeletonCount: number = 32;
111
+ protected hiddenElement: HTMLSelectElement;
112
+ protected isPopupOpen: boolean;
113
+ private isDocumentClick: boolean;
114
+ protected isInteracted: boolean;
115
+ private isFilterFocus: boolean;
116
+ protected beforePopupOpen: boolean;
117
+ protected initial: boolean;
118
+ private initRemoteRender: boolean;
119
+ private searchBoxHeight: number;
120
+ private popupObj: Popup;
121
+ private popupContentElement: HTMLElement;
122
+ private backIconElement: Element;
123
+ private clearIconElement: Element;
124
+ private containerStyle: ClientRect;
125
+ protected previousValue: string | number | boolean;
126
+ protected activeIndex: number;
127
+ protected filterInput: HTMLInputElement;
128
+ private searchKeyModule: KeyboardEvents;
129
+ private tabIndex: string;
130
+ private isNotSearchList: boolean;
131
+ protected isTyped: boolean;
132
+ protected isSelected: boolean;
133
+ protected preventFocus: boolean;
134
+ protected preventAutoFill: boolean;
135
+ protected queryString: string;
136
+ protected isValidKey: boolean;
137
+ protected typedString: string;
138
+ protected isEscapeKey: boolean;
139
+ private isPreventBlur: boolean;
140
+ protected isTabKey: boolean;
141
+ private actionCompleteData: ActionCompleteData;
142
+ private actionData: ActionCompleteData;
143
+ protected prevSelectPoints: { [key: string]: number };
144
+ protected isSelectCustom: boolean;
145
+ protected isDropDownClick: boolean;
146
+ protected preventAltUp: boolean;
147
+ private searchKeyEvent: KeyboardEventArgs;
148
+ private keyboardEvent: KeyboardEventArgs;
149
+ private filterInputObj: InputObject;
150
+ protected spinnerElement: HTMLElement;
151
+ protected keyConfigure: { [key: string]: string };
152
+ protected isCustomFilter: boolean;
153
+ private isSecondClick: boolean;
154
+ protected isListSearched: boolean = false;
155
+ protected preventChange: boolean = false;
156
+ protected isAngular: boolean = false;
157
+ protected selectedElementID: string;
158
+ protected itemCount: number = 10;
159
+ private virtualListHeight: number = 0;
160
+ private virtualItemCount: number;
161
+ private isVirtualScrolling: boolean = false;
162
+ private observer: VirtualScroll;
163
+ protected isPreventScrollAction: boolean = false;
164
+ private scrollPreStartIndex: number = 0;
165
+ private isScrollActionTriggered: boolean = false;
166
+ protected previousStartIndex: number = 0;
167
+ private isMouseScrollAction: boolean = false;
168
+ private isKeyBoardAction: boolean = false;
169
+ private isUpwardScrolling: boolean = false;
170
+ private containerElementRect: ClientRect;
171
+ protected previousEndIndex: number;
172
+ private previousInfo: VirtualInfo;
173
+ protected startIndex: number = 0;
174
+ private currentPageNumber: number = 0;
175
+ private pageCount: number = 0;
176
+ private isPreventKeyAction: boolean = false;
177
+ protected virtualItemStartIndex: number;
178
+ private virtualItemEndIndex: number;
179
+ private generatedDataObject: GeneratedData = {};
180
+ private preselectedIndex: number;
181
+ private isTouched: boolean = false;
182
+ protected virtualListInfo: VirtualInfo = {
183
+ currentPageNumber: null,
184
+ direction: null,
185
+ sentinelInfo: {},
186
+ offsets: {},
187
+ startIndex: 0,
188
+ endIndex: 0,
189
+ };
190
+ protected viewPortInfo: VirtualInfo = {
191
+ currentPageNumber: null,
192
+ direction: null,
193
+ sentinelInfo: {},
194
+ offsets: {},
195
+ startIndex: 0,
196
+ endIndex: 0,
197
+ };
198
+ private selectedValueInfo: VirtualInfo = {
199
+ currentPageNumber: null,
200
+ direction: null,
201
+ sentinelInfo: {},
202
+ offsets: {},
203
+ startIndex: 0,
204
+ endIndex: 0,
205
+ };
206
+
207
+ /**
208
+ * Sets CSS classes to the root element of the component that allows customization of appearance.
209
+ *
210
+ * @default null
211
+ */
212
+ @Property(null)
213
+ public cssClass: string;
214
+ /**
215
+ * Specifies the width of the component. By default, the component width sets based on the width of
216
+ * its parent container. You can also set the width in pixel values.
217
+ *
218
+ * @default '100%'
219
+ * @aspType string
220
+ */
221
+ @Property('100%')
222
+ public width: string | number;
223
+ /**
224
+ * Specifies a value that indicates whether the component is enabled or not.
225
+ *
226
+ * @default true
227
+ * @deprecated
228
+ */
229
+ @Property(true)
230
+ public enabled: boolean;
231
+ /**
232
+ * Enable or disable persisting component's state between page reloads.
233
+ * If enabled, following list of states will be persisted.
234
+ * 1. value
235
+ *
236
+ * @default false
237
+ * @deprecated
238
+ */
239
+ @Property(false)
240
+ public enablePersistence: boolean;
241
+ /**
242
+ * Specifies the height of the popup list.
243
+ * > For more details about the popup configuration refer to
244
+ * [`Popup Configuration`](../../drop-down-list/getting-started#configure-the-popup-list) documentation.
245
+ *
246
+ * @default '300px'
247
+ * @aspType string
248
+ */
249
+ @Property('300px')
250
+ public popupHeight: string | number;
251
+ /**
252
+ * Specifies the width of the popup list. By default, the popup width sets based on the width of
253
+ * the component.
254
+ * > For more details about the popup configuration refer to
255
+ * [`Popup Configuration`](../../drop-down-list/getting-started#configure-the-popup-list) documentation.
256
+ *
257
+ * @default '100%'
258
+ * @aspType string
259
+ */
260
+ @Property('100%')
261
+ public popupWidth: string | number;
262
+ /**
263
+ * Specifies a short hint that describes the expected value of the DropDownList component.
264
+ *
265
+ * @default null
266
+ */
267
+ @Property(null)
268
+ public placeholder: string;
269
+ /**
270
+ * Accepts the value to be displayed as a watermark text on the filter bar.
271
+ *
272
+ * @default null
273
+ */
274
+ @Property(null)
275
+ public filterBarPlaceholder: string;
276
+ /**
277
+ * Allows additional HTML attributes such as title, name, etc., and
278
+ * accepts n number of attributes in a key-value pair format.
279
+ *
280
+ * {% codeBlock src='dropdownlist/htmlAttributes/index.md' %}{% endcodeBlock %}
281
+ *
282
+ * @default {}
283
+ */
284
+ @Property({})
285
+ public htmlAttributes: { [key: string]: string };
286
+ /**
287
+ * Accepts the external `Query`
288
+ * that execute along with data processing.
289
+ *
290
+ * {% codeBlock src='dropdownlist/query/index.md' %}{% endcodeBlock %}
291
+ *
292
+ * @default null
293
+ * @deprecated
294
+ */
295
+ @Property(null)
296
+ public query: Query;
297
+ /**
298
+ * Accepts the template design and assigns it to the selected list item in the input element of the component.
299
+ * For more details about the available template options refer to
300
+ * [`Template`](../../drop-down-list/templates) documentation.
301
+ *
302
+ * We have built-in `template engine`
303
+ * which provides options to compile template string into a executable function.
304
+ * For EX: We have expression evolution as like ES6 expression string literals.
305
+ *
306
+ * @default null
307
+ * @aspType string
308
+ */
309
+ @Property(null)
310
+ public valueTemplate: string | Function;
311
+ /**
312
+ * Accepts the template design and assigns it to the header container of the popup list.
313
+ * > For more details about the available template options refer to [`Template`](../../drop-down-list/templates) documentation.
314
+ *
315
+ * @default null
316
+ * @aspType string
317
+ */
318
+ @Property(null)
319
+ public headerTemplate: string | Function;
320
+ /**
321
+ * Accepts the template design and assigns it to the footer container of the popup list.
322
+ * > For more details about the available template options refer to [`Template`](../../drop-down-list/templates) documentation.
323
+ *
324
+ * @default null
325
+ * @aspType string
326
+ */
327
+ @Property(null)
328
+ public footerTemplate: string | Function;
329
+ /**
330
+ * When allowFiltering is set to true, show the filter bar (search box) of the component.
331
+ * The filter action retrieves matched items through the `filtering` event based on
332
+ * the characters typed in the search TextBox.
333
+ *
334
+ * If no match is found, the value of the `noRecordsTemplate` property will be displayed.
335
+ * > For more details about the filtering refer to [`Filtering`](../../drop-down-list/filtering) documentation.
336
+ *
337
+ * {% codeBlock src="dropdownlist/allow-filtering-api/index.ts" %}{% endcodeBlock %}
338
+ *
339
+ * {% codeBlock src="dropdownlist/allow-filtering-api/index.html" %}{% endcodeBlock %}
340
+ *
341
+ * @default false
342
+ */
343
+ @Property(false)
344
+ public allowFiltering: boolean;
345
+ /**
346
+ * When set to true, the user interactions on the component are disabled.
347
+ *
348
+ * @default false
349
+ */
350
+ @Property(false)
351
+ public readonly: boolean;
352
+ /**
353
+ * Defines whether to enable virtual scrolling in the component.
354
+ *
355
+ * @default false
356
+ */
357
+ @Property(false)
358
+ public enableVirtualization: boolean;
359
+ /**
360
+ * Gets or sets the display text of the selected item in the component.
361
+ *
362
+ * @default null
363
+ */
364
+ @Property(null)
365
+ public text: string;
366
+ /**
367
+ * Gets or sets the value of the selected item in the component.
368
+ *
369
+ * @default null
370
+ * @isGenericType true
371
+ */
372
+ @Property(null)
373
+ public value: number | string | boolean;
374
+ /**
375
+ * Gets or sets the index of the selected item in the component.
376
+ *
377
+ * {% codeBlock src="dropdownlist/index-api/index.ts" %}{% endcodeBlock %}
378
+ *
379
+ * {% codeBlock src="dropdownlist/index-api/index.html" %}{% endcodeBlock %}
380
+ *
381
+ * @default null
382
+ */
383
+ @Property(null)
384
+ public index: number;
385
+ /**
386
+ * Specifies whether to display the floating label above the input element.
387
+ * Possible values are:
388
+ * * Never: The label will never float in the input when the placeholder is available.
389
+ * * Always: The floating label will always float above the input.
390
+ * * Auto: The floating label will float above the input after focusing or entering a value in the input.
391
+ *
392
+ * {% codeBlock src="dropdownlist/float-label-type-api/index.ts" %}{% endcodeBlock %}
393
+ *
394
+ * {% codeBlock src="dropdownlist/float-label-type-api/index.html" %}{% endcodeBlock %}
395
+ *
396
+ * @default Syncfusion.EJ2.Inputs.FloatLabelType.Never
397
+ * @aspType Syncfusion.EJ2.Inputs.FloatLabelType
398
+ * @isEnumeration true
399
+ */
400
+ @Property('Never')
401
+ public floatLabelType: FloatLabelType;
402
+ /**
403
+ * Specifies whether to show or hide the clear button.
404
+ * When the clear button is clicked, `value`, `text`, and `index` properties are reset to null.
405
+ *
406
+ * @default false
407
+ */
408
+ @Property(false)
409
+ public showClearButton: boolean;
410
+ /**
411
+ * Triggers on typing a character in the filter bar when the
412
+ * [`allowFiltering`](./#allowfiltering)
413
+ * is enabled.
414
+ * > For more details about the filtering refer to [`Filtering`](../../drop-down-list/filtering) documentation.
415
+ *
416
+ * @event filtering
417
+ */
418
+ @Event()
419
+ public filtering: EmitType<FilteringEventArgs>;
420
+
421
+ /**
422
+ * Triggers when an item in a popup is selected or when the model value is changed by user.
423
+ * Use change event to
424
+ * [`Configure the Cascading DropDownList`](../../drop-down-list/how-to/cascading)
425
+ *
426
+ * @event change
427
+ */
428
+ @Event()
429
+ public change: EmitType<ChangeEventArgs>;
430
+ /**
431
+ * Triggers when the popup before opens.
432
+ *
433
+ * @event beforeOpen
434
+ */
435
+ @Event()
436
+ public beforeOpen: EmitType<Object>;
437
+ /**
438
+ * Triggers when the popup opens.
439
+ *
440
+ * @event open
441
+ */
442
+ @Event()
443
+ public open: EmitType<PopupEventArgs>;
444
+ /**
445
+ * Triggers when the popup is closed.
446
+ *
447
+ * @event close
448
+ */
449
+ @Event()
450
+ public close: EmitType<PopupEventArgs>;
451
+ /**
452
+ * Triggers when focus moves out from the component.
453
+ *
454
+ * @event blur
455
+ */
456
+ @Event()
457
+ public blur: EmitType<Object>;
458
+ /**
459
+ * Triggers when the component is focused.
460
+ *
461
+ * @event focus
462
+ */
463
+ @Event()
464
+ public focus: EmitType<Object>;
465
+
466
+ /**
467
+ * * Constructor for creating the DropDownList component.
468
+ *
469
+ * @param {DropDownListModel} options - Specifies the DropDownList model.
470
+ * @param {string | HTMLElement} element - Specifies the element to render as component.
471
+ * @private
472
+ */
473
+ public constructor(options?: DropDownListModel, element?: string | HTMLElement) {
474
+ super(options, element);
475
+ }
476
+
477
+ /**
478
+ * Initialize the event handler.
479
+ *
480
+ * @private
481
+ * @returns {void}
482
+ */
483
+ protected preRender(): void {
484
+ this.valueTempElement = null;
485
+ this.element.style.opacity = '0';
486
+ this.initializeData();
487
+ super.preRender();
488
+ this.activeIndex = this.index;
489
+ this.queryString = '';
490
+ }
491
+
492
+ private initializeData(): void {
493
+ this.isPopupOpen = false;
494
+ this.isDocumentClick = false;
495
+ this.isInteracted = false;
496
+ this.isFilterFocus = false;
497
+ this.beforePopupOpen = false;
498
+ this.initial = true;
499
+ this.initRemoteRender = false;
500
+ this.isNotSearchList = false;
501
+ this.isTyped = false;
502
+ this.isSelected = false;
503
+ this.preventFocus = false;
504
+ this.preventAutoFill = false;
505
+ this.isValidKey = false;
506
+ this.typedString = '';
507
+ this.isEscapeKey = false;
508
+ this.isPreventBlur = false;
509
+ this.isTabKey = false;
510
+ this.actionCompleteData = { isUpdated: false };
511
+ this.actionData = { isUpdated: false };
512
+ this.prevSelectPoints = {};
513
+ this.isSelectCustom = false;
514
+ this.isDropDownClick = false;
515
+ this.preventAltUp = false;
516
+ this.isCustomFilter = false;
517
+ this.isSecondClick = false;
518
+ this.previousValue = null;
519
+ this.keyConfigure = {
520
+ tab: 'tab',
521
+ enter: '13',
522
+ escape: '27',
523
+ end: '35',
524
+ home: '36',
525
+ down: '40',
526
+ up: '38',
527
+ pageUp: '33',
528
+ pageDown: '34',
529
+ open: 'alt+40',
530
+ close: 'shift+tab',
531
+ hide: 'alt+38',
532
+ space: '32'
533
+ };
534
+ this.viewPortInfo = {
535
+ currentPageNumber: null,
536
+ direction: null,
537
+ sentinelInfo: {},
538
+ offsets: {},
539
+ startIndex: 0,
540
+ endIndex: this.itemCount,
541
+ };
542
+ }
543
+
544
+ protected setZIndex(): void {
545
+ if (this.popupObj) {
546
+ this.popupObj.setProperties({ 'zIndex': this.zIndex });
547
+ }
548
+ }
549
+
550
+ public requiredModules(): ModuleDeclaration[] {
551
+ const modules: ModuleDeclaration[] = [];
552
+ if (this.enableVirtualization) {
553
+ modules.push({ args: [this], member: 'VirtualScroll' });
554
+ }
555
+ return modules;
556
+ }
557
+
558
+ protected renderList(e?: MouseEvent | KeyboardEventArgs | TouchEvent, isEmptyData?: boolean): void {
559
+ super.render(e, isEmptyData);
560
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
561
+ this.totalItemCount = this.dataSource && (this.dataSource as any).length ? (this.dataSource as any).length : 0;
562
+ this.unWireListEvents();
563
+ this.wireListEvents();
564
+ }
565
+
566
+ private floatLabelChange(): void {
567
+ if (this.getModuleName() === 'dropdownlist' && this.floatLabelType === 'Auto') {
568
+ const floatElement: HTMLElement = <HTMLElement>this.inputWrapper.container.querySelector('.e-float-text');
569
+ if (this.inputElement.value !== '' || this.isInteracted) {
570
+ classList(floatElement, ['e-label-top'], ['e-label-bottom']);
571
+ } else {
572
+ classList(floatElement, ['e-label-bottom'], ['e-label-top']);
573
+ }
574
+ }
575
+ }
576
+
577
+ protected resetHandler(e: MouseEvent): void {
578
+ e.preventDefault();
579
+ this.clearAll(e);
580
+ if (this.enableVirtualization) {
581
+ this.list.scrollTop = 0;
582
+ this.virtualListInfo = null;
583
+ this.previousStartIndex = 0;
584
+ this.previousEndIndex = 0;
585
+ }
586
+ }
587
+
588
+ protected resetFocusElement(): void {
589
+ this.removeHover();
590
+ this.removeSelection();
591
+ this.removeFocus();
592
+ this.list.scrollTop = 0;
593
+ if (this.getModuleName() !== 'autocomplete' && !isNullOrUndefined(this.ulElement)) {
594
+ let li: Element = this.ulElement.querySelector('.' + dropDownListClasses.li);
595
+ if(this.enableVirtualization){
596
+ li = this.liCollections[this.skeletonCount];
597
+ }
598
+ if (li) {
599
+ li.classList.add(dropDownListClasses.focus);
600
+ }
601
+ }
602
+ }
603
+
604
+ protected clearAll(e?: MouseEvent | KeyboardEventArgs | TouchEvent, properties?: DropDownListModel): void {
605
+ this.previousItemData = (!isNullOrUndefined(this.itemData)) ? this.itemData : null;
606
+ if (isNullOrUndefined(properties) || (!isNullOrUndefined(properties) &&
607
+ (isNullOrUndefined(properties.dataSource) ||
608
+ (!(properties.dataSource instanceof DataManager) && properties.dataSource.length === 0)))) {
609
+ this.isActive = true;
610
+ this.resetSelection(properties);
611
+ }
612
+ const dataItem: { [key: string]: string } = this.getItemData();
613
+ if (this.previousValue === dataItem.value) {
614
+ return;
615
+ }
616
+ this.onChangeEvent(e);
617
+ this.checkAndResetCache();
618
+ if (this.enableVirtualization) {
619
+ this.updateInitialData();
620
+ }
621
+ }
622
+
623
+ private resetSelection(properties?: DropDownListModel): void {
624
+ if (this.list) {
625
+ if ((!isNullOrUndefined(properties) &&
626
+ (isNullOrUndefined(properties.dataSource) ||
627
+ (!(properties.dataSource instanceof DataManager) && properties.dataSource.length === 0)))) {
628
+ this.selectedLI = null;
629
+ this.actionCompleteData.isUpdated = false;
630
+ this.actionCompleteData.ulElement = null;
631
+ this.actionCompleteData.list = null;
632
+ this.resetList(properties.dataSource);
633
+ } else {
634
+ if (this.allowFiltering && this.getModuleName() !== 'autocomplete'
635
+ && !isNullOrUndefined(this.actionCompleteData.ulElement) && !isNullOrUndefined(this.actionCompleteData.list) &&
636
+ this.actionCompleteData.list.length > 0) {
637
+ this.onActionComplete(this.actionCompleteData.ulElement.cloneNode(true) as HTMLElement, this.actionCompleteData.list);
638
+ }
639
+ this.resetFocusElement();
640
+ }
641
+ }
642
+ if (!isNullOrUndefined(this.hiddenElement)) {
643
+ this.hiddenElement.innerHTML = '';
644
+ }
645
+ if (!isNullOrUndefined(this.inputElement)) {
646
+ this.inputElement.value = '';
647
+ }
648
+ this.value = null;
649
+ this.itemData = null;
650
+ this.text = null;
651
+ this.index = null;
652
+ this.activeIndex = null;
653
+ this.item = null;
654
+ this.queryString = '';
655
+ if (this.valueTempElement) {
656
+ detach(this.valueTempElement);
657
+ this.inputElement.style.display = 'block';
658
+ this.valueTempElement = null;
659
+ }
660
+ this.setSelection(null, null);
661
+ this.isSelectCustom = false;
662
+ this.updateIconState();
663
+ this.cloneElements();
664
+ }
665
+ private setHTMLAttributes(): void {
666
+ if (Object.keys(this.htmlAttributes).length) {
667
+ for (const htmlAttr of Object.keys(this.htmlAttributes)) {
668
+ if (htmlAttr === 'class') {
669
+ const updatedClassValue: string = (this.htmlAttributes[`${htmlAttr}`].replace(/\s+/g, ' ')).trim();
670
+ if (updatedClassValue !== '') {
671
+ addClass([this.inputWrapper.container], updatedClassValue.split(' '));
672
+ }
673
+ } else if (htmlAttr === 'disabled' && this.htmlAttributes[`${htmlAttr}`] === 'disabled') {
674
+ this.enabled = false;
675
+ this.setEnable();
676
+ } else if (htmlAttr === 'readonly' && !isNullOrUndefined(this.htmlAttributes[`${htmlAttr}`])) {
677
+ this.readonly = true;
678
+ this.dataBind();
679
+ } else if (htmlAttr === 'style') {
680
+ this.inputWrapper.container.setAttribute('style', this.htmlAttributes[`${htmlAttr}`]);
681
+ } else if (htmlAttr === 'aria-label') {
682
+ if ((this.getModuleName() === 'autocomplete' || this.getModuleName() === 'combobox') && !this.readonly) {
683
+ this.inputElement.setAttribute('aria-label', this.htmlAttributes[`${htmlAttr}`]);
684
+ }
685
+ else if (this.getModuleName() === 'dropdownlist') {
686
+ this.inputWrapper.container.setAttribute('aria-label', this.htmlAttributes[`${htmlAttr}`]);
687
+ }
688
+ } else {
689
+ const defaultAttr: string[] = ['title', 'id', 'placeholder',
690
+ 'role', 'autocomplete', 'autocapitalize', 'spellcheck', 'minlength', 'maxlength'];
691
+ const validateAttr: string[] = ['name', 'required'];
692
+ if (this.getModuleName() === 'autocomplete' || this.getModuleName() === 'combobox') {
693
+ defaultAttr.push('tabindex');
694
+ }
695
+ if (validateAttr.indexOf(htmlAttr) > -1 || htmlAttr.indexOf('data') === 0) {
696
+ this.hiddenElement.setAttribute(htmlAttr, this.htmlAttributes[`${htmlAttr}`]);
697
+ } else if (defaultAttr.indexOf(htmlAttr) > -1) {
698
+ if (htmlAttr === 'placeholder') {
699
+ Input.setPlaceholder(this.htmlAttributes[`${htmlAttr}`], this.inputElement);
700
+ } else {
701
+ this.inputElement.setAttribute(htmlAttr, this.htmlAttributes[`${htmlAttr}`]);
702
+ }
703
+ } else {
704
+ this.inputWrapper.container.setAttribute(htmlAttr, this.htmlAttributes[`${htmlAttr}`]);
705
+ }
706
+ }
707
+ }
708
+ }
709
+ if (this.getModuleName() === 'autocomplete' || this.getModuleName() === 'combobox') {
710
+ this.inputWrapper.container.removeAttribute('tabindex');
711
+ }
712
+ }
713
+
714
+ protected getAriaAttributes(): { [key: string]: string } {
715
+ return {
716
+ 'aria-disabled': 'false',
717
+ 'role': 'combobox',
718
+ 'aria-expanded': 'false',
719
+ 'aria-live': 'polite',
720
+ 'aria-labelledby': this.hiddenElement.id
721
+ };
722
+ }
723
+
724
+ protected setEnableRtl(): void {
725
+ Input.setEnableRtl(this.enableRtl, [this.inputElement.parentElement]);
726
+ if (this.popupObj) {
727
+ this.popupObj.enableRtl = this.enableRtl;
728
+ this.popupObj.dataBind();
729
+ }
730
+ }
731
+
732
+ private setEnable(): void {
733
+ Input.setEnabled(this.enabled, this.inputElement);
734
+ if (this.enabled) {
735
+ removeClass([this.inputWrapper.container], dropDownListClasses.disable);
736
+ this.inputElement.setAttribute('aria-disabled', 'false');
737
+ this.targetElement().setAttribute('tabindex', this.tabIndex);
738
+ } else {
739
+ this.hidePopup();
740
+ addClass([this.inputWrapper.container], dropDownListClasses.disable);
741
+ this.inputElement.setAttribute('aria-disabled', 'true');
742
+ this.targetElement().tabIndex = -1;
743
+ }
744
+ }
745
+ /**
746
+ * Get the properties to be maintained in the persisted state.
747
+ *
748
+ * @returns {string} Returns the persisted data of the component.
749
+ */
750
+ protected getPersistData(): string {
751
+ return this.addOnPersist(['value']);
752
+ }
753
+
754
+ protected getLocaleName(): string {
755
+ return 'drop-down-list';
756
+ }
757
+
758
+ private preventTabIndex(element: HTMLElement): void {
759
+ if (this.getModuleName() === 'dropdownlist') {
760
+ element.tabIndex = -1;
761
+ }
762
+ }
763
+
764
+ protected targetElement(): HTMLElement | HTMLInputElement {
765
+ return !isNullOrUndefined(this.inputWrapper) ? this.inputWrapper.container : null;
766
+ }
767
+
768
+ protected getNgDirective(): string {
769
+ return 'EJS-DROPDOWNLIST';
770
+ }
771
+
772
+ protected getElementByText(text: string): Element {
773
+ return this.getElementByValue(this.getValueByText(text));
774
+ }
775
+
776
+ protected getElementByValue(value: string | number | boolean): Element {
777
+ let item: Element;
778
+ const listItems: Element[] = this.getItems();
779
+ for (const liItem of listItems) {
780
+ if (this.getFormattedValue(liItem.getAttribute('data-value')) === value) {
781
+ item = liItem;
782
+ break;
783
+ }
784
+ }
785
+ return item;
786
+ }
787
+
788
+ private initValue(): void {
789
+ this.viewPortInfo.startIndex = this.virtualItemStartIndex = 0;
790
+ this.viewPortInfo.endIndex = this.virtualItemEndIndex = this.itemCount;
791
+ this.renderList();
792
+ if (this.dataSource instanceof DataManager) {
793
+ this.initRemoteRender = true;
794
+ } else {
795
+ this.updateValues();
796
+ }
797
+ }
798
+
799
+ protected updateValues(): void {
800
+ this.selectedValueInfo = this.viewPortInfo;
801
+ if (!isNullOrUndefined(this.value)) {
802
+ this.setSelection(this.getElementByValue(this.value), null);
803
+ } else if (this.text && isNullOrUndefined(this.value)) {
804
+ const element: Element = this.getElementByText(this.text);
805
+ if (isNullOrUndefined(element)) {
806
+ this.setProperties({ text: null });
807
+ return;
808
+ } else {
809
+ this.setSelection(element, null);
810
+ }
811
+ } else {
812
+ this.setSelection(this.liCollections[this.activeIndex], null);
813
+ }
814
+ this.setHiddenValue();
815
+ Input.setValue(this.text, this.inputElement, this.floatLabelType, this.showClearButton);
816
+ }
817
+
818
+ protected onBlurHandler(e: MouseEvent): void {
819
+ if (!this.enabled) {
820
+ return;
821
+ }
822
+ const target: HTMLElement = <HTMLElement>e.relatedTarget;
823
+ const currentTarget: HTMLElement = <HTMLElement>e.target;
824
+ const isPreventBlur: boolean = this.isPreventBlur;
825
+ this.isPreventBlur = false;
826
+ //IE 11 - issue
827
+ if (isPreventBlur && !this.isDocumentClick && this.isPopupOpen && (!isNullOrUndefined(currentTarget) ||
828
+ !this.isFilterLayout() && isNullOrUndefined(target))) {
829
+ if (this.getModuleName() === 'dropdownlist' && this.allowFiltering && this.isPopupOpen) {
830
+ this.filterInput.focus();
831
+ } else {
832
+ this.targetElement().focus();
833
+ }
834
+ return;
835
+ }
836
+ if (this.isDocumentClick || (!isNullOrUndefined(this.popupObj)
837
+ && document.body.contains(this.popupObj.element) &&
838
+ this.popupObj.element.classList.contains(dropDownListClasses.mobileFilter))) {
839
+ if (!this.beforePopupOpen) {
840
+ this.isDocumentClick = false;
841
+ }
842
+ return;
843
+ }
844
+ if (((this.getModuleName() === 'dropdownlist' && !this.isFilterFocus && target !== this.inputElement)
845
+ && (document.activeElement !== target || (document.activeElement === target &&
846
+ currentTarget.classList.contains(dropDownListClasses.inputFocus)))) ||
847
+ (isNullOrUndefined(target) && this.getModuleName() === 'dropdownlist' && this.allowFiltering &&
848
+ currentTarget !== this.inputWrapper.container) || this.getModuleName() !== 'dropdownlist' &&
849
+ !this.inputWrapper.container.contains(target) || this.isTabKey) {
850
+ this.isDocumentClick = this.isPopupOpen ? true : false;
851
+ this.focusOutAction(e);
852
+ this.isTabKey = false;
853
+ }
854
+ if (this.isRequested && !this.isPopupOpen && !this.isPreventBlur) {
855
+ this.isActive = false;
856
+ this.beforePopupOpen = false;
857
+ }
858
+ }
859
+
860
+ protected focusOutAction(e?: MouseEvent | KeyboardEventArgs): void {
861
+ this.isInteracted = false;
862
+ this.focusOut(e);
863
+ this.onFocusOut();
864
+ }
865
+
866
+ protected onFocusOut(): void {
867
+ if (!this.enabled) {
868
+ return;
869
+ }
870
+ if (this.isSelected) {
871
+ this.isSelectCustom = false;
872
+ this.onChangeEvent(null);
873
+ }
874
+ this.floatLabelChange();
875
+ this.dispatchEvent(this.hiddenElement as HTMLElement, 'change');
876
+ if (this.getModuleName() === 'dropdownlist' && this.element.tagName !== 'INPUT') {
877
+ this.dispatchEvent(this.inputElement as HTMLElement, 'blur');
878
+ }
879
+ if (this.inputWrapper.clearButton) {
880
+ addClass([this.inputWrapper.clearButton], dropDownListClasses.clearIconHide);
881
+ }
882
+ this.trigger('blur');
883
+ }
884
+
885
+ protected onFocus(e?: FocusEvent | MouseEvent | KeyboardEvent | TouchEvent): void {
886
+ if (!this.isInteracted) {
887
+ this.isInteracted = true;
888
+ const args: FocusEventArgs = { isInteracted: e ? true : false, event: e };
889
+ this.trigger('focus', args);
890
+ }
891
+ this.updateIconState();
892
+ }
893
+
894
+ private resetValueHandler(e: Event): void {
895
+ const formElement: HTMLFormElement = closest(this.inputElement, 'form') as HTMLFormElement;
896
+ if (formElement && e.target === formElement) {
897
+ const val: string = (this.element.tagName === this.getNgDirective()) ? null : this.inputElement.getAttribute('value');
898
+ this.text = val;
899
+ }
900
+ }
901
+
902
+ protected wireEvent(): void {
903
+ EventHandler.add(this.inputWrapper.container, 'mousedown', this.dropDownClick, this);
904
+ EventHandler.add(this.inputWrapper.container, 'focus', this.focusIn, this);
905
+ EventHandler.add(this.inputWrapper.container, 'keypress', this.onSearch, this);
906
+ EventHandler.add(<HTMLElement & Window>window, 'resize',this.windowResize, this);
907
+ this.bindCommonEvent();
908
+ }
909
+
910
+ protected bindCommonEvent(): void {
911
+ EventHandler.add(this.targetElement(), 'blur', this.onBlurHandler, this);
912
+ const formElement: HTMLFormElement = closest(this.inputElement, 'form') as HTMLFormElement;
913
+ if (formElement) {
914
+ EventHandler.add(formElement, 'reset', this.resetValueHandler, this);
915
+ }
916
+ if (!Browser.isDevice) {
917
+ this.keyboardModule = new KeyboardEvents(
918
+ this.targetElement(), {
919
+ keyAction: this.keyActionHandler.bind(this), keyConfigs: this.keyConfigure, eventName: 'keydown'
920
+ });
921
+ } else {
922
+ this.keyboardModule = new KeyboardEvents(
923
+ this.targetElement(), {
924
+ keyAction: this.mobileKeyActionHandler.bind(this), keyConfigs: this.keyConfigure, eventName: 'keydown'
925
+ });
926
+ }
927
+ this.bindClearEvent();
928
+ }
929
+
930
+ protected windowResize(): void {
931
+ if (this.isPopupOpen) {
932
+ this.popupObj.refreshPosition(this.inputWrapper.container);
933
+ }
934
+ }
935
+
936
+ private bindClearEvent(): void {
937
+ if (this.showClearButton) {
938
+ EventHandler.add(this.inputWrapper.clearButton, 'mousedown', this.resetHandler, this);
939
+ }
940
+ }
941
+
942
+
943
+ protected unBindCommonEvent(): void {
944
+ if (!isNullOrUndefined(this.inputWrapper) && this.targetElement()) {
945
+ EventHandler.remove(this.targetElement(), 'blur', this.onBlurHandler);
946
+ }
947
+ const formElement: HTMLFormElement = this.inputElement && closest(this.inputElement, 'form') as HTMLFormElement;
948
+ if (formElement) {
949
+ EventHandler.remove(formElement, 'reset', this.resetValueHandler);
950
+ }
951
+ if (!Browser.isDevice) {
952
+ this.keyboardModule.destroy();
953
+ }
954
+ if (this.showClearButton) {
955
+ EventHandler.remove(this.inputWrapper.clearButton, 'mousedown', this.resetHandler);
956
+ }
957
+ }
958
+
959
+ protected updateIconState(): void {
960
+ if (this.showClearButton) {
961
+ if (this.inputElement.value !== '' && !this.readonly) {
962
+ removeClass([this.inputWrapper.clearButton], dropDownListClasses.clearIconHide);
963
+ } else {
964
+ addClass([this.inputWrapper.clearButton], dropDownListClasses.clearIconHide);
965
+ }
966
+ }
967
+ }
968
+ /**
969
+ * Event binding for list
970
+ *
971
+ * @returns {void}
972
+ */
973
+ private wireListEvents(): void {
974
+ if (!isNullOrUndefined(this.list)) {
975
+ EventHandler.add(this.list, 'click', this.onMouseClick, this);
976
+ EventHandler.add(this.list, 'mouseover', this.onMouseOver, this);
977
+ EventHandler.add(this.list, 'mouseout', this.onMouseLeave, this);
978
+ }
979
+ }
980
+
981
+ private onSearch(e: KeyboardEventArgs): void {
982
+ if (e.charCode !== 32 && e.charCode !== 13) {
983
+ if (this.list === undefined) {
984
+ this.renderList();
985
+ }
986
+ this.searchKeyEvent = e;
987
+ this.onServerIncrementalSearch(e);
988
+ }
989
+ }
990
+
991
+ private onServerIncrementalSearch(e: KeyboardEventArgs): void {
992
+ if (!this.isRequested && !isNullOrUndefined(this.list) &&
993
+ !isNullOrUndefined(this.list.querySelector('li')) && this.enabled && !this.readonly) {
994
+ this.incrementalSearch(e);
995
+ }
996
+ }
997
+
998
+ protected onMouseClick(e: MouseEvent): void {
999
+ const target: Element = <Element>e.target;
1000
+ this.keyboardEvent = null;
1001
+ const li: HTMLElement = <HTMLElement>closest(target, '.' + dropDownBaseClasses.li);
1002
+ if (!this.isValidLI(li)) {
1003
+ return;
1004
+ }
1005
+ this.setSelection(li, e);
1006
+ if (Browser.isDevice && this.isFilterLayout()) {
1007
+ history.back();
1008
+ } else {
1009
+ const delay: number = 100;
1010
+ this.closePopup(delay, e);
1011
+ }
1012
+ }
1013
+
1014
+ private onMouseOver(e: MouseEvent): void {
1015
+ const currentLi: HTMLElement = <HTMLElement>closest(<Element>e.target, '.' + dropDownBaseClasses.li);
1016
+ this.setHover(currentLi);
1017
+ }
1018
+
1019
+ private setHover(li: HTMLElement): void {
1020
+ if (this.enabled && this.isValidLI(li) && !li.classList.contains(dropDownBaseClasses.hover)) {
1021
+ this.removeHover();
1022
+ addClass([li], dropDownBaseClasses.hover);
1023
+ }
1024
+ }
1025
+
1026
+ private onMouseLeave(): void {
1027
+ this.removeHover();
1028
+ }
1029
+
1030
+ protected removeHover(): void {
1031
+ if (this.list) {
1032
+ const hoveredItem: Element[] = <NodeListOf<Element> & Element[]>this.list.querySelectorAll('.' + dropDownBaseClasses.hover);
1033
+ if (hoveredItem && hoveredItem.length) {
1034
+ removeClass(hoveredItem, dropDownBaseClasses.hover);
1035
+ }
1036
+ }
1037
+ }
1038
+
1039
+ protected isValidLI(li: Element | HTMLElement): boolean {
1040
+ return (li && li.hasAttribute('role') && li.getAttribute('role') === 'option');
1041
+ }
1042
+
1043
+ protected incrementalSearch(e: KeyboardEventArgs): void {
1044
+ if (this.liCollections.length > 0) {
1045
+ const li: Element =
1046
+ incrementalSearch(e.charCode, this.liCollections, this.activeIndex, true, this.element.id);
1047
+ if (!isNullOrUndefined(li)) {
1048
+ this.setSelection(li, e);
1049
+ this.setScrollPosition();
1050
+ }
1051
+ }
1052
+ }
1053
+ /**
1054
+ * Hides the spinner loader.
1055
+ *
1056
+ * @returns {void}
1057
+ */
1058
+ public hideSpinner(): void {
1059
+ if (!isNullOrUndefined(this.spinnerElement)) {
1060
+ hideSpinner(this.spinnerElement);
1061
+ removeClass([this.spinnerElement], dropDownListClasses.disableIcon);
1062
+ this.spinnerElement.innerHTML = '';
1063
+ this.spinnerElement = null;
1064
+ }
1065
+ }
1066
+ /**
1067
+ * Shows the spinner loader.
1068
+ *
1069
+ * @returns {void}
1070
+ */
1071
+ public showSpinner(): void {
1072
+ if (isNullOrUndefined(this.spinnerElement)) {
1073
+ this.spinnerElement = Browser.isDevice && !isNullOrUndefined(this.filterInputObj) && this.filterInputObj.buttons[1] ||
1074
+ !isNullOrUndefined(this.filterInputObj) && this.filterInputObj.buttons[0] || this.inputWrapper.buttons[0];
1075
+ addClass([this.spinnerElement], dropDownListClasses.disableIcon);
1076
+ createSpinner(
1077
+ {
1078
+ target: this.spinnerElement,
1079
+ width: Browser.isDevice ? '16px' : '14px'
1080
+ },
1081
+ this.createElement);
1082
+ showSpinner(this.spinnerElement);
1083
+ }
1084
+ }
1085
+ protected keyActionHandler(e: KeyboardEventArgs): void {
1086
+ if (!this.enabled) {
1087
+ return;
1088
+ }
1089
+ this.keyboardEvent = e;
1090
+ if (this.isPreventKeyAction && this.enableVirtualization) {
1091
+ e.preventDefault();
1092
+ }
1093
+ const preventAction: boolean = e.action === 'pageUp' || e.action === 'pageDown';
1094
+ const preventHomeEnd: boolean = this.getModuleName() !== 'dropdownlist' && (e.action === 'home' || e.action === 'end');
1095
+ this.isEscapeKey = e.action === 'escape';
1096
+ this.isTabKey = !this.isPopupOpen && e.action === 'tab';
1097
+ const isNavigation: boolean = (e.action === 'down' || e.action === 'up' || e.action === 'pageUp' || e.action === 'pageDown'
1098
+ || e.action === 'home' || e.action === 'end');
1099
+ if ((this.isEditTextBox() || preventAction || preventHomeEnd) && !this.isPopupOpen) {
1100
+ return;
1101
+ }
1102
+ if (!this.readonly) {
1103
+ const isTabAction: boolean = e.action === 'tab' || e.action === 'close';
1104
+ if (isNullOrUndefined(this.list) && !this.isRequested && !isTabAction && e.action !== 'escape') {
1105
+ this.searchKeyEvent = e;
1106
+ this.renderList(e);
1107
+ }
1108
+ if (isNullOrUndefined(this.list) || (!isNullOrUndefined(this.liCollections) &&
1109
+ isNavigation && this.liCollections.length === 0) || this.isRequested) {
1110
+ return;
1111
+ }
1112
+ if ((isTabAction && this.getModuleName() !== 'autocomplete') && this.isPopupOpen
1113
+ || e.action === 'escape') {
1114
+ e.preventDefault();
1115
+ }
1116
+ this.isSelected = e.action === 'escape' ? false : this.isSelected;
1117
+ this.isTyped = (isNavigation || e.action === 'escape') ? false : this.isTyped;
1118
+ switch (e.action) {
1119
+ case 'down':
1120
+ case 'up':
1121
+ this.updateUpDownAction(e);
1122
+ break;
1123
+ case 'pageUp':
1124
+ this.pageUpSelection(this.activeIndex - this.getPageCount(), e);
1125
+ e.preventDefault();
1126
+ break;
1127
+ case 'pageDown':
1128
+ this.pageDownSelection(this.activeIndex + this.getPageCount(), e);
1129
+ e.preventDefault();
1130
+ break;
1131
+ case 'home':
1132
+ this.isMouseScrollAction = true;
1133
+ this.updateHomeEndAction(e);
1134
+ break;
1135
+ case 'end':
1136
+ this.isMouseScrollAction = true;
1137
+ this.updateHomeEndAction(e);
1138
+ break;
1139
+ case 'space':
1140
+ if (this.getModuleName() === 'dropdownlist') {
1141
+ if (!this.beforePopupOpen) {
1142
+ this.showPopup();
1143
+ }
1144
+ }
1145
+ break;
1146
+ case 'open':
1147
+ this.showPopup(e);
1148
+ break;
1149
+ case 'hide':
1150
+ this.preventAltUp = this.isPopupOpen;
1151
+ this.hidePopup(e);
1152
+ this.focusDropDown(e);
1153
+ break;
1154
+ case 'enter':
1155
+ this.selectCurrentItem(e);
1156
+ break;
1157
+ case 'tab':
1158
+ this.selectCurrentValueOnTab(e);
1159
+ break;
1160
+ case 'escape':
1161
+ case 'close':
1162
+ if (this.isPopupOpen) {
1163
+ this.hidePopup(e);
1164
+ this.focusDropDown(e);
1165
+ }
1166
+ break;
1167
+ }
1168
+ }
1169
+ }
1170
+
1171
+ private updateUpDownAction(e: KeyboardEventArgs, isVirtualKeyAction?: boolean): void {
1172
+ if (this.allowFiltering && !this.enableVirtualization && this.getModuleName() !== 'autocomplete') {
1173
+ let value = this.getItemData().value;
1174
+ if (isNullOrUndefined(value)) {
1175
+ value = 'null';
1176
+ }
1177
+ let filterIndex: number = this.getIndexByValue(value);
1178
+ if (!isNullOrUndefined(filterIndex)) {
1179
+ this.activeIndex = filterIndex;
1180
+ }
1181
+ }
1182
+ const focusEle: Element = this.list.querySelector('.' + dropDownListClasses.focus);
1183
+ if (this.isSelectFocusItem(focusEle) && !isVirtualKeyAction) {
1184
+ this.setSelection(focusEle, e);
1185
+ if (this.enableVirtualization) {
1186
+ let selectedLiOffsetTop = this.virtualListInfo && this.virtualListInfo.startIndex ? this.selectedLI.offsetTop + (this.virtualListInfo.startIndex * this.selectedLI.offsetHeight) : this.selectedLI.offsetTop;
1187
+ this.list.scrollTop = selectedLiOffsetTop - (this.list.querySelectorAll('.e-virtual-list').length * this.selectedLI.offsetHeight);
1188
+ }
1189
+ } else if (!isNullOrUndefined(this.liCollections)) {
1190
+ let virtualIndex = this.activeIndex;
1191
+ let index: number = e.action === 'down' ? this.activeIndex + 1 : this.activeIndex - 1;
1192
+ index = isVirtualKeyAction ? virtualIndex : index;
1193
+ let startIndex: number = 0;
1194
+ if (this.getModuleName() === 'autocomplete') {
1195
+ startIndex = e.action === 'down' && isNullOrUndefined(this.activeIndex) ? 0 : this.liCollections.length - 1;
1196
+ index = index < 0 ? this.liCollections.length - 1 : index === this.liCollections.length ? 0 : index;
1197
+ }
1198
+ let nextItem: Element;
1199
+ if (this.getModuleName() !== 'autocomplete' || this.getModuleName() === 'autocomplete' && this.isPopupOpen) {
1200
+ if (!this.enableVirtualization) {
1201
+ nextItem = isNullOrUndefined(this.activeIndex) ? this.liCollections[startIndex as number]
1202
+ : this.liCollections[index as number];
1203
+ }
1204
+ else {
1205
+ if (!isVirtualKeyAction) {
1206
+ nextItem = isNullOrUndefined(this.activeIndex) ? this.liCollections[this.skeletonCount]
1207
+ : this.liCollections[index as number];
1208
+ nextItem = !isNullOrUndefined(nextItem) && !nextItem.classList.contains('e-virtual-list') ? nextItem : null;
1209
+ }
1210
+ else {
1211
+ if (this.getModuleName() === 'autocomplete') {
1212
+ var value = this.selectedLI.dataset.value;
1213
+ nextItem = this.getElementByValue(value);
1214
+ } else {
1215
+ nextItem = this.getElementByValue(this.getItemData().value);
1216
+ }
1217
+ }
1218
+ }
1219
+ }
1220
+ if (!isNullOrUndefined(nextItem)) {
1221
+ this.setSelection(nextItem, e);
1222
+ }
1223
+ }
1224
+ if (this.allowFiltering && !this.enableVirtualization && this.getModuleName() !== 'autocomplete') {
1225
+ let value = this.getItemData().value;
1226
+ let filterIndex: number = this.getIndexByValueFilter(value);
1227
+ if (!isNullOrUndefined(filterIndex)) {
1228
+ this.activeIndex = filterIndex;
1229
+ }
1230
+ }
1231
+ e.preventDefault();
1232
+ }
1233
+
1234
+ private updateHomeEndAction(e: KeyboardEventArgs, isVirtualKeyAction?: boolean): void {
1235
+ if (this.getModuleName() === 'dropdownlist') {
1236
+ let findLi: number = 0;
1237
+ if (e.action === 'home') {
1238
+ findLi = 0;
1239
+ if (this.enableVirtualization) {
1240
+ findLi = this.skeletonCount;
1241
+ }
1242
+ } else {
1243
+ findLi = this.getItems().length - 1;
1244
+ }
1245
+ e.preventDefault();
1246
+ if (this.activeIndex === findLi) {
1247
+ if(isVirtualKeyAction){
1248
+ this.setSelection(this.liCollections[findLi as number], e);
1249
+ }
1250
+ return;
1251
+ }
1252
+ this.setSelection(this.liCollections[findLi as number], e);
1253
+ }
1254
+ }
1255
+
1256
+ protected selectCurrentValueOnTab(e: KeyboardEventArgs): void {
1257
+ if (this.getModuleName() === 'autocomplete') {
1258
+ this.selectCurrentItem(e);
1259
+ } else {
1260
+ if (this.isPopupOpen) {
1261
+ this.hidePopup(e);
1262
+ this.focusDropDown(e);
1263
+ }
1264
+ }
1265
+ }
1266
+
1267
+ protected mobileKeyActionHandler(e: KeyboardEventArgs): void {
1268
+ if (!this.enabled) {
1269
+ return;
1270
+ }
1271
+ if ((this.isEditTextBox()) && !this.isPopupOpen) {
1272
+ return;
1273
+ }
1274
+ if (!this.readonly) {
1275
+ if (this.list === undefined && !this.isRequested) {
1276
+ this.searchKeyEvent = e;
1277
+ this.renderList();
1278
+ }
1279
+ if (isNullOrUndefined(this.list) || (!isNullOrUndefined(this.liCollections) &&
1280
+ this.liCollections.length === 0) || this.isRequested) {
1281
+ return;
1282
+ }
1283
+ if (e.action === 'enter') {
1284
+ this.selectCurrentItem(e);
1285
+ }
1286
+ }
1287
+ }
1288
+
1289
+ private handleVirtualKeyboardActions(e: KeyboardEventArgs, pageCount: number): void {
1290
+ switch (e.action) {
1291
+ case 'down':
1292
+ case 'up':
1293
+ if (this.itemData != null || this.getModuleName() === 'autocomplete') {
1294
+ this.updateUpDownAction(e, true);
1295
+ }
1296
+ break;
1297
+ case 'pageUp':
1298
+ let count = (pageCount * 2) - 4;
1299
+ this.activeIndex = Math.round(count);
1300
+ this.pageUpSelection(this.activeIndex - this.getPageCount(), e, true);
1301
+ e.preventDefault();
1302
+ break;
1303
+ case 'pageDown':
1304
+ this.activeIndex = 1;
1305
+ this.pageDownSelection(this.activeIndex + this.getPageCount(), e, true);
1306
+ e.preventDefault();
1307
+ break;
1308
+ case 'home':
1309
+ this.isMouseScrollAction = true;
1310
+ this.updateHomeEndAction(e, true);
1311
+ break;
1312
+ case 'end':
1313
+ this.isMouseScrollAction = true;
1314
+ this.updateHomeEndAction(e, true);
1315
+ break;
1316
+ }
1317
+ this.keyboardEvent = null;
1318
+ }
1319
+
1320
+ protected selectCurrentItem(e: KeyboardEventArgs): void {
1321
+ if (this.isPopupOpen) {
1322
+ const li: Element = this.list.querySelector('.' + dropDownListClasses.focus);
1323
+ if (li) {
1324
+ this.setSelection(li, e);
1325
+ this.isTyped = false;
1326
+ }
1327
+ if (this.isSelected) {
1328
+ this.isSelectCustom = false;
1329
+ this.onChangeEvent(e);
1330
+ }
1331
+ this.hidePopup(e);
1332
+ this.focusDropDown(e);
1333
+ } else {
1334
+ this.showPopup();
1335
+ }
1336
+ }
1337
+
1338
+ protected isSelectFocusItem(element: Element): boolean {
1339
+ return !isNullOrUndefined(element);
1340
+ }
1341
+
1342
+ private getPageCount(returnExactCount?: boolean): number {
1343
+ const liHeight: string = this.list.classList.contains(dropDownBaseClasses.noData) ? null :
1344
+ getComputedStyle(this.getItems()[0], null).getPropertyValue('height');
1345
+ let pageCount = Math.round(this.list.getBoundingClientRect().height / parseInt(liHeight, 10));
1346
+ return returnExactCount? pageCount : Math.round(pageCount);
1347
+ }
1348
+
1349
+ private pageUpSelection(steps: number, event: KeyboardEventArgs, isVirtualKeyAction?: boolean): void {
1350
+ let previousItem: Element = steps >= 0 ? this.liCollections[steps + 1] : this.liCollections[0];
1351
+ if ((this.enableVirtualization && this.activeIndex == null) || isVirtualKeyAction) {
1352
+ previousItem = steps >= 0 ? this.liCollections[steps + this.skeletonCount + 1] : this.liCollections[0];
1353
+ }
1354
+ if(!isNullOrUndefined(previousItem) && previousItem.classList.contains('e-virtual-list')){
1355
+ previousItem = this.liCollections[this.skeletonCount];
1356
+ }
1357
+ this.PageUpDownSelection(previousItem, event);
1358
+ }
1359
+
1360
+ private PageUpDownSelection(previousItem: Element, event: KeyboardEventArgs): void {
1361
+ if (this.enableVirtualization) {
1362
+ if (!isNullOrUndefined(previousItem) && ((this.getModuleName() !== 'autocomplete' && !previousItem.classList.contains('e-active')) || (this.getModuleName() === 'autocomplete' && !previousItem.classList.contains('e-item-focus')))) {
1363
+ this.setSelection(previousItem, event);
1364
+ }
1365
+ }
1366
+ else{
1367
+ this.setSelection(previousItem, event);
1368
+ }
1369
+ }
1370
+
1371
+ private pageDownSelection(steps: number, event: KeyboardEventArgs, isVirtualKeyAction?: boolean): void {
1372
+ const list: Element[] = this.getItems();
1373
+ let previousItem: Element = steps <= list.length ? this.liCollections[steps - 1] : this.liCollections[list.length - 1];
1374
+ if ((this.enableVirtualization && this.activeIndex == null) || isVirtualKeyAction) {
1375
+ previousItem = steps <= list.length ? this.liCollections[steps + this.skeletonCount - 1] : this.liCollections[list.length - 1];
1376
+ }
1377
+ this.PageUpDownSelection(previousItem, event);
1378
+ }
1379
+
1380
+ protected unWireEvent(): void {
1381
+ if (!isNullOrUndefined(this.inputWrapper)) {
1382
+ EventHandler.remove(this.inputWrapper.container, 'mousedown', this.dropDownClick);
1383
+ EventHandler.remove(this.inputWrapper.container, 'keypress', this.onSearch);
1384
+ EventHandler.remove(this.inputWrapper.container, 'focus', this.focusIn);
1385
+ EventHandler.remove(<HTMLElement & Window>window, 'resize', this.windowResize);
1386
+ }
1387
+ this.unBindCommonEvent();
1388
+ }
1389
+ /**
1390
+ * Event un binding for list items.
1391
+ *
1392
+ * @returns {void}
1393
+ */
1394
+ private unWireListEvents(): void {
1395
+ if (this.list) {
1396
+ EventHandler.remove(this.list, 'click', this.onMouseClick);
1397
+ EventHandler.remove(this.list, 'mouseover', this.onMouseOver);
1398
+ EventHandler.remove(this.list, 'mouseout', this.onMouseLeave);
1399
+ }
1400
+ }
1401
+
1402
+ protected checkSelector(id: string): string {
1403
+ return '[id="' + id.replace(/(:|\.|\[|\]|,|=|@|\\|\/|#)/g, '\\$1') + '"]';
1404
+ }
1405
+ protected onDocumentClick(e: MouseEvent): void {
1406
+ const target: HTMLElement = <HTMLElement>e.target;
1407
+ if (!(!isNullOrUndefined(this.popupObj) && closest(target, this.checkSelector(this.popupObj.element.id))) &&
1408
+ !isNullOrUndefined(this.inputWrapper) && !this.inputWrapper.container.contains(e.target as Node)) {
1409
+ if (this.inputWrapper.container.classList.contains(dropDownListClasses.inputFocus) || this.isPopupOpen) {
1410
+ this.isDocumentClick = true;
1411
+ const isActive: boolean = this.isRequested;
1412
+ this.hidePopup(e);
1413
+ if (!isActive) {
1414
+ this.onFocusOut();
1415
+ this.inputWrapper.container.classList.remove(dropDownListClasses.inputFocus);
1416
+ }
1417
+ }
1418
+ } else if (target !== this.inputElement && !(this.allowFiltering && target === this.filterInput)
1419
+ && !(this.getModuleName() === 'combobox' &&
1420
+ !this.allowFiltering && Browser.isDevice && target === this.inputWrapper.buttons[0])) {
1421
+ this.isPreventBlur = (Browser.isIE || Browser.info.name === 'edge') && (document.activeElement === this.targetElement() ||
1422
+ document.activeElement === this.filterInput);
1423
+ e.preventDefault();
1424
+ }
1425
+ }
1426
+
1427
+ private activeStateChange(): void {
1428
+ if (this.isDocumentClick) {
1429
+ this.hidePopup();
1430
+ this.onFocusOut();
1431
+ this.inputWrapper.container.classList.remove(dropDownListClasses.inputFocus);
1432
+ }
1433
+ }
1434
+
1435
+ private focusDropDown(e?: MouseEvent | KeyboardEventArgs | TouchEvent): void {
1436
+ if (!this.initial && this.isFilterLayout()) {
1437
+ this.focusIn(e);
1438
+ }
1439
+ }
1440
+
1441
+ protected dropDownClick(e: MouseEvent): void {
1442
+ if (e.which === 3 || e.button === 2) {
1443
+ return;
1444
+ }
1445
+ this.keyboardEvent = null;
1446
+ if (this.targetElement().classList.contains(dropDownListClasses.disable) || this.inputWrapper.clearButton === e.target) {
1447
+ return;
1448
+ }
1449
+ const target: HTMLElement = <HTMLElement>e.target;
1450
+ if (target !== this.inputElement && !(this.allowFiltering && target === this.filterInput) && this.getModuleName() !== 'combobox') {
1451
+ e.preventDefault();
1452
+ }
1453
+ if (!this.readonly) {
1454
+ if (this.isPopupOpen) {
1455
+ this.hidePopup(e);
1456
+ if (this.isFilterLayout()) {
1457
+ this.focusDropDown(e);
1458
+ }
1459
+ } else {
1460
+ this.focusIn(e);
1461
+ this.floatLabelChange();
1462
+ this.queryString = this.inputElement.value.trim() === '' ? null : this.inputElement.value;
1463
+ this.isDropDownClick = true;
1464
+ this.showPopup(e);
1465
+ }
1466
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
1467
+ const proxy: this = this;
1468
+ // eslint-disable-next-line max-len
1469
+ const duration: number = (this.element.tagName === this.getNgDirective() && this.itemTemplate) ? 500 : 100;
1470
+ if (!this.isSecondClick) {
1471
+ setTimeout(() => {
1472
+ proxy.cloneElements(); proxy.isSecondClick = true;
1473
+ }, duration);
1474
+ }
1475
+ } else {
1476
+ this.focusIn(e);
1477
+ }
1478
+ }
1479
+ protected cloneElements(): void {
1480
+ if (this.list) {
1481
+ let ulElement: HTMLElement = this.list.querySelector('ul');
1482
+ if (ulElement) {
1483
+ ulElement = ulElement.cloneNode ? (ulElement.cloneNode(true) as HTMLElement) : ulElement;
1484
+ this.actionCompleteData.ulElement = ulElement;
1485
+ }
1486
+ }
1487
+ }
1488
+ protected updateSelectedItem(
1489
+ li: Element,
1490
+ e: MouseEvent | KeyboardEvent | TouchEvent,
1491
+ preventSelect?: boolean,
1492
+ isSelection?: boolean): void {
1493
+ this.removeSelection();
1494
+ li.classList.add(dropDownBaseClasses.selected);
1495
+ this.removeHover();
1496
+ const value: string | number | boolean = li.getAttribute('data-value') !== "null" ? this.getFormattedValue(li.getAttribute('data-value')) : null;
1497
+ const selectedData: string | number | boolean | {
1498
+ [key: string]: Object
1499
+ } = this.getDataByValue(value);
1500
+ if (!this.initial && !preventSelect && !isNullOrUndefined(e)) {
1501
+ const items: FieldSettingsModel = this.detachChanges(selectedData);
1502
+ this.isSelected = true;
1503
+ const eventArgs: SelectEventArgs = {
1504
+ e: e,
1505
+ item: li as HTMLLIElement,
1506
+ itemData: items,
1507
+ isInteracted: e ? true : false,
1508
+ cancel: false
1509
+ };
1510
+ this.trigger('select', eventArgs, (eventArgs: SelectEventArgs) => {
1511
+ if (eventArgs.cancel) {
1512
+ li.classList.remove(dropDownBaseClasses.selected);
1513
+ } else {
1514
+ this.selectEventCallback(li, e, preventSelect, selectedData, value);
1515
+ if (isSelection) {
1516
+ this.setSelectOptions(li, e);
1517
+ }
1518
+ }
1519
+ });
1520
+ } else {
1521
+ this.selectEventCallback(li, e, preventSelect, selectedData, value);
1522
+ if (isSelection) {
1523
+ this.setSelectOptions(li, e);
1524
+ }
1525
+ }
1526
+ }
1527
+
1528
+ private selectEventCallback(
1529
+ li: Element,
1530
+ e: MouseEvent | KeyboardEvent | TouchEvent,
1531
+ preventSelect?: boolean,
1532
+ selectedData?: string | number | boolean | { [key: string]: Object },
1533
+ value?: string | number | boolean): void {
1534
+ this.previousItemData = (!isNullOrUndefined(this.itemData)) ? this.itemData : null;
1535
+ if(this.itemData != selectedData){
1536
+ this.previousValue = (!isNullOrUndefined(this.itemData))? typeof this.itemData == "object" ? this.checkFieldValue(this.itemData as any, this.fields.value.split('.')): this.itemData: null;
1537
+ }
1538
+ this.item = li as HTMLLIElement;
1539
+ this.itemData = selectedData;
1540
+ const focusedItem: Element = this.list.querySelector('.' + dropDownBaseClasses.focus);
1541
+ if (focusedItem) {
1542
+ removeClass([focusedItem], dropDownBaseClasses.focus);
1543
+ }
1544
+ li.setAttribute('aria-selected', 'true');
1545
+ if (isNullOrUndefined(value)) {
1546
+ value = 'null';
1547
+ }
1548
+ if (this.allowFiltering && !this.enableVirtualization && this.getModuleName() !== 'autocomplete') {
1549
+ let filterIndex = this.getIndexByValueFilter(value);
1550
+ if (!isNullOrUndefined(filterIndex)) {
1551
+ this.activeIndex = filterIndex;
1552
+ }
1553
+ else {
1554
+ this.activeIndex = this.getIndexByValue(value);
1555
+ }
1556
+ }
1557
+ else {
1558
+ this.activeIndex = this.getIndexByValue(value);
1559
+ }
1560
+ }
1561
+
1562
+ protected activeItem(li: Element): void {
1563
+ if (this.isValidLI(li) && !li.classList.contains(dropDownBaseClasses.selected)) {
1564
+ this.removeSelection();
1565
+ li.classList.add(dropDownBaseClasses.selected);
1566
+ this.removeHover();
1567
+ li.setAttribute('aria-selected', 'true');
1568
+ }
1569
+ }
1570
+
1571
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
1572
+ protected setValue(e?: KeyboardEventArgs): boolean {
1573
+ const dataItem: { [key: string]: string } = this.getItemData();
1574
+ if (dataItem.value === null) {
1575
+ Input.setValue(null, this.inputElement, this.floatLabelType, this.showClearButton);
1576
+ } else {
1577
+ Input.setValue(dataItem.text, this.inputElement, this.floatLabelType, this.showClearButton);
1578
+ }
1579
+ if (this.valueTemplate && this.itemData !== null) {
1580
+ this.setValueTemplate();
1581
+ } else if (!isNullOrUndefined(this.valueTempElement) && this.inputElement.previousSibling === this.valueTempElement) {
1582
+ detach(this.valueTempElement);
1583
+ this.inputElement.style.display = 'block';
1584
+ }
1585
+ if (!isNullOrUndefined(dataItem.value) && !this.enableVirtualization && this.allowFiltering) {
1586
+ this.activeIndex = this.getIndexByValueFilter(dataItem.value);
1587
+ }
1588
+ const clearIcon: string = dropDownListClasses.clearIcon;
1589
+ const isFilterElement: boolean = this.isFiltering() && this.filterInput && (this.getModuleName() === 'combobox');
1590
+ const clearElement: HTMLElement = isFilterElement && this.filterInput.parentElement.querySelector('.' + clearIcon);
1591
+ if (this.isFiltering() && clearElement) {
1592
+ clearElement.style.removeProperty('visibility');
1593
+ }
1594
+ if (this.previousValue === dataItem.value) {
1595
+ this.isSelected = false;
1596
+ return true;
1597
+ } else {
1598
+ this.isSelected = !this.initial ? true : false;
1599
+ this.isSelectCustom = false;
1600
+ if (this.getModuleName() === 'dropdownlist') {
1601
+ this.updateIconState();
1602
+ }
1603
+ return false;
1604
+ }
1605
+ }
1606
+
1607
+ protected setSelection(li: Element, e: MouseEvent | KeyboardEventArgs | TouchEvent): void {
1608
+ if (this.isValidLI(li) && (!li.classList.contains(dropDownBaseClasses.selected) || (this.isPopupOpen && this.isSelected
1609
+ && li.classList.contains(dropDownBaseClasses.selected)))) {
1610
+ this.updateSelectedItem(li, e, false, true);
1611
+ } else {
1612
+ this.setSelectOptions(li, e);
1613
+ if (this.enableVirtualization) {
1614
+ const fields: string = (this.fields.value) ? this.fields.value : '';
1615
+ const getItem: any = <{ [key: string]: Object }[] | string[] | number[] | boolean[]>new DataManager(
1616
+ this.dataSource as DataOptions | JSON[]).executeLocal(new Query().where(new Predicate(fields, 'equal', this.value)));
1617
+
1618
+ if (getItem && getItem.length > 0) {
1619
+ this.itemData = getItem[0];
1620
+ this.setProperties({ 'text': getItem[0].text, 'value': getItem[0].value }, true);
1621
+ }
1622
+ }
1623
+ }
1624
+ }
1625
+ private setSelectOptions(li: Element, e?: MouseEvent | KeyboardEventArgs | KeyboardEvent | TouchEvent): void {
1626
+ if (this.list) {
1627
+ this.removeHover();
1628
+ }
1629
+ this.previousSelectedLI = (!isNullOrUndefined(this.selectedLI)) ? this.selectedLI : null;
1630
+ this.selectedLI = li as HTMLElement;
1631
+ if (this.setValue(e as KeyboardEventArgs)) {
1632
+ return;
1633
+ }
1634
+ if ((!this.isPopupOpen && !isNullOrUndefined(li)) || (this.isPopupOpen && !isNullOrUndefined(e) &&
1635
+ (e.type !== 'keydown' || e.type === 'keydown' && (e as KeyboardEventArgs).action === 'enter'))) {
1636
+ this.isSelectCustom = false;
1637
+ this.onChangeEvent(e);
1638
+ }
1639
+ if (this.isPopupOpen && !isNullOrUndefined(this.selectedLI) && this.itemData !== null && (!e || e.type !== 'click')) {
1640
+ this.setScrollPosition(e as KeyboardEventArgs);
1641
+ }
1642
+ if (Browser.info.name !== 'mozilla') {
1643
+ if (this.targetElement()) {
1644
+ attributes(this.targetElement(), { 'aria-describedby': this.inputElement.id !== '' ? this.inputElement.id : this.element.id });
1645
+ this.targetElement().removeAttribute('aria-live');
1646
+ }
1647
+ }
1648
+ if (this.isPopupOpen && !isNullOrUndefined(this.ulElement) && !isNullOrUndefined(this.ulElement.getElementsByClassName('e-item-focus')[0])) {
1649
+ attributes(this.targetElement(), { 'aria-activedescendant': this.ulElement.getElementsByClassName('e-item-focus')[0].id });
1650
+ } else if (this.isPopupOpen && !isNullOrUndefined(this.ulElement) && !isNullOrUndefined(this.ulElement.getElementsByClassName('e-active')[0])) {
1651
+ attributes(this.targetElement(), { 'aria-activedescendant': this.ulElement.getElementsByClassName('e-active')[0].id });
1652
+ }
1653
+ }
1654
+
1655
+ private dropdownCompiler(dropdownTemplate: string | Function): boolean {
1656
+ let checkTemplate: boolean = false;
1657
+ if (typeof dropdownTemplate !== 'function' && dropdownTemplate) {
1658
+ try {
1659
+ checkTemplate = (document.querySelectorAll(dropdownTemplate).length) ? true : false;
1660
+
1661
+ } catch (exception) {
1662
+ checkTemplate = false;
1663
+ }
1664
+ }
1665
+ return checkTemplate;
1666
+ }
1667
+
1668
+ private setValueTemplate(): void {
1669
+ let compiledString: Function;
1670
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1671
+ if ((this as any).isReact) {
1672
+ this.clearTemplate(['valueTemplate']);
1673
+ if (this.valueTempElement) {
1674
+ detach(this.valueTempElement);
1675
+ this.inputElement.style.display = 'block';
1676
+ this.valueTempElement = null;
1677
+ }
1678
+ }
1679
+ if (!this.valueTempElement) {
1680
+ this.valueTempElement = this.createElement('span', { className: dropDownListClasses.value });
1681
+ this.inputElement.parentElement.insertBefore(this.valueTempElement, this.inputElement);
1682
+ this.inputElement.style.display = 'none';
1683
+ }
1684
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1685
+ if (!(this as any).isReact) {
1686
+ this.valueTempElement.innerHTML = '';
1687
+ }
1688
+ const valuecheck: boolean = this.dropdownCompiler(this.valueTemplate);
1689
+ if (typeof this.valueTemplate !== 'function' && valuecheck) {
1690
+ compiledString = compile(document.querySelector(this.valueTemplate).innerHTML.trim());
1691
+ } else {
1692
+ compiledString = compile(this.valueTemplate);
1693
+ }
1694
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1695
+ const valueCompTemp: any = compiledString(
1696
+ this.itemData, this, 'valueTemplate', this.valueTemplateId, this.isStringTemplate, null, this.valueTempElement);
1697
+ if (valueCompTemp && valueCompTemp.length > 0) {
1698
+ append(valueCompTemp, this.valueTempElement);
1699
+ }
1700
+ this.renderReactTemplates();
1701
+ }
1702
+
1703
+ protected removeSelection(): void {
1704
+ if (this.list) {
1705
+ const selectedItems: Element[] = <NodeListOf<Element> &
1706
+ Element[]>this.list.querySelectorAll('.' + dropDownBaseClasses.selected);
1707
+ if (selectedItems.length) {
1708
+ removeClass(selectedItems, dropDownBaseClasses.selected);
1709
+ selectedItems[0].removeAttribute('aria-selected');
1710
+ }
1711
+ }
1712
+ }
1713
+
1714
+ protected getItemData(): { [key: string]: string } {
1715
+ const fields: FieldSettingsModel = this.fields;
1716
+ let dataItem: { [key: string]: string | Object } | string | boolean | number = null;
1717
+ dataItem = this.itemData;
1718
+ let dataValue: string;
1719
+ let dataText: string;
1720
+ if (!isNullOrUndefined(dataItem)) {
1721
+ dataValue = getValue(fields.value, dataItem);
1722
+ dataText = getValue(fields.text, dataItem);
1723
+ }
1724
+ const value: string = <string>(!isNullOrUndefined(dataItem) &&
1725
+ !isUndefined(dataValue) ? dataValue : dataItem);
1726
+ const text: string = <string>(!isNullOrUndefined(dataItem) &&
1727
+ !isUndefined(dataValue) ? dataText : dataItem);
1728
+ return { value: value, text: text };
1729
+ }
1730
+ /**
1731
+ * To trigger the change event for list.
1732
+ *
1733
+ * @param {MouseEvent | KeyboardEvent | TouchEvent} eve - Specifies the event arguments.
1734
+ * @returns {void}
1735
+ */
1736
+ protected onChangeEvent(eve: MouseEvent | KeyboardEvent | TouchEvent): void {
1737
+ const dataItem: { [key: string]: string } = this.getItemData();
1738
+ const index: number = this.isSelectCustom ? null : this.activeIndex;
1739
+ this.setProperties({ 'index': index, 'text': dataItem.text, 'value': dataItem.value }, true);
1740
+ this.detachChangeEvent(eve);
1741
+ }
1742
+
1743
+ private detachChanges(value: string | number | boolean | {
1744
+ [key: string]: Object
1745
+ }): FieldSettingsModel {
1746
+ let items: FieldSettingsModel;
1747
+ if (typeof value === 'string' ||
1748
+ typeof value === 'boolean' ||
1749
+ typeof value === 'number') {
1750
+ items = Object.defineProperties({}, {
1751
+ value: {
1752
+ value: value,
1753
+ enumerable: true
1754
+ },
1755
+ text: {
1756
+ value: value,
1757
+ enumerable: true
1758
+ }
1759
+ });
1760
+ } else {
1761
+ items = value;
1762
+ }
1763
+ return items;
1764
+ }
1765
+
1766
+ protected detachChangeEvent(eve: MouseEvent | KeyboardEvent | TouchEvent): void {
1767
+ this.isSelected = false;
1768
+ this.previousValue = this.value;
1769
+ this.activeIndex = this.index;
1770
+ this.typedString = !isNullOrUndefined(this.text) ? this.text : '';
1771
+ if (!this.initial) {
1772
+ const items: FieldSettingsModel = this.detachChanges(this.itemData);
1773
+ let preItems: FieldSettingsModel;
1774
+ if (typeof this.previousItemData === 'string' ||
1775
+ typeof this.previousItemData === 'boolean' ||
1776
+ typeof this.previousItemData === 'number') {
1777
+ preItems = Object.defineProperties({}, {
1778
+ value: {
1779
+ value: this.previousItemData,
1780
+ enumerable: true
1781
+ },
1782
+ text: {
1783
+ value: this.previousItemData,
1784
+ enumerable: true
1785
+ }
1786
+ });
1787
+ } else {
1788
+ preItems = this.previousItemData;
1789
+ }
1790
+ this.setHiddenValue();
1791
+ const eventArgs: ChangeEventArgs = {
1792
+ e: eve,
1793
+ item: this.item,
1794
+ itemData: items,
1795
+ previousItem: this.previousSelectedLI as HTMLLIElement,
1796
+ previousItemData: preItems,
1797
+ isInteracted: eve ? true : false,
1798
+ value: this.value,
1799
+ element: this.element,
1800
+ event: eve
1801
+ };
1802
+ if (this.isAngular && this.preventChange) {
1803
+ this.preventChange = false;
1804
+ } else {
1805
+ this.trigger('change', eventArgs);
1806
+ }
1807
+ }
1808
+ if ((isNullOrUndefined(this.value) || this.value === '') && this.floatLabelType !== 'Always') {
1809
+ removeClass([this.inputWrapper.container], 'e-valid-input');
1810
+ }
1811
+ }
1812
+
1813
+ protected setHiddenValue(): void {
1814
+ if (!isNullOrUndefined(this.value)) {
1815
+ if (this.hiddenElement.querySelector('option')) {
1816
+ const selectedElement: HTMLElement = this.hiddenElement.querySelector('option');
1817
+ selectedElement.textContent = this.text;
1818
+ selectedElement.setAttribute('value', this.value.toString());
1819
+ } else {
1820
+ if (!isNullOrUndefined(this.hiddenElement)) {
1821
+ this.hiddenElement.innerHTML = '<option selected>' + this.text + '</option>';
1822
+ const selectedElement: HTMLElement = this.hiddenElement.querySelector('option');
1823
+ selectedElement.setAttribute('value', this.value.toString());
1824
+ }
1825
+ }
1826
+ } else {
1827
+ this.hiddenElement.innerHTML = '';
1828
+ }
1829
+ }
1830
+ /**
1831
+ * Filter bar implementation
1832
+ *
1833
+ * @param {KeyboardEventArgs} e - Specifies the event arguments.
1834
+ * @returns {void}
1835
+ */
1836
+ protected onFilterUp(e: KeyboardEventArgs): void {
1837
+ if (!(e.ctrlKey && e.keyCode === 86) && (this.isValidKey || e.keyCode === 40 || e.keyCode === 38)) {
1838
+ this.isValidKey = false;
1839
+ switch (e.keyCode) {
1840
+ case 38: //up arrow
1841
+ case 40: //down arrow
1842
+ if (this.getModuleName() === 'autocomplete' && !this.isPopupOpen && !this.preventAltUp && !this.isRequested) {
1843
+ this.preventAutoFill = true;
1844
+ this.searchLists(e);
1845
+ } else {
1846
+ this.preventAutoFill = false;
1847
+ }
1848
+ this.preventAltUp = false;
1849
+ if (this.getModuleName() === 'autocomplete' && !isNullOrUndefined(this.ulElement) && !isNullOrUndefined(this.ulElement.getElementsByClassName('e-item-focus')[0])) {
1850
+ attributes(this.targetElement(), { 'aria-activedescendant': this.ulElement.getElementsByClassName('e-item-focus')[0].id });
1851
+ }
1852
+ e.preventDefault();
1853
+ break;
1854
+ case 46: //delete
1855
+ case 8: //backspace
1856
+ this.typedString = this.filterInput.value;
1857
+ if (!this.isPopupOpen && this.typedString !== '' || this.isPopupOpen && this.queryString.length > 0) {
1858
+ this.preventAutoFill = true;
1859
+ this.searchLists(e);
1860
+ } else if (this.typedString === '' && this.queryString === '' && this.getModuleName() !== 'autocomplete') {
1861
+ this.preventAutoFill = true;
1862
+ this.searchLists(e);
1863
+ } else if (this.typedString === '') {
1864
+ if (this.list) {
1865
+ this.resetFocusElement();
1866
+ }
1867
+ this.activeIndex = null;
1868
+ if (this.getModuleName() !== 'dropdownlist') {
1869
+ this.preventAutoFill = true;
1870
+ this.searchLists(e);
1871
+ if (this.getModuleName() === 'autocomplete') {
1872
+ this.hidePopup();
1873
+ }
1874
+ }
1875
+ }
1876
+ e.preventDefault();
1877
+ break;
1878
+ default:
1879
+ this.typedString = this.filterInput.value;
1880
+ this.preventAutoFill = false;
1881
+ this.searchLists(e);
1882
+ if (this.enableVirtualization) {
1883
+ this.getFilteringSkeletonCount();
1884
+ }
1885
+ break;
1886
+ }
1887
+ } else {
1888
+ this.isValidKey = false;
1889
+ }
1890
+ }
1891
+ protected getFilteringSkeletonCount(): void {
1892
+ const difference: number = this.dataCount - this.viewPortInfo.endIndex;
1893
+ const currentSkeletonCount: number = this.skeletonCount;
1894
+ this.getSkeletonCount(true);
1895
+ this.skeletonCount = this.dataCount > this.itemCount * 2 ? this.skeletonCount : difference > this.skeletonCount ? this.skeletonCount : difference > 0 ? difference : 0;
1896
+ if (!this.list.classList.contains(dropDownBaseClasses.noData)) {
1897
+ const isSkeletonCountChange: boolean = currentSkeletonCount !== this.skeletonCount;
1898
+ if(currentSkeletonCount !== this.skeletonCount){
1899
+ this.UpdateSkeleton(true,Math.abs(currentSkeletonCount - this.skeletonCount));
1900
+ }
1901
+ else{
1902
+ this.UpdateSkeleton();
1903
+ }
1904
+ this.liCollections = <HTMLElement[] & NodeListOf<Element>>this.list.querySelectorAll('.e-list-item');
1905
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1906
+ (this.list.getElementsByClassName('e-virtual-ddl')[0] as any).style = this.GetVirtualTrackHeight();
1907
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1908
+ (this.list.getElementsByClassName('e-virtual-ddl-content')[0] as any).style = this.getTransformValues();
1909
+ }
1910
+ }
1911
+
1912
+ protected getSkeletonCount(retainSkeleton?: boolean): void {
1913
+ this.virtualListHeight = this.listHeight != null ? parseInt(this.listHeight, 10) : this.virtualListHeight;
1914
+ const actualCount: number = this.virtualListHeight > 0 ? Math.floor(this.virtualListHeight / this.listItemHeight) : 0;
1915
+ this.skeletonCount = actualCount * 2 < this.itemCount ? this.itemCount : actualCount * 2;
1916
+ this.itemCount = retainSkeleton ? this.itemCount : this.skeletonCount;
1917
+ this.skeletonCount = Math.floor(this.skeletonCount / 2) + 2;
1918
+ }
1919
+
1920
+
1921
+ protected onFilterDown(e: KeyboardEventArgs): void {
1922
+ switch (e.keyCode) {
1923
+ case 13: //enter
1924
+ break;
1925
+ case 40: //down arrow
1926
+ case 38: //up arrow
1927
+ this.queryString = this.filterInput.value;
1928
+ e.preventDefault();
1929
+ break;
1930
+ case 9: //tab
1931
+ if (this.isPopupOpen && this.getModuleName() !== 'autocomplete') {
1932
+ e.preventDefault();
1933
+ }
1934
+ break;
1935
+ default:
1936
+ this.prevSelectPoints = this.getSelectionPoints();
1937
+ this.queryString = this.filterInput.value;
1938
+ break;
1939
+ }
1940
+ }
1941
+
1942
+ protected removeFillSelection(): void {
1943
+ if (this.isInteracted) {
1944
+ const selection: { [key: string]: number } = this.getSelectionPoints();
1945
+ this.inputElement.setSelectionRange(selection.end, selection.end);
1946
+ }
1947
+ }
1948
+ protected getQuery(query: Query): Query {
1949
+ let filterQuery: Query;
1950
+ if (!this.isCustomFilter && this.allowFiltering && this.filterInput) {
1951
+ filterQuery = query ? query.clone() : this.query ? this.query.clone() : new Query();
1952
+ const filterType: string = this.typedString === '' ? 'contains' : this.filterType;
1953
+ const dataType: string = <string>this.typeOfData(this.dataSource as { [key: string]: Object }[]).typeof;
1954
+ if (!(this.dataSource instanceof DataManager) && dataType === 'string' || dataType === 'number') {
1955
+ filterQuery.where('', filterType, this.typedString, this.ignoreCase, this.ignoreAccent);
1956
+ } else {
1957
+ const fields: string = (this.fields.text) ? this.fields.text : '';
1958
+ filterQuery.where(fields, filterType, this.typedString, this.ignoreCase, this.ignoreAccent);
1959
+ }
1960
+ } else {
1961
+ filterQuery = query ? query.clone() : this.query ? this.query.clone() : new Query();
1962
+ }
1963
+ if (this.enableVirtualization && (this.viewPortInfo.endIndex != 0)) {
1964
+ var takeValue = this.getTakeValue();
1965
+ if (this.allowFiltering) {
1966
+ filterQuery.skip(this.virtualItemStartIndex);
1967
+ }
1968
+ filterQuery.take(takeValue);
1969
+ filterQuery.requiresCount();
1970
+ }
1971
+ return filterQuery;
1972
+ }
1973
+
1974
+ protected getSelectionPoints(): { [key: string]: number } {
1975
+ const input: HTMLInputElement = <HTMLInputElement>this.inputElement;
1976
+ return { start: Math.abs(input.selectionStart), end: Math.abs(input.selectionEnd) };
1977
+ }
1978
+
1979
+ protected searchLists(e: KeyboardEventArgs | MouseEvent): void {
1980
+ this.isTyped = true;
1981
+ this.activeIndex = null;
1982
+ this.isListSearched = true;
1983
+ if (this.filterInput.parentElement.querySelector('.' + dropDownListClasses.clearIcon)) {
1984
+ const clearElement: HTMLElement = <HTMLElement>
1985
+ this.filterInput.parentElement.querySelector('.' + dropDownListClasses.clearIcon);
1986
+ clearElement.style.visibility = this.filterInput.value === '' ? 'hidden' : 'visible';
1987
+ }
1988
+ this.isDataFetched = false;
1989
+ if (this.isFiltering()) {
1990
+ this.checkAndResetCache();
1991
+ const eventArgs: FilteringEventArgs = {
1992
+ preventDefaultAction: false,
1993
+ text: this.filterInput.value,
1994
+ updateData: (
1995
+ dataSource: { [key: string]: Object }[] | DataManager | string[] | number[], query?: Query,
1996
+ fields?: FieldSettingsModel) => {
1997
+ if (eventArgs.cancel) {
1998
+ return;
1999
+ }
2000
+ this.isCustomFilter = true;
2001
+ this.filteringAction(dataSource, query, fields);
2002
+ },
2003
+ baseEventArgs: e,
2004
+ cancel: false
2005
+ };
2006
+ this.trigger('filtering', eventArgs, (eventArgs: FilteringEventArgs) => {
2007
+ if (!eventArgs.cancel && !this.isCustomFilter && !eventArgs.preventDefaultAction) {
2008
+ this.filteringAction(this.dataSource, null, this.fields);
2009
+ }
2010
+ });
2011
+ }
2012
+ }
2013
+ /**
2014
+ * To filter the data from given data source by using query
2015
+ *
2016
+ * @param {Object[] | DataManager } dataSource - Set the data source to filter.
2017
+ * @param {Query} query - Specify the query to filter the data.
2018
+ * @param {FieldSettingsModel} fields - Specify the fields to map the column in the data table.
2019
+ * @returns {void}
2020
+ * @deprecated
2021
+ */
2022
+ public filter(
2023
+ dataSource: { [key: string]: Object }[] | DataManager | string[] | number[] | boolean[],
2024
+ query?: Query, fields?: FieldSettingsModel): void {
2025
+ this.isCustomFilter = true;
2026
+ this.filteringAction(dataSource, query, fields);
2027
+ }
2028
+ private filteringAction(
2029
+ dataSource: { [key: string]: Object }[] | DataManager | string[] | number[] | boolean[],
2030
+ query?: Query, fields?: FieldSettingsModel): void {
2031
+ if (!isNullOrUndefined(this.filterInput)) {
2032
+ this.beforePopupOpen = (!this.isPopupOpen && this.getModuleName() === 'combobox' && this.filterInput.value === '') ?
2033
+ false : true;
2034
+ let isNoData = this.list.classList.contains(dropDownBaseClasses.noData);
2035
+ if (this.filterInput.value.trim() === '' && !this.itemTemplate) {
2036
+ this.actionCompleteData.isUpdated = false;
2037
+ this.isTyped = false;
2038
+ if (!isNullOrUndefined(this.actionCompleteData.ulElement) && !isNullOrUndefined(this.actionCompleteData.list)) {
2039
+ if (this.enableVirtualization) {
2040
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2041
+ this.totalItemCount = this.dataSource && (this.dataSource as any).length ? (this.dataSource as any).length : 0;
2042
+ this.resetList(dataSource, fields, query);
2043
+ if (isNoData && !this.list.classList.contains(dropDownBaseClasses.noData)) {
2044
+ if (!this.list.querySelector('.e-virtual-ddl-content')) {
2045
+ this.list.appendChild(this.createElement('div', {
2046
+ className: 'e-virtual-ddl-content',
2047
+ styles: this.getTransformValues()
2048
+ })).appendChild(this.list.querySelector('.e-list-parent'));
2049
+ }
2050
+ if (!this.list.querySelector('.e-virtual-ddl')) {
2051
+ var virualElement = this.createElement('div', {
2052
+ id: this.element.id + '_popup', className: 'e-virtual-ddl', styles: this.GetVirtualTrackHeight()
2053
+ });
2054
+ document.getElementsByClassName('e-popup')[0].querySelector('.e-dropdownbase').appendChild(virualElement);
2055
+ }
2056
+ }
2057
+ }
2058
+ this.onActionComplete(this.actionCompleteData.ulElement, this.actionCompleteData.list);
2059
+ }
2060
+ this.isTyped = true;
2061
+ if (!isNullOrUndefined(this.itemData) && this.getModuleName() === 'dropdownlist') {
2062
+ this.focusIndexItem();
2063
+ this.setScrollPosition();
2064
+ }
2065
+ this.isNotSearchList = true;
2066
+ } else {
2067
+ this.isNotSearchList = false;
2068
+ query = (this.filterInput.value.trim() === '') ? null : query;
2069
+ if (this.enableVirtualization && this.isFiltering() && this.isTyped) {
2070
+ this.isPreventScrollAction = true;
2071
+ this.list.scrollTop = 0;
2072
+ this.previousStartIndex = 0;
2073
+ this.virtualListInfo = null;
2074
+ }
2075
+ this.resetList(dataSource, fields, query);
2076
+ if (this.enableVirtualization && isNoData && !this.list.classList.contains(dropDownBaseClasses.noData)) {
2077
+ if (!this.list.querySelector('.e-virtual-ddl-content')) {
2078
+ this.list.appendChild(this.createElement('div', {
2079
+ className: 'e-virtual-ddl-content',
2080
+ styles: this.getTransformValues()
2081
+ })).appendChild(this.list.querySelector('.e-list-parent'));
2082
+ }
2083
+ if (!this.list.querySelector('.e-virtual-ddl')) {
2084
+ var virualElement = this.createElement('div', {
2085
+ id: this.element.id + '_popup', className: 'e-virtual-ddl', styles: this.GetVirtualTrackHeight()
2086
+ });
2087
+ document.getElementsByClassName('e-popup')[0].querySelector('.e-dropdownbase').appendChild(virualElement);
2088
+ }
2089
+ }
2090
+ }
2091
+ if (this.enableVirtualization) {
2092
+ this.getFilteringSkeletonCount();
2093
+ }
2094
+ this.renderReactTemplates();
2095
+ }
2096
+ }
2097
+ protected setSearchBox(popupElement: HTMLElement): InputObject {
2098
+ if (this.isFiltering()) {
2099
+ const parentElement: HTMLElement = popupElement.querySelector('.' + dropDownListClasses.filterParent) ?
2100
+ popupElement.querySelector('.' + dropDownListClasses.filterParent) : this.createElement('span', {
2101
+ className: dropDownListClasses.filterParent
2102
+ });
2103
+ this.filterInput = <HTMLInputElement>this.createElement('input', {
2104
+ attrs: { type: 'text' },
2105
+ className: dropDownListClasses.filterInput
2106
+ });
2107
+ this.element.parentNode.insertBefore(this.filterInput, this.element);
2108
+ let backIcon: boolean = false;
2109
+ if (Browser.isDevice) {
2110
+ backIcon = true;
2111
+ }
2112
+ this.filterInputObj = Input.createInput(
2113
+ {
2114
+ element: this.filterInput,
2115
+ buttons: backIcon ?
2116
+ [dropDownListClasses.backIcon, dropDownListClasses.filterBarClearIcon] : [dropDownListClasses.filterBarClearIcon],
2117
+ properties: { placeholder: this.filterBarPlaceholder }
2118
+ },
2119
+ this.createElement
2120
+ );
2121
+ if (!isNullOrUndefined(this.cssClass)) {
2122
+ if (this.cssClass.split(' ').indexOf('e-outline') !== -1) {
2123
+ addClass([this.filterInputObj.container], 'e-outline');
2124
+ } else if (this.cssClass.split(' ').indexOf('e-filled') !== -1) {
2125
+ addClass([this.filterInputObj.container], 'e-filled');
2126
+ }
2127
+ }
2128
+ append([this.filterInputObj.container], parentElement);
2129
+ prepend([parentElement], popupElement);
2130
+ attributes(this.filterInput, {
2131
+ 'aria-disabled': 'false',
2132
+ 'role': 'combobox',
2133
+ 'autocomplete': 'off',
2134
+ 'autocapitalize': 'off',
2135
+ 'spellcheck': 'false'
2136
+ });
2137
+ this.clearIconElement = this.filterInput.parentElement.querySelector('.' + dropDownListClasses.clearIcon);
2138
+ if (!Browser.isDevice && this.clearIconElement) {
2139
+ EventHandler.add(this.clearIconElement, 'click', this.clearText, this);
2140
+ (this.clearIconElement as HTMLElement).style.visibility = 'hidden';
2141
+ }
2142
+ if (!Browser.isDevice) {
2143
+ this.searchKeyModule = new KeyboardEvents(this.filterInput, {
2144
+ keyAction: this.keyActionHandler.bind(this),
2145
+ keyConfigs: this.keyConfigure,
2146
+ eventName: 'keydown'
2147
+ });
2148
+ } else {
2149
+ this.searchKeyModule = new KeyboardEvents(this.filterInput, {
2150
+ keyAction: this.mobileKeyActionHandler.bind(this),
2151
+ keyConfigs: this.keyConfigure,
2152
+ eventName: 'keydown'
2153
+ });
2154
+ }
2155
+ EventHandler.add(this.filterInput, 'input', this.onInput, this);
2156
+ EventHandler.add(this.filterInput, 'keyup', this.onFilterUp, this);
2157
+ EventHandler.add(this.filterInput, 'keydown', this.onFilterDown, this);
2158
+ EventHandler.add(this.filterInput, 'blur', this.onBlurHandler, this);
2159
+ EventHandler.add(this.filterInput, 'paste', this.pasteHandler, this);
2160
+ return this.filterInputObj;
2161
+ } else {
2162
+ return inputObject;
2163
+ }
2164
+ }
2165
+
2166
+ protected onInput(e: KeyboardEventArgs): void {
2167
+ this.isValidKey = true;
2168
+ if(this.getModuleName() === 'combobox') { this.updateIconState(); }
2169
+ // For filtering works in mobile firefox.
2170
+ if (Browser.isDevice && Browser.info.name === 'mozilla') {
2171
+ this.typedString = this.filterInput.value;
2172
+ this.preventAutoFill = true;
2173
+ this.searchLists(e as KeyboardEventArgs);
2174
+ }
2175
+ }
2176
+
2177
+ protected pasteHandler(e: KeyboardEventArgs): void {
2178
+ setTimeout((): void => {
2179
+ this.typedString = this.filterInput.value;
2180
+ this.searchLists(e);
2181
+ });
2182
+ }
2183
+
2184
+ protected onActionFailure(e: Object): void {
2185
+ super.onActionFailure(e);
2186
+ if (this.beforePopupOpen) {
2187
+ this.renderPopup();
2188
+ }
2189
+ }
2190
+ private UpdateSkeleton(isSkeletonCountChange?: boolean, skeletonCount?: number): void {
2191
+ let isContainSkeleton = this.list.querySelector('.e-virtual-ddl-content');
2192
+ let isContainVirtualList = this.list.querySelector('.e-virtual-list');
2193
+ if (isContainSkeleton && (!isContainVirtualList || isSkeletonCountChange) && this.enableVirtualization) {
2194
+ const totalSkeletonCount: number = isSkeletonCountChange ? skeletonCount : this.skeletonCount;
2195
+ for (let i = 0; i < totalSkeletonCount; i++) {
2196
+ const liElement = this.createElement('li', { className: dropDownListClasses.virtualList, styles: 'overflow: inherit' });
2197
+ if(this.enableVirtualization && this.itemTemplate){
2198
+ liElement.style.height = this.listItemHeight + 'px';
2199
+ }
2200
+ let skeleton: Skeleton = new Skeleton({
2201
+ shape: "Text",
2202
+ height: "10px",
2203
+ width: "95%",
2204
+ cssClass: "e-skeleton-text",
2205
+ });
2206
+ skeleton.appendTo(this.createElement('div'));
2207
+ liElement.appendChild(skeleton.element);
2208
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2209
+ isContainSkeleton.firstChild.insertBefore(liElement, (isContainSkeleton.firstChild as any).children[0]);
2210
+ }
2211
+ }
2212
+ }
2213
+
2214
+ protected getTakeValue(): number {
2215
+ return this.allowFiltering && this.getModuleName() === 'dropdownlist' && Browser.isDevice ? Math.round(window.outerHeight / this.listItemHeight) : this.itemCount;
2216
+ }
2217
+
2218
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2219
+ protected onActionComplete(ulElement: HTMLElement, list: { [key: string]: Object }[], e?: Object, isUpdated?: boolean): void {
2220
+ if (this.dataSource instanceof DataManager && !isNullOrUndefined(e)) {
2221
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2222
+ this.totalItemCount = (e as any).count;
2223
+ }
2224
+ if (this.isNotSearchList && !this.enableVirtualization) {
2225
+ this.isNotSearchList = false;
2226
+ return;
2227
+ }
2228
+ let tempItemCount = this.itemCount;
2229
+ if (this.isActive || !isNullOrUndefined(ulElement)) {
2230
+ const selectedItem: HTMLElement = this.selectedLI ? <HTMLElement>this.selectedLI.cloneNode(true) : null;
2231
+ super.onActionComplete(ulElement, list, e);
2232
+ this.skeletonCount = this.totalItemCount != 0 && this.totalItemCount < (this.itemCount * 2) ? 0 : this.skeletonCount;
2233
+ this.updateSelectElementData(this.allowFiltering);
2234
+ if (this.isRequested && !isNullOrUndefined(this.searchKeyEvent) && this.searchKeyEvent.type === 'keydown') {
2235
+ this.isRequested = false;
2236
+ this.keyActionHandler(this.searchKeyEvent);
2237
+ this.searchKeyEvent = null;
2238
+ }
2239
+ if (this.isRequested && !isNullOrUndefined(this.searchKeyEvent)) {
2240
+ this.incrementalSearch(this.searchKeyEvent);
2241
+ this.searchKeyEvent = null;
2242
+ }
2243
+ if (!this.enableVirtualization) {
2244
+ this.list.scrollTop = 0;
2245
+ }
2246
+ if (!isNullOrUndefined(ulElement)) {
2247
+ attributes(ulElement, { 'id': this.element.id + '_options', 'role': 'listbox', 'aria-hidden': 'false' });
2248
+ }
2249
+ if (this.initRemoteRender) {
2250
+ this.initial = true;
2251
+ this.activeIndex = this.index;
2252
+ this.initRemoteRender = false;
2253
+ if (this.value && this.dataSource instanceof DataManager) {
2254
+ const checkField: string = isNullOrUndefined(this.fields.value) ? this.fields.text : this.fields.value;
2255
+ const fieldValue: string[] = this.fields.value.split('.');
2256
+ const checkVal: boolean = list.some((x: { [key: string]: boolean | string | number }) =>
2257
+ isNullOrUndefined(x[checkField as string]) && fieldValue.length > 1 ?
2258
+ this.checkFieldValue(x, fieldValue) === this.value : x[checkField as string] === this.value);
2259
+ if (!checkVal) {
2260
+ this.dataSource.executeQuery(this.getQuery(this.query).where(new Predicate(checkField, 'equal', this.value)))
2261
+ .then((e: Object) => {
2262
+ if ((e as ResultData).result.length > 0) {
2263
+ this.addItem((e as ResultData).result, list.length);
2264
+ this.updateValues();
2265
+ } else {
2266
+ this.updateValues();
2267
+ }
2268
+ });
2269
+ } else {
2270
+ this.updateValues();
2271
+ }
2272
+ } else {
2273
+ this.updateValues();
2274
+ }
2275
+ this.initial = false;
2276
+ }
2277
+ else if (this.getModuleName() === 'autocomplete' && this.value) {
2278
+ this.setInputValue();
2279
+ }
2280
+ if (this.getModuleName() !== 'autocomplete' && this.isFiltering() && !this.isTyped) {
2281
+ if (!this.actionCompleteData.isUpdated || ((!this.isCustomFilter
2282
+ && !this.isFilterFocus) || (isNullOrUndefined(this.itemData) && this.allowFiltering)
2283
+ && ((this.dataSource instanceof DataManager)
2284
+ || (!isNullOrUndefined(this.dataSource) && !isNullOrUndefined(this.dataSource.length) &&
2285
+ this.dataSource.length !== 0)))) {
2286
+ if (this.itemTemplate && this.element.tagName === 'EJS-COMBOBOX' && this.allowFiltering) {
2287
+ setTimeout(
2288
+ () => {
2289
+ this.updateActionCompleteDataValues(ulElement, list);
2290
+ },
2291
+ 0);
2292
+ } else {
2293
+ this.updateActionCompleteDataValues(ulElement, list);
2294
+ }
2295
+ }
2296
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2297
+ if(((this as any).allowCustom || (this.allowFiltering && !this.isValueInList(list, this.value) && this.dataSource instanceof DataManager)) &&!this.enableVirtualization){
2298
+ this.addNewItem(list, selectedItem);
2299
+ }
2300
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2301
+ else if(((this as any).allowCustom || (this.allowFiltering && this.isValueInList(list, this.value))) && !this.enableVirtualization)
2302
+ {
2303
+ this.addNewItem(list, selectedItem);
2304
+ }
2305
+ if (!isNullOrUndefined(this.itemData) || (isNullOrUndefined(this.itemData) && this.enableVirtualization)) {
2306
+ this.focusIndexItem();
2307
+ }
2308
+ if(this.enableVirtualization){
2309
+ this.updateActionCompleteDataValues(ulElement, list);
2310
+ }
2311
+ } else if (this.enableVirtualization && this.getModuleName() !== 'autocomplete' && !this.isFiltering()) {
2312
+ const value: string | number = this.getItemData().value;
2313
+ this.activeIndex = this.getIndexByValue(value);
2314
+ const element: HTMLElement = this.findListElement(this.list, 'li', 'data-value', value);
2315
+ this.selectedLI = element;
2316
+ }
2317
+ else if(this.enableVirtualization && this.getModuleName() === 'autocomplete'){
2318
+ this.activeIndex = this.skeletonCount
2319
+ }
2320
+ if (this.beforePopupOpen) {
2321
+ this.renderPopup(e);
2322
+ if (this.enableVirtualization) {
2323
+ if (!this.list.querySelector('.e-virtual-list')) {
2324
+ this.UpdateSkeleton();
2325
+ this.liCollections = <HTMLElement[] & NodeListOf<Element>>this.list.querySelectorAll('.e-list-item');
2326
+ }
2327
+ }
2328
+ if (this.enableVirtualization && tempItemCount != this.itemCount) {
2329
+ this.resetList(this.dataSource, this.fields);
2330
+ }
2331
+ }
2332
+
2333
+ }
2334
+ }
2335
+
2336
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2337
+ private isValueInList(list: any[] | { [key: string]: any }, valueToFind: any): boolean {
2338
+ if (Array.isArray(list)) {
2339
+ for (let i = 0; i < list.length; i++) {
2340
+ if (list[i as number] === valueToFind) {
2341
+ return true;
2342
+ }
2343
+ }
2344
+ } else if (typeof list === 'object' && list !== null) {
2345
+ for (const key in list) {
2346
+ if (Object.prototype.hasOwnProperty.call(list, key) && list[key as any] === valueToFind) {
2347
+ return true;
2348
+ }
2349
+ }
2350
+ }
2351
+ return false;
2352
+ }
2353
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2354
+ private checkFieldValue(list: { [key: string]: boolean | string | number }, fieldValue: string[]): any {
2355
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2356
+ let checkField: any = list;
2357
+ fieldValue.forEach((value: string) => {
2358
+ checkField = checkField[value as string];
2359
+ });
2360
+ return checkField;
2361
+ }
2362
+
2363
+ private updateActionCompleteDataValues(ulElement: HTMLElement, list: { [key: string]: Object }[]): void {
2364
+ this.actionCompleteData = { ulElement: ulElement.cloneNode(true) as HTMLElement, list: list, isUpdated: true };
2365
+ if (this.actionData.list !== this.actionCompleteData.list && this.actionCompleteData.ulElement && this.actionCompleteData.list) {
2366
+ this.actionData = this.actionCompleteData;
2367
+ }
2368
+ }
2369
+
2370
+ private addNewItem(listData: { [key: string]: Object }[], newElement: HTMLElement): void {
2371
+ if (!isNullOrUndefined(this.itemData) && !isNullOrUndefined(newElement)) {
2372
+ const value: string | number = this.getItemData().value;
2373
+ const isExist: boolean = listData.some((data: { [key: string]: Object }) => {
2374
+ return (((typeof data === 'string' || typeof data === 'number') && data === value) ||
2375
+ (getValue(this.fields.value, data) === value));
2376
+ });
2377
+ if (!isExist) {
2378
+ this.addItem(this.itemData);
2379
+ }
2380
+ }
2381
+ }
2382
+
2383
+ protected updateActionCompleteData(li: HTMLElement, item: { [key: string]: Object }, index?: number): void {
2384
+ if (this.getModuleName() !== 'autocomplete' && this.actionCompleteData.ulElement) {
2385
+ if (this.itemTemplate && this.element.tagName === 'EJS-COMBOBOX' && this.allowFiltering) {
2386
+ setTimeout(
2387
+ () => {
2388
+ this.actionCompleteDataUpdate(li, item, index);
2389
+ },
2390
+ 0);
2391
+ } else {
2392
+ this.actionCompleteDataUpdate(li, item, index);
2393
+ }
2394
+ }
2395
+ }
2396
+
2397
+ private actionCompleteDataUpdate(li: HTMLElement, item: { [key: string]: Object }, index?: number): void {
2398
+ if (index !== null) {
2399
+ this.actionCompleteData.ulElement.
2400
+ insertBefore(li.cloneNode(true), this.actionCompleteData.ulElement.childNodes[index as number]);
2401
+ } else {
2402
+ this.actionCompleteData.ulElement.appendChild(li.cloneNode(true));
2403
+ }
2404
+ if (this.isFiltering() && this.actionCompleteData.list.indexOf(item) < 0) {
2405
+ this.actionCompleteData.list.push(item);
2406
+ }
2407
+ }
2408
+
2409
+ private focusIndexItem(): void {
2410
+ const value: string | number = this.getItemData().value;
2411
+ this.activeIndex = this.getIndexByValue(value);
2412
+ const element: HTMLElement = this.findListElement(this.list, 'li', 'data-value', value);
2413
+ this.selectedLI = element;
2414
+ this.activeItem(element);
2415
+ if (!(this.enableVirtualization && isNullOrUndefined(element))) {
2416
+ this.removeFocus();
2417
+ }
2418
+ }
2419
+
2420
+ protected updateSelection(): void {
2421
+ const selectedItem: Element = this.list.querySelector('.' + dropDownBaseClasses.selected);
2422
+ if (selectedItem) {
2423
+ this.setProperties({ 'index': this.getIndexByValue(selectedItem.getAttribute('data-value')) });
2424
+ this.activeIndex = this.index;
2425
+ } else {
2426
+ this.removeFocus();
2427
+ this.list.querySelector('.' + dropDownBaseClasses.li).classList.add(dropDownListClasses.focus);
2428
+ }
2429
+ }
2430
+
2431
+ private updateSelectionList(): void {
2432
+ let selectedItem: HTMLElement = this.list && this.list.querySelector('.' + 'e-active');
2433
+ if (!selectedItem && !isNullOrUndefined(this.value)) {
2434
+ var findEle = this.findListElement(this.list, 'li', 'data-value', this.value);
2435
+ if (findEle)
2436
+ {
2437
+ findEle.classList.add('e-active');
2438
+ }
2439
+ }
2440
+ }
2441
+
2442
+ protected checkAndResetCache(): void {
2443
+ if (this.enableVirtualization) {
2444
+ this.generatedDataObject = {};
2445
+ this.virtualItemStartIndex = this.virtualItemEndIndex = 0;
2446
+ this.viewPortInfo = { currentPageNumber: null,
2447
+ direction: null,
2448
+ sentinelInfo: {},
2449
+ offsets: {},
2450
+ startIndex: 0,
2451
+ endIndex: this.itemCount, };
2452
+ this.selectedValueInfo = null;
2453
+ }
2454
+ }
2455
+
2456
+
2457
+ protected removeFocus(): void {
2458
+ const highlightedItem: Element[] = <NodeListOf<Element> & Element[]>this.list.querySelectorAll('.' + dropDownListClasses.focus);
2459
+ if (highlightedItem && highlightedItem.length) {
2460
+ removeClass(highlightedItem, dropDownListClasses.focus);
2461
+ }
2462
+ }
2463
+ protected getTransformValues(): string {
2464
+ let translateY: number = this.viewPortInfo.startIndex * this.listItemHeight;
2465
+ translateY = translateY - (this.skeletonCount * this.listItemHeight);
2466
+ translateY = this.viewPortInfo.startIndex === 0 && this.listData && this.listData.length === 0 ? 0 : translateY;
2467
+ const styleText: string = `transform: translate(0px, ${translateY}px);`;
2468
+ return styleText;
2469
+ }
2470
+ protected GetVirtualTrackHeight(): string {
2471
+ const height: number = this.totalItemCount === this.viewPortInfo.endIndex ? this.totalItemCount * this.listItemHeight - this.itemCount * this.listItemHeight : this.totalItemCount * this.listItemHeight;
2472
+ const heightDimension: string = `height: ${height - this.itemCount * this.listItemHeight}px;`;
2473
+ return heightDimension;
2474
+ }
2475
+
2476
+ protected renderPopup(e?: MouseEvent | KeyboardEventArgs | TouchEvent | Object): void {
2477
+ if (this.popupObj && document.body.contains(this.popupObj.element)) {
2478
+ this.refreshPopup();
2479
+ return;
2480
+ }
2481
+ const args: BeforeOpenEventArgs = { cancel: false };
2482
+ this.trigger('beforeOpen', args, (args: BeforeOpenEventArgs) => {
2483
+ if (!args.cancel) {
2484
+ const popupEle: HTMLElement = this.createElement('div', {
2485
+ id: this.element.id + '_popup', className: 'e-ddl e-popup ' + (this.cssClass !== null ? this.cssClass : '')
2486
+ });
2487
+ const searchBox: InputObject = this.setSearchBox(popupEle);
2488
+ this.listHeight = formatUnit(this.popupHeight);
2489
+ if (this.headerTemplate) {
2490
+ this.setHeaderTemplate(popupEle);
2491
+ }
2492
+ append([this.list], popupEle);
2493
+ if (this.footerTemplate) {
2494
+ this.setFooterTemplate(popupEle);
2495
+ }
2496
+ document.body.appendChild(popupEle);
2497
+ if(this.enableVirtualization && this.itemTemplate) {
2498
+ var listitems = popupEle.querySelectorAll('li.e-list-item:not(.e-virtual-list)');
2499
+ this.listItemHeight = listitems.length > 0 ? Math.ceil(listitems[0].getBoundingClientRect().height) : 0;
2500
+ }
2501
+ if(this.enableVirtualization && !this.list.classList.contains(dropDownBaseClasses.noData)){
2502
+ if(!this.list.querySelector('.e-virtual-ddl-content')){
2503
+ this.list.appendChild(this.createElement('div', {
2504
+ className: 'e-virtual-ddl-content',
2505
+ styles: this.getTransformValues()
2506
+ })).appendChild(this.list.querySelector('.e-list-parent'));
2507
+ }
2508
+ else{
2509
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2510
+ (this.list.getElementsByClassName('e-virtual-ddl-content')[0] as any).style = this.getTransformValues();
2511
+ }
2512
+ this.UpdateSkeleton();
2513
+ this.liCollections = <HTMLElement[] & NodeListOf<Element>>this.list.querySelectorAll('.' + dropDownBaseClasses.li);
2514
+ this.virtualItemCount = this.itemCount;
2515
+ if(!this.list.querySelector('.e-virtual-ddl')){
2516
+ var virualElement = this.createElement('div', {
2517
+ id: this.element.id + '_popup', className: 'e-virtual-ddl', styles: this.GetVirtualTrackHeight()});
2518
+ popupEle.querySelector('.e-dropdownbase').appendChild(virualElement);
2519
+ }
2520
+ else{
2521
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2522
+ (this.list.getElementsByClassName('e-virtual-ddl')[0] as any).style = this.GetVirtualTrackHeight();
2523
+ }
2524
+ }
2525
+ popupEle.style.visibility = 'hidden';
2526
+ if (this.popupHeight !== 'auto') {
2527
+ this.searchBoxHeight = 0;
2528
+ if (!isNullOrUndefined(searchBox.container) && this.getModuleName() !== 'combobox' && this.getModuleName() !== 'autocomplete') {
2529
+ this.searchBoxHeight = (searchBox.container.parentElement).getBoundingClientRect().height;
2530
+ this.listHeight = (parseInt(this.listHeight, 10) - (this.searchBoxHeight)).toString() + 'px';
2531
+ }
2532
+ if (this.headerTemplate) {
2533
+ this.header = this.header ? this.header : popupEle.querySelector('.e-ddl-header');
2534
+ const height: number = Math.round(this.header.getBoundingClientRect().height);
2535
+ this.listHeight = (parseInt(this.listHeight, 10) - (height + this.searchBoxHeight)).toString() + 'px';
2536
+ }
2537
+ if (this.footerTemplate) {
2538
+ this.footer = this.footer ? this.footer : popupEle.querySelector('.e-ddl-footer');
2539
+ const height: number = Math.round(this.footer.getBoundingClientRect().height);
2540
+ this.listHeight = (parseInt(this.listHeight, 10) - (height + this.searchBoxHeight)).toString() + 'px';
2541
+ }
2542
+ this.list.style.maxHeight = (parseInt(this.listHeight, 10) - 2).toString() + 'px'; // due to box-sizing property
2543
+ popupEle.style.maxHeight = formatUnit(this.popupHeight);
2544
+ } else {
2545
+ popupEle.style.height = 'auto';
2546
+ }
2547
+ let offsetValue: number = 0;
2548
+ let left: number;
2549
+ this.isPreventScrollAction = true;
2550
+ if (!isNullOrUndefined(this.selectedLI) && (!isNullOrUndefined(this.activeIndex) && this.activeIndex >= 0)) {
2551
+ this.setScrollPosition();
2552
+ } else if(this.enableVirtualization){
2553
+ this.setScrollPosition();
2554
+ } else {
2555
+ this.list.scrollTop = 0;
2556
+ }
2557
+ if (Browser.isDevice && (!this.allowFiltering && (this.getModuleName() === 'dropdownlist' ||
2558
+ (this.isDropDownClick && this.getModuleName() === 'combobox')))) {
2559
+ offsetValue = this.getOffsetValue(popupEle);
2560
+ const firstItem: HTMLElement = this.isEmptyList() ? this.list : this.liCollections[0];
2561
+ if (!isNullOrUndefined(this.inputElement)) {
2562
+ left = -(parseInt(getComputedStyle(firstItem).textIndent, 10) -
2563
+ parseInt(getComputedStyle(this.inputElement).paddingLeft, 10) +
2564
+ parseInt(getComputedStyle(this.inputElement.parentElement).borderLeftWidth, 10));
2565
+ }
2566
+ }
2567
+ this.getFocusElement();
2568
+ this.createPopup(popupEle, offsetValue, left);
2569
+ this.popupContentElement = this.popupObj.element.querySelector('.e-content');
2570
+ this.checkCollision(popupEle);
2571
+ if (Browser.isDevice) {
2572
+ this.popupObj.element.classList.add(dropDownListClasses.device);
2573
+ if (this.getModuleName() === 'dropdownlist' || (this.getModuleName() === 'combobox'
2574
+ && !this.allowFiltering && this.isDropDownClick)) {
2575
+ this.popupObj.collision = { X: 'fit', Y: 'fit' };
2576
+ }
2577
+ if (this.isFilterLayout()) {
2578
+ this.popupObj.element.classList.add(dropDownListClasses.mobileFilter);
2579
+ this.popupObj.position = { X: 0, Y: 0 };
2580
+ this.popupObj.dataBind();
2581
+ attributes(this.popupObj.element, { style: 'left:0px;right:0px;top:0px;bottom:0px;' });
2582
+ addClass([document.body, this.popupObj.element], dropDownListClasses.popupFullScreen);
2583
+ this.setSearchBoxPosition();
2584
+ this.backIconElement = searchBox.container.querySelector('.e-back-icon');
2585
+ this.clearIconElement = searchBox.container.querySelector('.' + dropDownListClasses.clearIcon);
2586
+ EventHandler.add(this.backIconElement, 'click', this.clickOnBackIcon, this);
2587
+ EventHandler.add(this.clearIconElement, 'click', this.clearText, this);
2588
+ }
2589
+ }
2590
+ popupEle.style.visibility = 'visible';
2591
+ addClass([popupEle], 'e-popup-close');
2592
+ const scrollParentElements: HTMLElement[] = this.popupObj.getScrollableParent(this.inputWrapper.container);
2593
+ for (const element of scrollParentElements) {
2594
+ EventHandler.add(element, 'scroll', this.scrollHandler, this);
2595
+ }
2596
+ if (!isNullOrUndefined(this.list)) {
2597
+ this.unWireListEvents(); this.wireListEvents();
2598
+ }
2599
+ this.selectedElementID = this.selectedLI ? this.selectedLI.id : null;
2600
+ if(this.enableVirtualization){
2601
+ this.notify("bindScrollEvent", {
2602
+ module: "VirtualScroll",
2603
+ component: this.getModuleName(),
2604
+ enable: this.enableVirtualization,
2605
+ });
2606
+ setTimeout(() => {
2607
+ if (this.value) {
2608
+ this.updateSelectionList()
2609
+ if (this.selectedValueInfo && this.viewPortInfo && this.viewPortInfo.offsets.top) {
2610
+ this.list.scrollTop = this.viewPortInfo.offsets.top;
2611
+ } else {
2612
+ this.scrollBottom(true, true);
2613
+ }
2614
+
2615
+ }
2616
+ }, 5);
2617
+ }
2618
+ attributes(this.targetElement(), { 'aria-expanded': 'true', 'aria-owns': this.element.id + '_options' });
2619
+ this.inputElement.setAttribute('aria-expanded', 'true');
2620
+ const inputParent: HTMLElement = this.isFiltering() ? this.filterInput.parentElement : this.inputWrapper.container;
2621
+ addClass([inputParent], [dropDownListClasses.inputFocus]);
2622
+ const animModel: AnimationModel = { name: 'FadeIn', duration: 100 };
2623
+ this.beforePopupOpen = true;
2624
+ const popupInstance: Popup = this.popupObj;
2625
+ const eventArgs: PopupEventArgs = { popup: popupInstance, event: e, cancel: false, animation: animModel };
2626
+ this.trigger('open', eventArgs, (eventArgs: PopupEventArgs) => {
2627
+ if (!eventArgs.cancel) {
2628
+ if (!isNullOrUndefined(this.inputWrapper)) {
2629
+ addClass([this.inputWrapper.container], [dropDownListClasses.iconAnimation]);
2630
+ }
2631
+ this.renderReactTemplates();
2632
+ if (!isNullOrUndefined(this.popupObj)) {
2633
+ this.popupObj.show(new Animation(eventArgs.animation), (this.zIndex === 1000) ? this.element : null);
2634
+ }
2635
+ } else {
2636
+ this.beforePopupOpen = false;
2637
+ this.destroyPopup();
2638
+ }
2639
+ });
2640
+ } else {
2641
+ this.beforePopupOpen = false;
2642
+ }
2643
+ });
2644
+ }
2645
+ private checkCollision(popupEle: HTMLElement): void {
2646
+ if (!Browser.isDevice || (Browser.isDevice && !(this.getModuleName() === 'dropdownlist' || this.isDropDownClick))) {
2647
+ const collision: string[] = isCollide(popupEle);
2648
+ if (collision.length > 0) {
2649
+ popupEle.style.marginTop = -parseInt(getComputedStyle(popupEle).marginTop, 10) + 'px';
2650
+ }
2651
+ this.popupObj.resolveCollision();
2652
+ }
2653
+ }
2654
+ private getOffsetValue(popupEle: HTMLElement): number {
2655
+ const popupStyles: CSSStyleDeclaration = getComputedStyle(popupEle);
2656
+ const borderTop: number = parseInt(popupStyles.borderTopWidth, 10);
2657
+ const borderBottom: number = parseInt(popupStyles.borderBottomWidth, 10);
2658
+ return this.setPopupPosition(borderTop + borderBottom);
2659
+ }
2660
+ private createPopup(element: HTMLElement, offsetValue: number, left: number): void {
2661
+ this.popupObj = new Popup(element, {
2662
+ width: this.setWidth(), targetType: 'relative',
2663
+ relateTo: this.inputWrapper.container,
2664
+ collision: this.enableRtl ? { X: 'fit', Y: 'flip' } : { X: 'flip', Y: 'flip' }, offsetY: offsetValue,
2665
+ enableRtl: this.enableRtl, offsetX: left,
2666
+ position: this.enableRtl ? { X: 'right', Y: 'bottom' } : { X: 'left', Y: 'bottom' },
2667
+ zIndex: this.zIndex,
2668
+ close: () => {
2669
+ if (!this.isDocumentClick) {
2670
+ this.focusDropDown();
2671
+ }
2672
+ // eslint-disable-next-line
2673
+ if ((this as any).isReact) { this.clearTemplate(['headerTemplate', 'footerTemplate']); }
2674
+ this.isNotSearchList = false;
2675
+ this.isDocumentClick = false;
2676
+ this.destroyPopup();
2677
+ if (this.isFiltering() && this.actionCompleteData.list && this.actionCompleteData.list[0]) {
2678
+ this.isActive = true;
2679
+ this.onActionComplete(this.actionCompleteData.ulElement, this.actionCompleteData.list, null, true);
2680
+ }
2681
+ },
2682
+ open: () => {
2683
+ EventHandler.add(document, 'mousedown', this.onDocumentClick, this);
2684
+ this.isPopupOpen = true;
2685
+ const actionList: HTMLElement = this.actionCompleteData && this.actionCompleteData.ulElement &&
2686
+ this.actionCompleteData.ulElement.querySelector('li');
2687
+ const ulElement: HTMLElement = this.list.querySelector('ul li');
2688
+ if (!isNullOrUndefined(this.ulElement) && !isNullOrUndefined(this.ulElement.getElementsByClassName('e-item-focus')[0])) {
2689
+ attributes(this.targetElement(), { 'aria-activedescendant': this.ulElement.getElementsByClassName('e-item-focus')[0].id });
2690
+ } else if (!isNullOrUndefined(this.ulElement) && !isNullOrUndefined(this.ulElement.getElementsByClassName('e-active')[0])) {
2691
+ attributes(this.targetElement(), { 'aria-activedescendant': this.ulElement.getElementsByClassName('e-active')[0].id });
2692
+ }
2693
+ if (this.isFiltering() && this.itemTemplate && (this.element.tagName === this.getNgDirective()) &&
2694
+ (actionList && ulElement && actionList.textContent !== ulElement.textContent) &&
2695
+ this.element.tagName !== 'EJS-COMBOBOX') {
2696
+ this.cloneElements();
2697
+ }
2698
+ if (this.isFilterLayout()) {
2699
+ removeClass([this.inputWrapper.container], [dropDownListClasses.inputFocus]);
2700
+ this.isFilterFocus = true;
2701
+ this.filterInput.focus();
2702
+ if (this.inputWrapper.clearButton) {
2703
+ addClass([this.inputWrapper.clearButton], dropDownListClasses.clearIconHide);
2704
+ }
2705
+ }
2706
+ this.activeStateChange();
2707
+ },
2708
+ targetExitViewport: () => {
2709
+ if (!Browser.isDevice) {
2710
+ this.hidePopup();
2711
+ }
2712
+ }
2713
+ });
2714
+ }
2715
+ private isEmptyList(): boolean {
2716
+ return !isNullOrUndefined(this.liCollections) && this.liCollections.length === 0;
2717
+ }
2718
+
2719
+ protected getFocusElement(): void {
2720
+ // combo-box used this method
2721
+ }
2722
+
2723
+ private isFilterLayout(): boolean {
2724
+ return this.getModuleName() === 'dropdownlist' && this.allowFiltering;
2725
+ }
2726
+
2727
+ private scrollHandler(): void {
2728
+ if (Browser.isDevice && ((this.getModuleName() === 'dropdownlist' &&
2729
+ !this.isFilterLayout()) || (this.getModuleName() === 'combobox' && !this.allowFiltering && this.isDropDownClick))) {
2730
+ this.hidePopup();
2731
+ }
2732
+ }
2733
+
2734
+ private setSearchBoxPosition(): void {
2735
+ const searchBoxHeight: number = this.filterInput.parentElement.getBoundingClientRect().height;
2736
+ this.popupObj.element.style.maxHeight = '100%';
2737
+ this.popupObj.element.style.width = '100%';
2738
+ this.list.style.maxHeight = (window.innerHeight - searchBoxHeight) + 'px';
2739
+ this.list.style.height = (window.innerHeight - searchBoxHeight) + 'px';
2740
+ const clearElement: Element = this.filterInput.parentElement.querySelector('.' + dropDownListClasses.clearIcon);
2741
+ detach(this.filterInput);
2742
+ clearElement.parentElement.insertBefore(this.filterInput, clearElement);
2743
+ }
2744
+
2745
+ private setPopupPosition(border?: number): number {
2746
+ let offsetValue: number;
2747
+ const popupOffset: number = border;
2748
+ const selectedLI: HTMLElement = <HTMLElement>this.list.querySelector('.' + dropDownListClasses.focus) || this.selectedLI;
2749
+ const firstItem: HTMLElement = this.isEmptyList() ? this.list : this.liCollections[0];
2750
+ const lastItem: HTMLElement = this.isEmptyList() ? this.list : this.liCollections[this.getItems().length - 1];
2751
+ const liHeight: number = firstItem.getBoundingClientRect().height;
2752
+ this.listItemHeight = liHeight;
2753
+ const listHeight: number = this.list.offsetHeight / 2;
2754
+ const height: number = isNullOrUndefined(selectedLI) ? firstItem.offsetTop : selectedLI.offsetTop;
2755
+ const lastItemOffsetValue: number = lastItem.offsetTop;
2756
+ if (lastItemOffsetValue - listHeight < height && !isNullOrUndefined(this.liCollections) &&
2757
+ this.liCollections.length > 0 && !isNullOrUndefined(selectedLI)) {
2758
+ const count: number = this.list.offsetHeight / liHeight;
2759
+ const paddingBottom: number = parseInt(getComputedStyle(this.list).paddingBottom, 10);
2760
+ offsetValue = (count - (this.liCollections.length - this.activeIndex)) * liHeight - popupOffset + paddingBottom;
2761
+ this.list.scrollTop = selectedLI.offsetTop;
2762
+ } else if (height > listHeight && !this.enableVirtualization) {
2763
+ offsetValue = listHeight - liHeight / 2;
2764
+ this.list.scrollTop = height - listHeight + liHeight / 2;
2765
+ } else {
2766
+ offsetValue = height;
2767
+ }
2768
+ const inputHeight: number = this.inputWrapper.container.offsetHeight;
2769
+ offsetValue = offsetValue + liHeight + popupOffset - ((liHeight - inputHeight) / 2);
2770
+ return -offsetValue;
2771
+ }
2772
+
2773
+ private setWidth(): string {
2774
+ let width: string = formatUnit(this.popupWidth);
2775
+ if (width.indexOf('%') > -1) {
2776
+ const inputWidth: number = this.inputWrapper.container.offsetWidth * parseFloat(width) / 100;
2777
+ width = inputWidth.toString() + 'px';
2778
+ }
2779
+ if (Browser.isDevice && (!this.allowFiltering && (this.getModuleName() === 'dropdownlist' ||
2780
+ (this.isDropDownClick && this.getModuleName() === 'combobox')))) {
2781
+ const firstItem: HTMLElement = this.isEmptyList() ? this.list : this.liCollections[0];
2782
+ width = (parseInt(width, 10) + (parseInt(getComputedStyle(firstItem).textIndent, 10) -
2783
+ parseInt(getComputedStyle(this.inputElement).paddingLeft, 10) +
2784
+ parseInt(getComputedStyle(this.inputElement.parentElement).borderLeftWidth, 10)) * 2) + 'px';
2785
+ }
2786
+ return width;
2787
+ }
2788
+
2789
+ private scrollBottom(isInitial?: boolean, isInitialSelection: boolean = false, keyAction: string = null): void {
2790
+ if (isNullOrUndefined(this.selectedLI) && this.enableVirtualization) {
2791
+ this.selectedLI = this.list.querySelector('.' + dropDownBaseClasses.li);
2792
+ if(!isNullOrUndefined(this.selectedLI) && this.selectedLI.classList.contains('e-virtual-list')) {
2793
+ this.selectedLI = this.liCollections[this.skeletonCount];
2794
+ }
2795
+ }
2796
+ if (!isNullOrUndefined(this.selectedLI)) {
2797
+ this.isUpwardScrolling = false;
2798
+ let virtualListCount: number = this.list.querySelectorAll('.e-virtual-list').length;
2799
+ let lastElementValue: string = this.list.querySelector('li:last-of-type') ? this.list.querySelector('li:last-of-type').getAttribute('data-value') : null;
2800
+ let selectedLiOffsetTop: number = this.virtualListInfo && this.virtualListInfo.startIndex ? this.selectedLI.offsetTop + (this.virtualListInfo.startIndex * this.selectedLI.offsetHeight) : this.selectedLI.offsetTop;
2801
+ const currentOffset: number = this.list.offsetHeight;
2802
+ let nextBottom: number = selectedLiOffsetTop - (virtualListCount * this.selectedLI.offsetHeight) + this.selectedLI.offsetHeight - this.list.scrollTop;
2803
+ let nextOffset: number = this.list.scrollTop + nextBottom - currentOffset;
2804
+ let isScrollerCHanged: boolean = false;
2805
+ let isScrollTopChanged: boolean = false;
2806
+ nextOffset = isInitial ? nextOffset + parseInt(getComputedStyle(this.list).paddingTop, 10) * 2 : nextOffset + parseInt(getComputedStyle(this.list).paddingTop, 10);
2807
+ let boxRange: number = selectedLiOffsetTop - (virtualListCount * this.selectedLI.offsetHeight) + this.selectedLI.offsetHeight - this.list.scrollTop;
2808
+ boxRange = this.fields.groupBy && !isNullOrUndefined(this.fixedHeaderElement) ?
2809
+ boxRange - this.fixedHeaderElement.offsetHeight : boxRange;
2810
+ if (this.activeIndex === 0 && !this.enableVirtualization) {
2811
+ this.list.scrollTop = 0;
2812
+ isScrollerCHanged = this.isKeyBoardAction;
2813
+ } else if (nextBottom > currentOffset || !(boxRange > 0 && this.list.offsetHeight > boxRange)) {
2814
+ let currentElementValue: string = this.selectedLI ? this.selectedLI.getAttribute('data-value') : null;
2815
+ var liCount = keyAction == "pageDown" ? this.getPageCount() - 2 : 1;
2816
+ if (!this.enableVirtualization || this.isKeyBoardAction || isInitialSelection) {
2817
+ if (this.isKeyBoardAction && this.enableVirtualization && lastElementValue && currentElementValue === lastElementValue && keyAction != "end" && !this.isVirtualScrolling) {
2818
+ this.isPreventKeyAction = true;
2819
+ if(this.enableVirtualization && this.itemTemplate){
2820
+ this.list.scrollTop += nextOffset;
2821
+ }
2822
+ else{
2823
+ this.list.scrollTop += this.selectedLI.offsetHeight * liCount;
2824
+ }
2825
+ this.isPreventKeyAction = this.IsScrollerAtEnd() ? false : this.isPreventKeyAction;
2826
+ this.isKeyBoardAction = false;
2827
+ this.isPreventScrollAction = false;
2828
+ }
2829
+ else if (this.enableVirtualization && keyAction == "end") {
2830
+ this.isPreventKeyAction = false;
2831
+ this.isKeyBoardAction = false;
2832
+ this.isPreventScrollAction = false;
2833
+ this.list.scrollTop = this.list.scrollHeight;
2834
+
2835
+ } else {
2836
+ if (keyAction == "pageDown" && this.enableVirtualization && !this.isVirtualScrolling) {
2837
+ this.isPreventKeyAction = false;
2838
+ this.isKeyBoardAction = false;
2839
+ this.isPreventScrollAction = false;
2840
+ nextOffset = nextOffset + (this.selectedLI.offsetHeight * liCount);
2841
+ }
2842
+
2843
+ this.list.scrollTop = nextOffset;
2844
+ }
2845
+ }
2846
+ else {
2847
+ this.list.scrollTop = this.virtualListInfo && this.virtualListInfo.startIndex ? this.virtualListInfo.startIndex * this.listItemHeight : 0;
2848
+ }
2849
+ isScrollerCHanged = this.isKeyBoardAction;
2850
+ isScrollTopChanged = true;
2851
+ }
2852
+ this.isKeyBoardAction = isScrollerCHanged;
2853
+ }
2854
+ }
2855
+
2856
+ private scrollTop(keyAction: string = null): void {
2857
+ if (!isNullOrUndefined(this.selectedLI)) {
2858
+ let virtualListCount: number = this.list.querySelectorAll('.e-virtual-list').length;
2859
+ let selectedLiOffsetTop: number = (this.virtualListInfo && this.virtualListInfo.startIndex) ? this.selectedLI.offsetTop + (this.virtualListInfo.startIndex * this.selectedLI.offsetHeight) : this.selectedLI.offsetTop;
2860
+ let nextOffset: number = selectedLiOffsetTop - (virtualListCount * this.selectedLI.offsetHeight) - this.list.scrollTop;
2861
+ let firstElementValue: string = this.list.querySelector('li.e-list-item:not(.e-virtual-list)') ? this.list.querySelector('li.e-list-item:not(.e-virtual-list)').getAttribute('data-value') : null;
2862
+ nextOffset = this.fields.groupBy && !isNullOrUndefined(this.fixedHeaderElement) ?
2863
+ nextOffset - this.fixedHeaderElement.offsetHeight : nextOffset;
2864
+ let boxRange: number = (selectedLiOffsetTop - (virtualListCount * this.selectedLI.offsetHeight) + this.selectedLI.offsetHeight - this.list.scrollTop);
2865
+ let isPageUpKeyAction: boolean = this.enableVirtualization && this.getModuleName() === 'autocomplete' && nextOffset <= 0 ;
2866
+ if (this.activeIndex === 0 && !this.enableVirtualization) {
2867
+ this.list.scrollTop = 0;
2868
+ } else if (nextOffset < 0 || isPageUpKeyAction) {
2869
+ var currentElementValue = this.selectedLI ? this.selectedLI.getAttribute('data-value') : null;
2870
+ var liCount = keyAction == "pageUp" ? this.getPageCount() - 2 : 1;
2871
+ if (this.enableVirtualization && this.isKeyBoardAction && firstElementValue && currentElementValue === firstElementValue && keyAction != "home" && !this.isVirtualScrolling) {
2872
+ this.isUpwardScrolling = true;
2873
+ this.isPreventKeyAction = true;
2874
+ this.list.scrollTop -= this.selectedLI.offsetHeight * liCount;
2875
+ this.isPreventKeyAction = this.list.scrollTop != 0 ? this.isPreventKeyAction : false;
2876
+ this.isKeyBoardAction = false;
2877
+ this.isPreventScrollAction = false;
2878
+ }
2879
+ else if (this.enableVirtualization && keyAction == "home") {
2880
+ this.isPreventScrollAction = false;
2881
+ this.isPreventKeyAction = true;
2882
+ this.isKeyBoardAction = false;
2883
+ this.list.scrollTo(0, 0);
2884
+ }
2885
+ else {
2886
+ if (keyAction == "pageUp" && this.enableVirtualization && !this.isVirtualScrolling) {
2887
+ this.isPreventKeyAction = false;
2888
+ this.isKeyBoardAction = false;
2889
+ this.isPreventScrollAction = false;
2890
+ nextOffset = nextOffset - (this.selectedLI.offsetHeight * liCount);
2891
+ }
2892
+ this.list.scrollTop = this.list.scrollTop + nextOffset;
2893
+ }
2894
+ } else if (!(boxRange > 0 && this.list.offsetHeight > boxRange)) {
2895
+ this.list.scrollTop = this.selectedLI.offsetTop - (this.fields.groupBy && !isNullOrUndefined(this.fixedHeaderElement) ?
2896
+ this.fixedHeaderElement.offsetHeight : 0);
2897
+ }
2898
+ }
2899
+ }
2900
+
2901
+ private IsScrollerAtEnd = function () {
2902
+ return this.list && this.list.scrollTop + this.list.clientHeight >= this.list.scrollHeight;
2903
+ }
2904
+
2905
+ protected isEditTextBox(): boolean {
2906
+ return false;
2907
+ }
2908
+
2909
+ protected isFiltering(): boolean {
2910
+ return this.allowFiltering;
2911
+ }
2912
+
2913
+ protected isPopupButton(): boolean {
2914
+ return true;
2915
+ }
2916
+
2917
+ protected setScrollPosition(e?: KeyboardEventArgs): void {
2918
+ this.isPreventScrollAction = true;
2919
+ if (!isNullOrUndefined(e)) {
2920
+ switch (e.action) {
2921
+ case 'pageDown':
2922
+ case 'down':
2923
+ case 'end':
2924
+ this.isKeyBoardAction = true;
2925
+ this.scrollBottom(false, false, e.action)
2926
+ break;
2927
+ default:
2928
+ this.isKeyBoardAction = e.action == 'up' || e.action == 'pageUp' || e.action == 'open';
2929
+ this.scrollTop(e.action)
2930
+ break;
2931
+ }
2932
+ } else {
2933
+ this.scrollBottom(true);
2934
+ }
2935
+ this.isKeyBoardAction = false;
2936
+ }
2937
+
2938
+ private clearText(): void {
2939
+ this.filterInput.value = this.typedString = '';
2940
+ this.searchLists(null);
2941
+ if(this.enableVirtualization){
2942
+ this.list.scrollTop = 0;
2943
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2944
+ this.totalItemCount = this.dataCount = this.dataSource && (this.dataSource as any).length ? (this.dataSource as any).length : 0;
2945
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2946
+ if(this.list.getElementsByClassName('e-virtual-ddl')[0] as any){
2947
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2948
+ (this.list.getElementsByClassName('e-virtual-ddl')[0] as any).style = this.GetVirtualTrackHeight();
2949
+ }
2950
+ this.getSkeletonCount();
2951
+ this.UpdateSkeleton();
2952
+ this.liCollections = <HTMLElement[] & NodeListOf<Element>>this.list.querySelectorAll('.e-list-item');
2953
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2954
+ if(this.list.getElementsByClassName('e-virtual-ddl-content')[0] as any){
2955
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2956
+ (this.list.getElementsByClassName('e-virtual-ddl-content')[0] as any).style = this.getTransformValues();
2957
+ }
2958
+ }
2959
+ }
2960
+
2961
+ private setEleWidth(width: string | number): void {
2962
+ if (!isNullOrUndefined(width)) {
2963
+ if (typeof width === 'number') {
2964
+ this.inputWrapper.container.style.width = formatUnit(width);
2965
+ } else if (typeof width === 'string') {
2966
+ this.inputWrapper.container.style.width = (width.match(/px|%|em/)) ? <string>(width) : <string>(formatUnit(width));
2967
+ }
2968
+ }
2969
+ }
2970
+
2971
+ private closePopup(delay: number, e: MouseEvent | KeyboardEventArgs | TouchEvent): void {
2972
+ let isFilterValue = !isNullOrUndefined(this.filterInput) && !isNullOrUndefined(this.filterInput.value) && this.filterInput.value !== '';
2973
+ const typedString: string = this.getModuleName() === 'combobox' ? this.typedString : null;
2974
+ this.isTyped = false;
2975
+ if (!(this.popupObj && document.body.contains(this.popupObj.element) && this.beforePopupOpen)) {
2976
+ return;
2977
+ }
2978
+ this.keyboardEvent = null;
2979
+ EventHandler.remove(document, 'mousedown', this.onDocumentClick);
2980
+ this.isActive = false;
2981
+ this.filterInputObj = null;
2982
+ this.isDropDownClick = false;
2983
+ this.preventAutoFill = false;
2984
+ const scrollableParentElements: HTMLElement[] = this.popupObj.getScrollableParent(this.inputWrapper.container);
2985
+ for (const element of scrollableParentElements) {
2986
+ EventHandler.remove(element, 'scroll', this.scrollHandler);
2987
+ }
2988
+ if (Browser.isDevice && this.isFilterLayout()) {
2989
+ removeClass([document.body, this.popupObj.element], dropDownListClasses.popupFullScreen);
2990
+ }
2991
+ if (this.isFilterLayout()) {
2992
+ if (!Browser.isDevice) {
2993
+ this.searchKeyModule.destroy();
2994
+ if (this.clearIconElement) {
2995
+ EventHandler.remove(this.clearIconElement, 'click', this.clearText);
2996
+ }
2997
+ }
2998
+ if (this.backIconElement) {
2999
+ EventHandler.remove(this.backIconElement, 'click', this.clickOnBackIcon);
3000
+ EventHandler.remove(this.clearIconElement, 'click', this.clearText);
3001
+ }
3002
+ if (!isNullOrUndefined(this.filterInput)) {
3003
+ EventHandler.remove(this.filterInput, 'input', this.onInput);
3004
+ EventHandler.remove(this.filterInput, 'keyup', this.onFilterUp);
3005
+ EventHandler.remove(this.filterInput, 'keydown', this.onFilterDown);
3006
+ EventHandler.remove(this.filterInput, 'blur', this.onBlurHandler);
3007
+ EventHandler.remove(this.filterInput, 'paste', this.pasteHandler);
3008
+ }
3009
+ this.filterInput = null;
3010
+ }
3011
+ attributes(this.targetElement(), { 'aria-expanded': 'false' });
3012
+ this.inputElement.setAttribute('aria-expanded', 'false');
3013
+ this.targetElement().removeAttribute('aria-owns');
3014
+ this.targetElement().removeAttribute('aria-activedescendant');
3015
+ this.inputWrapper.container.classList.remove(dropDownListClasses.iconAnimation);
3016
+ if (this.isFiltering()) {
3017
+ this.actionCompleteData.isUpdated = false;
3018
+ }
3019
+ if (this.enableVirtualization)
3020
+ {
3021
+ if ((this.value == null || this.isTyped))
3022
+ {
3023
+ this.viewPortInfo.endIndex = this.viewPortInfo && this.viewPortInfo.endIndex > 0 ? this.viewPortInfo.endIndex : this.itemCount;
3024
+ if (this.getModuleName() === 'autocomplete'|| (this.getModuleName() === 'dropdownlist' && !isNullOrUndefined(this.typedString) && this.typedString != "") || (this.getModuleName() === 'combobox' && this.allowFiltering && !isNullOrUndefined(this.typedString) && this.typedString != ""))
3025
+ {
3026
+ this.checkAndResetCache();
3027
+ }
3028
+ }
3029
+ else if(this.getModuleName() === 'autocomplete')
3030
+ {
3031
+ this.checkAndResetCache();
3032
+ }
3033
+ if((this.getModuleName() === 'dropdownlist' || this.getModuleName() === 'combobox') && !(this.skeletonCount==0))
3034
+ {
3035
+ this.getSkeletonCount(true);
3036
+ }
3037
+ }
3038
+ this.beforePopupOpen = false;
3039
+ const animModel: AnimationModel = {
3040
+ name: 'FadeOut',
3041
+ duration: 100,
3042
+ delay: delay ? delay : 0
3043
+ };
3044
+ const popupInstance: Popup = this.popupObj;
3045
+ const eventArgs: PopupEventArgs = { popup: popupInstance, cancel: false, animation: animModel, event: e || null };
3046
+ this.trigger('close', eventArgs, (eventArgs: PopupEventArgs) => {
3047
+ if (!isNullOrUndefined(this.popupObj) &&
3048
+ !isNullOrUndefined(this.popupObj.element.querySelector('.e-fixed-head'))) {
3049
+ const fixedHeader: HTMLElement = this.popupObj.element.querySelector('.e-fixed-head');
3050
+ fixedHeader.parentNode.removeChild(fixedHeader);
3051
+ this.fixedHeaderElement = null;
3052
+ }
3053
+ if (!eventArgs.cancel) {
3054
+ if (this.getModuleName() === 'autocomplete') {
3055
+ this.rippleFun();
3056
+ }
3057
+ if (this.isPopupOpen) {
3058
+ this.popupObj.hide(new Animation(eventArgs.animation));
3059
+ } else {
3060
+ this.destroyPopup();
3061
+ }
3062
+ }
3063
+ });
3064
+ if((this as any).isReact && this.isFiltering() && this.itemTemplate != null){
3065
+ (this as any).actionCompleteData.ulElement = this.ulElement.cloneNode(true);
3066
+ }
3067
+ const dataSourceCount: number = this.dataSource && (this.dataSource as any).length ? (this.dataSource as any).length : 0;
3068
+ if (this.enableVirtualization && this.isFiltering() && this.value != null && isFilterValue && this.totalItemCount !== dataSourceCount) {
3069
+ this.updateInitialData();
3070
+ this.checkAndResetCache();
3071
+ }
3072
+ }
3073
+
3074
+ private updateInitialData(): void {
3075
+ let currentData : any[]= this.selectData;
3076
+ let ulElement = this.renderItems(currentData, this.fields);
3077
+ this.list.scrollTop = 0;
3078
+ this.virtualListInfo = {
3079
+ currentPageNumber: null,
3080
+ direction: null,
3081
+ sentinelInfo: {},
3082
+ offsets: {},
3083
+ startIndex: 0,
3084
+ endIndex: 0,
3085
+ };
3086
+ if(this.getModuleName() === 'combobox'){
3087
+ this.typedString = "";
3088
+ }
3089
+ this.previousStartIndex = 0;
3090
+ this.previousEndIndex = 0;
3091
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3092
+ this.totalItemCount = this.dataCount = this.dataSource && (this.dataSource as any).length ? (this.dataSource as any).length : 0;
3093
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3094
+ if(this.list.getElementsByClassName('e-virtual-ddl')[0] as any){
3095
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3096
+ (this.list.getElementsByClassName('e-virtual-ddl')[0] as any).style = this.GetVirtualTrackHeight();
3097
+ }
3098
+ if(this.getModuleName() !== 'autocomplete' && this.totalItemCount != 0 && this.totalItemCount > (this.itemCount * 2)){
3099
+ this.getSkeletonCount();
3100
+ }
3101
+ this.UpdateSkeleton();
3102
+ this.listData = currentData;
3103
+ this.updateActionCompleteDataValues(ulElement, currentData);
3104
+ this.liCollections = <HTMLElement[] & NodeListOf<Element>>this.list.querySelectorAll('.e-list-item');
3105
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3106
+ if(this.list.getElementsByClassName('e-virtual-ddl-content')[0] as any){
3107
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3108
+ (this.list.getElementsByClassName('e-virtual-ddl-content')[0] as any).style = this.getTransformValues();
3109
+ }
3110
+ }
3111
+
3112
+ private destroyPopup(): void {
3113
+ this.isPopupOpen = false;
3114
+ this.isFilterFocus = false;
3115
+ if(this.popupObj)
3116
+ {
3117
+ this.popupObj.destroy();
3118
+ detach(this.popupObj.element);
3119
+ }
3120
+ }
3121
+
3122
+ private clickOnBackIcon(): void {
3123
+ this.hidePopup();
3124
+ this.focusIn();
3125
+ }
3126
+ /**
3127
+ * To Initialize the control rendering
3128
+ *
3129
+ * @private
3130
+ * @returns {void}
3131
+ */
3132
+ public render(): void {
3133
+ this.preselectedIndex = !isNullOrUndefined(this.index)? this.index : null;
3134
+ if (this.element.tagName === 'INPUT') {
3135
+ this.inputElement = this.element as HTMLInputElement;
3136
+ if (isNullOrUndefined(this.inputElement.getAttribute('role'))) {
3137
+ this.inputElement.setAttribute('role', 'combobox');
3138
+ }
3139
+ if (isNullOrUndefined(this.inputElement.getAttribute('type'))) {
3140
+ this.inputElement.setAttribute('type', 'text');
3141
+ }
3142
+ this.inputElement.setAttribute('aria-expanded', 'false');
3143
+ } else {
3144
+ this.inputElement = this.createElement('input', { attrs: { role: 'combobox', type: 'text' } }) as HTMLInputElement;
3145
+ if (this.element.tagName !== this.getNgDirective()) {
3146
+ this.element.style.display = 'none';
3147
+ }
3148
+ this.element.parentElement.insertBefore(this.inputElement, this.element);
3149
+ this.preventTabIndex(this.inputElement);
3150
+ }
3151
+ let updatedCssClassValues: string = this.cssClass;
3152
+ if (!isNullOrUndefined(this.cssClass) && this.cssClass !== '') {
3153
+ updatedCssClassValues = (this.cssClass.replace(/\s+/g, ' ')).trim();
3154
+ }
3155
+ if (!isNullOrUndefined(closest(this.element, 'fieldset') as HTMLFieldSetElement) && (closest(this.element, 'fieldset') as HTMLFieldSetElement).disabled) {
3156
+ this.enabled = false;
3157
+ }
3158
+ this.inputWrapper = Input.createInput(
3159
+ {
3160
+ element: <HTMLInputElement>this.inputElement,
3161
+ buttons: this.isPopupButton() ? [dropDownListClasses.icon] : null,
3162
+ floatLabelType: this.floatLabelType,
3163
+ properties: {
3164
+ readonly: this.getModuleName() === 'dropdownlist' ? true : this.readonly,
3165
+ placeholder: this.placeholder,
3166
+ cssClass: updatedCssClassValues,
3167
+ enabled: this.enabled,
3168
+ enableRtl: this.enableRtl,
3169
+ showClearButton: this.showClearButton
3170
+ }
3171
+ },
3172
+ this.createElement
3173
+ );
3174
+ if (this.element.tagName === this.getNgDirective()) {
3175
+ this.element.appendChild(this.inputWrapper.container);
3176
+ } else {
3177
+ this.inputElement.parentElement.insertBefore(this.element, this.inputElement);
3178
+ }
3179
+ this.hiddenElement = this.createElement('select', {
3180
+ attrs: { 'aria-hidden': 'true', 'aria-label': this.getModuleName(), 'tabindex': '-1', 'class': dropDownListClasses.hiddenElement }
3181
+ }) as HTMLSelectElement;
3182
+ prepend([this.hiddenElement], this.inputWrapper.container);
3183
+ this.validationAttribute(this.element, this.hiddenElement);
3184
+ this.setReadOnly();
3185
+ this.setFields();
3186
+ this.inputWrapper.container.style.width = formatUnit(this.width);
3187
+ this.inputWrapper.container.classList.add('e-ddl');
3188
+ if (this.floatLabelType === 'Auto') {
3189
+ Input.calculateWidth(this.inputElement, this.inputWrapper.container);
3190
+ }
3191
+ if (!isNullOrUndefined(this.inputWrapper.buttons[0]) && this.inputWrapper.container.getElementsByClassName('e-float-text-content')[0] && this.floatLabelType !== 'Never') {
3192
+ this.inputWrapper.container.getElementsByClassName('e-float-text-content')[0].classList.add('e-icon');
3193
+ }
3194
+ this.wireEvent();
3195
+ this.tabIndex = this.element.hasAttribute('tabindex') ? this.element.getAttribute('tabindex') : '0';
3196
+ this.element.removeAttribute('tabindex');
3197
+ const id: string = this.element.getAttribute('id') ? this.element.getAttribute('id') : getUniqueID('ej2_dropdownlist');
3198
+ this.element.id = id;
3199
+ this.hiddenElement.id = id + '_hidden';
3200
+ this.targetElement().setAttribute('tabindex', this.tabIndex);
3201
+ if((this.getModuleName() === 'autocomplete' || this.getModuleName() === 'combobox') && !this.readonly){
3202
+ this.inputElement.setAttribute('aria-label', this.getModuleName());
3203
+ }else if (this.getModuleName() === 'dropdownlist'){
3204
+ attributes(this.targetElement(), { 'aria-label': this.getModuleName()});
3205
+ }
3206
+ attributes(this.targetElement(), this.getAriaAttributes());
3207
+ this.updateDataAttribute(this.htmlAttributes);
3208
+ this.setHTMLAttributes();
3209
+ if (this.targetElement() === this.inputElement) {
3210
+ this.inputElement.removeAttribute('aria-labelledby');
3211
+ }
3212
+ if (this.value !== null || this.activeIndex !== null || this.text !== null) {
3213
+ if(this.enableVirtualization){
3214
+ this.listItemHeight = this.getListHeight();
3215
+ this.getSkeletonCount();
3216
+ this.updateVirtualizationProperties(this.itemCount, this.allowFiltering);
3217
+ }
3218
+ this.initValue();
3219
+ this.selectedValueInfo = this.viewPortInfo;
3220
+ if (this.enableVirtualization) {
3221
+ this.activeIndex = this.activeIndex + this.skeletonCount;
3222
+ }
3223
+ } else if (this.element.tagName === 'SELECT' && (<HTMLSelectElement>this.element).options[0]) {
3224
+ const selectElement: HTMLSelectElement = <HTMLSelectElement>this.element;
3225
+ this.value = selectElement.options[selectElement.selectedIndex].value;
3226
+ this.text = isNullOrUndefined(this.value) ? null : selectElement.options[selectElement.selectedIndex].textContent;
3227
+ this.initValue();
3228
+ }
3229
+ this.setEnabled();
3230
+ this.preventTabIndex(this.element);
3231
+ if (!this.enabled) {
3232
+ this.targetElement().tabIndex = -1;
3233
+ }
3234
+ this.initial = false;
3235
+ this.element.style.opacity = '';
3236
+ this.inputElement.onselect = (e: UIEvent) => {
3237
+ e.stopImmediatePropagation();
3238
+ };
3239
+ this.inputElement.onchange = (e: UIEvent) => {
3240
+ e.stopImmediatePropagation();
3241
+ };
3242
+ if (this.element.hasAttribute('autofocus')) {
3243
+ this.focusIn();
3244
+ }
3245
+ if (!isNullOrUndefined(this.text)) {
3246
+ this.inputElement.setAttribute('value', this.text);
3247
+ }
3248
+ if (this.element.hasAttribute('data-val')) {
3249
+ this.element.setAttribute('data-val', 'false');
3250
+ }
3251
+ const floatLabelElement: HTMLElement = <HTMLElement>this.inputWrapper.container.getElementsByClassName('e-float-text')[0];
3252
+ if (!isNullOrUndefined(this.element.id) && this.element.id !== '' && !isNullOrUndefined(floatLabelElement)) {
3253
+ floatLabelElement.id = 'label_' + this.element.id.replace(/ /g, '_');
3254
+ attributes(this.inputElement, { 'aria-labelledby': floatLabelElement.id });
3255
+ }
3256
+ this.renderComplete();
3257
+ this.listItemHeight = this.getListHeight();
3258
+ this.getSkeletonCount();
3259
+ if(this.enableVirtualization){
3260
+ this.updateVirtualizationProperties(this.itemCount, this.allowFiltering);
3261
+ }
3262
+ this.viewPortInfo.startIndex = this.virtualItemStartIndex = 0;
3263
+ this.viewPortInfo.endIndex = this.virtualItemEndIndex = this.viewPortInfo.startIndex > 0 ? this.viewPortInfo.endIndex : this.itemCount;
3264
+ }
3265
+
3266
+ private getListHeight(): number {
3267
+ let listParent: HTMLElement = this.createElement('div', {
3268
+ className: 'e-dropdownbase'
3269
+ });
3270
+ let item: HTMLElement = this.createElement('li', {
3271
+ className: 'e-list-item'
3272
+ });
3273
+ let listParentHeight: string = formatUnit(this.popupHeight);
3274
+ listParent.style.height = (parseInt(listParentHeight, 10)).toString() + 'px';
3275
+ listParent.appendChild(item);
3276
+ document.body.appendChild(listParent);
3277
+ this.virtualListHeight = listParent.getBoundingClientRect().height;
3278
+ let listItemHeight: number = Math.ceil(item.getBoundingClientRect().height);
3279
+ listParent.remove();
3280
+ return listItemHeight;
3281
+ }
3282
+
3283
+ private setFooterTemplate(popupEle: HTMLElement): void {
3284
+ let compiledString: Function;
3285
+ if (this.footer) {
3286
+ if ((this as any).isReact && typeof this.footerTemplate === 'function') {
3287
+ this.clearTemplate(['footerTemplate']);
3288
+ } else {
3289
+ this.footer.innerHTML = '';
3290
+ }
3291
+ } else {
3292
+ this.footer = this.createElement('div');
3293
+ addClass([this.footer], dropDownListClasses.footer);
3294
+ }
3295
+ const footercheck: boolean = this.dropdownCompiler(this.footerTemplate);
3296
+ if (typeof this.footerTemplate !== 'function' && footercheck) {
3297
+ compiledString = compile(select(this.footerTemplate, document).innerHTML.trim());
3298
+ } else {
3299
+ compiledString = compile(this.footerTemplate);
3300
+ }
3301
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3302
+ const footerCompTemp: any = compiledString(
3303
+ {}, this, 'footerTemplate', this.footerTemplateId, this.isStringTemplate, null, this.footer);
3304
+ if (footerCompTemp && footerCompTemp.length > 0) {
3305
+ append(footerCompTemp, this.footer);
3306
+ }
3307
+ append([this.footer], popupEle);
3308
+ }
3309
+
3310
+ private setHeaderTemplate(popupEle: HTMLElement): void {
3311
+ let compiledString: Function;
3312
+ if (this.header) {
3313
+ this.header.innerHTML = '';
3314
+ } else {
3315
+ this.header = this.createElement('div');
3316
+ addClass([this.header], dropDownListClasses.header);
3317
+ }
3318
+ const headercheck: boolean = this.dropdownCompiler(this.headerTemplate);
3319
+ if (typeof this.headerTemplate !== 'function' && headercheck) {
3320
+ compiledString = compile(select(this.headerTemplate, document).innerHTML.trim());
3321
+ } else {
3322
+ compiledString = compile(this.headerTemplate);
3323
+ }
3324
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3325
+ const headerCompTemp: any = compiledString(
3326
+ {}, this, 'headerTemplate', this.headerTemplateId, this.isStringTemplate, null, this.header);
3327
+ if (headerCompTemp && headerCompTemp.length) {
3328
+ append(headerCompTemp, this.header);
3329
+ }
3330
+ const contentEle: Element = popupEle.querySelector('div.e-content');
3331
+ popupEle.insertBefore(this.header, contentEle);
3332
+ }
3333
+
3334
+ /**
3335
+ * Sets the enabled state to DropDownBase.
3336
+ *
3337
+ * @returns {void}
3338
+ */
3339
+ protected setEnabled(): void {
3340
+ this.element.setAttribute('aria-disabled', (this.enabled) ? 'false' : 'true');
3341
+ }
3342
+
3343
+ protected setOldText(text: string): void {
3344
+ this.text = text;
3345
+ }
3346
+
3347
+ protected setOldValue(value: string | number | boolean): void {
3348
+ this.value = value;
3349
+ }
3350
+
3351
+ protected refreshPopup(): void {
3352
+ if (!isNullOrUndefined(this.popupObj) && document.body.contains(this.popupObj.element) &&
3353
+ ((this.allowFiltering && !(Browser.isDevice && this.isFilterLayout())) || this.getModuleName() === 'autocomplete')) {
3354
+ removeClass([this.popupObj.element], 'e-popup-close');
3355
+ this.popupObj.refreshPosition(this.inputWrapper.container);
3356
+ this.popupObj.resolveCollision();
3357
+ }
3358
+ }
3359
+ protected checkData(newProp?: DropDownListModel): void {
3360
+ if (newProp.dataSource && !isNullOrUndefined(Object.keys(newProp.dataSource)) && this.itemTemplate && this.allowFiltering &&
3361
+ !(this.isListSearched && (newProp.dataSource instanceof DataManager))) {
3362
+ this.list = null;
3363
+ this.actionCompleteData = { ulElement: null, list: null, isUpdated: false };
3364
+ }
3365
+ this.isListSearched = false;
3366
+ const isChangeValue: boolean = Object.keys(newProp).indexOf('value') !== -1 && isNullOrUndefined(newProp.value);
3367
+ const isChangeText: boolean = Object.keys(newProp).indexOf('text') !== -1 && isNullOrUndefined(newProp.text);
3368
+ if (this.getModuleName() !== 'autocomplete' && this.allowFiltering && (isChangeValue || isChangeText)) {
3369
+ this.itemData = null;
3370
+ }
3371
+ if (this.allowFiltering && newProp.dataSource && !isNullOrUndefined(Object.keys(newProp.dataSource))) {
3372
+ this.actionCompleteData = { ulElement: null, list: null, isUpdated: false };
3373
+ this.actionData = this.actionCompleteData;
3374
+ } else if (this.allowFiltering && newProp.query && !isNullOrUndefined(Object.keys(newProp.query))) {
3375
+ this.actionCompleteData = this.getModuleName() === 'combobox' ?
3376
+ { ulElement: null, list: null, isUpdated: false } : this.actionCompleteData;
3377
+ this.actionData = this.actionCompleteData;
3378
+ }
3379
+ }
3380
+ protected updateDataSource(props?: DropDownListModel): void {
3381
+ if (this.inputElement.value !== '' || (!isNullOrUndefined(props) && (isNullOrUndefined(props.dataSource)
3382
+ || (!(props.dataSource instanceof DataManager) && props.dataSource.length === 0)))) {
3383
+ this.clearAll(null, props);
3384
+ }
3385
+ if ((this.fields.groupBy && props.fields) && !this.isGroupChecking && this.list) {
3386
+ EventHandler.remove(this.list, 'scroll', this.setFloatingHeader);
3387
+ EventHandler.add(this.list, 'scroll', this.setFloatingHeader, this);
3388
+ }
3389
+ if (!(!isNullOrUndefined(props) && (isNullOrUndefined(props.dataSource)
3390
+ || (!(props.dataSource instanceof DataManager) && props.dataSource.length === 0))) || !(props.dataSource === [])) {
3391
+ this.typedString = '';
3392
+ this.resetList(this.dataSource);
3393
+ }
3394
+ if (!this.isCustomFilter && !this.isFilterFocus && document.activeElement !== this.filterInput) {
3395
+ this.checkCustomValue();
3396
+ }
3397
+ }
3398
+ protected checkCustomValue(): void {
3399
+ this.itemData = this.getDataByValue(this.value);
3400
+ const dataItem: { [key: string]: string } = this.getItemData();
3401
+ this.setProperties({ 'text': dataItem.text, 'value': dataItem.value });
3402
+ }
3403
+ private updateInputFields(): void {
3404
+ if (this.getModuleName() === 'dropdownlist') {
3405
+ Input.setValue(this.text, this.inputElement, this.floatLabelType, this.showClearButton);
3406
+ }
3407
+ }
3408
+ /**
3409
+ * Dynamically change the value of properties.
3410
+ *
3411
+ * @private
3412
+ * @param {DropDownListModel} newProp - Returns the dynamic property value of the component.
3413
+ * @param {DropDownListModel} oldProp - Returns the previous previous value of the component.
3414
+ * @returns {void}
3415
+ */
3416
+ public onPropertyChanged(newProp: DropDownListModel, oldProp: DropDownListModel): void {
3417
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3418
+ if (!isNullOrUndefined(newProp.dataSource) && !this.isTouched && (isNullOrUndefined(newProp.value) && isNullOrUndefined(newProp.index)) && !isNullOrUndefined(this.preselectedIndex)) {
3419
+ newProp.index = this.preselectedIndex;
3420
+ }
3421
+ if (!isNullOrUndefined(newProp.value) || !isNullOrUndefined(newProp.index)) {
3422
+ this.isTouched = true;
3423
+ }
3424
+ if (this.getModuleName() === 'dropdownlist') {
3425
+ this.checkData(newProp);
3426
+ this.setUpdateInitial(['fields', 'query', 'dataSource'], newProp as { [key: string]: string });
3427
+ }
3428
+ for (const prop of Object.keys(newProp)) {
3429
+ switch (prop) {
3430
+ case 'query':
3431
+ case 'dataSource':
3432
+ this.getSkeletonCount();
3433
+ this.checkAndResetCache();
3434
+ break;
3435
+ case 'htmlAttributes': this.setHTMLAttributes();
3436
+ break;
3437
+ case 'width': this.setEleWidth(newProp.width); Input.calculateWidth(this.inputElement, this.inputWrapper.container); break;
3438
+ case 'placeholder': Input.setPlaceholder(newProp.placeholder, this.inputElement as HTMLInputElement); break;
3439
+ case 'filterBarPlaceholder':
3440
+ if (this.filterInput) {
3441
+ Input.setPlaceholder(newProp.filterBarPlaceholder, this.filterInput as HTMLInputElement);
3442
+ }
3443
+ break;
3444
+ case 'readonly':
3445
+ if (this.getModuleName() !== 'dropdownlist') {
3446
+ Input.setReadonly(newProp.readonly, this.inputElement as HTMLInputElement);
3447
+ }
3448
+ this.setReadOnly();
3449
+ break;
3450
+ case 'cssClass': this.setCssClass(newProp.cssClass, oldProp.cssClass); Input.calculateWidth(this.inputElement, this.inputWrapper.container); break;
3451
+ case 'enableRtl': this.setEnableRtl(); break;
3452
+ case 'enabled': this.setEnable(); break;
3453
+ case 'text': if (newProp.text === null) {
3454
+ this.clearAll(); break;
3455
+ }
3456
+ if (!this.list) {
3457
+ if (this.dataSource instanceof DataManager) {
3458
+ this.initRemoteRender = true;
3459
+ }
3460
+ this.renderList();
3461
+ }
3462
+ if (!this.initRemoteRender) {
3463
+ const li: Element = this.getElementByText(newProp.text);
3464
+ if (!this.checkValidLi(li)) {
3465
+ if (this.liCollections && this.liCollections.length === 100 &&
3466
+ this.getModuleName() === 'autocomplete' && this.listData.length > 100) {
3467
+ this.setSelectionData(newProp.text, oldProp.text, 'text');
3468
+ } else if (newProp.text && this.dataSource instanceof DataManager) {
3469
+ const listLength: number = this.getItems().length;
3470
+ const checkField: string = isNullOrUndefined(this.fields.text) ? this.fields.value : this.fields.text;
3471
+ this.typedString = '';
3472
+ this.dataSource.executeQuery(this.getQuery(this.query).where(new Predicate(checkField, 'equal', newProp.text)))
3473
+ .then((e: Object) => {
3474
+ if ((e as ResultData).result.length > 0) {
3475
+ this.addItem((e as ResultData).result, listLength);
3476
+ this.updateValues();
3477
+ } else {
3478
+ this.setOldText(oldProp.text);
3479
+ }
3480
+ });
3481
+ } else if (this.getModuleName() === 'autocomplete') {
3482
+ this.setInputValue(newProp, oldProp);
3483
+ } else {
3484
+ this.setOldText(oldProp.text);
3485
+ }
3486
+ }
3487
+ this.updateInputFields();
3488
+ }
3489
+ break;
3490
+ case 'value': if (newProp.value === null) {
3491
+ this.clearAll(); break;
3492
+ }
3493
+ this.notify('beforeValueChange', { newProp: newProp }); // gird component value type change
3494
+ if (!this.list) {
3495
+ if (this.dataSource instanceof DataManager) {
3496
+ this.initRemoteRender = true;
3497
+ }
3498
+ this.renderList();
3499
+ }
3500
+ if (!this.initRemoteRender) {
3501
+ const item: Element = this.getElementByValue(newProp.value);
3502
+ if (!this.checkValidLi(item)) {
3503
+ if (this.liCollections && this.liCollections.length === 100 &&
3504
+ this.getModuleName() === 'autocomplete' && this.listData.length > 100) {
3505
+ this.setSelectionData(newProp.value, oldProp.value, 'value');
3506
+ } else if (newProp.value && this.dataSource instanceof DataManager) {
3507
+ const listLength: number = this.getItems().length;
3508
+ const checkField: string = isNullOrUndefined(this.fields.value) ? this.fields.text : this.fields.value;
3509
+ this.typedString = '';
3510
+ this.dataSource.executeQuery(this.getQuery(this.query).where(new Predicate(checkField, 'equal', newProp.value)))
3511
+ .then((e: Object) => {
3512
+ if ((e as ResultData).result.length > 0) {
3513
+ this.addItem((e as ResultData).result, listLength);
3514
+ this.updateValues();
3515
+ } else {
3516
+ this.setOldValue(oldProp.value);
3517
+ }
3518
+ });
3519
+ } else if (this.getModuleName() === 'autocomplete') {
3520
+ this.setInputValue(newProp, oldProp);
3521
+ } else {
3522
+ this.setOldValue(oldProp.value);
3523
+ }
3524
+ }
3525
+ this.updateInputFields();
3526
+ this.preventChange = this.isAngular && this.preventChange ? !this.preventChange : this.preventChange;
3527
+ }
3528
+ break;
3529
+ case 'index': if (newProp.index === null) {
3530
+ this.clearAll(); break;
3531
+ }
3532
+ if (!this.list) {
3533
+ if (this.dataSource instanceof DataManager) {
3534
+ this.initRemoteRender = true;
3535
+ }
3536
+ this.renderList();
3537
+ }
3538
+ if (!this.initRemoteRender && this.liCollections) {
3539
+ const element: Element = this.liCollections[newProp.index] as Element;
3540
+ if (!this.checkValidLi(element)) {
3541
+ if (this.liCollections && this.liCollections.length === 100 &&
3542
+ this.getModuleName() === 'autocomplete' && this.listData.length > 100) {
3543
+ this.setSelectionData(newProp.index, oldProp.index, 'index');
3544
+ } else {
3545
+ this.index = oldProp.index;
3546
+ }
3547
+ }
3548
+ this.updateInputFields();
3549
+ }
3550
+ break;
3551
+ case 'footerTemplate': if (this.popupObj) {
3552
+ this.setFooterTemplate(this.popupObj.element);
3553
+ } break;
3554
+ case 'headerTemplate': if (this.popupObj) {
3555
+ this.setHeaderTemplate(this.popupObj.element);
3556
+ } break;
3557
+ case 'valueTemplate':
3558
+ if (!isNullOrUndefined(this.itemData) && this.valueTemplate !== null) {
3559
+ this.setValueTemplate();
3560
+ } break;
3561
+ case 'allowFiltering':
3562
+ if (this.allowFiltering) {
3563
+ this.actionCompleteData = {
3564
+ ulElement: this.ulElement,
3565
+ list: this.listData as { [key: string]: Object }[], isUpdated: true
3566
+ };
3567
+ this.actionData = this.actionCompleteData;
3568
+ this.updateSelectElementData(this.allowFiltering);
3569
+ }
3570
+ break;
3571
+ case 'floatLabelType':
3572
+ Input.removeFloating(this.inputWrapper);
3573
+ Input.addFloating(this.inputElement, newProp.floatLabelType, this.placeholder, this.createElement);
3574
+ if (!isNullOrUndefined(this.inputWrapper.buttons[0]) && this.inputWrapper.container.getElementsByClassName('e-float-text-overflow')[0] && this.floatLabelType !== 'Never') {
3575
+ this.inputWrapper.container.getElementsByClassName('e-float-text-overflow')[0].classList.add('e-icon');
3576
+ }
3577
+ break;
3578
+ case 'showClearButton':
3579
+ if(!this.inputWrapper.clearButton){
3580
+ Input.setClearButton(newProp.showClearButton, this.inputElement, this.inputWrapper, null, this.createElement);
3581
+ this.bindClearEvent();
3582
+ }
3583
+ break;
3584
+ default: {
3585
+ // eslint-disable-next-line max-len
3586
+ const ddlProps: { [key: string]: Object } = this.getPropObject(prop, <{ [key: string]: string }>newProp, <{ [key: string]: string }>oldProp);
3587
+ super.onPropertyChanged(ddlProps.newProperty, ddlProps.oldProperty);
3588
+ }
3589
+ break;
3590
+ }
3591
+ }
3592
+ }
3593
+
3594
+ private checkValidLi(element: Element): boolean {
3595
+ if (this.isValidLI(element)) {
3596
+ this.setSelection(element, null);
3597
+ return true;
3598
+ }
3599
+ return false;
3600
+ }
3601
+
3602
+ private setSelectionData(
3603
+ newProp: number | string | boolean,
3604
+ oldProp: number | string | boolean,
3605
+ prop: string
3606
+ ): void {
3607
+ let li: Element;
3608
+ this.updateListValues = (): void => {
3609
+ if (prop === 'text') {
3610
+ li = this.getElementByText(newProp as string);
3611
+ if (!this.checkValidLi(li)) {
3612
+ this.setOldText(oldProp as string);
3613
+ }
3614
+ } else if (prop === 'value') {
3615
+ li = this.getElementByValue(newProp);
3616
+ if (!this.checkValidLi(li)) {
3617
+ this.setOldValue(oldProp);
3618
+ }
3619
+ } else if (prop === 'index') {
3620
+ li = this.liCollections[newProp as number] as Element;
3621
+ if (!this.checkValidLi(li)) {
3622
+ this.index = oldProp as number;
3623
+ }
3624
+ }
3625
+ };
3626
+ }
3627
+
3628
+ protected setReadOnly(): void {
3629
+ if (this.readonly) {
3630
+ addClass([this.inputWrapper.container], ['e-readonly']);
3631
+ } else {
3632
+ removeClass([this.inputWrapper.container], ['e-readonly']);
3633
+ }
3634
+ }
3635
+
3636
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3637
+ protected setInputValue(newProp?: any, oldProp?: any): void {
3638
+ }
3639
+
3640
+ private setCssClass(newClass: string, oldClass: string): void {
3641
+ if (!isNullOrUndefined(oldClass)) {
3642
+ oldClass = (oldClass.replace(/\s+/g, ' ')).trim();
3643
+ }
3644
+ if (!isNullOrUndefined(newClass)) {
3645
+ newClass = (newClass.replace(/\s+/g, ' ')).trim();
3646
+ }
3647
+ Input.setCssClass(newClass, [this.inputWrapper.container], oldClass);
3648
+ if (this.popupObj) {
3649
+ Input.setCssClass(newClass, [this.popupObj.element], oldClass);
3650
+ }
3651
+ }
3652
+ /**
3653
+ * Return the module name of this component.
3654
+ *
3655
+ * @private
3656
+ * @returns {string} Return the module name of this component.
3657
+ */
3658
+ public getModuleName(): string {
3659
+ return 'dropdownlist';
3660
+ }
3661
+ /* eslint-disable valid-jsdoc, jsdoc/require-param */
3662
+ /**
3663
+ * Opens the popup that displays the list of items.
3664
+ *
3665
+ * @returns {void}
3666
+ */
3667
+ public showPopup(e?: MouseEvent | KeyboardEventArgs | TouchEvent): void {
3668
+ /* eslint-enable valid-jsdoc, jsdoc/require-param */
3669
+ if (!this.enabled) {
3670
+ return;
3671
+ }
3672
+ if((this as any).isReact && this.getModuleName() === 'combobox' && this.itemTemplate && this.isCustomFilter && this.isAddNewItemTemplate){
3673
+ this.renderList();
3674
+ this.isAddNewItemTemplate = false;
3675
+ }
3676
+ if (this.isFiltering() && this.dataSource instanceof DataManager && (this.actionData.list !== this.actionCompleteData.list) &&
3677
+ this.actionData.list && this.actionData.ulElement) {
3678
+ this.actionCompleteData = this.actionData;
3679
+ this.onActionComplete(this.actionCompleteData.ulElement, this.actionCompleteData.list, null, true);
3680
+ }
3681
+ if (this.beforePopupOpen) {
3682
+ this.refreshPopup();
3683
+ return;
3684
+ }
3685
+ this.beforePopupOpen = true;
3686
+ if (this.isFiltering() && !this.isActive && this.actionCompleteData.list && this.actionCompleteData.list[0]) {
3687
+ this.isActive = true;
3688
+ this.onActionComplete(this.actionCompleteData.ulElement, this.actionCompleteData.list, null, true);
3689
+ } else if (isNullOrUndefined(this.list) || !isUndefined(this.list) && (this.list.classList.contains(dropDownBaseClasses.noData) ||
3690
+ this.list.querySelectorAll('.' + dropDownBaseClasses.li).length <= 0)) {
3691
+ this.renderList(e);
3692
+ }
3693
+ if (this.enableVirtualization && this.listData && this.listData.length) {
3694
+ if (!isNullOrUndefined(this.value) && (this.getModuleName() === 'dropdownlist' || this.getModuleName() === 'combobox')) {
3695
+ this.removeHover();
3696
+ }
3697
+ if (!this.beforePopupOpen) {
3698
+ this.notify("setCurrentViewDataAsync", {
3699
+ module: "VirtualScroll",
3700
+ });
3701
+ }
3702
+ }
3703
+ this.invokeRenderPopup(e);
3704
+ if (this.enableVirtualization && !this.allowFiltering && this.selectedValueInfo != null && this.selectedValueInfo.startIndex > 0 && this.value != null)
3705
+ {
3706
+ this.notify("dataProcessAsync", {
3707
+ module: "VirtualScroll",
3708
+ isOpen: true,
3709
+ });
3710
+ }
3711
+ }
3712
+
3713
+ private invokeRenderPopup(e?: MouseEvent | KeyboardEventArgs | TouchEvent): void {
3714
+ if (Browser.isDevice && this.isFilterLayout()) {
3715
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
3716
+ const proxy: this = this;
3717
+ window.onpopstate = () => {
3718
+ proxy.hidePopup();
3719
+ };
3720
+ history.pushState({}, '');
3721
+ }
3722
+
3723
+ if (!isNullOrUndefined(this.list) && (!isNullOrUndefined(this.list.children[0]) ||
3724
+ this.list.classList.contains(dropDownBaseClasses.noData))) {
3725
+ this.renderPopup(e);
3726
+ }
3727
+ }
3728
+
3729
+ protected renderHightSearch(): void {
3730
+ // update high light search
3731
+ }
3732
+ /* eslint-disable valid-jsdoc, jsdoc/require-param */
3733
+ /**
3734
+ * Hides the popup if it is in an open state.
3735
+ *
3736
+ * @returns {void}
3737
+ */
3738
+ public hidePopup(e?: MouseEvent | KeyboardEventArgs | TouchEvent): void {
3739
+ /* eslint-enable valid-jsdoc, jsdoc/require-param */
3740
+ if (this.isEscapeKey && this.getModuleName() === 'dropdownlist') {
3741
+ if (!isNullOrUndefined(this.inputElement)) {
3742
+ Input.setValue(this.text, this.inputElement, this.floatLabelType, this.showClearButton);
3743
+ }
3744
+ this.isEscapeKey = false;
3745
+ if (!isNullOrUndefined(this.index)) {
3746
+ const element: HTMLElement = this.findListElement(this.ulElement, 'li', 'data-value', this.value);
3747
+ this.selectedLI = this.liCollections[this.index] || element;
3748
+ if (this.selectedLI) {
3749
+ this.updateSelectedItem(this.selectedLI, null, true);
3750
+ if (this.valueTemplate && this.itemData !== null) {
3751
+ this.setValueTemplate();
3752
+ }
3753
+ }
3754
+ } else {
3755
+ this.resetSelection();
3756
+ }
3757
+ }
3758
+ this.closePopup(0, e);
3759
+ const dataItem: { [key: string]: string } = this.getItemData();
3760
+ const isSelectVal: boolean = !isNullOrUndefined(this.selectedLI);
3761
+ if (this.inputElement && this.inputElement.value.trim() === '' && !this.isInteracted && (this.isSelectCustom ||
3762
+ isSelectVal && this.inputElement.value !== dataItem.text)) {
3763
+ this.isSelectCustom = false;
3764
+ this.clearAll(e);
3765
+ }
3766
+ this.isInteracted = false;
3767
+ }
3768
+ /* eslint-disable valid-jsdoc, jsdoc/require-param */
3769
+ /**
3770
+ * Sets the focus on the component for interaction.
3771
+ *
3772
+ * @returns {void}
3773
+ */
3774
+ public focusIn(e?: FocusEvent | MouseEvent | KeyboardEvent | TouchEvent): void {
3775
+ if (!this.enabled) {
3776
+ return;
3777
+ }
3778
+ if (this.targetElement().classList.contains(dropDownListClasses.disable)) {
3779
+ return;
3780
+ }
3781
+ let isFocused: boolean = false;
3782
+ if (this.preventFocus && Browser.isDevice) {
3783
+ this.inputWrapper.container.tabIndex = 1;
3784
+ this.inputWrapper.container.focus();
3785
+ this.preventFocus = false;
3786
+ isFocused = true;
3787
+ }
3788
+ if (!isFocused) {
3789
+ this.targetElement().focus();
3790
+ }
3791
+ addClass([this.inputWrapper.container], [dropDownListClasses.inputFocus]);
3792
+ this.onFocus(e);
3793
+ if (this.floatLabelType === 'Auto') {
3794
+ Input.calculateWidth(this.inputElement, this.inputWrapper.container);
3795
+ }
3796
+ }
3797
+ /**
3798
+ * Moves the focus from the component if the component is already focused.
3799
+ *
3800
+ * @returns {void}
3801
+ */
3802
+ public focusOut(e?: MouseEvent | KeyboardEventArgs): void {
3803
+ /* eslint-enable valid-jsdoc, jsdoc/require-param */
3804
+ if (!this.enabled) {
3805
+ return;
3806
+ }
3807
+ if (!this.enableVirtualization && this.getModuleName() === 'combobox') {
3808
+ this.isTyped = true;
3809
+ }
3810
+ this.hidePopup(e);
3811
+ if (this.targetElement()) {
3812
+ this.targetElement().blur();
3813
+ }
3814
+ removeClass([this.inputWrapper.container], [dropDownListClasses.inputFocus]);
3815
+ if (this.floatLabelType === 'Auto' && this.inputElement.value === '') {
3816
+ Input.calculateWidth(this.inputElement, this.inputWrapper.container);
3817
+ }
3818
+ }
3819
+ /**
3820
+ * Removes the component from the DOM and detaches all its related event handlers. Also it removes the attributes and classes.
3821
+ *
3822
+ * @method destroy
3823
+ * @returns {void}
3824
+ */
3825
+ public destroy(): void {
3826
+ this.isActive = false;
3827
+ resetIncrementalSearchValues(this.element.id);
3828
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3829
+ if ((this as any).isReact) {
3830
+ this.clearTemplate();
3831
+ }
3832
+ this.hidePopup();
3833
+ this.unWireEvent();
3834
+ if (this.list) {
3835
+ this.unWireListEvents();
3836
+ }
3837
+ if (this.element && !this.element.classList.contains('e-' + this.getModuleName())) {
3838
+ return;
3839
+ }
3840
+ if (this.inputElement) {
3841
+ const attrArray: string[] = ['readonly', 'aria-disabled', 'placeholder', 'aria-labelledby',
3842
+ 'aria-expanded', 'autocomplete', 'aria-readonly', 'autocapitalize',
3843
+ 'spellcheck', 'aria-autocomplete', 'aria-live', 'aria-describedby', 'aria-label'];
3844
+ for (let i: number = 0; i < attrArray.length; i++) {
3845
+ this.inputElement.removeAttribute(attrArray[i as number]);
3846
+ }
3847
+ this.inputElement.setAttribute('tabindex', this.tabIndex);
3848
+ this.inputElement.classList.remove('e-input');
3849
+ Input.setValue('', this.inputElement, this.floatLabelType, this.showClearButton);
3850
+ }
3851
+ this.element.style.display = 'block';
3852
+ if (this.inputWrapper.container.parentElement.tagName === this.getNgDirective()) {
3853
+ detach(this.inputWrapper.container);
3854
+ } else {
3855
+ this.inputWrapper.container.parentElement.insertBefore(this.element, this.inputWrapper.container);
3856
+ detach(this.inputWrapper.container);
3857
+ }
3858
+ this.hiddenElement = null;
3859
+ this.inputWrapper = null;
3860
+ this.keyboardModule = null;
3861
+ this.ulElement = null;
3862
+ this.list = null;
3863
+ this.popupObj = null;
3864
+ this.popupContentElement = null;
3865
+ this.rippleFun = null;
3866
+ this.selectedLI = null;
3867
+ this.liCollections = null;
3868
+ this.item = null;
3869
+ this.inputWrapper = null;
3870
+ this.footer = null;
3871
+ this.header = null;
3872
+ this.previousSelectedLI = null;
3873
+ this.valueTempElement = null;
3874
+ this.actionData.ulElement = null;
3875
+ if (this.inputElement && !isNullOrUndefined(this.inputElement.onchange)) {
3876
+ this.inputElement.onchange = null;
3877
+ }
3878
+ if (this.isAngular) {
3879
+ this.inputElement = null;
3880
+ }
3881
+ super.destroy();
3882
+ }
3883
+ /* eslint-disable valid-jsdoc, jsdoc/require-returns-description */
3884
+ /**
3885
+ * Gets all the list items bound on this component.
3886
+ *
3887
+ * @returns {Element[]}
3888
+ */
3889
+ public getItems(): Element[] {
3890
+ if (!this.list) {
3891
+ if (this.dataSource instanceof DataManager) {
3892
+ this.initRemoteRender = true;
3893
+ }
3894
+ this.renderList();
3895
+ }
3896
+ return this.ulElement ? super.getItems() : [];
3897
+ }
3898
+ /**
3899
+ * Gets the data Object that matches the given value.
3900
+ *
3901
+ * @param { string | number } value - Specifies the value of the list item.
3902
+ * @returns {Object}
3903
+ */
3904
+ public getDataByValue(value: string | number | boolean)
3905
+ : { [key: string]: Object } | string | number | boolean {
3906
+ return super.getDataByValue(value);
3907
+ }
3908
+ /* eslint-enable valid-jsdoc, jsdoc/require-returns-description */
3909
+ /**
3910
+ * Allows you to clear the selected values from the component.
3911
+ *
3912
+ * @returns {void}
3913
+ */
3914
+ public clear(): void {
3915
+ this.value = null;
3916
+ }
3917
+ }
3918
+ type ScrollArg = { direction: string, sentinel: SentinelType, offset: Offsets, focusElement: HTMLElement };
3919
+
3920
+ export interface DropDownListClassList {
3921
+ root: string
3922
+ hover: string
3923
+ selected: string
3924
+ rtl: string
3925
+ base: string
3926
+ disable: string
3927
+ input: string
3928
+ inputFocus: string
3929
+ li: string
3930
+ icon: string
3931
+ iconAnimation: string
3932
+ value: string
3933
+ focus: string
3934
+ device: string
3935
+ backIcon: string
3936
+ filterBarClearIcon: string
3937
+ filterInput: string
3938
+ filterParent: string
3939
+ mobileFilter: string
3940
+ footer: string
3941
+ header: string
3942
+ clearIcon: string
3943
+ clearIconHide: string
3944
+ popupFullScreen: string
3945
+ disableIcon: string
3946
+ hiddenElement: string
3947
+ content: string
3948
+ virtualList: string
3949
+ }
3950
+ interface ActionCompleteData {
3951
+ ulElement?: HTMLElement
3952
+ list?: { [key: string]: Object }[]
3953
+ isUpdated: boolean
3954
+ }