@syncfusion/ej2-dropdowns 23.1.38 → 23.1.40-85814

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (306) hide show
  1. package/CHANGELOG.md +2042 -2034
  2. package/{README.md → ReadMe.md} +217 -217
  3. package/dist/ej2-dropdowns.umd.min.js +1 -10
  4. package/dist/ej2-dropdowns.umd.min.js.map +1 -1
  5. package/dist/es6/ej2-dropdowns.es2015.js +60 -57
  6. package/dist/es6/ej2-dropdowns.es2015.js.map +1 -1
  7. package/dist/es6/ej2-dropdowns.es5.js +202 -199
  8. package/dist/es6/ej2-dropdowns.es5.js.map +1 -1
  9. package/dist/global/ej2-dropdowns.min.js +1 -10
  10. package/dist/global/ej2-dropdowns.min.js.map +1 -1
  11. package/dist/global/index.d.ts +0 -9
  12. package/dist/ts/auto-complete/auto-complete.ts +615 -0
  13. package/dist/ts/combo-box/combo-box.ts +1028 -0
  14. package/dist/ts/common/highlight-search.ts +57 -0
  15. package/dist/ts/common/incremental-search.ts +131 -0
  16. package/dist/ts/common/interface.ts +72 -0
  17. package/dist/ts/common/virtual-scroll.ts +354 -0
  18. package/dist/ts/drop-down-base/drop-down-base.ts +1838 -0
  19. package/dist/ts/drop-down-list/drop-down-list.ts +3889 -0
  20. package/dist/ts/drop-down-tree/drop-down-tree.ts +3750 -0
  21. package/dist/ts/list-box/list-box.ts +2736 -0
  22. package/dist/ts/mention/mention.ts +1828 -0
  23. package/dist/ts/multi-select/checkbox-selection.ts +547 -0
  24. package/dist/ts/multi-select/float-label.ts +176 -0
  25. package/dist/ts/multi-select/interface.ts +70 -0
  26. package/dist/ts/multi-select/multi-select.ts +4874 -0
  27. package/helpers/e2e/autocomplete.js +13 -13
  28. package/helpers/e2e/combobox.js +13 -13
  29. package/helpers/e2e/dropdownlist.js +13 -13
  30. package/helpers/e2e/index.js +3 -3
  31. package/helpers/e2e/listboxHelper.js +13 -13
  32. package/helpers/e2e/multiselect.js +13 -13
  33. package/license +2 -2
  34. package/package.json +79 -79
  35. package/src/auto-complete/auto-complete-model.d.ts +188 -188
  36. package/src/auto-complete/auto-complete.d.ts +12 -12
  37. package/src/auto-complete/auto-complete.js +21 -21
  38. package/src/combo-box/combo-box-model.d.ts +224 -224
  39. package/src/combo-box/combo-box.d.ts +27 -27
  40. package/src/combo-box/combo-box.js +29 -29
  41. package/src/common/virtual-scroll.js +46 -46
  42. package/src/drop-down-base/drop-down-base-model.d.ts +200 -200
  43. package/src/drop-down-base/drop-down-base.d.ts +15 -15
  44. package/src/drop-down-base/drop-down-base.js +20 -20
  45. package/src/drop-down-list/drop-down-list-model.d.ts +202 -202
  46. package/src/drop-down-list/drop-down-list.d.ts +4 -4
  47. package/src/drop-down-list/drop-down-list.js +24 -21
  48. package/src/drop-down-tree/drop-down-tree-model.d.ts +468 -468
  49. package/src/drop-down-tree/drop-down-tree.js +19 -19
  50. package/src/list-box/list-box-model.d.ts +193 -193
  51. package/src/list-box/list-box.d.ts +2 -2
  52. package/src/list-box/list-box.js +19 -19
  53. package/src/mention/mention-model.d.ts +261 -261
  54. package/src/mention/mention.js +19 -19
  55. package/src/multi-select/multi-select-model.d.ts +512 -512
  56. package/src/multi-select/multi-select.js +19 -19
  57. package/styles/auto-complete/_all.scss +1 -1
  58. package/styles/auto-complete/_bootstrap-dark-definition.scss +3 -3
  59. package/styles/auto-complete/_bootstrap-definition.scss +2 -2
  60. package/styles/auto-complete/_bootstrap4-definition.scss +11 -11
  61. package/styles/auto-complete/_bootstrap5-definition.scss +2 -2
  62. package/styles/auto-complete/_fabric-dark-definition.scss +2 -2
  63. package/styles/auto-complete/_fabric-definition.scss +2 -2
  64. package/styles/auto-complete/_fluent-definition.scss +2 -2
  65. package/styles/auto-complete/_fusionnew-definition.scss +2 -2
  66. package/styles/auto-complete/_highcontrast-definition.scss +2 -2
  67. package/styles/auto-complete/_highcontrast-light-definition.scss +2 -2
  68. package/styles/auto-complete/_material-dark-definition.scss +2 -2
  69. package/styles/auto-complete/_material-definition.scss +2 -2
  70. package/styles/auto-complete/_material3-definition.scss +2 -2
  71. package/styles/auto-complete/_tailwind-definition.scss +2 -2
  72. package/styles/auto-complete/bootstrap4.css +13 -2
  73. package/styles/auto-complete/material3-dark.scss +1 -1
  74. package/styles/auto-complete/material3.scss +1 -1
  75. package/styles/bootstrap-dark.css +12 -1
  76. package/styles/bootstrap.css +12 -1
  77. package/styles/bootstrap4.css +44 -3
  78. package/styles/bootstrap5-dark.css +12 -1
  79. package/styles/bootstrap5.css +12 -1
  80. package/styles/combo-box/_all.scss +1 -1
  81. package/styles/combo-box/_bootstrap-dark-definition.scss +2 -2
  82. package/styles/combo-box/_bootstrap-definition.scss +2 -2
  83. package/styles/combo-box/_bootstrap4-definition.scss +11 -11
  84. package/styles/combo-box/_bootstrap5-definition.scss +2 -2
  85. package/styles/combo-box/_fabric-dark-definition.scss +2 -2
  86. package/styles/combo-box/_fabric-definition.scss +2 -2
  87. package/styles/combo-box/_fluent-definition.scss +2 -2
  88. package/styles/combo-box/_fusionnew-definition.scss +2 -2
  89. package/styles/combo-box/_highcontrast-definition.scss +2 -2
  90. package/styles/combo-box/_highcontrast-light-definition.scss +3 -3
  91. package/styles/combo-box/_material-dark-definition.scss +2 -2
  92. package/styles/combo-box/_material-definition.scss +2 -2
  93. package/styles/combo-box/_material3-definition.scss +2 -2
  94. package/styles/combo-box/_tailwind-definition.scss +2 -2
  95. package/styles/combo-box/bootstrap4.css +13 -2
  96. package/styles/combo-box/material3-dark.scss +1 -1
  97. package/styles/combo-box/material3.scss +1 -1
  98. package/styles/drop-down-base/_all.scss +2 -2
  99. package/styles/drop-down-base/_bootstrap-dark-definition.scss +83 -83
  100. package/styles/drop-down-base/_bootstrap-definition.scss +83 -83
  101. package/styles/drop-down-base/_bootstrap4-definition.scss +90 -90
  102. package/styles/drop-down-base/_bootstrap5-definition.scss +117 -117
  103. package/styles/drop-down-base/_definition.scss +23 -23
  104. package/styles/drop-down-base/_fabric-dark-definition.scss +86 -86
  105. package/styles/drop-down-base/_fabric-definition.scss +84 -84
  106. package/styles/drop-down-base/_fluent-definition.scss +121 -121
  107. package/styles/drop-down-base/_fusionnew-definition.scss +117 -117
  108. package/styles/drop-down-base/_highcontrast-definition.scss +105 -105
  109. package/styles/drop-down-base/_highcontrast-light-definition.scss +105 -105
  110. package/styles/drop-down-base/_layout.scss +195 -195
  111. package/styles/drop-down-base/_material-dark-definition.scss +86 -86
  112. package/styles/drop-down-base/_material-definition.scss +85 -85
  113. package/styles/drop-down-base/_material3-definition.scss +87 -87
  114. package/styles/drop-down-base/_tailwind-definition.scss +129 -129
  115. package/styles/drop-down-base/_theme.scss +391 -391
  116. package/styles/drop-down-base/material3-dark.scss +1 -1
  117. package/styles/drop-down-base/material3.scss +1 -1
  118. package/styles/drop-down-list/_all.scss +3 -3
  119. package/styles/drop-down-list/_bootstrap-dark-definition.scss +157 -157
  120. package/styles/drop-down-list/_bootstrap-definition.scss +156 -156
  121. package/styles/drop-down-list/_bootstrap4-definition.scss +202 -191
  122. package/styles/drop-down-list/_bootstrap5-definition.scss +201 -201
  123. package/styles/drop-down-list/_fabric-dark-definition.scss +128 -128
  124. package/styles/drop-down-list/_fabric-definition.scss +124 -124
  125. package/styles/drop-down-list/_fluent-definition.scss +185 -185
  126. package/styles/drop-down-list/_fusionnew-definition.scss +201 -201
  127. package/styles/drop-down-list/_highcontrast-definition.scss +142 -142
  128. package/styles/drop-down-list/_highcontrast-light-definition.scss +144 -144
  129. package/styles/drop-down-list/_layout.scss +310 -310
  130. package/styles/drop-down-list/_material-dark-definition.scss +143 -143
  131. package/styles/drop-down-list/_material-definition.scss +167 -167
  132. package/styles/drop-down-list/_material3-definition.scss +180 -180
  133. package/styles/drop-down-list/_tailwind-definition.scss +134 -134
  134. package/styles/drop-down-list/_theme.scss +10 -10
  135. package/styles/drop-down-list/bootstrap4.css +13 -2
  136. package/styles/drop-down-list/icons/_bootstrap-dark.scss +14 -14
  137. package/styles/drop-down-list/icons/_bootstrap.scss +14 -14
  138. package/styles/drop-down-list/icons/_bootstrap4.scss +14 -14
  139. package/styles/drop-down-list/icons/_bootstrap5.scss +14 -14
  140. package/styles/drop-down-list/icons/_fabric-dark.scss +14 -14
  141. package/styles/drop-down-list/icons/_fabric.scss +14 -14
  142. package/styles/drop-down-list/icons/_fluent.scss +14 -14
  143. package/styles/drop-down-list/icons/_fusionnew.scss +14 -14
  144. package/styles/drop-down-list/icons/_highcontrast-light.scss +14 -14
  145. package/styles/drop-down-list/icons/_highcontrast.scss +14 -14
  146. package/styles/drop-down-list/icons/_material-dark.scss +14 -14
  147. package/styles/drop-down-list/icons/_material.scss +14 -14
  148. package/styles/drop-down-list/icons/_material3.scss +14 -14
  149. package/styles/drop-down-list/icons/_tailwind.scss +14 -14
  150. package/styles/drop-down-list/material3-dark.scss +1 -1
  151. package/styles/drop-down-list/material3.scss +1 -1
  152. package/styles/drop-down-tree/_all.scss +2 -2
  153. package/styles/drop-down-tree/_bootstrap-dark-definition.scss +71 -71
  154. package/styles/drop-down-tree/_bootstrap-definition.scss +70 -70
  155. package/styles/drop-down-tree/_bootstrap4-definition.scss +71 -71
  156. package/styles/drop-down-tree/_bootstrap5-definition.scss +59 -59
  157. package/styles/drop-down-tree/_fabric-dark-definition.scss +71 -71
  158. package/styles/drop-down-tree/_fabric-definition.scss +71 -71
  159. package/styles/drop-down-tree/_fluent-definition.scss +65 -65
  160. package/styles/drop-down-tree/_fusionnew-definition.scss +59 -59
  161. package/styles/drop-down-tree/_highcontrast-definition.scss +71 -71
  162. package/styles/drop-down-tree/_highcontrast-light-definition.scss +71 -71
  163. package/styles/drop-down-tree/_layout.scss +1418 -1412
  164. package/styles/drop-down-tree/_material-dark-definition.scss +72 -72
  165. package/styles/drop-down-tree/_material-definition.scss +72 -72
  166. package/styles/drop-down-tree/_material3-definition.scss +76 -76
  167. package/styles/drop-down-tree/_tailwind-definition.scss +61 -61
  168. package/styles/drop-down-tree/_theme.scss +132 -132
  169. package/styles/drop-down-tree/fluent-dark.css +2 -0
  170. package/styles/drop-down-tree/fluent.css +2 -0
  171. package/styles/drop-down-tree/icons/_bootstrap-dark.scss +11 -11
  172. package/styles/drop-down-tree/icons/_bootstrap.scss +11 -11
  173. package/styles/drop-down-tree/icons/_bootstrap4.scss +11 -11
  174. package/styles/drop-down-tree/icons/_bootstrap5.scss +11 -11
  175. package/styles/drop-down-tree/icons/_fabric-dark.scss +11 -11
  176. package/styles/drop-down-tree/icons/_fabric.scss +11 -11
  177. package/styles/drop-down-tree/icons/_fluent.scss +11 -11
  178. package/styles/drop-down-tree/icons/_fusionnew.scss +11 -11
  179. package/styles/drop-down-tree/icons/_highcontrast-light.scss +11 -11
  180. package/styles/drop-down-tree/icons/_highcontrast.scss +11 -11
  181. package/styles/drop-down-tree/icons/_material-dark.scss +11 -11
  182. package/styles/drop-down-tree/icons/_material.scss +11 -11
  183. package/styles/drop-down-tree/icons/_material3.scss +11 -11
  184. package/styles/drop-down-tree/icons/_tailwind-dark.scss +11 -11
  185. package/styles/drop-down-tree/icons/_tailwind.scss +11 -11
  186. package/styles/drop-down-tree/material3-dark.scss +1 -1
  187. package/styles/drop-down-tree/material3.scss +1 -1
  188. package/styles/fabric-dark.css +13 -2
  189. package/styles/fabric.css +13 -2
  190. package/styles/fluent-dark.css +14 -1
  191. package/styles/fluent.css +14 -1
  192. package/styles/highcontrast-light.css +12 -1
  193. package/styles/highcontrast.css +12 -1
  194. package/styles/list-box/_all.scss +2 -2
  195. package/styles/list-box/_bootstrap-dark-definition.scss +126 -126
  196. package/styles/list-box/_bootstrap-definition.scss +119 -119
  197. package/styles/list-box/_bootstrap4-definition.scss +124 -124
  198. package/styles/list-box/_bootstrap5-definition.scss +120 -120
  199. package/styles/list-box/_fabric-dark-definition.scss +126 -126
  200. package/styles/list-box/_fabric-definition.scss +119 -119
  201. package/styles/list-box/_fluent-definition.scss +120 -120
  202. package/styles/list-box/_fusionnew-definition.scss +111 -111
  203. package/styles/list-box/_highcontrast-definition.scss +119 -119
  204. package/styles/list-box/_highcontrast-light-definition.scss +126 -126
  205. package/styles/list-box/_layout.scss +542 -542
  206. package/styles/list-box/_material-dark-definition.scss +126 -126
  207. package/styles/list-box/_material-definition.scss +119 -119
  208. package/styles/list-box/_material3-definition.scss +119 -119
  209. package/styles/list-box/_tailwind-definition.scss +119 -119
  210. package/styles/list-box/_theme.scss +382 -382
  211. package/styles/list-box/icons/_bootstrap-dark.scss +25 -25
  212. package/styles/list-box/icons/_bootstrap.scss +25 -25
  213. package/styles/list-box/icons/_bootstrap4.scss +25 -25
  214. package/styles/list-box/icons/_bootstrap5.scss +25 -25
  215. package/styles/list-box/icons/_fabric-dark.scss +25 -25
  216. package/styles/list-box/icons/_fabric.scss +25 -25
  217. package/styles/list-box/icons/_fluent.scss +25 -25
  218. package/styles/list-box/icons/_fusionnew.scss +25 -25
  219. package/styles/list-box/icons/_highcontrast-light.scss +25 -25
  220. package/styles/list-box/icons/_highcontrast.scss +25 -25
  221. package/styles/list-box/icons/_material-dark.scss +25 -25
  222. package/styles/list-box/icons/_material.scss +25 -25
  223. package/styles/list-box/icons/_material3.scss +25 -25
  224. package/styles/list-box/icons/_tailwind-dark.scss +25 -25
  225. package/styles/list-box/icons/_tailwind.scss +25 -25
  226. package/styles/list-box/material3-dark.scss +1 -1
  227. package/styles/list-box/material3.scss +1 -1
  228. package/styles/material-dark.css +12 -1
  229. package/styles/material.css +12 -1
  230. package/styles/material3-dark.css +10 -0
  231. package/styles/material3-dark.scss +1 -1
  232. package/styles/material3.css +10 -0
  233. package/styles/material3.scss +1 -1
  234. package/styles/mention/_all.scss +1 -1
  235. package/styles/mention/_bootstrap-dark-definition.scss +3 -3
  236. package/styles/mention/_bootstrap-definition.scss +3 -3
  237. package/styles/mention/_bootstrap4-definition.scss +3 -3
  238. package/styles/mention/_bootstrap5-definition.scss +1 -1
  239. package/styles/mention/_fabric-dark-definition.scss +2 -2
  240. package/styles/mention/_fabric-definition.scss +3 -3
  241. package/styles/mention/_fluent-definition.scss +1 -1
  242. package/styles/mention/_fusionnew-definition.scss +1 -1
  243. package/styles/mention/_highcontrast-definition.scss +3 -3
  244. package/styles/mention/_highcontrast-light-definition.scss +3 -3
  245. package/styles/mention/_layout.scss +6 -6
  246. package/styles/mention/_material-dark-definition.scss +3 -3
  247. package/styles/mention/_material-definition.scss +3 -3
  248. package/styles/mention/_material3-definition.scss +1 -1
  249. package/styles/mention/_tailwind-definition.scss +1 -1
  250. package/styles/mention/material3-dark.scss +1 -1
  251. package/styles/mention/material3.scss +1 -1
  252. package/styles/multi-select/_all.scss +2 -2
  253. package/styles/multi-select/_bootstrap-dark-definition.scss +198 -196
  254. package/styles/multi-select/_bootstrap-definition.scss +192 -190
  255. package/styles/multi-select/_bootstrap4-definition.scss +278 -257
  256. package/styles/multi-select/_bootstrap5-definition.scss +229 -227
  257. package/styles/multi-select/_fabric-dark-definition.scss +187 -185
  258. package/styles/multi-select/_fabric-definition.scss +183 -181
  259. package/styles/multi-select/_fluent-definition.scss +240 -238
  260. package/styles/multi-select/_fusionnew-definition.scss +227 -227
  261. package/styles/multi-select/_highcontrast-definition.scss +298 -296
  262. package/styles/multi-select/_highcontrast-light-definition.scss +297 -295
  263. package/styles/multi-select/_layout.scss +2199 -2188
  264. package/styles/multi-select/_material-dark-definition.scss +230 -228
  265. package/styles/multi-select/_material-definition.scss +223 -221
  266. package/styles/multi-select/_material3-definition.scss +246 -246
  267. package/styles/multi-select/_tailwind-definition.scss +234 -232
  268. package/styles/multi-select/_theme.scss +586 -586
  269. package/styles/multi-select/bootstrap-dark.css +12 -1
  270. package/styles/multi-select/bootstrap.css +12 -1
  271. package/styles/multi-select/bootstrap4.css +31 -1
  272. package/styles/multi-select/bootstrap5-dark.css +12 -1
  273. package/styles/multi-select/bootstrap5.css +12 -1
  274. package/styles/multi-select/fabric-dark.css +13 -2
  275. package/styles/multi-select/fabric.css +13 -2
  276. package/styles/multi-select/fluent-dark.css +12 -1
  277. package/styles/multi-select/fluent.css +12 -1
  278. package/styles/multi-select/highcontrast-light.css +12 -1
  279. package/styles/multi-select/highcontrast.css +12 -1
  280. package/styles/multi-select/icons/_bootstrap-dark.scss +26 -26
  281. package/styles/multi-select/icons/_bootstrap.scss +26 -26
  282. package/styles/multi-select/icons/_bootstrap4.scss +37 -37
  283. package/styles/multi-select/icons/_bootstrap5.scss +26 -26
  284. package/styles/multi-select/icons/_fabric-dark.scss +26 -26
  285. package/styles/multi-select/icons/_fabric.scss +26 -26
  286. package/styles/multi-select/icons/_fluent.scss +55 -55
  287. package/styles/multi-select/icons/_fusionnew.scss +26 -26
  288. package/styles/multi-select/icons/_highcontrast-light.scss +26 -26
  289. package/styles/multi-select/icons/_highcontrast.scss +26 -26
  290. package/styles/multi-select/icons/_material-dark.scss +693 -693
  291. package/styles/multi-select/icons/_material.scss +693 -693
  292. package/styles/multi-select/icons/_material3.scss +692 -692
  293. package/styles/multi-select/icons/_tailwind.scss +26 -26
  294. package/styles/multi-select/material-dark.css +12 -1
  295. package/styles/multi-select/material.css +12 -1
  296. package/styles/multi-select/material3-dark.css +10 -0
  297. package/styles/multi-select/material3-dark.scss +1 -1
  298. package/styles/multi-select/material3.css +10 -0
  299. package/styles/multi-select/material3.scss +1 -1
  300. package/styles/multi-select/tailwind-dark.css +12 -1
  301. package/styles/multi-select/tailwind.css +12 -1
  302. package/styles/tailwind-dark.css +12 -1
  303. package/styles/tailwind.css +12 -1
  304. package/.eslintrc.json +0 -260
  305. package/dist/ej2-dropdowns.min.js +0 -10
  306. package/tslint.json +0 -111
