@syncfusion/ej2-dropdowns 24.1.43 → 24.1.45-12082

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