@syncfusion/ej2-dropdowns 23.1.38 → 23.1.40-85814

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