@@ -0,0 +1,57 @@
1
+ export type HightLightType = 'Contains' | 'StartsWith' | 'EndsWith';
2
+ /**
3
+ * Function helps to find which highlightSearch is to call based on your data.
4
+ *
5
+ * @param {HTMLElement} element - Specifies an li element.
6
+ * @param {string} query - Specifies the string to be highlighted.
7
+ * @param {boolean} ignoreCase - Specifies the ignoreCase option.
8
+ * @param {HightLightType} type - Specifies the type of highlight.
9
+ * @returns {void}
10
+ */
11
+ export function highlightSearch(element: HTMLElement, query: string, ignoreCase: boolean, type?: HightLightType): void {
12
+ if (query === '') {
13
+ return;
14
+ } else {
15
+ const ignoreRegex: string = ignoreCase ? 'gim' : 'gm';
16
+ // eslint-disable-next-line
17
+ query = /^[a-zA-Z0-9- ]*$/.test(query) ? query : query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
18
+ const replaceQuery: string = type === 'StartsWith' ? '^(' + query + ')' : type === 'EndsWith' ?
19
+ '(' + query + ')$' : '(' + query + ')';
20
+ // eslint-disable-next-line security/detect-non-literal-regexp
21
+ findTextNode(element, new RegExp(replaceQuery, ignoreRegex));
22
+ }
23
+ }
24
+ /* eslint-enable jsdoc/require-param, valid-jsdoc */
25
+ /**
26
+ *
27
+ * @param {HTMLElement} element - Specifies the element.
28
+ * @param {RegExp} pattern - Specifies the regex to match the searched text.
29
+ * @returns {void}
30
+ */
31
+ function findTextNode(element: HTMLElement, pattern: RegExp): void {
32
+ for (let index: number = 0; element.childNodes && (index < element.childNodes.length); index++) {
33
+ if (element.childNodes[index as number].nodeType === 3 && element.childNodes[index as number].textContent.trim() !== '') {
34
+ const value: string = element.childNodes[index as number].nodeValue.trim().replace(pattern, '<span class="e-highlight">$1</span>');
35
+ element.childNodes[index as number].nodeValue = '';
36
+ element.innerHTML = element.innerHTML.trim() + value;
37
+ break;
38
+ } else {
39
+ findTextNode(element.childNodes[index as number] as HTMLElement, pattern);
40
+ }
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Function helps to remove highlighted element based on your data.
46
+ *
47
+ * @param {HTMLElement} content - Specifies an content element.
48
+ * @returns {void}
49
+ */
50
+ export function revertHighlightSearch(content: HTMLElement): void {
51
+ const contentElement: NodeListOf<Element> = content.querySelectorAll('.e-highlight');
52
+ for (let i: number = contentElement.length - 1; i >= 0; i--) {
53
+ const parent: Node = contentElement[i as number].parentNode;
54
+ const text: Text = document.createTextNode(contentElement[i as number].textContent);
55
+ parent.replaceChild(text, contentElement[i as number]);
56
+ }
57
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * IncrementalSearch module file
3
+ */
4
+
5
+ let queryString: string = '';
6
+ let prevString: string = '';
7
+ let matches: Element[] = [];
8
+ const activeClass: string = 'e-active';
9
+ let prevElementId: string = '';
10
+ export type SearchType = 'StartsWith' | 'Equal' | 'EndsWith' | 'Contains';
11
+ /**
12
+ * Search and focus the list item based on key code matches with list text content
13
+ *
14
+ * @param { number } keyCode - Specifies the key code which pressed on keyboard events.
15
+ * @param { HTMLElement[]} items - Specifies an array of HTMLElement, from which matches find has done.
16
+ * @param { number } selectedIndex - Specifies the selected item in list item, so that search will happen
17
+ * after selected item otherwise it will do from initial.
18
+ * @param { boolean } ignoreCase - Specifies the case consideration when search has done.
19
+ * @param {string} elementId - Specifies the list element ID.
20
+ * @returns {Element} Returns list item based on key code matches with list text content.
21
+ */
22
+ export function incrementalSearch(
23
+ keyCode: number, items: HTMLElement[], selectedIndex: number, ignoreCase: boolean, elementId: string): Element {
24
+ queryString += String.fromCharCode(keyCode);
25
+ setTimeout(() => {
26
+ queryString = '';
27
+ }, 1000);
28
+ let index: number;
29
+ queryString = ignoreCase ? queryString.toLowerCase() : queryString;
30
+ if (prevElementId === elementId && prevString === queryString) {
31
+ for (let i: number = 0; i < matches.length; i++) {
32
+ if (matches[i as number].classList.contains(activeClass)) {
33
+ index = i; break;
34
+ }
35
+ }
36
+ index = index + 1;
37
+ return matches[index as number] ? matches[index as number] : matches[0];
38
+ } else {
39
+ const listItems: Element[] = items;
40
+ const strLength: number = queryString.length;
41
+ let text: string;
42
+ let item: HTMLElement;
43
+ selectedIndex = selectedIndex ? selectedIndex + 1 : 0;
44
+ let i: number = selectedIndex;
45
+ matches = [];
46
+ do {
47
+ if (i === listItems.length) {
48
+ i = -1;
49
+ }
50
+ if (i === -1) {
51
+ index = 0;
52
+ } else {
53
+ index = i;
54
+ }
55
+ item = listItems[index as number] as HTMLElement;
56
+ text = ignoreCase ? item.innerText.toLowerCase() : item.innerText;
57
+ if (text.substr(0, strLength) === queryString) {
58
+ matches.push(listItems[index as number]);
59
+ }
60
+ i++;
61
+ } while (i !== selectedIndex);
62
+ prevString = queryString;
63
+ prevElementId = elementId;
64
+ return matches[0];
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Search the list item based on given input value matches with search type.
70
+ *
71
+ * @param {string} inputVal - Specifies the given input value.
72
+ * @param {HTMLElement[]} items - Specifies the list items.
73
+ * @param {SearchType} searchType - Specifies the filter type.
74
+ * @param {boolean} ignoreCase - Specifies the case sensitive option for search operation.
75
+ * @returns {Element | number} Returns the search matched items.
76
+ */
77
+ export function Search(
78
+ inputVal: string, items: HTMLElement[], searchType: SearchType, ignoreCase?: boolean, dataSource?: string[] | number[] | boolean[] | {
79
+ [key: string]: Object
80
+ }[], fields?: any, type?: string): { [key: string]: Element | number } {
81
+ const listItems: HTMLElement[] = items;
82
+ ignoreCase = ignoreCase !== undefined && ignoreCase !== null ? ignoreCase : true;
83
+ const itemData: { [key: string]: Element | number } = { item: null, index: null };
84
+ if (inputVal && inputVal.length) {
85
+ const strLength: number = inputVal.length;
86
+ let queryStr: string = ignoreCase ? inputVal.toLocaleLowerCase() : inputVal;
87
+ queryStr = escapeCharRegExp(queryStr);
88
+ for (let i: number = 0, itemsData: Element[] = listItems; i < itemsData.length; i++) {
89
+ const item: Element = itemsData[i as number];
90
+ let text: string;
91
+ let filterValue: string;
92
+ if (items && dataSource) {
93
+ let checkField: Element = item;
94
+ let fieldValue = fields.text.split('.');
95
+ (dataSource as { [key: string]: Object }[]).filter(function (data: any) {
96
+ Array.prototype.slice.call(fieldValue).forEach(function (value: string | number) {
97
+ /* eslint-disable security/detect-object-injection */
98
+ if (type === 'object' && (!data.isHeader && checkField.textContent.toString().indexOf(data[value]) !== -1) && checkField.getAttribute('data-value') === data[fields.value].toString() || type === 'string' && checkField.textContent.toString().indexOf(data) !== -1) {
99
+ filterValue = type === 'object' ? data[value] : data;
100
+ }
101
+ });
102
+ })
103
+ }
104
+ text = dataSource && filterValue ? (ignoreCase ? filterValue.toLocaleLowerCase() : filterValue).replace(/^\s+|\s+$/g, '') : (ignoreCase ? item.textContent.toLocaleLowerCase() : item.textContent).replace(/^\s+|\s+$/g, '');
105
+ /* eslint-disable security/detect-non-literal-regexp */
106
+ if ((searchType === 'Equal' && text === queryStr) || (searchType === 'StartsWith' && text.substr(0, strLength) === queryStr) || (searchType === 'EndsWith' && text.substr(text.length - queryStr.length) === queryStr) || (searchType === 'Contains' && new RegExp(queryStr, "g").test(text))) {
107
+ itemData.item = item;
108
+ itemData.index = i;
109
+ return { item: item, index: i };
110
+ }
111
+ }
112
+ return itemData;
113
+ /* eslint-enable security/detect-non-literal-regexp */
114
+
115
+ }
116
+ return itemData;
117
+ }
118
+ /* eslint-enable security/detect-object-injection */
119
+
120
+ export function escapeCharRegExp(value: string) {
121
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
122
+ }
123
+
124
+ export function resetIncrementalSearchValues(elementId: string): void {
125
+ if (prevElementId === elementId) {
126
+ prevElementId = '';
127
+ prevString = '';
128
+ queryString = '';
129
+ matches = [];
130
+ }
131
+ }
@@ -0,0 +1,72 @@
1
+ import { Component, KeyboardEventArgs } from '@syncfusion/ej2-base';
2
+ import { Popup } from '@syncfusion/ej2-popups';
3
+ import { VirtualInfo } from '../common/virtual-scroll';
4
+ import { DataManager, Query } from '@syncfusion/ej2-data';
5
+ import { FieldSettingsModel } from '../drop-down-base/drop-down-base-model';
6
+ import { GeneratedData } from '../drop-down-list/drop-down-list';
7
+ /**
8
+ * Specifies virtual scroll interfaces.
9
+ *
10
+ * @hidden
11
+ */
12
+
13
+ export interface IDropdownlist extends Component<HTMLElement> {
14
+ popupContentElement: HTMLElement;
15
+ isPreventScrollAction: boolean;
16
+ listHeight: string;
17
+ previousStartIndex: number;
18
+ previousEndIndex: number;
19
+ previousInfo: VirtualInfo;
20
+ startIndex: number;
21
+ currentPageNumber: number;
22
+ isMouseScrollAction: boolean;
23
+ isPreventKeyAction: boolean;
24
+ pageCount: number;
25
+ isKeyBoardAction: boolean;
26
+ viewPortInfo: VirtualInfo;
27
+ isUpwardScrolling: boolean;
28
+ queryString: string;
29
+ containerElementRect: ClientRect;
30
+ isScrollActionTriggered: boolean;
31
+ virtualListInfo: VirtualInfo;
32
+ selectedValueInfo: VirtualInfo;
33
+ value: number | string | boolean;
34
+ totalItemCount: number;
35
+ virtualItemCount: number;
36
+ virtualItemEndIndex: number;
37
+ virtualItemStartIndex: number;
38
+ popupObj: Popup;
39
+ listItemHeight: number;
40
+ scrollPreStartIndex: number;
41
+ list: HTMLElement;
42
+ liCollections: HTMLElement[];
43
+ typedString: string
44
+ isVirtualScrolling: boolean;
45
+ isCustomFilter: boolean;
46
+ allowFiltering: boolean;
47
+ isPopupOpen: boolean;
48
+ isTyped: boolean;
49
+ itemCount: number;
50
+ fields: FieldSettingsModel;
51
+ generatedDataObject: GeneratedData;
52
+ keyboardEvent: KeyboardEventArgs;
53
+ dataCount: number;
54
+ filterInput: HTMLInputElement;
55
+ dataSource: { [key: string]: Object }[] | DataManager | string[] | number[] | boolean[];
56
+ listData: { [key: string]: Object }[] | string[] | boolean[] | number[];
57
+ getSkeletonCount(retainSkeleton?: boolean): void;
58
+ getItems(): HTMLElement[];
59
+ getQuery(query: Query): Query;
60
+ getTransformValues(): string;
61
+ UpdateSkeleton(): void;
62
+ updateSelectionList(): void;
63
+ GetVirtualTrackHeight(): string;
64
+ getPageCount(returnExactCount?: boolean): number;
65
+ handleVirtualKeyboardActions(e: KeyboardEventArgs, pageCount: number): void;
66
+ renderItems(listData: { [key: string]: Object }[], fields: FieldSettingsModel): HTMLElement
67
+ resetList(
68
+ dataSource?: { [key: string]: Object }[] | DataManager | string[] | number[] | boolean[],
69
+ fields?: FieldSettingsModel, query?: Query, e?: MouseEvent | KeyboardEventArgs | TouchEvent): void
70
+ findListElement(list: HTMLElement, findNode: string, attribute: string, value: string | boolean | number): HTMLElement;
71
+ }
72
+
@@ -0,0 +1,354 @@
1
+ import { EventHandler, Browser, ScrollEventArgs, select, isNullOrUndefined } from '@syncfusion/ej2-base';
2
+ import { debounce, Touch } from '@syncfusion/ej2-base';
3
+ import { IDropdownlist } from './interface';
4
+ import { DropDownList } from '../drop-down-list/';
5
+ import { Query } from '@syncfusion/ej2-data';
6
+ export type ScrollDirection = 'up' | 'down';
7
+ type ScrollArg = { direction: string, sentinel: SentinelType, offset: Offsets, focusElement: HTMLElement };
8
+ export type SentinelType = {
9
+ check?: (rect: ClientRect, info: SentinelType) => boolean,
10
+ top?: number, entered?: boolean,
11
+ axis?: string;
12
+ };
13
+
14
+ export type SentinelInfo = { up?: SentinelType, down?: SentinelType, right?: SentinelType, left?: SentinelType };
15
+
16
+ export type Offsets = { top?: number, left?: number };
17
+ export interface VirtualInfo {
18
+ currentPageNumber?: number;
19
+ direction?: string;
20
+ sentinelInfo?: SentinelType;
21
+ offsets?: Offsets;
22
+ startIndex?: number;
23
+ endIndex?: number;
24
+ }
25
+
26
+ export class VirtualScroll {
27
+ private parent: IDropdownlist;
28
+ private containerElementRect: ClientRect;
29
+ private element: HTMLElement;
30
+ private options: any;
31
+ private touchModule: Touch;
32
+ private component: string;
33
+
34
+ constructor(parent: IDropdownlist) {
35
+ this.parent = parent;
36
+ this.removeEventListener();
37
+ this.addEventListener();
38
+ }
39
+
40
+ public addEventListener(): void {
41
+ if (this.parent.isDestroyed) {
42
+ return;
43
+ }
44
+ this.parent.on('observe', this.observe, this);
45
+ this.parent.on('setGeneratedData', this.setGeneratedData, this);
46
+ this.parent.on('dataProcessAsync', this.dataProcessAsync, this);
47
+ this.parent.on('setCurrentViewDataAsync', this.setCurrentViewDataAsync, this);
48
+ this.parent.on('bindScrollEvent', this.bindScrollEvent, this);
49
+ }
50
+
51
+ public removeEventListener(): void {
52
+ if (this.parent.isDestroyed) {
53
+ return;
54
+ }
55
+ this.parent.off('observe', this.observe);
56
+ this.parent.off('setGeneratedData', this.setGeneratedData);
57
+ this.parent.off('dataProcessAsync', this.dataProcessAsync);
58
+ this.parent.off('setCurrentViewDataAsync', this.setCurrentViewDataAsync);
59
+ this.parent.off('bindScrollEvent', this.bindScrollEvent);
60
+ }
61
+
62
+ private bindScrollEvent(component: object): void {
63
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
64
+ this.component = (component as any).component;
65
+ this.observe((scrollArgs: ScrollArg) => this.scrollListener(scrollArgs));
66
+ }
67
+
68
+ private observe(callback: Function): void {
69
+ this.containerElementRect = this.parent.popupContentElement.getBoundingClientRect();
70
+ EventHandler.add(this.parent.popupContentElement, 'wheel mousedown', this.popupScrollHandler, this);
71
+ this.touchModule = new Touch(this.parent.popupContentElement, {
72
+ scroll: this.popupScrollHandler.bind(this)
73
+ });
74
+ EventHandler.add(this.parent.popupContentElement, 'scroll', this.virtualScrollHandler(callback), this);
75
+ }
76
+
77
+ public getModuleName(): string {
78
+ return 'VirtualScroll';
79
+ }
80
+
81
+ private popupScrollHandler(e: ScrollEventArgs): void {
82
+ this.parent.isMouseScrollAction = true;
83
+ this.parent.isPreventScrollAction = false;
84
+ }
85
+
86
+ private getPageQuery(query: Query, virtualStartIndex: number, virtualEndIndex: number): Query {
87
+ if (virtualEndIndex !== 0 && !this.parent.allowFiltering && this.component !== 'autocomplete') {
88
+ query = query.skip(virtualStartIndex);
89
+ }
90
+ return query;
91
+ }
92
+
93
+ private setGeneratedData(qStartIndex: number, recentlyGeneratedData: object[]): void {
94
+ let loopIteration: number = 0;
95
+ let endIndex: number = this.parent.listData.length + this.parent.virtualItemStartIndex;
96
+ for (let i = this.parent.virtualItemStartIndex; i < endIndex; i++) {
97
+ const alreadyAddedData: object | undefined = this.parent.generatedDataObject[i as number];
98
+ if (!alreadyAddedData) {
99
+ if (recentlyGeneratedData !== null && this.parent.listData.slice(loopIteration, loopIteration + 1).length > 0) {
100
+ const slicedData = this.parent.listData.slice(loopIteration, loopIteration + 1);
101
+ if (slicedData.length > 0) {
102
+ // Safely assign slicedData to this.parent.generatedDataObject[i]
103
+ this.parent.generatedDataObject[i as number] = slicedData;
104
+ }
105
+ }
106
+ }
107
+ loopIteration++;
108
+ }
109
+ }
110
+
111
+ private generateAndExecuteQueryAsync(query: Query, virtualItemStartIndex: number = 0, virtualItemEndIndex: number = 0, isQueryGenerated: boolean = false): void {
112
+ let dataSource = this.parent.dataSource;
113
+ if (!isQueryGenerated) {
114
+ query = this.getPageQuery(query, virtualItemStartIndex, virtualItemEndIndex);
115
+ }
116
+ this.parent.resetList(dataSource, this.parent.fields, query);
117
+ }
118
+
119
+ public setCurrentViewDataAsync(): void {
120
+ // eslint-disable-next-line
121
+ let currentData: any = [];
122
+ for (let i = this.parent.viewPortInfo.startIndex; i < this.parent.viewPortInfo.endIndex; i++) {
123
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
124
+ const alreadyAddedData: any = this.parent.generatedDataObject[i as number];
125
+ if (alreadyAddedData) {
126
+ currentData.push(alreadyAddedData[0]);
127
+ }
128
+ }
129
+ this.parent.renderItems(currentData, this.parent.fields);
130
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
131
+ const virtualTrackElement = this.parent.list.getElementsByClassName('e-virtual-ddl')[0] as any;
132
+ if (virtualTrackElement) {
133
+ (virtualTrackElement).style = this.parent.GetVirtualTrackHeight();
134
+ }
135
+ this.parent.UpdateSkeleton();
136
+ this.parent.liCollections = <HTMLElement[] & NodeListOf<Element>>this.parent.list.querySelectorAll('.e-list-item');
137
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
138
+ const virtualContentElement = this.parent.list.getElementsByClassName('e-virtual-ddl-content')[0] as any;
139
+ if (virtualContentElement) {
140
+ (virtualContentElement).style = this.parent.getTransformValues();
141
+ }
142
+ }
143
+
144
+ private generateQueryAndSetQueryIndexAsync(query: Query, isPopupOpen?: boolean): void {
145
+ let isStartIndexInitialised: boolean = false;
146
+ let queryStartIndex: number = 0;
147
+ let queryEndIndex: number = 0;
148
+ let sortedDataStartIndex: number = 0;
149
+ let vEndIndex: number = this.parent && this.parent.viewPortInfo.endIndex !== 0 ? this.parent.viewPortInfo.endIndex : sortedDataStartIndex + this.parent.getItems().length;
150
+ if (!isPopupOpen && vEndIndex !== 0) {
151
+ for (let i = this.parent.viewPortInfo.startIndex; i <= vEndIndex; i++) {
152
+ if (!(i in this.parent.generatedDataObject)) {
153
+ if (!isStartIndexInitialised) {
154
+ isStartIndexInitialised = true;
155
+ queryStartIndex = queryEndIndex = i;
156
+ } else {
157
+ queryEndIndex = i === vEndIndex ? i : i + 1;
158
+ }
159
+ }
160
+ }
161
+ }
162
+ if (isStartIndexInitialised && !((this.parent.totalItemCount == queryStartIndex) && (this.parent.totalItemCount == queryEndIndex))) {
163
+ this.parent.virtualItemStartIndex = queryStartIndex;
164
+ this.parent.virtualItemEndIndex = queryEndIndex;
165
+ this.generateAndExecuteQueryAsync(query, queryStartIndex, queryEndIndex);
166
+ }
167
+ this.setCurrentViewDataAsync();
168
+ }
169
+ private dataProcessAsync(isOpenPopup?: boolean): void {
170
+ this.parent.selectedValueInfo = null;
171
+ this.parent.virtualItemStartIndex = this.parent.viewPortInfo.startIndex;
172
+ this.parent.virtualItemEndIndex = this.parent.viewPortInfo.endIndex;
173
+ this.generateQueryAndSetQueryIndexAsync(new Query(), isOpenPopup);
174
+ }
175
+ private async virtualScrollRefreshAsync(): Promise<void> {
176
+ this.parent.isCustomFilter = (!(this.parent.isTyped || (this.component === 'combobox' && this.parent.allowFiltering && this.parent.queryString != this.parent.typedString) || (!isNullOrUndefined(this.parent.filterInput) && !isNullOrUndefined(this.parent.filterInput.value) && this.parent.filterInput.value !=='') && this.component !== 'combobox') && !(this.component === 'autocomplete' && this.parent.value != null)) || this.parent.isCustomFilter;
177
+ if (this.parent.allowFiltering || this.component === 'autocomplete') {
178
+ if (!isNullOrUndefined(this.parent.typedString) && !(this.component === 'combobox' && !isNullOrUndefined(this.parent.typedString) && this.parent.allowFiltering)) {
179
+ if (this.parent.viewPortInfo.endIndex >= this.parent.dataCount) {
180
+ this.parent.viewPortInfo.endIndex = this.parent.dataCount;
181
+ }
182
+ if (this.parent.viewPortInfo.startIndex >= this.parent.dataCount) {
183
+ this.parent.viewPortInfo.startIndex = this.parent.dataCount - this.parent.itemCount;
184
+ }
185
+ }
186
+ else {
187
+ this.parent.getSkeletonCount(true);
188
+ }
189
+ }
190
+ await this.dataProcessAsync();
191
+ if (this.parent.keyboardEvent != null) {
192
+ this.parent.handleVirtualKeyboardActions(this.parent.keyboardEvent, this.parent.pageCount);
193
+ }
194
+ this.parent.isCustomFilter = false;
195
+ }
196
+
197
+ public scrollListener(scrollArgs: ScrollArg): void {
198
+ if (!this.parent.isPreventScrollAction) {
199
+ let info: SentinelType = scrollArgs.sentinel;
200
+ let pStartIndex: number = this.parent.previousStartIndex;
201
+ this.parent.viewPortInfo = this.getInfoFromView(scrollArgs.direction, info, scrollArgs.offset, false);
202
+ this.parent.isUpwardScrolling = false;
203
+ if (this.parent.previousStartIndex !== pStartIndex && !this.parent.isKeyBoardAction) {
204
+ this.parent.isScrollActionTriggered = false;
205
+ this.parent.currentPageNumber = this.parent.viewPortInfo.currentPageNumber;
206
+ this.parent.virtualListInfo = { ...this.parent.viewPortInfo };
207
+ this.parent.isPreventKeyAction = true;
208
+ this.parent.isVirtualScrolling = true;
209
+ setTimeout(() => {
210
+ this.parent.pageCount = this.parent.getPageCount();
211
+ this.virtualScrollRefreshAsync().then(() => {
212
+ if (this.parent.popupObj) {
213
+ this.parent.list = this.parent.popupObj.element.querySelector('.' + 'e-content') || select('.' + 'e-content');
214
+ this.parent.updateSelectionList();
215
+ this.parent.liCollections = <HTMLElement[] & NodeListOf<Element>>this.parent.getItems();
216
+ }
217
+ this.parent.isKeyBoardAction = false;
218
+ this.parent.isVirtualScrolling = false;
219
+ this.parent.isPreventKeyAction = false;
220
+ });
221
+ }, 5);
222
+ }
223
+ else if (this.parent.isScrollActionTriggered) {
224
+ this.parent.isPreventKeyAction = false;
225
+ this.parent.isScrollActionTriggered = false;
226
+ let virtualListCount: number = this.parent.list.querySelectorAll('.e-virtual-list').length;
227
+ let listElement: HTMLElement = this.parent.list.querySelector('.' + 'e-list-item');
228
+ let translateY: number = scrollArgs.offset.top - (listElement.offsetHeight * virtualListCount);
229
+ (this.parent.list.getElementsByClassName('e-virtual-ddl-content') as HTMLCollectionOf<HTMLElement>)[0].style.transform = "translate(0px," + translateY + "px)"
230
+ }
231
+ this.parent.previousInfo = this.parent.viewPortInfo;
232
+ }
233
+ }
234
+
235
+ private getPageCount(popupElement: HTMLElement, returnExactCount: boolean = false): number {
236
+ var list = popupElement && popupElement.querySelector('.e-content');
237
+ if (list) {
238
+ var liHeight = list.classList.contains('e-nodata') ? null : getComputedStyle(list.querySelectorAll('.e-list-item')[0], null).getPropertyValue('height');
239
+ var pageCount = list.getBoundingClientRect().height / parseInt(liHeight, 10)
240
+ return returnExactCount ? pageCount : Math.round(pageCount);
241
+ }
242
+ return 0;
243
+ };
244
+
245
+ private getRowHeight(): number {
246
+ return (isNullOrUndefined(this.parent.liCollections) || this.parent.liCollections.length == 0) ? 0 : Math.ceil(this.parent.liCollections[0].getBoundingClientRect().height);
247
+ }
248
+ private getInfoFromView(direction: string, info: SentinelType, e: Offsets, isscrollAction: boolean): VirtualInfo {
249
+
250
+ let infoType: VirtualInfo = {
251
+ direction: direction, sentinelInfo: info, offsets: e,
252
+ startIndex: this.parent.previousStartIndex, endIndex: this.parent.previousEndIndex
253
+ };
254
+ let vHeight: string | number = this.parent.popupContentElement.getBoundingClientRect().height;
255
+ //Row Start and End Index calculation
256
+ let rowHeight: number = this.parent.listItemHeight;
257
+ let exactTopIndex: number = e.top / rowHeight;
258
+ let infoViewIndices: number = vHeight / rowHeight;
259
+ let exactEndIndex: number = exactTopIndex + infoViewIndices;
260
+ let pageSizeBy4: number = this.parent.virtualItemCount / 4;
261
+ let totalItemCount: number = this.parent.totalItemCount;
262
+ if (infoType.direction === 'down') {
263
+ let sIndex: number = Math.round(exactEndIndex) - Math.round((pageSizeBy4));
264
+
265
+ if (isNullOrUndefined(infoType.startIndex) || (exactEndIndex >
266
+ (infoType.startIndex + Math.round((this.parent.virtualItemCount / 2 + pageSizeBy4)))
267
+ && infoType.endIndex !== totalItemCount)) {
268
+ infoType.startIndex = sIndex >= 0 ? Math.round(sIndex) : 0;
269
+ infoType.startIndex = infoType.startIndex > exactTopIndex ? Math.floor(exactTopIndex) : infoType.startIndex;
270
+ let eIndex: number = infoType.startIndex + this.parent.virtualItemCount;
271
+ infoType.startIndex = eIndex < exactEndIndex ? (Math.ceil(exactEndIndex) - this.parent.virtualItemCount)
272
+ : infoType.startIndex;
273
+ infoType.endIndex = eIndex < totalItemCount ? eIndex : totalItemCount;
274
+ infoType.startIndex = eIndex >= totalItemCount ? (infoType.endIndex - this.parent.virtualItemCount > 0 ? infoType.endIndex - this.parent.virtualItemCount : 0) : infoType.startIndex;
275
+ infoType.currentPageNumber = Math.ceil(infoType.endIndex / this.parent.virtualItemCount);
276
+ }
277
+ } else if (infoType.direction === 'up') {
278
+ if (infoType.startIndex && infoType.endIndex) {
279
+ let loadAtIndex: number = Math.round(((infoType.startIndex * rowHeight) + (pageSizeBy4 * rowHeight)) / rowHeight);
280
+ if (exactTopIndex < loadAtIndex) {
281
+ let idxAddedToExactTop: number = (pageSizeBy4) > infoViewIndices ? pageSizeBy4 :
282
+ (infoViewIndices + infoViewIndices / 4);
283
+ let eIndex: number = Math.round(exactTopIndex + idxAddedToExactTop);
284
+ infoType.endIndex = eIndex < totalItemCount ? eIndex : totalItemCount;
285
+ let sIndex: number = infoType.endIndex - this.parent.virtualItemCount;
286
+ infoType.startIndex = sIndex > 0 ? sIndex : 0;
287
+ infoType.endIndex = sIndex < 0 ? this.parent.virtualItemCount : infoType.endIndex;
288
+ infoType.currentPageNumber = Math.ceil(infoType.startIndex / this.parent.virtualItemCount);
289
+ }
290
+ }
291
+ }
292
+ if (!isscrollAction) {
293
+ this.parent.previousStartIndex = infoType.startIndex;
294
+ this.parent.startIndex = infoType.startIndex;
295
+ this.parent.previousEndIndex = infoType.endIndex;
296
+ }
297
+ else {
298
+ this.parent.scrollPreStartIndex = infoType.startIndex;
299
+ }
300
+ return infoType;
301
+ }
302
+ private sentinelInfo: SentinelInfo = {
303
+ 'up': {
304
+ check: (rect: ClientRect, info: SentinelType) => {
305
+ let top: number = rect.top - this.containerElementRect.top;
306
+ info.entered = top >= 0;
307
+ return top + (this.parent.listItemHeight * this.parent.virtualItemCount / 2) >= 0;
308
+ },
309
+ axis: 'Y'
310
+ },
311
+ 'down': {
312
+ check: (rect: ClientRect, info: SentinelType) => {
313
+ let cHeight: number = this.parent.popupContentElement.clientHeight;
314
+ let top: number = rect.bottom;
315
+ info.entered = rect.bottom <= this.containerElementRect.bottom;
316
+ return top - (this.parent.listItemHeight * this.parent.virtualItemCount / 2) <= this.parent.listItemHeight * this.parent.virtualItemCount / 2;
317
+ }, axis: 'Y'
318
+ }
319
+ };
320
+
321
+ private virtualScrollHandler(callback?: Function): Function {
322
+ let delay: number = Browser.info.name === 'chrome' ? 200 : 100;
323
+ let prevTop: number = 0; let debounced100: Function = debounce(callback, delay);
324
+ let debounced50: Function = debounce(callback, 50);
325
+ return (e: Event) => {
326
+ let top: number = (<HTMLElement>e.target).scrollTop;
327
+ let left: number = (<HTMLElement>e.target).scrollLeft;
328
+ let direction: ScrollDirection = prevTop < top && !this.parent.isUpwardScrolling ? 'down' : 'up';
329
+ prevTop = top;
330
+ let current: SentinelType = this.sentinelInfo[direction as 'up' | 'down'];
331
+ var pstartIndex = this.parent.scrollPreStartIndex;
332
+ var scrollOffsetargs = {
333
+ top: top,
334
+ left: left
335
+ }
336
+ if (this.parent.list.querySelectorAll('.e-virtual-list').length > 0) {
337
+ var infoview = this.getInfoFromView(direction, current, scrollOffsetargs, true)
338
+ if (this.parent.scrollPreStartIndex != pstartIndex && !this.parent.isPreventScrollAction) {
339
+ this.parent.isScrollActionTriggered = true;
340
+ let virtualPoup: HTMLElement = (this.parent.list.querySelector('.e-virtual-ddl-content'));
341
+ virtualPoup.style.transform = "translate(0px," + top + "px)";
342
+ }
343
+ }
344
+ let debounceFunction: Function = debounced100;
345
+ if (current.axis === 'X') { debounceFunction = debounced50; }
346
+ debounceFunction({ direction: direction, sentinel: current, offset: { top: top, left: left },
347
+ focusElement: document.activeElement});
348
+ };
349
+ }
350
+
351
+ public destroy(): void {
352
+ this.removeEventListener();
353
+ }
354
+ }