@syncfusion/ej2-dropdowns 23.1.43 → 23.2.4-13895

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/CHANGELOG.md +2114 -2084
  2. package/{README.md → ReadMe.md} +217 -217
  3. package/dist/ej2-dropdowns.min.js +1 -10
  4. package/dist/ej2-dropdowns.umd.min.js +1 -10
  5. package/dist/ej2-dropdowns.umd.min.js.map +1 -1
  6. package/dist/es6/ej2-dropdowns.es2015.js +83 -71
  7. package/dist/es6/ej2-dropdowns.es2015.js.map +1 -1
  8. package/dist/es6/ej2-dropdowns.es5.js +225 -212
  9. package/dist/es6/ej2-dropdowns.es5.js.map +1 -1
  10. package/dist/global/ej2-dropdowns.min.js +1 -10
  11. package/dist/global/ej2-dropdowns.min.js.map +1 -1
  12. package/dist/global/index.d.ts +0 -9
  13. package/dist/ts/auto-complete/auto-complete.ts +615 -0
  14. package/dist/ts/combo-box/combo-box.ts +1028 -0
  15. package/dist/ts/common/highlight-search.ts +57 -0
  16. package/dist/ts/common/incremental-search.ts +131 -0
  17. package/dist/ts/common/interface.ts +72 -0
  18. package/dist/ts/common/virtual-scroll.ts +354 -0
  19. package/dist/ts/drop-down-base/drop-down-base.ts +1864 -0
  20. package/dist/ts/drop-down-list/drop-down-list.ts +3954 -0
  21. package/dist/ts/drop-down-tree/drop-down-tree.ts +3741 -0
  22. package/dist/ts/list-box/list-box.ts +2753 -0
  23. package/dist/ts/mention/mention.ts +1857 -0
  24. package/dist/ts/multi-select/checkbox-selection.ts +547 -0
  25. package/dist/ts/multi-select/float-label.ts +176 -0
  26. package/dist/ts/multi-select/interface.ts +70 -0
  27. package/dist/ts/multi-select/multi-select.ts +4880 -0
  28. package/helpers/e2e/autocomplete.js +13 -13
  29. package/helpers/e2e/combobox.js +13 -13
  30. package/helpers/e2e/dropdownlist.js +13 -13
  31. package/helpers/e2e/index.js +3 -3
  32. package/helpers/e2e/listboxHelper.js +13 -13
  33. package/helpers/e2e/multiselect.js +13 -13
  34. package/license +2 -2
  35. package/package.json +80 -80
  36. package/src/auto-complete/auto-complete-model.d.ts +188 -188
  37. package/src/auto-complete/auto-complete.d.ts +12 -12
  38. package/src/auto-complete/auto-complete.js +21 -21
  39. package/src/combo-box/combo-box-model.d.ts +224 -224
  40. package/src/combo-box/combo-box.d.ts +27 -27
  41. package/src/combo-box/combo-box.js +29 -29
  42. package/src/common/virtual-scroll.js +46 -46
  43. package/src/drop-down-base/drop-down-base-model.d.ts +200 -200
  44. package/src/drop-down-base/drop-down-base.d.ts +15 -15
  45. package/src/drop-down-base/drop-down-base.js +23 -21
  46. package/src/drop-down-list/drop-down-list-model.d.ts +202 -202
  47. package/src/drop-down-list/drop-down-list.d.ts +4 -4
  48. package/src/drop-down-list/drop-down-list.js +24 -21
  49. package/src/drop-down-tree/drop-down-tree-model.d.ts +468 -468
  50. package/src/drop-down-tree/drop-down-tree.d.ts +0 -1
  51. package/src/drop-down-tree/drop-down-tree.js +19 -27
  52. package/src/list-box/list-box-model.d.ts +193 -193
  53. package/src/list-box/list-box.d.ts +5 -2
  54. package/src/list-box/list-box.js +38 -21
  55. package/src/mention/mention-model.d.ts +261 -261
  56. package/src/mention/mention.js +20 -21
  57. package/src/multi-select/multi-select-model.d.ts +512 -512
  58. package/src/multi-select/multi-select.js +19 -19
  59. package/styles/auto-complete/_all.scss +1 -1
  60. package/styles/auto-complete/_bootstrap-dark-definition.scss +3 -3
  61. package/styles/auto-complete/_bootstrap-definition.scss +2 -2
  62. package/styles/auto-complete/_bootstrap4-definition.scss +11 -11
  63. package/styles/auto-complete/_bootstrap5-definition.scss +2 -2
  64. package/styles/auto-complete/_fabric-dark-definition.scss +2 -2
  65. package/styles/auto-complete/_fabric-definition.scss +2 -2
  66. package/styles/auto-complete/_fluent-definition.scss +2 -2
  67. package/styles/auto-complete/_fusionnew-definition.scss +2 -2
  68. package/styles/auto-complete/_highcontrast-definition.scss +2 -2
  69. package/styles/auto-complete/_highcontrast-light-definition.scss +2 -2
  70. package/styles/auto-complete/_material-dark-definition.scss +2 -2
  71. package/styles/auto-complete/_material-definition.scss +2 -2
  72. package/styles/auto-complete/_material3-definition.scss +2 -2
  73. package/styles/auto-complete/_tailwind-definition.scss +2 -2
  74. package/styles/auto-complete/material3-dark.scss +1 -1
  75. package/styles/auto-complete/material3.scss +1 -1
  76. package/styles/bootstrap-dark.css +5 -0
  77. package/styles/bootstrap5-dark.css +2 -1
  78. package/styles/bootstrap5.css +2 -1
  79. package/styles/combo-box/_all.scss +1 -1
  80. package/styles/combo-box/_bootstrap-dark-definition.scss +2 -2
  81. package/styles/combo-box/_bootstrap-definition.scss +2 -2
  82. package/styles/combo-box/_bootstrap4-definition.scss +11 -11
  83. package/styles/combo-box/_bootstrap5-definition.scss +2 -2
  84. package/styles/combo-box/_fabric-dark-definition.scss +2 -2
  85. package/styles/combo-box/_fabric-definition.scss +2 -2
  86. package/styles/combo-box/_fluent-definition.scss +2 -2
  87. package/styles/combo-box/_fusionnew-definition.scss +2 -2
  88. package/styles/combo-box/_highcontrast-definition.scss +2 -2
  89. package/styles/combo-box/_highcontrast-light-definition.scss +3 -3
  90. package/styles/combo-box/_material-dark-definition.scss +2 -2
  91. package/styles/combo-box/_material-definition.scss +2 -2
  92. package/styles/combo-box/_material3-definition.scss +2 -2
  93. package/styles/combo-box/_tailwind-definition.scss +2 -2
  94. package/styles/combo-box/material3-dark.scss +1 -1
  95. package/styles/combo-box/material3.scss +1 -1
  96. package/styles/drop-down-base/_all.scss +2 -2
  97. package/styles/drop-down-base/_bootstrap-dark-definition.scss +83 -83
  98. package/styles/drop-down-base/_bootstrap-definition.scss +83 -83
  99. package/styles/drop-down-base/_bootstrap4-definition.scss +90 -90
  100. package/styles/drop-down-base/_bootstrap5-definition.scss +117 -117
  101. package/styles/drop-down-base/_definition.scss +23 -23
  102. package/styles/drop-down-base/_fabric-dark-definition.scss +86 -86
  103. package/styles/drop-down-base/_fabric-definition.scss +84 -84
  104. package/styles/drop-down-base/_fluent-definition.scss +121 -121
  105. package/styles/drop-down-base/_fusionnew-definition.scss +117 -117
  106. package/styles/drop-down-base/_highcontrast-definition.scss +105 -105
  107. package/styles/drop-down-base/_highcontrast-light-definition.scss +105 -105
  108. package/styles/drop-down-base/_layout.scss +195 -195
  109. package/styles/drop-down-base/_material-dark-definition.scss +86 -86
  110. package/styles/drop-down-base/_material-definition.scss +85 -85
  111. package/styles/drop-down-base/_material3-definition.scss +87 -87
  112. package/styles/drop-down-base/_tailwind-definition.scss +129 -129
  113. package/styles/drop-down-base/_theme.scss +391 -391
  114. package/styles/drop-down-base/material3-dark.scss +1 -1
  115. package/styles/drop-down-base/material3.scss +1 -1
  116. package/styles/drop-down-list/_all.scss +3 -3
  117. package/styles/drop-down-list/_bootstrap-dark-definition.scss +157 -157
  118. package/styles/drop-down-list/_bootstrap-definition.scss +156 -156
  119. package/styles/drop-down-list/_bootstrap4-definition.scss +202 -202
  120. package/styles/drop-down-list/_bootstrap5-definition.scss +201 -201
  121. package/styles/drop-down-list/_fabric-dark-definition.scss +128 -128
  122. package/styles/drop-down-list/_fabric-definition.scss +124 -124
  123. package/styles/drop-down-list/_fluent-definition.scss +185 -185
  124. package/styles/drop-down-list/_fusionnew-definition.scss +201 -201
  125. package/styles/drop-down-list/_highcontrast-definition.scss +142 -142
  126. package/styles/drop-down-list/_highcontrast-light-definition.scss +144 -144
  127. package/styles/drop-down-list/_layout.scss +310 -310
  128. package/styles/drop-down-list/_material-dark-definition.scss +143 -143
  129. package/styles/drop-down-list/_material-definition.scss +167 -167
  130. package/styles/drop-down-list/_material3-definition.scss +180 -180
  131. package/styles/drop-down-list/_tailwind-definition.scss +134 -134
  132. package/styles/drop-down-list/_theme.scss +10 -10
  133. package/styles/drop-down-list/icons/_bootstrap-dark.scss +14 -14
  134. package/styles/drop-down-list/icons/_bootstrap.scss +14 -14
  135. package/styles/drop-down-list/icons/_bootstrap4.scss +14 -14
  136. package/styles/drop-down-list/icons/_bootstrap5.scss +14 -14
  137. package/styles/drop-down-list/icons/_fabric-dark.scss +14 -14
  138. package/styles/drop-down-list/icons/_fabric.scss +14 -14
  139. package/styles/drop-down-list/icons/_fluent.scss +14 -14
  140. package/styles/drop-down-list/icons/_fusionnew.scss +14 -14
  141. package/styles/drop-down-list/icons/_highcontrast-light.scss +14 -14
  142. package/styles/drop-down-list/icons/_highcontrast.scss +14 -14
  143. package/styles/drop-down-list/icons/_material-dark.scss +14 -14
  144. package/styles/drop-down-list/icons/_material.scss +14 -14
  145. package/styles/drop-down-list/icons/_material3.scss +14 -14
  146. package/styles/drop-down-list/icons/_tailwind.scss +14 -14
  147. package/styles/drop-down-list/material3-dark.scss +1 -1
  148. package/styles/drop-down-list/material3.scss +1 -1
  149. package/styles/drop-down-tree/_all.scss +2 -2
  150. package/styles/drop-down-tree/_bootstrap-dark-definition.scss +71 -71
  151. package/styles/drop-down-tree/_bootstrap-definition.scss +70 -70
  152. package/styles/drop-down-tree/_bootstrap4-definition.scss +71 -71
  153. package/styles/drop-down-tree/_bootstrap5-definition.scss +59 -59
  154. package/styles/drop-down-tree/_fabric-dark-definition.scss +71 -71
  155. package/styles/drop-down-tree/_fabric-definition.scss +71 -71
  156. package/styles/drop-down-tree/_fluent-definition.scss +65 -65
  157. package/styles/drop-down-tree/_fusionnew-definition.scss +59 -59
  158. package/styles/drop-down-tree/_highcontrast-definition.scss +71 -71
  159. package/styles/drop-down-tree/_highcontrast-light-definition.scss +71 -71
  160. package/styles/drop-down-tree/_layout.scss +1418 -1412
  161. package/styles/drop-down-tree/_material-dark-definition.scss +72 -72
  162. package/styles/drop-down-tree/_material-definition.scss +72 -72
  163. package/styles/drop-down-tree/_material3-definition.scss +76 -76
  164. package/styles/drop-down-tree/_tailwind-definition.scss +61 -61
  165. package/styles/drop-down-tree/_theme.scss +132 -132
  166. package/styles/drop-down-tree/fluent-dark.css +2 -0
  167. package/styles/drop-down-tree/fluent.css +2 -0
  168. package/styles/drop-down-tree/icons/_bootstrap-dark.scss +11 -11
  169. package/styles/drop-down-tree/icons/_bootstrap.scss +11 -11
  170. package/styles/drop-down-tree/icons/_bootstrap4.scss +11 -11
  171. package/styles/drop-down-tree/icons/_bootstrap5.scss +11 -11
  172. package/styles/drop-down-tree/icons/_fabric-dark.scss +11 -11
  173. package/styles/drop-down-tree/icons/_fabric.scss +11 -11
  174. package/styles/drop-down-tree/icons/_fluent.scss +11 -11
  175. package/styles/drop-down-tree/icons/_fusionnew.scss +11 -11
  176. package/styles/drop-down-tree/icons/_highcontrast-light.scss +11 -11
  177. package/styles/drop-down-tree/icons/_highcontrast.scss +11 -11
  178. package/styles/drop-down-tree/icons/_material-dark.scss +11 -11
  179. package/styles/drop-down-tree/icons/_material.scss +11 -11
  180. package/styles/drop-down-tree/icons/_material3.scss +11 -11
  181. package/styles/drop-down-tree/icons/_tailwind-dark.scss +11 -11
  182. package/styles/drop-down-tree/icons/_tailwind.scss +11 -11
  183. package/styles/drop-down-tree/material3-dark.scss +1 -1
  184. package/styles/drop-down-tree/material3.scss +1 -1
  185. package/styles/fabric-dark.css +5 -0
  186. package/styles/fluent-dark.css +4 -1
  187. package/styles/fluent.css +4 -1
  188. package/styles/highcontrast.css +5 -0
  189. package/styles/list-box/_all.scss +2 -2
  190. package/styles/list-box/_bootstrap-dark-definition.scss +126 -126
  191. package/styles/list-box/_bootstrap-definition.scss +119 -119
  192. package/styles/list-box/_bootstrap4-definition.scss +124 -124
  193. package/styles/list-box/_bootstrap5-definition.scss +120 -120
  194. package/styles/list-box/_fabric-dark-definition.scss +126 -126
  195. package/styles/list-box/_fabric-definition.scss +119 -119
  196. package/styles/list-box/_fluent-definition.scss +120 -120
  197. package/styles/list-box/_fusionnew-definition.scss +111 -111
  198. package/styles/list-box/_highcontrast-definition.scss +119 -119
  199. package/styles/list-box/_highcontrast-light-definition.scss +126 -126
  200. package/styles/list-box/_layout.scss +542 -542
  201. package/styles/list-box/_material-dark-definition.scss +126 -126
  202. package/styles/list-box/_material-definition.scss +119 -119
  203. package/styles/list-box/_material3-definition.scss +119 -119
  204. package/styles/list-box/_tailwind-definition.scss +119 -119
  205. package/styles/list-box/_theme.scss +382 -382
  206. package/styles/list-box/icons/_bootstrap-dark.scss +25 -25
  207. package/styles/list-box/icons/_bootstrap.scss +25 -25
  208. package/styles/list-box/icons/_bootstrap4.scss +25 -25
  209. package/styles/list-box/icons/_bootstrap5.scss +25 -25
  210. package/styles/list-box/icons/_fabric-dark.scss +25 -25
  211. package/styles/list-box/icons/_fabric.scss +25 -25
  212. package/styles/list-box/icons/_fluent.scss +25 -25
  213. package/styles/list-box/icons/_fusionnew.scss +25 -25
  214. package/styles/list-box/icons/_highcontrast-light.scss +25 -25
  215. package/styles/list-box/icons/_highcontrast.scss +25 -25
  216. package/styles/list-box/icons/_material-dark.scss +25 -25
  217. package/styles/list-box/icons/_material.scss +25 -25
  218. package/styles/list-box/icons/_material3.scss +25 -25
  219. package/styles/list-box/icons/_tailwind-dark.scss +25 -25
  220. package/styles/list-box/icons/_tailwind.scss +25 -25
  221. package/styles/list-box/material3-dark.scss +1 -1
  222. package/styles/list-box/material3.scss +1 -1
  223. package/styles/material3-dark.scss +1 -1
  224. package/styles/material3.scss +1 -1
  225. package/styles/mention/_all.scss +1 -1
  226. package/styles/mention/_bootstrap-dark-definition.scss +3 -3
  227. package/styles/mention/_bootstrap-definition.scss +3 -3
  228. package/styles/mention/_bootstrap4-definition.scss +3 -3
  229. package/styles/mention/_bootstrap5-definition.scss +1 -1
  230. package/styles/mention/_fabric-dark-definition.scss +2 -2
  231. package/styles/mention/_fabric-definition.scss +3 -3
  232. package/styles/mention/_fluent-definition.scss +1 -1
  233. package/styles/mention/_fusionnew-definition.scss +1 -1
  234. package/styles/mention/_highcontrast-definition.scss +3 -3
  235. package/styles/mention/_highcontrast-light-definition.scss +3 -3
  236. package/styles/mention/_layout.scss +6 -6
  237. package/styles/mention/_material-dark-definition.scss +3 -3
  238. package/styles/mention/_material-definition.scss +3 -3
  239. package/styles/mention/_material3-definition.scss +1 -1
  240. package/styles/mention/_tailwind-definition.scss +1 -1
  241. package/styles/mention/material3-dark.scss +1 -1
  242. package/styles/mention/material3.scss +1 -1
  243. package/styles/multi-select/_all.scss +2 -2
  244. package/styles/multi-select/_bootstrap-dark-definition.scss +203 -198
  245. package/styles/multi-select/_bootstrap-definition.scss +192 -192
  246. package/styles/multi-select/_bootstrap4-definition.scss +278 -278
  247. package/styles/multi-select/_bootstrap5-definition.scss +230 -229
  248. package/styles/multi-select/_fabric-dark-definition.scss +192 -187
  249. package/styles/multi-select/_fabric-definition.scss +183 -183
  250. package/styles/multi-select/_fluent-definition.scss +241 -240
  251. package/styles/multi-select/_fusionnew-definition.scss +227 -227
  252. package/styles/multi-select/_highcontrast-definition.scss +303 -298
  253. package/styles/multi-select/_highcontrast-light-definition.scss +297 -297
  254. package/styles/multi-select/_layout.scss +2199 -2199
  255. package/styles/multi-select/_material-dark-definition.scss +230 -230
  256. package/styles/multi-select/_material-definition.scss +223 -223
  257. package/styles/multi-select/_material3-definition.scss +246 -246
  258. package/styles/multi-select/_tailwind-definition.scss +235 -234
  259. package/styles/multi-select/_theme.scss +586 -586
  260. package/styles/multi-select/bootstrap-dark.css +5 -0
  261. package/styles/multi-select/bootstrap5-dark.css +2 -1
  262. package/styles/multi-select/bootstrap5.css +2 -1
  263. package/styles/multi-select/fabric-dark.css +5 -0
  264. package/styles/multi-select/fluent-dark.css +2 -1
  265. package/styles/multi-select/fluent.css +2 -1
  266. package/styles/multi-select/highcontrast.css +5 -0
  267. package/styles/multi-select/icons/_bootstrap-dark.scss +26 -26
  268. package/styles/multi-select/icons/_bootstrap.scss +26 -26
  269. package/styles/multi-select/icons/_bootstrap4.scss +37 -37
  270. package/styles/multi-select/icons/_bootstrap5.scss +26 -26
  271. package/styles/multi-select/icons/_fabric-dark.scss +26 -26
  272. package/styles/multi-select/icons/_fabric.scss +26 -26
  273. package/styles/multi-select/icons/_fluent.scss +55 -55
  274. package/styles/multi-select/icons/_fusionnew.scss +26 -26
  275. package/styles/multi-select/icons/_highcontrast-light.scss +26 -26
  276. package/styles/multi-select/icons/_highcontrast.scss +26 -26
  277. package/styles/multi-select/icons/_material-dark.scss +693 -693
  278. package/styles/multi-select/icons/_material.scss +693 -693
  279. package/styles/multi-select/icons/_material3.scss +692 -692
  280. package/styles/multi-select/icons/_tailwind.scss +26 -26
  281. package/styles/multi-select/material3-dark.scss +1 -1
  282. package/styles/multi-select/material3.scss +1 -1
  283. package/styles/multi-select/tailwind-dark.css +2 -1
  284. package/styles/multi-select/tailwind.css +2 -1
  285. package/styles/tailwind-dark.css +2 -1
  286. package/styles/tailwind.css +2 -1
  287. package/.eslintrc.json +0 -260
  288. package/tslint.json +0 -111
@@ -0,0 +1,3741 @@
1
+ import { Input, InputObject, FloatLabelType, TextBox, InputEventArgs } from '@syncfusion/ej2-inputs';
2
+ import { createCheckBox } from '@syncfusion/ej2-buttons';
3
+ import { NotifyPropertyChanges, INotifyPropertyChanged, Property, Event, EmitType, SanitizeHtmlHelper } from '@syncfusion/ej2-base';
4
+ import { Component, EventHandler, attributes, formatUnit, ChildProperty, remove, L10n, extend } from '@syncfusion/ej2-base';
5
+ import { addClass, removeClass, detach, prepend, Complex, closest, setValue, getValue, compile, append } from '@syncfusion/ej2-base';
6
+ import { select, selectAll, isNullOrUndefined as isNOU, matches, Browser, KeyboardEvents, KeyboardEventArgs } from '@syncfusion/ej2-base';
7
+ import { DataManager, Query, DataUtil } from '@syncfusion/ej2-data';
8
+ import { Popup } from '@syncfusion/ej2-popups';
9
+ import { TreeView, NodeSelectEventArgs, DataBoundEventArgs, FieldsSettingsModel, NodeClickEventArgs, NodeExpandEventArgs } from '@syncfusion/ej2-navigations';
10
+ import { NodeCheckEventArgs, FailureEventArgs} from '@syncfusion/ej2-navigations';
11
+ import { DropDownTreeModel, FieldsModel, TreeSettingsModel } from './drop-down-tree-model';
12
+
13
+ const RTL: string = 'e-rtl';
14
+ const DROPDOWNTREE: string = 'e-ddt';
15
+ const HIDDENELEMENT: string = 'e-ddt-hidden';
16
+ const DROPDOWNICON: string = 'e-input-group-icon e-ddt-icon e-icons';
17
+ const SHOW_CHIP: string = 'e-show-chip';
18
+ const SHOW_CLEAR: string = 'e-show-clear';
19
+ const SHOW_DD_ICON: string = 'e-show-dd-icon';
20
+ const CHIP_INPUT: string = 'e-chip-input';
21
+ const INPUTFOCUS: string = 'e-input-focus';
22
+ const INPUTGROUP: string = 'e-input-group';
23
+ const ICONANIMATION: string = 'e-icon-anim';
24
+ const CLOSEICON_CLASS: string = 'e-clear-icon e-icons';
25
+ const CHIP_WRAPPER: string = 'e-chips-wrapper';
26
+ const CHIP_COLLECTION: string = 'e-chips-collection';
27
+ const CHIP: string = 'e-chips';
28
+ const CHIP_CONTENT: string = 'e-chipcontent';
29
+ const CHIP_CLOSE: string = 'e-chips-close';
30
+ const HIDEICON: string = 'e-icon-hide';
31
+ const DDTHIDEICON: string = 'e-ddt-icon-hide';
32
+ const POPUP_CLASS: string = 'e-ddt e-popup';
33
+ const PARENTITEM: string = 'e-list-parent';
34
+ const CONTENT: string = 'e-popup-content';
35
+ const DROPDOWN: string = 'e-dropdown';
36
+ const DISABLED: string = 'e-disabled';
37
+ const ICONS: string = 'e-icons';
38
+ const CHECKALLPARENT: string = 'e-selectall-parent';
39
+ const CHECKALLHIDE: string = 'e-hide-selectall';
40
+ const BIGGER: string = 'e-bigger';
41
+ const SMALL: string = 'e-small';
42
+ const ALLTEXT: string = 'e-all-text';
43
+ const CHECKBOXFRAME: string = 'e-frame';
44
+ const CHECK: string = 'e-check';
45
+ const CHECKBOXWRAP: string = 'e-checkbox-wrapper';
46
+ const FILTERWRAP: string = 'e-filter-wrap';
47
+ const DDTICON: string = 'e-ddt-icon';
48
+ const FOOTER: string = 'e-ddt-footer';
49
+ const HEADER: string = 'e-ddt-header';
50
+ const NODATACONTAINER: string = 'e-ddt-nodata';
51
+ const NODATA: string = 'e-no-data';
52
+ const HEADERTEMPLATE: string = 'HeaderTemplate';
53
+ const FOOTERTEMPLATE: string = 'FooterTemplate';
54
+ const NORECORDSTEMPLATE: string = 'NoRecordsTemplate';
55
+ const ACTIONFAILURETEMPLATE: string = 'ActionFailureTemplate';
56
+ const CUSTOMTEMPLATE: string = 'CustomTemplate';
57
+ const REMAIN_WRAPPER: string = 'e-remain';
58
+ const OVERFLOW_VIEW: string = 'e-overflow';
59
+ const SHOW_TEXT: string = 'e-show-text';
60
+ const TOTAL_COUNT_WRAPPER: string = 'e-total-count';
61
+ const REMAIN_COUNT: string = 'e-wrap-count';
62
+
63
+ /**
64
+ * Specifies the different ways to filter values.
65
+ * ```props
66
+ * StartsWith :- Checks whether a value begins with the specified value.
67
+ * EndsWith :- Checks whether a value ends with the specified value.
68
+ * Contains :- Checks whether a value contains with specified value.
69
+ * ```
70
+ */
71
+ export type TreeFilterType = 'StartsWith' | 'EndsWith' | 'Contains';
72
+
73
+ export class Fields extends ChildProperty<Fields> {
74
+
75
+ /**
76
+ * This field specifies the child items or mapping field for the nested child items that contains an array of JSON objects.
77
+ */
78
+ @Property('child')
79
+ public child: string | FieldsModel;
80
+
81
+ /**
82
+ * Specifies the array of JavaScript objects or instance of Data Manager to populate the dropdown tree items.
83
+ *
84
+ * @default []
85
+ */
86
+ /* eslint-disable */
87
+ @Property([])
88
+ public dataSource: DataManager | { [key: string]: Object }[];
89
+ /* eslint-enable */
90
+ /**
91
+ * This fields specifies the mapping field to define the expanded state of a Dropdown tree item.
92
+ */
93
+ @Property('expanded')
94
+ public expanded: string;
95
+
96
+ /**
97
+ * This field specifies the mapping field to indicate whether the Dropdown tree item has children or not.
98
+ */
99
+ @Property('hasChildren')
100
+ public hasChildren: string;
101
+
102
+ /**
103
+ * Specifies the mapping field for htmlAttributes to be added to the Dropdown Tree item.
104
+ */
105
+ @Property('htmlAttributes')
106
+ public htmlAttributes: string;
107
+
108
+ /**
109
+ * Specifies the mapping field for icon class of each Dropdown Tree item that will be added before the text.
110
+ */
111
+ @Property('iconCss')
112
+ public iconCss: string;
113
+
114
+ /**
115
+ * Specifies the mapping field for image URL of each Dropdown Tree item where image will be added before the text.
116
+ */
117
+ @Property('imageUrl')
118
+ public imageUrl: string;
119
+
120
+ /**
121
+ * Specifies the parent value field mapped in the data source.
122
+ */
123
+ @Property('parentValue')
124
+ public parentValue: string;
125
+
126
+ /**
127
+ * Defines the external [`Query`](https://ej2.syncfusion.com/documentation/api/data/query/)
128
+ * that will execute along with the data processing.
129
+ *
130
+ * @default null
131
+ */
132
+ @Property(null)
133
+ public query: Query;
134
+
135
+ /**
136
+ * Specifies whether the node can be selected by users or not
137
+ * When set to false, the user interaction is prevented for the corresponding node.
138
+ */
139
+ @Property('selectable')
140
+ public selectable: string;
141
+
142
+ /**
143
+ * Specifies the mapping field for the selected state of the Dropdown Tree item.
144
+ */
145
+ @Property('selected')
146
+ public selected: string;
147
+
148
+ /**
149
+ * Specifies the table name used to fetch data from a specific table in the server.
150
+ */
151
+ @Property(null)
152
+ public tableName: string;
153
+
154
+ /**
155
+ * Specifies the mapping field for text displayed as Dropdown Tree items display text.
156
+ */
157
+ @Property('text')
158
+ public text: string;
159
+
160
+ /**
161
+ * Specifies the mapping field for tooltip that will be displayed as hovering text of the Dropdown Tree item.
162
+ */
163
+ @Property('tooltip')
164
+ public tooltip: string;
165
+
166
+ /**
167
+ * Specifies the value(ID) field mapped in the data source.
168
+ */
169
+ @Property('value')
170
+ public value: string;
171
+ }
172
+
173
+ export class TreeSettings extends ChildProperty<TreeSettings> {
174
+ /**
175
+ * Specifies whether the child and parent tree items check states are dependent over each other when checkboxes are enabled.
176
+ *
177
+ * @default false
178
+ */
179
+
180
+ @Property(false)
181
+ public autoCheck: boolean;
182
+
183
+ /**
184
+ * Specifies the action on which the parent items in the pop-up should expand or collapse. The available actions are
185
+ * * `Auto` - In desktop, the expand or collapse operation happens when you double-click the node,
186
+ * and in mobile devices it happens on single-tap.
187
+ * * `Click` - The expand or collapse operation happens when you perform single-click/tap
188
+ * on the pop-up item in both desktop and mobile devices.
189
+ * * `DblClick` - The expand or collapse operation happens when you perform a double-click/tap
190
+ * on the pop-up item in both desktop and mobile devices.
191
+ * * `None` - The expand or collapse operation will not happen when you perform single-click/tap
192
+ * or double-click/tap on the pop-up items in both desktop and mobile devices.
193
+ *
194
+ * @default 'Auto'
195
+ */
196
+ @Property('Auto')
197
+ public expandOn: ExpandOn;
198
+
199
+ /**
200
+ * By default, the load on demand (Lazy load) is set to false.
201
+ * Enabling this property will render only the parent tree items in the popup and
202
+ * the child items will be rendered on demand when expanding the corresponding parent node.
203
+ *
204
+ * @default false
205
+ */
206
+ @Property(false)
207
+ public loadOnDemand: boolean;
208
+ }
209
+
210
+ export interface DdtChangeEventArgs {
211
+ /**
212
+ * If the event is triggered by interaction, it returns true. Otherwise, it returns false.
213
+ */
214
+ isInteracted: boolean;
215
+ /**
216
+ * Returns the component previous values.
217
+ */
218
+ oldValue: string[];
219
+ /**
220
+ * Returns the updated component values.
221
+ */
222
+ value: string[];
223
+ /**
224
+ * Specifies the original event.
225
+ */
226
+ e: MouseEvent | KeyboardEvent;
227
+ /**
228
+ * Returns the root element of the component.
229
+ */
230
+ element: HTMLElement;
231
+ }
232
+
233
+ export interface DdtBeforeOpenEventArgs {
234
+ /**
235
+ * Determines whether the current action needs to be prevented or not.
236
+ */
237
+ cancel: boolean;
238
+ }
239
+
240
+ export interface DdtPopupEventArgs {
241
+ /**
242
+ * Specifies the pop-up object.
243
+ */
244
+ popup: Popup;
245
+ }
246
+
247
+ export interface DdtDataBoundEventArgs {
248
+ /**
249
+ * Return the DropDownTree data.
250
+ */
251
+ // eslint-disable-next-line
252
+ data: { [key: string]: Object }[];
253
+ }
254
+
255
+
256
+ export interface DdtFocusEventArgs {
257
+ /**
258
+ * Specifies whether the element is interacted when focusing or not.
259
+ */
260
+ isInteracted?: boolean;
261
+ /**
262
+ * Specifies the original event.
263
+ */
264
+ event?: MouseEvent | FocusEvent | TouchEvent | KeyboardEvent;
265
+ }
266
+
267
+ export interface DdtFilteringEventArgs {
268
+ /**
269
+ * To prevent the internal filtering action.
270
+ */
271
+ preventDefaultAction: boolean;
272
+ /**
273
+ * Gets the `input` event arguments.
274
+ */
275
+ event: Event;
276
+ /**
277
+ * Determines whether the current action needs to be prevented or not.
278
+ */
279
+ cancel: boolean;
280
+ /**
281
+ * Filter text value.
282
+ */
283
+ text: string;
284
+ /**
285
+ * Gets or sets the fields of Dropdown Tree.
286
+ */
287
+ fields: FieldsModel;
288
+ }
289
+
290
+ export interface DdtSelectEventArgs {
291
+ /**
292
+ * Returns the name of action like select or unselect.
293
+ */
294
+ action: string;
295
+ /**
296
+ * If the event is triggered by interacting the Dropdown Tree, it returns true. Otherwise, it returns false.
297
+ */
298
+ isInteracted: boolean;
299
+ /**
300
+ * Returns the currently selected Dropdown item.
301
+ */
302
+ item: HTMLLIElement;
303
+ /**
304
+ * Return the currently selected item as JSON object from the data source.
305
+ */
306
+ // eslint-disable-next-line
307
+ itemData: { [key: string]: Object };
308
+ }
309
+
310
+ export interface DdtKeyPressEventArgs {
311
+ /**
312
+ * If you want to cancel this event then, set cancel as true. Otherwise, false.
313
+ */
314
+ cancel: boolean;
315
+ /**
316
+ * Return the actual event.
317
+ */
318
+ event: KeyboardEventArgs;
319
+ }
320
+
321
+ /**
322
+ * Configures visibility mode for component interaction when allowMultiSelection or checkbox is enabled.
323
+ * ```props
324
+ * Default :- On blur component will act in the delimiter mode.
325
+ * Delimiter :- Selected items will be visualized in the text content.
326
+ * Box :- Selected items will be visualized in chip.
327
+ * Custom :- Selected items will be visualized with the given custom template value.
328
+ * ```
329
+ */
330
+ export type Mode = 'Default' | 'Delimiter' | 'Box' | 'Custom';
331
+
332
+ /**
333
+ * Specifies a value that indicates whether the items are sorted in the ascending or descending order, or not sorted at all.
334
+ * ```props
335
+ * None :- Indicates that the nodes are not sorted.
336
+ * Ascending :- Indicates that the nodes are sorted in the ascending order.
337
+ * Descending :- Indicates that the nodes are sorted in the descending order.
338
+ * ```
339
+ */
340
+ export type SortOrder = 'None' | 'Ascending' | 'Descending';
341
+
342
+ /**
343
+ * Specifies the expansion of tree nodes within the Dropdown Tree.
344
+ * ```props
345
+ * Auto :- In desktop, the expand or collapse operation happens when you double-click the node, and in mobile devices it happens on single-tap.
346
+ * Click :- The expand or collapse operation happens when you perform single-click/tap on the pop-up item in both desktop and mobile devices.
347
+ * DblClick :- The expand or collapse operation happens when you perform a double-click/tap on the pop-up item in both desktop and mobile devices.
348
+ * None :- The expand or collapse operation will not happen when you perform single-click/tap or double-click/tap on the pop-up items in both desktop and mobile devices.
349
+ * ```
350
+ */
351
+ export type ExpandOn = 'Auto' | 'Click' | 'DblClick' | 'None';
352
+
353
+ /**
354
+ * The Dropdown Tree control allows you to select single or multiple values from hierarchical data in a tree-like structure.
355
+ * It has several out-of-the-box features, such as data binding, check boxes, templates, filter,
356
+ * UI customization, accessibility, and preselected values.
357
+ * ```html
358
+ * <input type="text" id="tree"></input>
359
+ * ```
360
+ * ```typescript
361
+ * let ddtObj: DropDownTree = new DropDownTree();
362
+ * ddtObj.appendTo("#tree");
363
+ * ```
364
+ */
365
+
366
+ @NotifyPropertyChanges
367
+ export class DropDownTree extends Component<HTMLElement> implements INotifyPropertyChanged {
368
+ private inputEle: HTMLInputElement;
369
+ private inputObj: InputObject;
370
+ private hiddenElement: HTMLSelectElement;
371
+ private isReverseUpdate: boolean;
372
+ private checkSelectAll: boolean;
373
+ private inputWrapper: HTMLElement;
374
+ private popupDiv: HTMLElement;
375
+ private tree: HTMLElement;
376
+ private isPopupOpen: boolean;
377
+ private inputFocus: boolean;
378
+ private popupObj: Popup;
379
+ private treeObj: TreeView;
380
+ private overAllClear: HTMLElement;
381
+ private isClearButtonClick: boolean;
382
+ private isDocumentClick: boolean;
383
+ private isFirstRender: boolean;
384
+ private hasTemplate: string | Function;
385
+ private isInitialized: boolean;
386
+ private treeDataType: number;
387
+ private oldValue: string[];
388
+ private removeValue: boolean;
389
+ private currentValue: string[];
390
+ private currentText: string;
391
+ // eslint-disable-next-line
392
+ private treeItems: { [key: string]: Object }[];
393
+ private filterTimer: number = null;
394
+ private filterContainer: HTMLElement;
395
+ private isRemoteData: boolean;
396
+ private selectedText: string[];
397
+ private chipWrapper: HTMLElement;
398
+ private chipCollection: HTMLElement;
399
+ private isChipDelete: boolean;
400
+ private checkAllParent: HTMLElement;
401
+ private selectAllSpan: HTMLElement;
402
+ private checkBoxElement: Element;
403
+ private checkWrapper: HTMLElement;
404
+ private isNodeSelected: boolean;
405
+ private dataValue: string;
406
+ private popupEle: HTMLElement;
407
+ private isDynamicChange: boolean;
408
+ private header: HTMLElement;
409
+ private footer: HTMLElement;
410
+ private noRecord: HTMLElement;
411
+ private headerTemplateId: string;
412
+ private footerTemplateId: string;
413
+ private l10n: L10n;
414
+ private actionFailureTemplateId: string;
415
+ private customTemplateId: string;
416
+ private noRecordsTemplateId: string;
417
+ private isValueChange: boolean;
418
+ private keyEventArgs: KeyboardEvent;
419
+ private keyboardModule: KeyboardEvents;
420
+ private keyConfigs: { [key: string]: string };
421
+ private overFlowWrapper: HTMLElement;
422
+ private isFilteredData: boolean = false;
423
+ private isFilterRestore: boolean = false;
424
+ // eslint-disable-next-line
425
+ private treeData: { [key: string]: Object }[];
426
+ // eslint-disable-next-line
427
+ private selectedData: { [key: string]: Object }[] = [];
428
+ private filterObj: TextBox;
429
+ private filterDelayTime: number = 300;
430
+ private nestedTableUpdate: { flag: boolean, fields: FieldsModel };
431
+ private clearIconWidth: number;
432
+ private isClicked: boolean = false;
433
+ // Specifies if the checkAll method has been called
434
+ private isCheckAllCalled: boolean = false;
435
+ private isFromFilterChange = false;
436
+
437
+ /**
438
+ * Specifies the template that renders to the popup list content of the
439
+ * Dropdown Tree component when the data fetch request from the remote server fails.
440
+ *
441
+ * @default 'The Request Failed'
442
+ * @aspType string
443
+ */
444
+ @Property('The Request Failed')
445
+ public actionFailureTemplate: string | Function;
446
+
447
+ /**
448
+ * When allowFiltering is set to true, it shows the filter bar (search text box) of the component.
449
+ * The filter action retrieves matched items through the **filtering** event based on the characters typed in the search text box.
450
+ * If no match is found, the value of the **noRecordsTemplate** property will be displayed.
451
+ *
452
+ * @default false
453
+ */
454
+ @Property(false)
455
+ public allowFiltering: boolean;
456
+
457
+ /**
458
+ * Enables or disables the multi-selection of items. To select multiple items:
459
+ * * Select the items by holding down the **Ctrl** key when clicking on the items.
460
+ * * Select consecutive items by clicking the first item to select and hold down the **Shift** key and click the last item to select.
461
+ *
462
+ * @default false
463
+ */
464
+ @Property(false)
465
+ public allowMultiSelection: boolean;
466
+
467
+ /**
468
+ * By default, the Dropdown Tree component fires the change event while focusing out the component.
469
+ * If you want to fire the change event on every value selection and remove, then disable this property.
470
+ *
471
+ * @default true
472
+ */
473
+ @Property(true)
474
+ public changeOnBlur: boolean;
475
+
476
+ /**
477
+ * Specifies the CSS classes to be added with the root and popup element of the Dropdown Tree component.
478
+ * that allows customization of appearance.
479
+ *
480
+ * @default ''
481
+ */
482
+ @Property('')
483
+ public cssClass: string;
484
+
485
+ /**
486
+ * This property is used to customize the display text of the selected items in the Dropdown Tree. The given custom template is
487
+ * added to the input instead of the selected item text in the Dropdown Tree when the multi-selection or checkbox support is enabled.
488
+ *
489
+ * @default "${value.length} item(s) selected"
490
+ * @aspType string
491
+ */
492
+ @Property("${value.length} item(s) selected")
493
+ public customTemplate: string | Function;
494
+
495
+ /**
496
+ * Defines the value separator character in the input element when multi-selection or checkbox is enabled in the Dropdown Tree.
497
+ * The delimiter character is applicable only for **default** and **delimiter** visibility modes.
498
+ *
499
+ * @default ","
500
+ */
501
+ @Property(',')
502
+ public delimiterChar: string;
503
+
504
+ /**
505
+ * Specifies a value that indicates whether the Dropdown Tree component is enabled or not.
506
+ *
507
+ * @default true
508
+ */
509
+ @Property(true)
510
+ public enabled: boolean;
511
+
512
+ /**
513
+ * Specifies the data source and mapping fields to render Dropdown Tree items.
514
+ *
515
+ * @default {value: 'value', text: 'text', dataSource: [], child: 'child', parentValue: 'parentValue', hasChildren: 'hasChildren',
516
+ * expanded: 'expanded', htmlAttributes: 'htmlAttributes', iconCss: 'iconCss', imageUrl: 'imageUrl',
517
+ * query: null, selected: 'selected', selectable: 'selectable', tableName: null, tooltip: 'tooltip' }
518
+ */
519
+ @Complex<FieldsModel>({}, Fields)
520
+ public fields: FieldsModel;
521
+
522
+ /**
523
+ * Accepts the value to be displayed as a watermark text on the filter bar.
524
+ *
525
+ * @default null
526
+ */
527
+ @Property(null)
528
+ public filterBarPlaceholder: string;
529
+
530
+ /**
531
+ * Determines on which filter type, the component needs to be considered on search action.
532
+ * The **TreeFilterType** and its supported data types are,
533
+ *
534
+ * <table>
535
+ * <tr>
536
+ * <td colSpan=1 rowSpan=1><b>
537
+ * TreeFilterType</b></td><td colSpan=1 rowSpan=1><b>
538
+ * Description</b></td><td colSpan=1 rowSpan=1><b>
539
+ * Supported Types</b></td></tr>
540
+ * <tr>
541
+ * <td colSpan=1 rowSpan=1>
542
+ * StartsWith<br/></td><td colSpan=1 rowSpan=1>
543
+ * Checks whether a value begins with the specified value.<br/></td><td colSpan=1 rowSpan=1>
544
+ * String<br/></td></tr>
545
+ * <tr>
546
+ * <td colSpan=1 rowSpan=1>
547
+ * EndsWith<br/></td><td colSpan=1 rowSpan=1>
548
+ * Checks whether a value ends with the specified value.<br/></td><td colSpan=1 rowSpan=1>
549
+ * String<br/></td></tr>
550
+ * <tr>
551
+ * <td colSpan=1 rowSpan=1>
552
+ * Contains<br/></td><td colSpan=1 rowSpan=1>
553
+ * Checks whether a value contains with specified value.<br/></td><td colSpan=1 rowSpan=1>
554
+ * String<br/></td></tr>
555
+ * </table>
556
+ *
557
+ * The default value set to **StartsWith**, all the suggestion items which starts with typed characters to listed in the
558
+ * suggestion popup.
559
+ *
560
+ * @default 'StartsWith'
561
+ */
562
+ @Property('StartsWith')
563
+ public filterType: TreeFilterType;
564
+
565
+ /**
566
+ * Specifies whether to display the floating label above the input element.
567
+ * Possible values are:
568
+ * * Never: The label will never float in the input when the placeholder is available.
569
+ * * Always: The floating label will always float above the input.
570
+ * * Auto: The floating label will float above the input after focusing or entering a value in the input.
571
+ *
572
+ * @default Syncfusion.EJ2.Inputs.FloatLabelType.Never
573
+ * @isEnumeration true
574
+ */
575
+ @Property('Never')
576
+ public floatLabelType: FloatLabelType;
577
+
578
+ /**
579
+ * Specifies the template that renders a customized footer container at the bottom of the pop-up list.
580
+ * By default, the footerTemplate will be null and there will be no footer container for the pop-up list.
581
+ *
582
+ * @default null
583
+ * @angularType string | object
584
+ * @reactType string | function | JSX.Element
585
+ * @vueType string | function
586
+ * @aspType string
587
+ */
588
+ @Property(null)
589
+ public footerTemplate: string | Function;
590
+
591
+ /**
592
+ * When **ignoreAccent** is set to true, then it ignores the diacritic characters or accents when filtering.
593
+ */
594
+ @Property(false)
595
+ public ignoreAccent: boolean;
596
+
597
+ /**
598
+ * When set to false, consider the case-sensitive on performing the search to find suggestions. By default, consider the casing.
599
+ *
600
+ * @default true
601
+ */
602
+ @Property(true)
603
+ public ignoreCase: boolean;
604
+
605
+ /**
606
+ * Specifies the template that renders a customized header container at the top of the pop-up list.
607
+ * By default, the headerTemplate will be null and there will be no header container for the pop-up list.
608
+ *
609
+ * @default null
610
+ * @angularType string | object
611
+ * @reactType string | function | JSX.Element
612
+ * @vueType string | function
613
+ * @aspType string
614
+ */
615
+ @Property(null)
616
+ public headerTemplate: string | Function;
617
+
618
+ /**
619
+ * Allows additional HTML attributes such as title, name, etc., and accepts n number of attributes in a key-value pair format.
620
+ *
621
+ * @default {}
622
+ */
623
+ @Property({})
624
+ public htmlAttributes: { [key: string]: string; };
625
+
626
+ /**
627
+ * Specifies a template to render customized content for all the items.
628
+ * If the **itemTemplate** property is set, the template content overrides the displayed item text.
629
+ * The property accepts [template string](https://ej2.syncfusion.com/documentation/common/template-engine/)
630
+ * or HTML element ID holding the content.
631
+ *
632
+ * @default null
633
+ * @angularType string | object
634
+ * @reactType string | function | JSX.Element
635
+ * @vueType string | function
636
+ * @aspType string
637
+ */
638
+ @Property(null)
639
+ public itemTemplate: string | Function;
640
+
641
+ /**
642
+ * Configures visibility mode for component interaction when allowMultiSelection or checkbox is enabled.
643
+ * Different modes are:
644
+ * * Box : Selected items will be visualized in chip.
645
+ * * Delimiter : Selected items will be visualized in the text content.
646
+ * * Default : On focus in component will act in the box mode. On blur component will act in the delimiter mode.
647
+ * * Custom : Selected items will be visualized with the given custom template value. The given custom template
648
+ * is added to the input instead of the selected item text in the Dropdown Tree when the multi-selection or checkbox support is enabled.
649
+ */
650
+ @Property('Default')
651
+ public mode: Mode;
652
+
653
+ /**
654
+ * Specifies the template that renders a customized pop-up list content when there is no data available
655
+ * to be displayed within the pop-up.
656
+ *
657
+ * @default 'No Records Found'
658
+ * @aspType string
659
+ */
660
+ @Property('No Records Found')
661
+ public noRecordsTemplate: string | Function;
662
+
663
+ /**
664
+ * Specifies a short hint that describes the expected value of the Dropdown Tree component.
665
+ *
666
+ * @default null
667
+ */
668
+ @Property(null)
669
+ public placeholder: string;
670
+
671
+ /**
672
+ * Specifies the height of the pop-up list.
673
+ *
674
+ * @default '300px'
675
+ */
676
+ @Property('300px')
677
+ public popupHeight: string | number;
678
+
679
+ /**
680
+ * Specifies the width of the popup list. By default, the popup width sets based on the width of the Dropdown Tree element.
681
+ *
682
+ * @default '100%'
683
+ */
684
+ @Property('100%')
685
+ public popupWidth: string | number;
686
+
687
+ /**
688
+ * When set to true, the user interactions on the component will be disabled.
689
+ *
690
+ * @default false
691
+ */
692
+ @Property(false)
693
+ public readonly: boolean;
694
+
695
+ /**
696
+ * Specifies whether to show or hide the selectAll checkbox in the pop-up which allows you to select all the items in the pop-up.
697
+ *
698
+ * @default false
699
+ */
700
+ @Property(false)
701
+ public showSelectAll: boolean;
702
+ /**
703
+ * Specifies the display text for the selectAll checkbox in the pop-up.
704
+ *
705
+ * @default 'Select All'
706
+ */
707
+ @Property('Select All')
708
+ public selectAllText: string;
709
+
710
+ /**
711
+ * Enables or disables the checkbox option in the Dropdown Tree component.
712
+ * If enabled, the Checkbox will be displayed next to the expand or collapse icon of the tree items.
713
+ *
714
+ * @default false
715
+ */
716
+ @Property(false)
717
+ public showCheckBox: boolean;
718
+
719
+ /**
720
+ * Specifies whether to allow rendering of untrusted HTML values in the Dropdown Tree component.
721
+ * While enable this property, it sanitize suspected untrusted strings and script, and update in the Dropdown Tree component.
722
+ *
723
+ * @default false
724
+ */
725
+ @Property(false)
726
+ public enableHtmlSanitizer: boolean;
727
+
728
+ /**
729
+ * Specifies whether to show or hide the clear icon in textbox.
730
+ * When the clear button is clicked, `value`, `text` properties will be reset to null.
731
+ *
732
+ * @default true
733
+ */
734
+ @Property(true)
735
+ public showClearButton: boolean;
736
+
737
+ /**
738
+ * Specifies whether to show or hide the Dropdown button.
739
+ *
740
+ * @default true
741
+ */
742
+ @Property(true)
743
+ public showDropDownIcon: boolean;
744
+
745
+ /**
746
+ * Specifies a value that indicates whether the items are sorted in the ascending or descending order, or not sorted at all.
747
+ * The available types of sort order are,
748
+ * * `None` - The items are not sorted.
749
+ * * `Ascending` - The items are sorted in the ascending order.
750
+ * * `Descending` - The items are sorted in the descending order.
751
+ *
752
+ * @default 'None'
753
+ */
754
+ @Property('None')
755
+ public sortOrder: SortOrder;
756
+
757
+ /**
758
+ * Gets or sets the display text of the selected item which maps the data **text** field in the component.
759
+ *
760
+ * @default null
761
+ */
762
+ @Property(null)
763
+ public text: string;
764
+
765
+ /**
766
+ * Configures the pop-up tree settings.
767
+ *
768
+ * @default {autoCheck: false, expandOn: 'Auto', loadOnDemand: false}
769
+ */
770
+ @Complex<TreeSettingsModel>({}, TreeSettings)
771
+ public treeSettings: TreeSettingsModel;
772
+
773
+ /**
774
+ * Specifies the display text for the unselect all checkbox in the pop-up.
775
+ *
776
+ * @default 'Unselect All'
777
+ */
778
+ @Property('Unselect All')
779
+ public unSelectAllText: string;
780
+
781
+ /**
782
+ * Gets or sets the value of selected item(s) which maps the data **value** field in the component.
783
+ *
784
+ * @default null
785
+ * @aspType Object
786
+ */
787
+ @Property(null)
788
+ public value: string[];
789
+ /**
790
+ * Specifies the width of the component. By default, the component width sets based on the width of its parent container.
791
+ * You can also set the width in pixel values.
792
+ *
793
+ * @default '100%'
794
+ */
795
+ @Property('100%')
796
+ public width: string | number;
797
+
798
+ /**
799
+ * Specifies the z-index value of the pop-up element.
800
+ *
801
+ * @default 1000
802
+ */
803
+ @Property(1000)
804
+ public zIndex: number;
805
+
806
+ /**
807
+ * Defines whether to enable or disable the feature called wrap the selected items into multiple lines when the selected item's text
808
+ * content exceeded the input width limit.
809
+ *
810
+ * @default false
811
+ */
812
+ @Property(false)
813
+ public wrapText: boolean;
814
+
815
+ /**
816
+ * Triggers when the data fetch request from the remote server fails.
817
+ *
818
+ * @event
819
+ */
820
+ /* eslint-disable */
821
+ @Event()
822
+ public actionFailure: EmitType<Object>;
823
+ /* eslint-enable */
824
+
825
+ /**
826
+ * Fires when popup opens before animation.
827
+ *
828
+ * @event
829
+ */
830
+ @Event()
831
+ public beforeOpen: EmitType<DdtBeforeOpenEventArgs>;
832
+
833
+ /**
834
+ * Triggers when an item in a popup is selected or when the model value is changed by user.
835
+ *
836
+ * @event
837
+ */
838
+ @Event()
839
+ public change: EmitType<DdtChangeEventArgs>;
840
+ /**
841
+ * Fires when popup close after animation completion.
842
+ *
843
+ * @event
844
+ */
845
+ @Event()
846
+ public close: EmitType<DdtPopupEventArgs>;
847
+
848
+ /**
849
+ * Triggers when the Dropdown Tree input element gets focus-out.
850
+ *
851
+ * @event
852
+ */
853
+ /* eslint-disable */
854
+ @Event()
855
+ public blur: EmitType<Object>;
856
+ /* eslint-enable */
857
+ /**
858
+ * Triggers when the Dropdown Tree is created successfully.
859
+ *
860
+ * @event
861
+ */
862
+ /* eslint-disable */
863
+ @Event()
864
+ public created: EmitType<Object>;
865
+ /* eslint-enable */
866
+
867
+ /**
868
+      * Triggers when data source is populated in the Dropdown Tree.
869
+ *
870
+      * @event
871
+      */
872
+ @Event()
873
+ public dataBound: EmitType<DdtDataBoundEventArgs>;
874
+
875
+ /**
876
+ * Triggers when the Dropdown Tree is destroyed successfully.
877
+ *
878
+ * @event
879
+ */
880
+ /* eslint-disable */
881
+ @Event()
882
+ public destroyed: EmitType<Object>;
883
+ /* eslint-enable */
884
+
885
+ /**
886
+ * Triggers on typing a character in the filter bar when the **allowFiltering** is enabled.
887
+ *
888
+ * @event
889
+ */
890
+ @Event()
891
+ public filtering: EmitType<DdtFilteringEventArgs>;
892
+
893
+ /**
894
+ * Triggers when the Dropdown Tree input element is focused.
895
+ *
896
+ * @event
897
+ */
898
+ @Event()
899
+ public focus: EmitType<DdtFocusEventArgs>;
900
+
901
+ /**
902
+ * Triggers when key press is successful. It helps to customize the operations at key press.
903
+ *
904
+ * @event
905
+ */
906
+ @Event()
907
+ public keyPress: EmitType<DdtKeyPressEventArgs>;
908
+
909
+ /**
910
+ * Fires when popup opens after animation completion.
911
+ *
912
+ * @event
913
+ */
914
+ @Event()
915
+ public open: EmitType<DdtPopupEventArgs>;
916
+
917
+ /**
918
+ * Triggers when an item in the popup is selected by the user either with mouse/tap or with keyboard navigation.
919
+ *
920
+ * @event
921
+ */
922
+ @Event()
923
+ public select: EmitType<DdtSelectEventArgs>;
924
+
925
+ constructor(options?: DropDownTreeModel, element?: string | HTMLElement) {
926
+ super(options, <HTMLElement | string>element);
927
+ }
928
+
929
+ /**
930
+ * Get the properties to be maintained in the persisted state.
931
+ *
932
+ * @returns {string}
933
+ * @hidden
934
+ */
935
+
936
+ public getPersistData(): string {
937
+ const keyEntity: string[] = ['value'];
938
+ return this.addOnPersist(keyEntity);
939
+ }
940
+
941
+ public getLocaleName(): string {
942
+ return 'drop-down-tree';
943
+ }
944
+
945
+ /**
946
+ * Initialize the event handler.
947
+ *
948
+ * @returns {void}
949
+ * @private
950
+ */
951
+ protected preRender(): void {
952
+ this.inputFocus = false;
953
+ this.isPopupOpen = false;
954
+ this.isFirstRender = true;
955
+ this.isInitialized = false;
956
+ this.currentText = null;
957
+ this.currentValue = null;
958
+ this.oldValue = null;
959
+ this.removeValue = false;
960
+ this.selectedText = [];
961
+ this.treeItems = [];
962
+ this.dataValue = null;
963
+ this.isNodeSelected = false;
964
+ this.isDynamicChange = false;
965
+ this.clearIconWidth = 0;
966
+ this.headerTemplateId = `${this.element.id}${HEADERTEMPLATE}`;
967
+ this.footerTemplateId = `${this.element.id}${FOOTERTEMPLATE}`;
968
+ this.actionFailureTemplateId = `${this.element.id}${ACTIONFAILURETEMPLATE}`;
969
+ this.noRecordsTemplateId = `${this.element.id}${NORECORDSTEMPLATE}`;
970
+ this.customTemplateId = `${this.element.id}${CUSTOMTEMPLATE}`;
971
+ this.keyConfigs = {
972
+ escape: 'escape',
973
+ altUp: 'alt+uparrow',
974
+ altDown: 'alt+downarrow',
975
+ tab: 'tab',
976
+ shiftTab: 'shift+tab',
977
+ end: 'end',
978
+ enter: 'enter',
979
+ home: 'home',
980
+ moveDown: 'downarrow',
981
+ moveLeft: 'leftarrow',
982
+ moveRight: 'rightarrow',
983
+ moveUp: 'uparrow',
984
+ ctrlDown: 'ctrl+downarrow',
985
+ ctrlUp: 'ctrl+uparrow',
986
+ ctrlEnter: 'ctrl+enter',
987
+ ctrlHome: 'ctrl+home',
988
+ ctrlEnd: 'ctrl+end',
989
+ shiftDown: 'shift+downarrow',
990
+ shiftUp: 'shift+uparrow',
991
+ shiftEnter: 'shift+enter',
992
+ shiftHome: 'shift+home',
993
+ shiftEnd: 'shift+end',
994
+ csDown: 'ctrl+shift+downarrow',
995
+ csUp: 'ctrl+shift+uparrow',
996
+ csEnter: 'ctrl+shift+enter',
997
+ csHome: 'ctrl+shift+home',
998
+ csEnd: 'ctrl+shift+end',
999
+ space: 'space',
1000
+ ctrlA: 'ctrl+A'
1001
+ };
1002
+ }
1003
+
1004
+ /**
1005
+ * To Initialize the control rendering
1006
+ *
1007
+ * @private
1008
+ * @returns {void}
1009
+ */
1010
+ public render(): void {
1011
+ const isTree: Element = select('#' + this.element.id + '_tree', document);
1012
+ if (isTree) {
1013
+ const popupDiv: Element = select('#' + this.element.id + '_popup', document);
1014
+ detach(popupDiv ? popupDiv : isTree.parentElement);
1015
+ }
1016
+ if (this.element.tagName === 'INPUT') {
1017
+ this.inputEle = this.element as HTMLInputElement;
1018
+ if (isNOU(this.inputEle.getAttribute('role'))) {
1019
+ this.inputEle.setAttribute('role', 'textbox');
1020
+ }
1021
+ if (isNOU(this.inputEle.getAttribute('type'))) {
1022
+ this.inputEle.setAttribute('type', 'text');
1023
+ }
1024
+ } else {
1025
+ this.inputEle = this.createElement('input', { attrs: { role: 'textbox', type: 'text' } }) as HTMLInputElement;
1026
+ this.element.parentElement.insertBefore(this.inputEle, this.element);
1027
+ }
1028
+ this.inputObj = Input.createInput(
1029
+ {
1030
+ element: this.inputEle,
1031
+ floatLabelType: this.floatLabelType,
1032
+ buttons: this.showDropDownIcon ? [DROPDOWNICON] : null,
1033
+ properties: {
1034
+ readonly: true,
1035
+ placeholder: this.placeholder,
1036
+ enabled: this.enabled,
1037
+ cssClass: this.cssClass,
1038
+ enableRtl: this.enableRtl
1039
+ }
1040
+ },
1041
+ this.createElement
1042
+ );
1043
+ this.inputWrapper = this.inputObj.container;
1044
+ if (!this.inputWrapper.classList.contains(INPUTGROUP)) {
1045
+ this.inputWrapper.classList.add(INPUTGROUP);
1046
+ }
1047
+ if (this.showDropDownIcon) {
1048
+ this.inputWrapper.classList.add(SHOW_DD_ICON);
1049
+ }
1050
+ if (this.element.tagName === this.getDirective()) {
1051
+ this.element.appendChild(this.inputWrapper);
1052
+ }
1053
+ this.createHiddenElement();
1054
+ this.createClearIcon();
1055
+ this.inputWrapper.classList.add(DROPDOWNTREE);
1056
+ this.setElementWidth(this.width);
1057
+ this.updateDataAttribute();
1058
+ this.setHTMLAttributes();
1059
+ this.setAttributes();
1060
+ this.popupDiv = this.createElement('div', { className: CONTENT });
1061
+ this.popupDiv.classList.add(DROPDOWN);
1062
+ this.tree = this.createElement('div', { id: this.element.id + '_tree' });
1063
+ this.popupDiv.appendChild(this.tree);
1064
+ document.body.appendChild(this.popupDiv);
1065
+ this.wireTreeEvents();
1066
+ addClass([this.popupDiv], DDTHIDEICON);
1067
+ this.renderTree();
1068
+ this.isRemoteData = this.fields.dataSource instanceof DataManager;
1069
+ if (this.allowMultiSelection || this.showCheckBox) {
1070
+ if (this.mode !== 'Delimiter') {
1071
+ this.createChip();
1072
+ }
1073
+ if (!this.wrapText && this.mode !== 'Custom') {
1074
+ this.overFlowWrapper = this.createElement('span', { className: OVERFLOW_VIEW + ' ' + HIDEICON });
1075
+ this.inputWrapper.insertBefore(this.overFlowWrapper, this.hiddenElement);
1076
+ if (this.mode !== 'Box') {
1077
+ addClass([this.overFlowWrapper], SHOW_TEXT);
1078
+ }
1079
+ }
1080
+ }
1081
+ if (!this.isRemoteData) {
1082
+ this.setTreeValue();
1083
+ this.setTreeText();
1084
+ this.updateHiddenValue();
1085
+ this.setSelectedValue();
1086
+ if (!this.wrapText ) {
1087
+ this.updateView();
1088
+ }
1089
+ }
1090
+ this.wireEvents();
1091
+ const firstUl: Element = select('.' + PARENTITEM, this.treeObj.element);
1092
+ if (firstUl && firstUl.getAttribute('aria-multiselectable')) {
1093
+ firstUl.removeAttribute('aria-multiselectable');
1094
+ }
1095
+ this.oldValue = this.value;
1096
+ this.isInitialized = true;
1097
+ this.hasTemplate = this.itemTemplate || this.headerTemplate || this.footerTemplate || this.actionFailureTemplate
1098
+ || this.noRecordsTemplate || this.customTemplate;
1099
+ this.renderComplete();
1100
+ }
1101
+
1102
+ private hideCheckAll(flag: boolean): void {
1103
+ const checkAllEle : HTMLElement = !isNOU(this.popupEle) ? (this.popupEle.querySelector('.' + CHECKALLPARENT) as HTMLElement) : null;
1104
+ if (!isNOU(checkAllEle)) {
1105
+ if (flag && !checkAllEle.classList.contains(CHECKALLHIDE)) {
1106
+ addClass([checkAllEle], CHECKALLHIDE);
1107
+ } else if (!flag && checkAllEle.classList.contains(CHECKALLHIDE)) {
1108
+ removeClass([checkAllEle], CHECKALLHIDE);
1109
+ }
1110
+ }
1111
+ }
1112
+
1113
+ private renderFilter(): void {
1114
+ this.filterContainer = this.createElement('div', {
1115
+ id: this.element.id + '_filter_wrap',
1116
+ className: FILTERWRAP
1117
+ });
1118
+ const filterInput: HTMLElement = this.createElement('input', {
1119
+ id: this.element.id + '_filter',
1120
+ attrs: { autocomplete: 'off', 'aria-label': this.filterBarPlaceholder }
1121
+ });
1122
+ this.filterContainer.appendChild(filterInput);
1123
+ prepend([this.filterContainer], this.popupEle);
1124
+ this.filterObj = new TextBox({
1125
+ value: '',
1126
+ showClearButton: true,
1127
+ placeholder: this.filterBarPlaceholder,
1128
+ input: this.filterChangeHandler.bind(this)
1129
+ });
1130
+ this.filterObj.appendTo('#' + this.element.id + '_filter');
1131
+ }
1132
+ private filterChangeHandler(args?: InputEventArgs): void {
1133
+ if (!isNOU(args.value)) {
1134
+ window.clearTimeout(this.filterTimer);
1135
+ this.filterTimer = window.setTimeout(() => { this.filterHandler(args.value, args.event); }, this.filterDelayTime);
1136
+ }
1137
+ }
1138
+
1139
+ private filterHandler(value: string, event: Event): void {
1140
+ this.isFromFilterChange = true;
1141
+ if (!this.isFilteredData) { this.treeData = this.treeObj.getTreeData(); }
1142
+ const filterFields: FieldsModel = this.cloneFields(this.fields);
1143
+ const args: DdtFilteringEventArgs = {
1144
+ cancel: false,
1145
+ preventDefaultAction: false,
1146
+ event: event,
1147
+ text: value,
1148
+ fields: filterFields
1149
+ };
1150
+ this.trigger('filtering', args, (args: DdtFilteringEventArgs) => {
1151
+ if (!args.cancel) {
1152
+ let flag: boolean = false;
1153
+ let fields: FieldsModel;
1154
+ this.isFilteredData = true;
1155
+ if (value === '') {
1156
+ this.isFilteredData = false;
1157
+ this.isFilterRestore = true;
1158
+ fields = this.cloneFields(this.fields);
1159
+ } else if (args.preventDefaultAction) {
1160
+ fields = args.fields;
1161
+ } else {
1162
+ if (this.treeDataType === 1) {
1163
+ fields = this.selfReferencefilter(value, args.fields);
1164
+ } else {
1165
+ if (this.fields.dataSource instanceof DataManager) {
1166
+ flag = true;
1167
+ } else {
1168
+ fields = this.nestedFilter(value, args.fields);
1169
+ }
1170
+ }
1171
+ }
1172
+ this.hideCheckAll(this.isFilteredData);
1173
+ if (flag) { return; }
1174
+ this.treeObj.fields = this.getTreeFields(fields);
1175
+ this.treeObj.dataBind();
1176
+ if (this.hasTemplate && (this as any).portals ) {
1177
+ (this as any).portals = [].concat((this.treeObj as any).portals) ;
1178
+ if ((this as any).isReact) {
1179
+ this.renderReactTemplates();
1180
+ }
1181
+ }
1182
+ }
1183
+ });
1184
+ }
1185
+
1186
+ private nestedFilter(value: string, filteredFields: FieldsModel): FieldsModel {
1187
+ // eslint-disable-next-line
1188
+ const matchedDataSource: { [key: string]: Object }[] = [];
1189
+ for (let i: number = 0; i < this.treeData.length; i++) {
1190
+ // eslint-disable-next-line
1191
+ const filteredChild: { [key: string]: Object } = this.nestedChildFilter(value, this.treeData[i]);
1192
+ if (!isNOU(filteredChild)) { matchedDataSource.push(filteredChild); }
1193
+ }
1194
+ filteredFields.dataSource = matchedDataSource;
1195
+ return filteredFields;
1196
+ }
1197
+
1198
+ // eslint-disable-next-line
1199
+ private nestedChildFilter(value: string, node: { [key: string]: Object }): { [key: string]: Object } {
1200
+ // eslint-disable-next-line
1201
+ const children: { [key: string]: Object }[] = <{ [key: string]: Object }[]>node[this.fields.child as string];
1202
+ if (isNOU(children)) {
1203
+ return (this.isMatchedNode(value, node)) ? node : null;
1204
+ } else {
1205
+ // eslint-disable-next-line
1206
+ const matchedChildren: { [key: string]: Object }[] = [];
1207
+ for (let i: number = 0; i < children.length; i++) {
1208
+ // eslint-disable-next-line
1209
+ const filteredChild: { [key: string]: Object } = this.nestedChildFilter(value, children[i]);
1210
+ if (!isNOU(filteredChild)) { matchedChildren.push(filteredChild); }
1211
+ }
1212
+ let filteredItems: any = (<any>Object).assign({}, node);
1213
+ if (matchedChildren.length !== 0) {
1214
+ filteredItems[this.fields.child as string] = matchedChildren;
1215
+ return filteredItems;
1216
+ } else {
1217
+ filteredItems[this.fields.child as string] = null;
1218
+ return (this.isMatchedNode(value, filteredItems)) ? filteredItems : null;
1219
+ }
1220
+ }
1221
+ }
1222
+
1223
+ private selfReferencefilter(value: string, filteredFields: FieldsModel): FieldsModel {
1224
+ // eslint-disable-next-line
1225
+ const matchedData: { [key: string]: Object }[] = [];
1226
+ // eslint-disable-next-line
1227
+ const matchedDataSource: { [key: string]: Object }[] = [];
1228
+ for (let i: number = 0; i < this.treeData.length; i++) {
1229
+ if (this.isMatchedNode(value, this.treeData[i as number])) {
1230
+ matchedData.push(this.treeData[i as number]);
1231
+ }
1232
+ }
1233
+ for (let i: number = 0; i < matchedData.length; i++) {
1234
+ if (matchedDataSource.indexOf(matchedData[i as number]) === -1) {
1235
+ matchedDataSource.push(matchedData[i as number]);
1236
+ // eslint-disable-next-line
1237
+ let parentId: object = matchedData[i][this.fields.parentValue];
1238
+ while (!isNOU(parentId)) {
1239
+ // eslint-disable-next-line
1240
+ let parent: { [key: string]: Object } = null;
1241
+ for (let j: number = 0; j < this.treeData.length; j++) {
1242
+ // eslint-disable-next-line
1243
+ const value: object = this.treeData[j][this.fields.value];
1244
+ if (!isNOU(value) && (value === parentId)) {
1245
+ parent = this.treeData[j as number];
1246
+ break;
1247
+ }
1248
+ }
1249
+ if (!isNOU(parent) && (matchedDataSource.indexOf(parent) === -1)) {
1250
+ matchedDataSource.push(parent);
1251
+ parentId = parent[this.fields.parentValue];
1252
+ } else {
1253
+ break;
1254
+ }
1255
+ }
1256
+ }
1257
+ }
1258
+ filteredFields.dataSource = matchedDataSource;
1259
+ return filteredFields;
1260
+ }
1261
+
1262
+ // eslint-disable-next-line
1263
+ private isMatchedNode(value: string, node: { [key: string]: Object }): boolean {
1264
+ let checkValue: string = node[this.fields.text] as string;
1265
+ if (this.ignoreCase) {
1266
+ checkValue = checkValue.toLowerCase();
1267
+ value = value.toLowerCase();
1268
+ }
1269
+ if (this.ignoreAccent) {
1270
+ checkValue = DataUtil.ignoreDiacritics(checkValue) as string;
1271
+ value = DataUtil.ignoreDiacritics(value) as string;
1272
+ }
1273
+ if (this.filterType === 'StartsWith') {
1274
+ return checkValue.slice(0, value.length) === value;
1275
+ } else if (this.filterType === 'EndsWith') {
1276
+ return checkValue.slice(-value.length) === value;
1277
+ } else {
1278
+ return checkValue.indexOf(value) !== -1;
1279
+ }
1280
+ }
1281
+
1282
+ /* To wire events for the dropdown tree */
1283
+ private wireEvents(): void {
1284
+ EventHandler.add(this.inputWrapper, 'mouseup', this.dropDownClick, this);
1285
+ EventHandler.add(this.inputWrapper, 'focus', this.focusIn, this);
1286
+ EventHandler.add(this.inputWrapper, 'blur', this.focusOut, this);
1287
+ EventHandler.add(this.inputWrapper, 'mousemove', this.mouseIn, this);
1288
+ EventHandler.add(this.inputWrapper, 'mouseout', this.onMouseLeave, this);
1289
+ EventHandler.add(this.overAllClear, 'mousedown', this.clearAll, this);
1290
+ EventHandler.add(<HTMLElement & Window><unknown>window, 'resize', this.windowResize, this);
1291
+ const formElement: HTMLFormElement = closest(this.inputWrapper, 'form') as HTMLFormElement;
1292
+ if (formElement) {
1293
+ EventHandler.add(formElement, 'reset', this.resetValueHandler, this);
1294
+ }
1295
+ this.keyboardModule = new KeyboardEvents(
1296
+ this.inputWrapper,
1297
+ {
1298
+ keyAction: this.keyActionHandler.bind(this),
1299
+ keyConfigs: this.keyConfigs,
1300
+ eventName: 'keydown'
1301
+ }
1302
+ );
1303
+ }
1304
+
1305
+ private wireTreeEvents(): void {
1306
+ this.keyboardModule = new KeyboardEvents(
1307
+ this.tree,
1308
+ {
1309
+ keyAction: this.treeAction.bind(this),
1310
+ keyConfigs: this.keyConfigs,
1311
+ eventName: 'keydown'
1312
+ }
1313
+ );
1314
+ }
1315
+
1316
+ private wireCheckAllWrapperEvents(): void {
1317
+ this.keyboardModule = new KeyboardEvents(
1318
+ this.checkAllParent,
1319
+ {
1320
+ keyAction: this.checkAllAction.bind(this),
1321
+ keyConfigs: this.keyConfigs,
1322
+ eventName: 'keydown'
1323
+ }
1324
+ );
1325
+ }
1326
+
1327
+ /* To unwire events for the dropdown tree */
1328
+ private unWireEvents(): void {
1329
+ EventHandler.remove(this.inputWrapper, 'mouseup', this.dropDownClick);
1330
+ EventHandler.remove(this.inputWrapper, 'focus', this.focusIn);
1331
+ EventHandler.remove(this.inputWrapper, 'blur', this.focusOut);
1332
+ EventHandler.remove(this.inputWrapper, 'mousemove', this.mouseIn);
1333
+ EventHandler.remove(this.inputWrapper, 'mouseout', this.onMouseLeave);
1334
+ EventHandler.remove(this.overAllClear, 'mousedown', this.clearAll);
1335
+ EventHandler.remove(<HTMLElement & Window><unknown>window, 'resize', this.windowResize);
1336
+ const formElement: HTMLFormElement = closest(this.inputWrapper, 'form') as HTMLFormElement;
1337
+ if (formElement) {
1338
+ EventHandler.remove(formElement, 'reset', this.resetValueHandler);
1339
+ }
1340
+ }
1341
+
1342
+ /* Trigger when the dropdown is clicked */
1343
+ private dropDownClick(e: MouseEvent): void {
1344
+ if (!this.enabled || this.readonly) {
1345
+ return;
1346
+ }
1347
+ if (this.isClearButtonClick) {
1348
+ this.isClearButtonClick = false;
1349
+ return;
1350
+ }
1351
+ if (this.isPopupOpen) {
1352
+ this.hidePopup();
1353
+ } else {
1354
+ this.focusIn(e);
1355
+ this.renderPopup();
1356
+ }
1357
+ this.showOverAllClear();
1358
+ }
1359
+
1360
+ private mouseIn(): void {
1361
+ if (this.enabled || !this.readonly) {
1362
+ this.showOverAllClear();
1363
+ }
1364
+ }
1365
+
1366
+ private onMouseLeave(): void {
1367
+ if (!this.inputFocus) {
1368
+ addClass([this.overAllClear], HIDEICON);
1369
+ removeClass([this.inputWrapper], SHOW_CLEAR);
1370
+ }
1371
+ }
1372
+
1373
+ protected getDirective(): string {
1374
+ return 'EJS-DROPDOWNTREE';
1375
+ }
1376
+
1377
+ private focusOut(e: MouseEvent): void {
1378
+ if (!this.enabled || this.readonly || !this.inputFocus) {
1379
+ return;
1380
+ }
1381
+ if ((Browser.isIE || Browser.info.name === 'edge') && (e.target === this.inputWrapper)) {
1382
+ return;
1383
+ }
1384
+ const target: HTMLElement = <HTMLElement>e.relatedTarget;
1385
+ if ((target !== this.inputEle) && (isNOU(target)) && (e.target !== this.inputWrapper || !this.isPopupOpen)) {
1386
+ this.onFocusOut(e);
1387
+ }
1388
+ }
1389
+
1390
+ private onFocusOut(event?: MouseEvent): void {
1391
+ this.inputFocus = false;
1392
+ if (this.isPopupOpen) {
1393
+ this.hidePopup();
1394
+ }
1395
+ if (this.isClearButtonClick) {
1396
+ this.isClearButtonClick = false;
1397
+ }
1398
+ if (this.showClearButton) {
1399
+ this.clearIconWidth = (<HTMLElement>select('.e-clear-icon', this.inputWrapper)).offsetWidth;
1400
+ addClass([this.overAllClear], HIDEICON);
1401
+ removeClass([this.inputWrapper], SHOW_CLEAR);
1402
+ }
1403
+ removeClass([this.inputWrapper], [INPUTFOCUS]);
1404
+ if ((this.allowMultiSelection || this.showCheckBox)) {
1405
+ const isValue: boolean = this.value ? (this.value.length ? true : false) : false;
1406
+ if (this.mode !== 'Delimiter' && this.mode !== 'Custom') {
1407
+ if (this.chipWrapper && (this.mode === 'Default')) {
1408
+ addClass([this.chipWrapper], HIDEICON);
1409
+ removeClass([this.inputWrapper], SHOW_CHIP);
1410
+ removeClass([this.inputEle], CHIP_INPUT);
1411
+ }
1412
+ }
1413
+ if (!this.wrapText && isValue) {
1414
+ this.updateView();
1415
+ }
1416
+ }
1417
+ if (this.changeOnBlur) {
1418
+ this.triggerChangeEvent(event);
1419
+ }
1420
+ this.removeValue = false;
1421
+ this.oldValue = this.value;
1422
+ this.trigger('blur');
1423
+ }
1424
+
1425
+ private updateView(): void {
1426
+ if ((!this.showCheckBox && !this.allowMultiSelection) || this.mode === 'Custom' || this.inputFocus) {
1427
+ return;
1428
+ }
1429
+ if (this.mode !== 'Box') {
1430
+ addClass([this.inputWrapper, this.overFlowWrapper], SHOW_TEXT);
1431
+ } else {
1432
+ addClass([this.inputWrapper], SHOW_CHIP);
1433
+ }
1434
+ if (this.value && this.value.length !== 0) {
1435
+ if (this.inputWrapper.contains(this.chipWrapper)) {
1436
+ addClass([this.chipWrapper], HIDEICON);
1437
+ }
1438
+ addClass([this.inputEle], CHIP_INPUT);
1439
+ this.updateOverFlowView();
1440
+ this.ensurePlaceHolder();
1441
+ }
1442
+ }
1443
+
1444
+ private triggerChangeEvent(event?: MouseEvent | KeyboardEvent): void {
1445
+ const isEqual: boolean = this.ddtCompareValues(this.oldValue, this.value);
1446
+ if ((!isEqual || this.isChipDelete) && !this.removeValue) {
1447
+ const eventArgs: DdtChangeEventArgs = {
1448
+ e: event,
1449
+ oldValue: this.oldValue,
1450
+ value: this.value,
1451
+ isInteracted: event ? true : false,
1452
+ element: this.element
1453
+ };
1454
+ this.trigger('change', eventArgs);
1455
+ this.oldValue = this.value;
1456
+ }
1457
+ }
1458
+
1459
+ private ddtCompareValues(oldValue: string[], newValue: string[]): boolean {
1460
+ if (oldValue === null || newValue === null ) {
1461
+ const isValid: boolean = oldValue === null ? ((newValue === oldValue) ? true : false) :
1462
+ (oldValue.length === 0 ? (newValue === oldValue) : false);
1463
+ return isValid;
1464
+ } else if (oldValue.length !== newValue.length) {
1465
+ return false;
1466
+ }
1467
+ for (let i: number = 0; i < oldValue.length; i++) {
1468
+ if (oldValue[i as number] !== newValue[i as number]) {
1469
+ return false;
1470
+ }
1471
+ }
1472
+ return true;
1473
+ }
1474
+
1475
+ private focusIn(e?: FocusEvent | MouseEvent | KeyboardEvent | TouchEvent): void {
1476
+ if (!this.enabled || this.readonly || this.inputFocus) {
1477
+ return;
1478
+ }
1479
+ this.showOverAllClear();
1480
+ this.inputFocus = true;
1481
+ addClass([this.inputWrapper], [INPUTFOCUS]);
1482
+ if (this.allowMultiSelection || this.showCheckBox) {
1483
+ if (this.mode !== 'Delimiter' && this.inputFocus) {
1484
+ if (this.chipWrapper && (this.value && this.value.length !== 0)) {
1485
+ removeClass([this.chipWrapper], HIDEICON);
1486
+ addClass([this.inputEle], CHIP_INPUT);
1487
+ }
1488
+ addClass([this.inputWrapper], SHOW_CHIP);
1489
+ if (this.popupObj) {
1490
+ this.popupObj.refreshPosition();
1491
+ }
1492
+ }
1493
+ if (!this.wrapText && this.mode !== 'Custom') {
1494
+ if (this.inputWrapper.contains(this.overFlowWrapper)) {
1495
+ addClass([this.overFlowWrapper], HIDEICON);
1496
+ }
1497
+ if (this.mode === 'Delimiter') {
1498
+ removeClass([this.inputWrapper], SHOW_CHIP);
1499
+ removeClass([this.inputEle], CHIP_INPUT);
1500
+ } else {
1501
+ addClass([this.inputWrapper], SHOW_CHIP);
1502
+ }
1503
+ removeClass([this.inputWrapper], SHOW_TEXT);
1504
+ this.ensurePlaceHolder();
1505
+ }
1506
+ }
1507
+ const args: DdtFocusEventArgs = { isInteracted: e ? true : false, event: e };
1508
+ this.trigger('focus', args);
1509
+ }
1510
+
1511
+ private treeAction(e: KeyboardEventArgs): void {
1512
+ const eventArgs: DdtKeyPressEventArgs = {
1513
+ cancel: false,
1514
+ event: e
1515
+ };
1516
+ this.trigger('keyPress', eventArgs, (observedArgs: DdtKeyPressEventArgs) => {
1517
+ if (!observedArgs.cancel) {
1518
+ switch (e.action) {
1519
+ case 'escape':
1520
+ case 'altUp':
1521
+ this.inputWrapper.focus();
1522
+ e.preventDefault();
1523
+ if (this.isPopupOpen) {
1524
+ this.hidePopup();
1525
+ }
1526
+ break;
1527
+ case 'tab':
1528
+ case 'shiftTab':
1529
+ if (this.isPopupOpen) {
1530
+ this.hidePopup();
1531
+ }
1532
+ break;
1533
+ case 'enter':
1534
+ case 'ctrlEnter':
1535
+ case 'shiftEnter':
1536
+ case 'csEnter':
1537
+ if (!this.showCheckBox) {
1538
+ this.isValueChange = true;
1539
+ this.keyEventArgs = e;
1540
+ }
1541
+ break;
1542
+ case 'space':
1543
+ this.isValueChange = true;
1544
+ this.keyEventArgs = e;
1545
+ break;
1546
+ case 'ctrlA':
1547
+ if (this.allowMultiSelection) {
1548
+ this.selectAll(true);
1549
+ }
1550
+ break;
1551
+ case 'moveRight':
1552
+ case 'moveLeft':
1553
+ case 'shiftDown':
1554
+ case 'moveDown':
1555
+ case 'ctrlDown':
1556
+ case 'csDown':
1557
+ case 'shiftUp':
1558
+ case 'moveUp':
1559
+ case 'ctrlUp':
1560
+ case 'csUp':
1561
+ case 'home':
1562
+ case 'shiftHome':
1563
+ case 'ctrlHome':
1564
+ case 'csHome':
1565
+ case 'end':
1566
+ case 'shiftEnd':
1567
+ case 'ctrlEnd':
1568
+ case 'csEnd':
1569
+ }
1570
+ } else {
1571
+ e.stopImmediatePropagation();
1572
+ }
1573
+ });
1574
+ }
1575
+
1576
+ private keyActionHandler(e: KeyboardEventArgs): void {
1577
+ const eventArgs: DdtKeyPressEventArgs = {
1578
+ cancel: false,
1579
+ event: e
1580
+ };
1581
+ this.trigger('keyPress', eventArgs, (observedArgs: DdtKeyPressEventArgs) => {
1582
+ if (!observedArgs.cancel) {
1583
+ switch (e.action) {
1584
+ case 'escape':
1585
+ case 'altUp':
1586
+ if (this.isPopupOpen) {
1587
+ this.hidePopup();
1588
+ }
1589
+ break;
1590
+ case 'shiftTab':
1591
+ case 'tab':
1592
+ if (this.isPopupOpen) {
1593
+ this.hidePopup();
1594
+ }
1595
+ if (this.inputFocus) {
1596
+ this.onFocusOut();
1597
+ }
1598
+ break;
1599
+ case 'altDown':
1600
+ if (!this.isPopupOpen) {
1601
+ this.showPopup();
1602
+ e.preventDefault();
1603
+ }
1604
+ break;
1605
+ case 'moveDown':
1606
+ if (this.showSelectAll && this.showCheckBox) {
1607
+ this.checkAllParent.focus();
1608
+ }
1609
+ break;
1610
+ }
1611
+ }
1612
+ });
1613
+ }
1614
+
1615
+ private checkAllAction(e: KeyboardEventArgs): void {
1616
+ const eventArgs: DdtKeyPressEventArgs = {
1617
+ cancel: false,
1618
+ event: e
1619
+ };
1620
+ this.trigger('keyPress', eventArgs, (observedArgs: DdtKeyPressEventArgs) => {
1621
+ if (!observedArgs.cancel) {
1622
+ switch (e.action) {
1623
+ case 'space':
1624
+ this.clickHandler(e);
1625
+ break;
1626
+ case 'moveDown':
1627
+ let focusedElement: HTMLElement= this.treeObj.element.querySelector('li');
1628
+ focusedElement.focus();
1629
+ addClass([focusedElement], ['e-node-focus']);
1630
+ }
1631
+ }
1632
+ });
1633
+ }
1634
+
1635
+ private windowResize(): void {
1636
+ if (this.popupObj) {
1637
+ this.popupObj.setProperties({ width: this.setWidth() });
1638
+ this.popupObj.refreshPosition();
1639
+ }
1640
+ }
1641
+
1642
+ private resetValueHandler(e: Event): void {
1643
+ const formElement: HTMLFormElement = closest(this.inputWrapper, 'form') as HTMLFormElement;
1644
+ if (formElement && e.target === formElement) {
1645
+ this.isDynamicChange = true;
1646
+ this.setProperties({ value: null }, true);
1647
+ this.resetValue(true);
1648
+ this.isDynamicChange = false;
1649
+ }
1650
+ }
1651
+
1652
+ protected getAriaAttributes(): { [key: string]: string } {
1653
+ const disable: string = this.enabled ? 'false' : 'true';
1654
+ return {
1655
+ 'aria-disabled': disable,
1656
+ 'aria-owns': this.element.id + '_options',
1657
+ 'role': 'listbox',
1658
+ 'aria-haspopup': 'true',
1659
+ 'aria-expanded': 'false',
1660
+ 'aria-activedescendant': 'null',
1661
+ 'aria-labelledby': this.hiddenElement.id
1662
+ };
1663
+ }
1664
+
1665
+ private updateOverFlowView(): void {
1666
+ this.overFlowWrapper.classList.remove(TOTAL_COUNT_WRAPPER);
1667
+ removeClass([this.overFlowWrapper], HIDEICON);
1668
+ if (this.value && this.value.length) {
1669
+ let data: string = ''; let overAllContainer: number;
1670
+ let temp: string; let tempData: string;
1671
+ let tempIndex: number = 1; let wrapperleng: number;
1672
+ let remaining: number; let downIconWidth: number = 0;
1673
+ this.overFlowWrapper.innerHTML = '';
1674
+ // eslint-disable-next-line
1675
+ const l10nLocale: Object = { overflowCountTemplate: '+${count} more..', totalCountTemplate: '${count} selected' };
1676
+ this.l10n = new L10n(this.getLocaleName(), l10nLocale, this.locale);
1677
+ const remainContent: string = this.l10n.getConstant('overflowCountTemplate');
1678
+ const totalContent: string = this.l10n.getConstant('totalCountTemplate');
1679
+ const remainElement: HTMLElement = this.createElement('span', { className: REMAIN_WRAPPER });
1680
+ this.overFlowWrapper.appendChild(remainElement);
1681
+ remainElement.innerText = remainContent.replace('${count}',this.value.length.toString());
1682
+ const remainSize: number = remainElement.offsetWidth;
1683
+ remove(remainElement);
1684
+ if (this.showDropDownIcon) {
1685
+ downIconWidth = (<HTMLElement>select('.' + DDTICON, this.inputWrapper)).offsetWidth;
1686
+ }
1687
+ if (!isNOU(this.value)) {
1688
+ if (this.mode !== 'Box') {
1689
+ for (let index: number = 0; !isNOU(this.value[index as number]); index++) {
1690
+ data += (index === 0) ? '' : this.delimiterChar + ' ';
1691
+ temp = this.getOverflowVal(index);
1692
+ data += temp;
1693
+ temp = this.overFlowWrapper.innerHTML;
1694
+ if (this.enableHtmlSanitizer) {
1695
+ this.overFlowWrapper.innerText = SanitizeHtmlHelper.sanitize(data);
1696
+ }
1697
+ else { this.overFlowWrapper.innerHTML = data; }
1698
+ wrapperleng = this.overFlowWrapper.offsetWidth;
1699
+ overAllContainer = this.inputWrapper.offsetWidth;
1700
+ if ((wrapperleng + downIconWidth + this.clearIconWidth) > overAllContainer) {
1701
+ if (tempData !== undefined && tempData !== '') {
1702
+ temp = tempData;
1703
+ index = tempIndex + 1;
1704
+ }
1705
+ this.overFlowWrapper.innerHTML = temp;
1706
+ remaining = this.value.length - index;
1707
+ wrapperleng = this.overFlowWrapper.offsetWidth;
1708
+ while (((wrapperleng + remainSize + downIconWidth + this.clearIconWidth) >= overAllContainer)
1709
+ && wrapperleng !== 0 && this.overFlowWrapper.innerHTML !== '') {
1710
+ const textArr: string[] = this.overFlowWrapper.innerHTML.split(this.delimiterChar);
1711
+ textArr.pop();
1712
+ this.overFlowWrapper.innerHTML = textArr.join(this.delimiterChar);
1713
+ remaining++;
1714
+ wrapperleng = this.overFlowWrapper.offsetWidth;
1715
+ }
1716
+ break;
1717
+ } else if ((wrapperleng + remainSize + downIconWidth + this.clearIconWidth) <= overAllContainer) {
1718
+ tempData = data; tempIndex = index;
1719
+ } else if (index === 0) { tempData = ''; tempIndex = -1; }
1720
+ }
1721
+ } else {
1722
+ addClass([this.chipWrapper], HIDEICON);
1723
+ const ele: HTMLElement = <HTMLElement>(this.chipWrapper as Node).cloneNode(true);
1724
+ const chips: HTMLElement[] = selectAll('.' + CHIP, ele);
1725
+ for (let i: number = 0; i < chips.length; i++) {
1726
+ temp = this.overFlowWrapper.innerHTML;
1727
+ this.overFlowWrapper.appendChild(chips[i as number]);
1728
+ data = this.overFlowWrapper.innerHTML;
1729
+ wrapperleng = this.overFlowWrapper.offsetWidth;
1730
+ overAllContainer = this.inputWrapper.offsetWidth;
1731
+ if ((wrapperleng + downIconWidth + this.clearIconWidth) > overAllContainer) {
1732
+ if (tempData !== undefined && tempData !== '') {
1733
+ temp = tempData; i = tempIndex + 1;
1734
+ }
1735
+ this.overFlowWrapper.innerHTML = temp;
1736
+ remaining = this.value.length - i;
1737
+ wrapperleng = this.overFlowWrapper.offsetWidth;
1738
+ while (((wrapperleng + remainSize + downIconWidth + this.clearIconWidth) >= overAllContainer)
1739
+ && wrapperleng !== 0 && this.overFlowWrapper.innerHTML !== '') {
1740
+ this.overFlowWrapper.removeChild( this.overFlowWrapper.lastChild);
1741
+ remaining++;
1742
+ wrapperleng = this.overFlowWrapper.offsetWidth;
1743
+ }
1744
+ break;
1745
+ } else if ((wrapperleng + remainSize + downIconWidth + this.clearIconWidth) <= overAllContainer) {
1746
+ tempData = data; tempIndex = i;
1747
+ } else if (i === 0) {
1748
+ tempData = ''; tempIndex = -1;
1749
+ }
1750
+ }
1751
+ }
1752
+ }
1753
+ if (remaining > 0) {
1754
+ this.overFlowWrapper.appendChild(
1755
+ this.updateRemainTemplate(remainElement, remaining, remainContent, totalContent)
1756
+ );
1757
+ }
1758
+ if (this.mode === 'Box' && !this.overFlowWrapper.classList.contains(TOTAL_COUNT_WRAPPER)) {
1759
+ addClass([remainElement], REMAIN_COUNT);
1760
+ }
1761
+ } else {
1762
+ this.overFlowWrapper.innerHTML = '';
1763
+ addClass([this.overFlowWrapper], HIDEICON);
1764
+ }
1765
+ this.updateDelimMode();
1766
+ }
1767
+
1768
+ private updateRemainTemplate(
1769
+ remainElement: HTMLElement,
1770
+ remaining: number,
1771
+ remainContent: string,
1772
+ totalContent: string): HTMLElement {
1773
+ if (this.overFlowWrapper.firstChild && this.overFlowWrapper.firstChild.nodeType === 3 &&
1774
+ this.overFlowWrapper.firstChild.nodeValue === '') {
1775
+ this.overFlowWrapper.removeChild(this.overFlowWrapper.firstChild);
1776
+ }
1777
+ remainElement.innerHTML = '';
1778
+ remainElement.innerText = (this.overFlowWrapper.firstChild && (this.overFlowWrapper.firstChild.nodeType === 3 || this.mode === 'Box')) ?
1779
+ remainContent.replace('${count}', remaining.toString()) : totalContent.replace('${count}', remaining.toString());
1780
+ if (this.overFlowWrapper.firstChild && (this.overFlowWrapper.firstChild.nodeType === 3 || this.mode === 'Box')) {
1781
+ removeClass([this.overFlowWrapper], TOTAL_COUNT_WRAPPER);
1782
+ } else {
1783
+ addClass([this.overFlowWrapper], TOTAL_COUNT_WRAPPER);
1784
+ removeClass([this.overFlowWrapper], REMAIN_COUNT);
1785
+ }
1786
+ return remainElement;
1787
+ }
1788
+
1789
+ private getOverflowVal(index: number): string {
1790
+ // eslint-disable-next-line
1791
+ const selectedData: { [key: string]: Object } = this.getSelectedData(this.value[index]);
1792
+ return getValue(this.treeSettings.loadOnDemand ? this.fields.text : 'text', selectedData);
1793
+ }
1794
+
1795
+ private updateDelimMode(): void {
1796
+ if (this.mode !== 'Box') {
1797
+ if (select('.' + REMAIN_WRAPPER, this.overFlowWrapper) && !this.overFlowWrapper.classList.contains(TOTAL_COUNT_WRAPPER)) {
1798
+ addClass([this.overFlowWrapper], REMAIN_COUNT);
1799
+ addClass([this.overFlowWrapper], SHOW_TEXT);
1800
+ } else {
1801
+ this.overFlowWrapper.classList.remove(REMAIN_COUNT);
1802
+ removeClass([this.overFlowWrapper], REMAIN_COUNT);
1803
+ }
1804
+ } else if (select('.' + REMAIN_WRAPPER, this.overFlowWrapper)) {
1805
+ this.overFlowWrapper.classList.remove(REMAIN_COUNT);
1806
+ }
1807
+ }
1808
+
1809
+ private createHiddenElement(): void {
1810
+ if (this.allowMultiSelection || this.showCheckBox) {
1811
+ this.hiddenElement = this.createElement('select', {
1812
+ attrs: { 'aria-hidden': 'true', 'class': HIDDENELEMENT, 'tabindex': '-1', 'multiple': '' }
1813
+ }) as HTMLSelectElement;
1814
+ } else {
1815
+ this.hiddenElement = this.createElement('select', {
1816
+ attrs: { 'aria-hidden': 'true', 'tabindex': '-1', 'class': HIDDENELEMENT }
1817
+ }) as HTMLSelectElement;
1818
+ }
1819
+ prepend([this.hiddenElement], this.inputWrapper);
1820
+ this.validationAttribute();
1821
+ }
1822
+
1823
+ private createClearIcon(): void {
1824
+ this.overAllClear = this.createElement('span', {
1825
+ className: CLOSEICON_CLASS
1826
+ });
1827
+ addClass([this.overAllClear], HIDEICON);
1828
+ removeClass([this.inputWrapper], SHOW_CLEAR);
1829
+ if (this.showClearButton) {
1830
+ this.inputWrapper.insertBefore(this.overAllClear, this.inputObj.buttons[0]);
1831
+ }
1832
+ }
1833
+
1834
+ private validationAttribute(): void {
1835
+ const name: string = this.inputEle.getAttribute('name') ? this.inputEle.getAttribute('name') : this.inputEle.getAttribute('id');
1836
+ this.hiddenElement.setAttribute('name', name);
1837
+ this.inputEle.removeAttribute('name');
1838
+ const attributes: string[] = ['required', 'aria-required', 'form'];
1839
+ for (let i: number = 0; i < attributes.length; i++) {
1840
+ const attr: string = this.inputEle.getAttribute(attributes[i as number]);
1841
+ if (attr) {
1842
+ this.hiddenElement.setAttribute(attributes[i as number], attr);
1843
+ this.inputEle.removeAttribute(attributes[i as number]);
1844
+ }
1845
+ }
1846
+ }
1847
+
1848
+ private createChip(): void {
1849
+ if (!this.inputWrapper.contains(this.chipWrapper)) {
1850
+ this.chipWrapper = this.createElement('span', {
1851
+ className: CHIP_WRAPPER
1852
+ });
1853
+ this.chipCollection = this.createElement('span', {
1854
+ className: CHIP_COLLECTION
1855
+ });
1856
+ this.chipWrapper.appendChild(this.chipCollection);
1857
+ this.inputWrapper.insertBefore(this.chipWrapper, this.hiddenElement);
1858
+ addClass([this.inputWrapper], SHOW_CHIP);
1859
+ const isValid: boolean = this.getValidMode();
1860
+ if (isValid && this.value !== null && (this.value && this.value.length !== 0)) {
1861
+ addClass([this.inputEle], CHIP_INPUT);
1862
+ } else if (this.value === null || (this.value && this.value.length === 0) || this.checkWrapper) {
1863
+ addClass([this.chipWrapper], HIDEICON);
1864
+ }
1865
+ }
1866
+ }
1867
+
1868
+ private getValidMode(): boolean {
1869
+ if (this.allowMultiSelection || this.showCheckBox) {
1870
+ return this.mode === 'Box' ? true : (this.mode === 'Default' && this.inputFocus) ? true : false;
1871
+ } else {
1872
+ return false;
1873
+ }
1874
+ }
1875
+
1876
+ private createSelectAllWrapper(): void {
1877
+ this.checkAllParent = this.createElement('div', {
1878
+ className: CHECKALLPARENT, attrs: { 'tabindex': '0' }
1879
+ });
1880
+ this.selectAllSpan = this.createElement('span', {
1881
+ className: ALLTEXT
1882
+ });
1883
+ this.selectAllSpan.textContent = '';
1884
+ const ele: Element = closest(this.element, '.' + BIGGER);
1885
+ const touchClass: string = isNOU(ele) ? '' : SMALL;
1886
+ this.checkBoxElement = createCheckBox(this.createElement, true, { cssClass: touchClass });
1887
+ this.checkBoxElement.setAttribute('role', 'checkbox');
1888
+ this.checkAllParent.appendChild(this.checkBoxElement);
1889
+ this.checkAllParent.appendChild(this.selectAllSpan);
1890
+ this.setLocale();
1891
+ EventHandler.add(this.checkAllParent, 'mouseup', this.clickHandler, this);
1892
+ this.wireCheckAllWrapperEvents();
1893
+ }
1894
+
1895
+ private clickHandler(e: MouseEvent| KeyboardEvent): void {
1896
+ let target: EventTarget;
1897
+ if ((e.currentTarget && (e.currentTarget as HTMLElement).classList.contains(CHECKALLPARENT))) {
1898
+ target = (e.currentTarget as HTMLElement).firstElementChild.lastElementChild;
1899
+ } else {
1900
+ target = <Element>e.target;
1901
+ }
1902
+ this.checkWrapper = closest((target as HTMLElement), '.' + CHECKBOXWRAP) as HTMLElement;
1903
+ if (!isNOU(this.checkWrapper)) {
1904
+ this.isClicked = true;
1905
+ const checkElement: Element = select('.' + CHECKBOXFRAME, this.checkWrapper);
1906
+ this.changeState(this.checkWrapper, checkElement.classList.contains(CHECK) ? 'uncheck' : 'check', e);
1907
+ this.isClicked = false;
1908
+ }
1909
+ e.preventDefault();
1910
+ }
1911
+
1912
+ private changeState(
1913
+ wrapper: HTMLElement | Element, state: string, e?: MouseEvent | KeyboardEvent): void {
1914
+ let ariaState: string;
1915
+ const frameSpan: Element = wrapper.getElementsByClassName(CHECKBOXFRAME)[0];
1916
+ if (state === 'check' && !frameSpan.classList.contains(CHECK)) {
1917
+ frameSpan.classList.add(CHECK);
1918
+ ariaState = 'true';
1919
+ if (!this.isReverseUpdate) {
1920
+ this.isCheckAllCalled = true;
1921
+ this.treeObj.checkAll();
1922
+ if (!this.changeOnBlur) {
1923
+ this.triggerChangeEvent(e);
1924
+ }
1925
+ }
1926
+ this.setLocale(true);
1927
+ } else if (state === 'uncheck' && (frameSpan.classList.contains(CHECK))) {
1928
+ frameSpan.classList.remove(CHECK);
1929
+ ariaState = 'false';
1930
+ if (!this.isReverseUpdate) {
1931
+ this.treeObj.uncheckAll();
1932
+ if (!this.changeOnBlur) {
1933
+ this.triggerChangeEvent(e);
1934
+ }
1935
+ }
1936
+ this.setLocale(false);
1937
+ }
1938
+ this.setMultiSelect();
1939
+ this.ensurePlaceHolder();
1940
+ ariaState = state === 'check' ? 'true' : 'false';
1941
+ if (!isNOU(ariaState)) {
1942
+ wrapper.setAttribute('aria-checked', ariaState);
1943
+ }
1944
+ }
1945
+
1946
+ private setLocale(unSelect?: boolean): void {
1947
+ if (!this.selectAllSpan) {return; }
1948
+ if (this.selectAllText !== 'Select All' || this.unSelectAllText !== 'Unselect All') {
1949
+ const template: string = unSelect ? this.unSelectAllText : this.selectAllText;
1950
+ this.selectAllSpan.textContent = '';
1951
+ // eslint-disable-next-line
1952
+ const compiledString: Function = compile(template);
1953
+ const templateName: string = unSelect ? 'unSelectAllText' : 'selectAllText';
1954
+ for (const item of compiledString({}, this, templateName, null, !this.isStringTemplate)) {
1955
+ this.selectAllSpan.textContent = item.textContent;
1956
+ }
1957
+ } else {
1958
+ this.selectAllSpan.textContent = unSelect ? this.unSelectAllText : this.selectAllText;
1959
+ }
1960
+ }
1961
+
1962
+ private setAttributes(): void {
1963
+ this.inputEle.setAttribute('tabindex', '-1');
1964
+ const id: string = this.element.getAttribute('id');
1965
+ this.hiddenElement.id = id + '_hidden';
1966
+ this.inputWrapper.setAttribute('tabindex', '0');
1967
+ attributes(this.inputWrapper, this.getAriaAttributes());
1968
+ }
1969
+
1970
+ private setHTMLAttributes(): void {
1971
+ if (Object.keys(this.htmlAttributes).length) {
1972
+ for (const htmlAttr of Object.keys(this.htmlAttributes)) {
1973
+ if (htmlAttr === 'class') {
1974
+ this.inputWrapper.classList.add(this.htmlAttributes[`${htmlAttr}`]);
1975
+ } else if (htmlAttr === 'disabled' && this.htmlAttributes[`${htmlAttr}`] === 'disabled') {
1976
+ this.setProperties({ enabled: false }, true);
1977
+ this.setEnable();
1978
+ } else if (htmlAttr === 'readonly' && !isNOU(this.htmlAttributes[`${htmlAttr}`])) {
1979
+ this.setProperties({ readonly: true }, true);
1980
+ this.dataBind();
1981
+ } else if (htmlAttr === 'style') {
1982
+ this.inputWrapper.setAttribute('style', this.htmlAttributes[`${htmlAttr}`]);
1983
+ } else {
1984
+ const defaultAttr: string[] = ['title', 'id', 'placeholder', 'aria-placeholder',
1985
+ 'role', 'autocorrect', 'autocomplete', 'autocapitalize', 'spellcheck', 'minlength', 'maxlength'];
1986
+ const validateAttr: string[] = ['name', 'required'];
1987
+ if (htmlAttr.indexOf('data') === 0 || validateAttr.indexOf(htmlAttr) > -1) {
1988
+ this.hiddenElement.setAttribute(htmlAttr, this.htmlAttributes[`${htmlAttr}`]);
1989
+ } else if (defaultAttr.indexOf(htmlAttr) > -1) {
1990
+ if (htmlAttr === 'placeholder') {
1991
+ Input.setPlaceholder(this.htmlAttributes[`${htmlAttr}`], this.inputEle);
1992
+ } else {
1993
+ this.inputEle.setAttribute(htmlAttr, this.htmlAttributes[`${htmlAttr}`]);
1994
+ }
1995
+ } else {
1996
+ this.inputWrapper.setAttribute(htmlAttr, this.htmlAttributes[`${htmlAttr}`]);
1997
+ }
1998
+ }
1999
+ }
2000
+ }
2001
+ }
2002
+
2003
+ private updateDataAttribute() : void {
2004
+ const value: { [key: string]: string; } = this.htmlAttributes;
2005
+ const invalidAttr: string[] = ['class', 'style', 'id', 'type'];
2006
+ const attr: { [key: string]: string; } = {};
2007
+ for (let a: number = 0; a < this.element.attributes.length; a++) {
2008
+ if (invalidAttr.indexOf(this.element.attributes[a as number].name) === -1 &&
2009
+ !( this.element.attributes[a as number].name === 'readonly')) {
2010
+ attr[this.element.attributes[a as number].name] = this.element.getAttribute(this.element.attributes[a as number].name);
2011
+ }
2012
+ }
2013
+ extend(attr, value, attr);
2014
+ this.setProperties({ htmlAttributes: attr }, true);
2015
+ }
2016
+
2017
+ private showOverAllClear(): void {
2018
+ if (!this.enabled || this.readonly) {
2019
+ return;
2020
+ }
2021
+ if (this.overAllClear) {
2022
+ const isValue: boolean = this.value ? (this.value.length ? true : false) : false;
2023
+ if (isValue && this.showClearButton) {
2024
+ removeClass([this.overAllClear], HIDEICON);
2025
+ addClass([this.inputWrapper], SHOW_CLEAR);
2026
+ } else {
2027
+ addClass([this.overAllClear], HIDEICON);
2028
+ removeClass([this.inputWrapper], SHOW_CLEAR);
2029
+ }
2030
+ }
2031
+ }
2032
+
2033
+ private setTreeValue(): void {
2034
+ if (this.value !== null && this.value.length !== 0) {
2035
+ // eslint-disable-next-line
2036
+ let data: { [key: string]: Object };
2037
+ if (this.showCheckBox || this.allowMultiSelection) {
2038
+ for (let i: number = 0; i < this.value.length; i++) {
2039
+ data = this.treeObj.getTreeData(this.value[i as number])[0];
2040
+ if (isNOU(data)) {
2041
+ this.value.splice(this.value.indexOf(this.value[i as number]), 1);
2042
+ }
2043
+ }
2044
+ if (this.value.length !== 0) {
2045
+ this.setValidValue();
2046
+ }
2047
+ } else {
2048
+ data = this.treeObj.getTreeData(this.value[0])[0];
2049
+ if (!isNOU(data)) {
2050
+ this.setProperties({ text: data[this.fields.text] }, true);
2051
+ this.setValidValue();
2052
+ } else {
2053
+ this.setProperties({ value: this.currentValue }, true);
2054
+ }
2055
+ }
2056
+ }
2057
+ }
2058
+
2059
+ private setTreeText(): void {
2060
+ if (this.value !== null && !this.isInitialized) {
2061
+ return;
2062
+ }
2063
+ if (this.text !== null) {
2064
+ // eslint-disable-next-line
2065
+ let data: { [key: string]: Object };
2066
+ const valArr: string[] = [];
2067
+ if (this.showCheckBox || this.allowMultiSelection) {
2068
+ const textArr: string[] = this.text.split(this.delimiterChar);
2069
+ for (let i: number = 0; i < textArr.length; i++) {
2070
+ data = this.getItems(textArr[i as number]);
2071
+ if (!isNOU(data)) {
2072
+ valArr.push(data[this.fields.value].toString());
2073
+ }
2074
+ }
2075
+ if (valArr.length !== 0) {
2076
+ this.oldValue = this.value;
2077
+ this.setProperties({ value: valArr }, true);
2078
+ this.setValidValue();
2079
+ } else {
2080
+ this.setProperties({ text: this.currentText }, true);
2081
+ }
2082
+ } else {
2083
+ data = this.getItems(this.text);
2084
+ if (!isNOU(data)) {
2085
+ this.oldValue = this.value;
2086
+ this.setProperties({ value: [data[this.fields.value].toString()] }, true);
2087
+ this.setValidValue();
2088
+ } else {
2089
+ this.setProperties({ text: this.currentText }, true);
2090
+ }
2091
+ }
2092
+ }
2093
+ }
2094
+
2095
+ private setSelectedValue(): void {
2096
+ if (this.value != null) {
2097
+ return;
2098
+ }
2099
+ if (!this.isInitialized) {
2100
+ this.oldValue = this.value;
2101
+ if (this.treeObj.selectedNodes.length > 0 && !this.showCheckBox) {
2102
+ this.setProperties({ value: this.treeObj.selectedNodes }, true);
2103
+ if (this.allowMultiSelection) {
2104
+ this.updateMode();
2105
+ }
2106
+ } else if (this.showCheckBox && this.treeObj.checkedNodes) {
2107
+ if (this.treeObj.checkedNodes.length > 0) {
2108
+ this.setProperties({ value: this.treeObj.checkedNodes }, true);
2109
+ setValue('selectedNodes', [], this.treeObj);
2110
+ this.treeObj.dataBind();
2111
+ this.updateMode();
2112
+ }
2113
+ }
2114
+ this.updateSelectedValues();
2115
+ this.currentText = this.text;
2116
+ this.currentValue = this.value;
2117
+ }
2118
+ }
2119
+
2120
+ private setValidValue(): void {
2121
+ if (!this.showCheckBox && !this.allowMultiSelection) {
2122
+ Input.setValue(this.text, this.inputEle, this.floatLabelType);
2123
+ const id: string = this.value[0].toString();
2124
+ if (this.treeObj.selectedNodes[0] !== id) {
2125
+ setValue('selectedNodes', [id], this.treeObj);
2126
+ }
2127
+ } else {
2128
+ if (this.showCheckBox) {
2129
+ let difference: string[] = this.value.filter((e) => {
2130
+ return this.treeObj.checkedNodes.indexOf(e) === -1;
2131
+ });
2132
+ if (difference.length > 0 || this.treeSettings.autoCheck) {
2133
+ this.treeObj.checkedNodes = this.value.slice();
2134
+ this.treeObj.dataBind();
2135
+ this.setMultiSelect();
2136
+ }
2137
+ } else {
2138
+ this.treeObj.selectedNodes = this.value.slice();
2139
+ this.selectedText = [];
2140
+ this.updateSelectedValues();
2141
+ }
2142
+ this.treeObj.dataBind();
2143
+ }
2144
+ this.currentText = this.text;
2145
+ this.currentValue = this.value;
2146
+ if (this.isInitialized) {
2147
+ this.triggerChangeEvent();
2148
+ }
2149
+ }
2150
+
2151
+ // eslint-disable-next-line
2152
+ private getItems(givenText: string): { [key: string]: Object } {
2153
+ // eslint-disable-next-line
2154
+ let data: { [key: string]: Object };
2155
+ if (this.treeDataType === 1) {
2156
+ for (let i: number = 0; i < this.treeItems.length; i++) {
2157
+ // eslint-disable-next-line
2158
+ const text: Object = getValue(this.fields.text, this.treeItems[i]);
2159
+ if (!isNOU(this.treeItems[i as number]) && !isNOU(text) && text === givenText) {
2160
+ data = this.treeItems[i as number];
2161
+ break;
2162
+ }
2163
+ }
2164
+ } else {
2165
+ data = this.getNestedItems(this.treeItems, this.fields, givenText);
2166
+ }
2167
+ return data;
2168
+ }
2169
+
2170
+ // eslint-disable-next-line
2171
+ private getNestedItems(data: { [key: string]: Object }[], field: FieldsModel, givenText: string): { [key: string]: Object } {
2172
+ // eslint-disable-next-line
2173
+ let newData: { [key: string]: Object };
2174
+ for (let i: number = 0, objlen: number = data.length; i < objlen; i++) {
2175
+ // eslint-disable-next-line
2176
+ const dataId: Object = getValue(this.fields.text, data[i]);
2177
+ if (data[i as number] && dataId && dataId.toString() === givenText) {
2178
+ return data[i as number];
2179
+ } else if (typeof field.child === 'string' && !isNOU(getValue(field.child, data[i as number]))) {
2180
+ // eslint-disable-next-line
2181
+ const childData: Object = getValue(field.child, data[i]);
2182
+ // eslint-disable-next-line
2183
+ newData = this.getNestedItems(<{ [key: string]: Object }[]>childData, this.getChildType(field), givenText);
2184
+ if (newData !== undefined) {
2185
+ break;
2186
+ }
2187
+ } else if (this.fields.dataSource instanceof DataManager && !isNOU(getValue('child', data[i as number]))) {
2188
+ const child: string = 'child';
2189
+ // eslint-disable-next-line
2190
+ newData = this.getNestedItems(<{ [key: string]: Object }[]>getValue(child, data[i]), this.getChildType(field), givenText);
2191
+ if (newData !== undefined) {
2192
+ break;
2193
+ }
2194
+ }
2195
+ }
2196
+ return newData;
2197
+ }
2198
+
2199
+ private getChildType(mapper: FieldsModel): FieldsModel {
2200
+ return (typeof mapper.child === 'string' || isNOU(mapper.child)) ? mapper : mapper.child;
2201
+ }
2202
+
2203
+ /* To render the treeview */
2204
+ private renderTree(): void {
2205
+ this.treeObj = new TreeView({
2206
+ fields: this.getTreeFields(this.fields),
2207
+ enableRtl: this.enableRtl,
2208
+ nodeSelected: this.onNodeSelected.bind(this),
2209
+ nodeChecked: this.onNodeChecked.bind(this),
2210
+ nodeChecking: this.beforeCheck.bind(this),
2211
+ nodeExpanded: this.onNodeExpanded.bind(this),
2212
+ actionFailure: this.onActionFailure.bind(this),
2213
+ nodeClicked: this.onNodeClicked.bind(this),
2214
+ dataBound: this.OnDataBound.bind(this),
2215
+ allowMultiSelection: this.allowMultiSelection,
2216
+ enableHtmlSanitizer: this.enableHtmlSanitizer,
2217
+ showCheckBox: this.showCheckBox,
2218
+ autoCheck: this.treeSettings.autoCheck,
2219
+ sortOrder: this.sortOrder,
2220
+ expandOn: this.treeSettings.expandOn,
2221
+ loadOnDemand: this.treeSettings.loadOnDemand,
2222
+ nodeSelecting: this.onBeforeSelect.bind(this),
2223
+ nodeTemplate: this.itemTemplate
2224
+ });
2225
+ this.treeObj.root = this.root ? this.root : this;
2226
+ this.treeObj.appendTo('#' + this.tree.id);
2227
+ }
2228
+
2229
+ /* To render the popup element */
2230
+ private renderPopup(): void {
2231
+ if (this.isFilteredData) {
2232
+ this.filterObj.value = '';
2233
+ this.treeObj.fields = this.getTreeFields(this.fields);
2234
+ this.isFilterRestore = true;
2235
+ this.isFilteredData = false;
2236
+ this.hideCheckAll(false);
2237
+ }
2238
+ let isCancelled: boolean = false;
2239
+ const args: DdtBeforeOpenEventArgs = { cancel: false };
2240
+ this.trigger('beforeOpen', args, (args: DdtBeforeOpenEventArgs) => {
2241
+ if (!args.cancel) {
2242
+ addClass([this.inputWrapper], [ICONANIMATION]);
2243
+ if (this.isFirstRender) {
2244
+ this.popupEle = this.createElement('div', {
2245
+ id: this.element.id + '_popup', className: POPUP_CLASS + ' ' + (this.cssClass != null ? this.cssClass : '')
2246
+ });
2247
+ document.body.appendChild(this.popupEle);
2248
+ this.createPopup(this.popupEle);
2249
+ } else {
2250
+ this.popupEle = this.popupObj.element;
2251
+ }
2252
+ } else {
2253
+ isCancelled = true;
2254
+ }
2255
+ if (this.isFirstRender && !isCancelled) {
2256
+ prepend([this.popupDiv], this.popupEle);
2257
+ removeClass([this.popupDiv], DDTHIDEICON);
2258
+ if (this.allowFiltering) { this.renderFilter(); }
2259
+ if (this.showCheckBox && this.showSelectAll && (!this.popupDiv.classList.contains(NODATA))) {
2260
+ this.createSelectAllWrapper();
2261
+ this.popupEle.insertBefore(this.checkAllParent, this.popupDiv);
2262
+ }
2263
+ if (this.headerTemplate) { this.setHeaderTemplate(); }
2264
+ if (this.footerTemplate) { this.setFooterTemplate(); }
2265
+ this.isFirstRender = false;
2266
+ /* eslint-disable */
2267
+ if (this.hasTemplate && (this as any).portals) {
2268
+ (this as any).portals = (this as any).portals.concat((this.treeObj as any).portals);
2269
+ /* eslint-enable */
2270
+ this.renderReactTemplates();
2271
+ }
2272
+ }
2273
+ if (!isCancelled) {
2274
+ attributes(this.inputWrapper, { 'aria-expanded': 'true' });
2275
+ this.popupObj.show(null, (this.zIndex === 1000) ? this.inputEle : null);
2276
+ removeClass([this.popupEle], DDTHIDEICON);
2277
+ this.updatePopupHeight();
2278
+ this.popupObj.refreshPosition();
2279
+ if (!(this.showCheckBox && this.showSelectAll) && (!this.popupDiv.classList.contains(NODATA)
2280
+ && this.treeItems.length > 0)) {
2281
+ let focusedElement: HTMLElement= this.treeObj.element.querySelector('li');
2282
+ focusedElement.focus();
2283
+ addClass([focusedElement], ['e-node-focus']);
2284
+ }
2285
+ if (this.checkSelectAll && this.checkBoxElement) {
2286
+ const wrap: HTMLElement = closest((this.checkBoxElement as HTMLElement), '.' + CHECKBOXWRAP) as HTMLElement;
2287
+ this.changeState(wrap, 'check');
2288
+ this.checkSelectAll = false;
2289
+ }
2290
+ if (this.allowFiltering) {
2291
+ removeClass([this.inputWrapper], [INPUTFOCUS]);
2292
+ this.filterObj.element.focus();
2293
+ }
2294
+ const eventArgs: DdtPopupEventArgs = { popup: this.popupObj };
2295
+ this.trigger('open', eventArgs);
2296
+ }
2297
+ });
2298
+ }
2299
+
2300
+ private updatePopupHeight(): void {
2301
+ if (this.isFirstRender) {return; }
2302
+ let popupHeight: string = this.getHeight();
2303
+ this.popupEle.style.maxHeight = popupHeight;
2304
+ if (this.allowFiltering) {
2305
+ const height: number = Math.round(this.filterContainer.getBoundingClientRect().height);
2306
+ popupHeight = formatUnit(parseInt(popupHeight, 10) - height + 'px');
2307
+ }
2308
+ if (this.headerTemplate) {
2309
+ const height: number = Math.round(this.header.getBoundingClientRect().height);
2310
+ popupHeight = formatUnit(parseInt(popupHeight, 10) - height + 'px');
2311
+ }
2312
+ if (this.showCheckBox && this.showSelectAll && (!this.popupDiv.classList.contains(NODATA))) {
2313
+ const height: number = Math.round(this.checkAllParent.getBoundingClientRect().height);
2314
+ popupHeight = formatUnit(parseInt(popupHeight, 10) - height + 'px');
2315
+ }
2316
+ if (this.footerTemplate) {
2317
+ const height: number = Math.round(this.footer.getBoundingClientRect().height);
2318
+ popupHeight = formatUnit(parseInt(popupHeight, 10) - height + 'px');
2319
+ }
2320
+ let border: number = parseInt(window.getComputedStyle(this.popupEle).borderTopWidth, 10);
2321
+ border = border + parseInt(window.getComputedStyle(this.popupEle).borderBottomWidth, 10);
2322
+ popupHeight = formatUnit(parseInt(popupHeight, 10) - border + 'px');
2323
+ this.popupDiv.style.maxHeight = popupHeight;
2324
+ }
2325
+
2326
+ private createPopup(element: HTMLElement): void {
2327
+ if (this.isFirstRender) {
2328
+ this.popupObj = new Popup(element, {
2329
+ width: this.setWidth(),
2330
+ targetType: 'relative',
2331
+ collision: { X: 'flip', Y: 'flip' },
2332
+ relateTo: this.inputWrapper,
2333
+ zIndex: this.zIndex,
2334
+ enableRtl: this.enableRtl,
2335
+ position: { X: 'left', Y: 'bottom' },
2336
+ close: () => {
2337
+ this.isPopupOpen = false;
2338
+ },
2339
+ open: () => {
2340
+ EventHandler.add(document, 'mousedown', this.onDocumentClick, this);
2341
+ this.isPopupOpen = true;
2342
+ },
2343
+ targetExitViewport: () => {
2344
+ if (!Browser.isDevice) { this.hidePopup(); }
2345
+ }
2346
+ });
2347
+ }
2348
+ }
2349
+
2350
+ /* To calculate the width when change via set model */
2351
+ private setElementWidth(inputWidth: string | number): void {
2352
+ const ddElement: HTMLElement = this.inputWrapper;
2353
+ if (!isNOU(inputWidth)) {
2354
+ if (typeof inputWidth === 'number') {
2355
+ ddElement.style.width = formatUnit(inputWidth);
2356
+ } else if (typeof inputWidth === 'string') {
2357
+ ddElement.style.width = (inputWidth.match(/px|%|em/)) ? (inputWidth) :
2358
+ (formatUnit(inputWidth));
2359
+ }
2360
+ }
2361
+ }
2362
+
2363
+ /* To calculate the width of the popup */
2364
+ private setWidth(): string {
2365
+ let width: string = formatUnit(this.popupWidth);
2366
+ if (width.indexOf('%') > -1) {
2367
+ width = (this.inputWrapper.offsetWidth * parseFloat(width) / 100).toString() + 'px';
2368
+ } else if (typeof this.popupWidth === 'string') {
2369
+ width = (this.popupWidth.match(/px|em/)) ? (this.popupWidth) : width;
2370
+ }
2371
+ return width;
2372
+ }
2373
+
2374
+ /* To calculate the height of the popup */
2375
+ private getHeight(): string {
2376
+ let height: string = formatUnit(this.popupHeight);
2377
+ if (height.indexOf('%') > -1) {
2378
+ // Will set the height of the popup according to the view port height
2379
+ height = (document.documentElement.clientHeight * parseFloat(height) / 100).toString() + 'px';
2380
+ } else if (typeof this.popupHeight === 'string') {
2381
+ height = (this.popupHeight.match(/px|em/)) ? (this.popupHeight) : height;
2382
+ }
2383
+ return height;
2384
+ }
2385
+
2386
+ private onDocumentClick(e: MouseEvent): void {
2387
+ const target: HTMLElement = <HTMLElement>e.target;
2388
+ const isTree: Element = closest(target, '.' + PARENTITEM);
2389
+ const isFilter: Element = closest(target, '.' + FILTERWRAP);
2390
+ const isHeader: Element = closest(target, '.' + HEADER);
2391
+ const isFooter: Element = closest(target, '.' + FOOTER);
2392
+ const isScroller: boolean = target.classList.contains(DROPDOWN) ? true :
2393
+ (matches(target, '.e-ddt .e-popup') || matches(target, '.e-ddt .e-treeview'));
2394
+ if ((this.isPopupOpen && ((!isNOU(this.inputWrapper) && this.inputWrapper.contains(target)) || isTree || isScroller || isHeader || isFooter)) ||
2395
+ ((this.allowMultiSelection || this.showCheckBox) && (this.isPopupOpen && target.classList.contains(CHIP_CLOSE) ||
2396
+ (this.isPopupOpen && (target.classList.contains(CHECKALLPARENT) || target.classList.contains(ALLTEXT)
2397
+ || target.classList.contains(CHECKBOXFRAME)))))) {
2398
+ this.isDocumentClick = false;
2399
+ e.preventDefault();
2400
+ } else if (!isNOU(this.inputWrapper) && !this.inputWrapper.contains(target) && this.inputFocus && !isFilter) {
2401
+ this.focusOut(e);
2402
+ }
2403
+ }
2404
+
2405
+ private onActionFailure(e: FailureEventArgs): void {
2406
+ this.trigger('actionFailure', e);
2407
+ this.l10nUpdate(true);
2408
+ addClass([this.popupDiv], NODATA);
2409
+ }
2410
+
2411
+ private OnDataBound(args: DataBoundEventArgs): void {
2412
+ this.treeItems = args.data;
2413
+ if (this.treeItems.length <= 0) {
2414
+ this.l10nUpdate();
2415
+ addClass([this.popupDiv], NODATA);
2416
+ this.hideCheckAll(true);
2417
+ } else if (this.popupDiv.classList.contains(NODATA) && this.treeItems.length >= 1) {
2418
+ removeClass([this.popupDiv], NODATA);
2419
+ this.hideCheckAll(false);
2420
+ }
2421
+ this.treeDataType = this.getTreeDataType(this.treeItems, this.fields);
2422
+ if (this.isFirstRender && this.isRemoteData) {
2423
+ this.setTreeValue();
2424
+ this.setTreeText();
2425
+ this.updateHiddenValue();
2426
+ this.setSelectedValue();
2427
+ if (!this.wrapText ) {
2428
+ this.updateView();
2429
+ }
2430
+ this.treeObj.element.focus();
2431
+ }
2432
+ const eventArgs: DdtDataBoundEventArgs = { data: args.data };
2433
+ this.trigger('dataBound', eventArgs);
2434
+ if (this.filterObj === null) { this.isFilteredData = false; }
2435
+ if (this.isFilteredData) { this.treeObj.expandAll(); }
2436
+ if (this.isFilterRestore) {
2437
+ this.restoreFilterSelection();
2438
+ this.isFilterRestore = false;
2439
+ }
2440
+ }
2441
+
2442
+ private restoreFilterSelection(): void {
2443
+ if (this.showCheckBox) {
2444
+ this.treeObj.checkedNodes = this.value ? this.value : [];
2445
+ } else {
2446
+ this.treeObj.selectedNodes = this.value ? this.value : [];
2447
+ }
2448
+ }
2449
+
2450
+ /* To set cssclass for the dropdowntree */
2451
+ private setCssClass(newClass: string, oldClass: string): void {
2452
+ const elements: HTMLElement[] = this.popupObj ? [this.inputWrapper, this.popupObj.element] : [this.inputWrapper];
2453
+ if (!isNOU(oldClass) && oldClass !== '') {
2454
+ removeClass(elements, oldClass.split(' '));
2455
+ }
2456
+ if (!isNOU(newClass) && newClass !== '') {
2457
+ addClass(elements, newClass.split(' '));
2458
+ }
2459
+ }
2460
+
2461
+ private setEnableRTL(state: boolean): void {
2462
+ if (state) {
2463
+ this.inputWrapper.classList.add(RTL);
2464
+ } else {
2465
+ this.inputWrapper.classList.remove(RTL);
2466
+ }
2467
+ if (this.popupObj) {
2468
+ this.popupObj.enableRtl = state;
2469
+ this.popupObj.dataBind();
2470
+ }
2471
+ if (this.treeObj) {
2472
+ this.treeObj.enableRtl = state;
2473
+ this.treeObj.dataBind();
2474
+ }
2475
+ }
2476
+
2477
+ /* To set enable property */
2478
+ private setEnable(): void {
2479
+ Input.setEnabled(this.enabled, this.inputEle);
2480
+ if (this.enabled) {
2481
+ removeClass([this.inputWrapper], DISABLED);
2482
+ this.inputEle.setAttribute('aria-disabled', 'false');
2483
+ this.inputWrapper.setAttribute('aria-disabled', 'false');
2484
+ } else {
2485
+ if (this.isPopupOpen) {
2486
+ this.hidePopup();
2487
+ }
2488
+ addClass([this.inputWrapper], DISABLED);
2489
+ if (this.inputWrapper && this.inputWrapper.classList.contains(INPUTFOCUS)) {
2490
+ removeClass([this.inputWrapper], [INPUTFOCUS]);
2491
+ }
2492
+ this.inputEle.setAttribute('aria-disabled', 'true');
2493
+ this.inputWrapper.setAttribute('aria-disabled', 'true');
2494
+ }
2495
+ }
2496
+ private cloneFields(fields: FieldsModel): FieldsModel {
2497
+ const clonedField: FieldsModel = {
2498
+ dataSource: fields.dataSource, value: fields.value, text: fields.text, parentValue: fields.parentValue,
2499
+ child: this.cloneChildField(fields.child), hasChildren: fields.hasChildren, expanded: fields.expanded,
2500
+ iconCss: fields.iconCss, imageUrl: fields.imageUrl, htmlAttributes: fields.htmlAttributes, query: fields.query,
2501
+ selected: fields.selected, selectable: fields.selectable, tableName: fields.tableName, tooltip: fields.tooltip
2502
+ };
2503
+ return clonedField;
2504
+ }
2505
+ private cloneChildField(fields: FieldsModel | string): string | FieldsModel {
2506
+ if (typeof fields === 'string') {
2507
+ return fields;
2508
+ } else {
2509
+ const clonedField: FieldsModel = {
2510
+ dataSource: fields.dataSource, value: fields.value, text: fields.text, parentValue: fields.parentValue,
2511
+ child: (fields.child ? this.cloneChildField(fields.child) : null), hasChildren: fields.hasChildren,
2512
+ expanded: fields.expanded, iconCss: fields.iconCss, imageUrl: fields.imageUrl, htmlAttributes: fields.htmlAttributes,
2513
+ query: fields.query, selected: fields.selected, selectable: fields.selectable, tableName: fields.tableName, tooltip: fields.tooltip
2514
+ };
2515
+ return clonedField;
2516
+ }
2517
+ }
2518
+
2519
+ private getTreeFields(fields: FieldsModel): FieldsSettingsModel {
2520
+ const treeFields: FieldsSettingsModel = {
2521
+ dataSource: fields.dataSource, id: fields.value, text: fields.text, parentID: fields.parentValue,
2522
+ child: this.getTreeChildren(fields.child), hasChildren: fields.hasChildren, expanded: fields.expanded,
2523
+ iconCss: fields.iconCss, imageUrl: fields.imageUrl, isChecked: fields.selected,
2524
+ htmlAttributes: fields.htmlAttributes, query: fields.query, selectable: fields.selectable, selected: fields.selected,
2525
+ tableName: fields.tableName, tooltip: fields.tooltip
2526
+ };
2527
+ return treeFields;
2528
+ }
2529
+
2530
+ private getTreeChildren(mapper: FieldsModel | string): FieldsSettingsModel | string {
2531
+ if (typeof mapper === 'string') {
2532
+ return mapper;
2533
+ } else if (!isNOU(mapper)) {
2534
+ mapper = this.getActualProperties(mapper) as FieldsModel;
2535
+ const childFields: FieldsSettingsModel | string = mapper;
2536
+ if (mapper.value) {
2537
+ childFields.id = mapper.value;
2538
+ }
2539
+ if (mapper.parentValue) {
2540
+ childFields.parentID = mapper.parentValue;
2541
+ }
2542
+ if (mapper.child) {
2543
+ childFields.child = this.getTreeChildren(mapper.child);
2544
+ }
2545
+ if (mapper.selected && this.showCheckBox) {
2546
+ childFields.isChecked = mapper.selected;
2547
+ }
2548
+ return childFields;
2549
+ }
2550
+ return null;
2551
+ }
2552
+
2553
+ // eslint-disable-next-line
2554
+ private getTreeDataType(ds: { [key: string]: Object }[], field: FieldsModel): number {
2555
+ if (this.fields.dataSource instanceof DataManager) {
2556
+ for (let i: number = 0; i < ds.length; i++) {
2557
+ if ((typeof field.child === 'string') && isNOU(getValue(field.child, ds[i as number]))) {
2558
+ return 1;
2559
+ }
2560
+ }
2561
+ return 2;
2562
+ }
2563
+ if(isNOU(this.fields.dataSource)) this.fields.dataSource = [];
2564
+ for (let i: number = 0, len: number = this.fields.dataSource.length; i < len; i++) {
2565
+ if ((typeof field.child === 'string') && !isNOU(getValue(field.child, this.fields.dataSource[i as number]))) {
2566
+ return 2;
2567
+ }
2568
+ if (!isNOU(getValue(field.parentValue, this.fields.dataSource[i as number])) || !isNOU(getValue(field.hasChildren, this.fields.dataSource[i as number]))) {
2569
+ return 1;
2570
+ }
2571
+ }
2572
+ return 1;
2573
+ }
2574
+
2575
+ /* Triggers when the tree fields is changed dynamically */
2576
+ private setFields(): void {
2577
+ this.resetValue();
2578
+ if (this.hasTemplate) {
2579
+ this.updateTemplate();
2580
+ }
2581
+ this.treeObj.fields = this.getTreeFields(this.fields);
2582
+ this.treeObj.dataBind();
2583
+ }
2584
+ private getEventArgs(args: NodeCheckEventArgs | NodeSelectEventArgs): DdtSelectEventArgs {
2585
+ // eslint-disable-next-line
2586
+ const checkData: { [key: string]: Object }[] = (args as NodeCheckEventArgs).data;
2587
+ // eslint-disable-next-line
2588
+ const selectData: { [key: string]: Object } = (args as NodeSelectEventArgs).nodeData;
2589
+ let state: string;
2590
+ if (this.showCheckBox) {
2591
+ if (args.action === 'check') {
2592
+ state = 'select';
2593
+ } else if (args.action === 'uncheck') {
2594
+ state = 'un-select';
2595
+ }
2596
+ }
2597
+ const eventArgs: DdtSelectEventArgs = {
2598
+ action: this.showCheckBox ? state : args.action,
2599
+ isInteracted: this.isClicked ? true : args.isInteracted,
2600
+ item: args.node,
2601
+ itemData: this.showCheckBox ? checkData[0] : selectData
2602
+ };
2603
+ return eventArgs;
2604
+ }
2605
+
2606
+ private onBeforeSelect(args: NodeSelectEventArgs): void {
2607
+ if (args.isInteracted) {
2608
+ this.oldValue = this.value ? this.value.slice() : this.value;
2609
+ if (this.value === null) {
2610
+ this.setProperties({ value: [] }, true);
2611
+ }
2612
+ }
2613
+ }
2614
+
2615
+ private updateHiddenValue(): void {
2616
+ if (this.allowMultiSelection || this.showCheckBox) {
2617
+ return;
2618
+ }
2619
+ if (this.value && this.value.length) {
2620
+ this.hiddenElement.innerHTML = '<option selected value ="' + this.value[0] + '">' + this.text + '</option>';
2621
+ } else {
2622
+ this.hiddenElement.innerHTML = '';
2623
+ }
2624
+ }
2625
+
2626
+ /* Triggers when the tree node is selected */
2627
+ private onNodeSelected(args: NodeSelectEventArgs): void {
2628
+ if (this.showCheckBox) {
2629
+ return;
2630
+ }
2631
+ let selectedText: string;
2632
+ if (args.isInteracted) {
2633
+ const id: string = getValue('id', args.nodeData).toString();
2634
+ if (!this.allowMultiSelection) {
2635
+ this.hiddenElement.innerHTML = '';
2636
+ this.setProperties({ value: [id] }, true);
2637
+ if (this.itemTemplate) {
2638
+ selectedText = getValue('text', this.treeObj.getNode(id));
2639
+ } else {
2640
+ selectedText = getValue('text', args.nodeData).toString();
2641
+ }
2642
+ Input.setValue(selectedText, this.inputEle, this.floatLabelType);
2643
+ this.setProperties({ text: selectedText }, true);
2644
+ this.currentText = this.text;
2645
+ this.currentValue = this.value;
2646
+ attributes(this.inputWrapper, { 'aria-describedby': this.element.id });
2647
+ attributes(this.inputWrapper, { 'aria-activedescendant': id.toString() });
2648
+ this.updateHiddenValue();
2649
+ this.showOverAllClear();
2650
+ this.hidePopup();
2651
+ this.isNodeSelected = true;
2652
+ } else if (this.allowMultiSelection) {
2653
+ this.setMultiSelect();
2654
+ }
2655
+ }
2656
+ const eventArgs: DdtSelectEventArgs = this.getEventArgs(args);
2657
+ this.trigger('select', eventArgs);
2658
+ if (this.isValueChange && !this.changeOnBlur) {
2659
+ this.triggerChangeEvent(this.keyEventArgs);
2660
+ this.isValueChange = false;
2661
+ }
2662
+ }
2663
+
2664
+ private onNodeClicked(args: NodeClickEventArgs): void {
2665
+ if (!this.changeOnBlur && this.isNodeSelected) {
2666
+ this.triggerChangeEvent(args.event);
2667
+ this.isNodeSelected = false;
2668
+ }
2669
+ const target: Element = <Element>args.event.target;
2670
+ if ((target.classList.contains('e-fullrow') || target.classList.contains('e-list-text')) && this.showCheckBox) {
2671
+ this.isClicked = true;
2672
+ // eslint-disable-next-line
2673
+ const getNodeDetails: { [key: string]: Object } = this.treeObj.getNode(args.node);
2674
+ if (getNodeDetails.isChecked === 'true') {
2675
+ this.treeObj.uncheckAll([args.node]);
2676
+ } else {
2677
+ this.treeObj.checkAll([args.node]);
2678
+ }
2679
+ this.isClicked = false;
2680
+ this.setMultiSelect();
2681
+ this.ensurePlaceHolder();
2682
+ }
2683
+ if (!this.changeOnBlur && (this.allowMultiSelection || this.showCheckBox)) {
2684
+ this.triggerChangeEvent(args.event);
2685
+ }
2686
+ }
2687
+
2688
+ private onNodeChecked(args: NodeCheckEventArgs): void {
2689
+ const eventArgs: DdtSelectEventArgs = this.getEventArgs(args);
2690
+ this.trigger('select', eventArgs);
2691
+ if (this.isFilteredData && args.action === 'uncheck') {
2692
+ const id: string = getValue('id', args.data[0]).toString();
2693
+ this.removeSelectedData(id , true);
2694
+ }
2695
+ if (!this.isChipDelete && args.isInteracted) {
2696
+ this.setMultiSelect();
2697
+ this.ensurePlaceHolder();
2698
+ }
2699
+ if (this.showSelectAll && this.checkBoxElement) {
2700
+ const nodes: NodeList = this.treeObj.element.querySelectorAll('li');
2701
+ const checkedNodes: NodeList = this.treeObj.element.querySelectorAll('li .e-checkbox-wrapper[aria-checked=true]');
2702
+ const wrap: HTMLElement = closest((this.checkBoxElement as HTMLElement), '.' + CHECKBOXWRAP) as HTMLElement;
2703
+ if (wrap && args.action === 'uncheck' && (args.isInteracted || checkedNodes.length === 0 || (!isNOU(args.data[0]) && args.data[0].isChecked === 'false'))) {
2704
+ this.isReverseUpdate = true;
2705
+ this.changeState(wrap, 'uncheck');
2706
+ this.isReverseUpdate = false;
2707
+ } else if (wrap && args.action === 'check' && checkedNodes.length === nodes.length && (args.isInteracted || this.isCheckAllCalled || (!isNOU(args.data[0]) && args.data[0].isChecked === 'true'))) {
2708
+ this.isReverseUpdate = true;
2709
+ this.isCheckAllCalled = false;
2710
+ this.changeState(wrap, 'check');
2711
+ this.isReverseUpdate = false;
2712
+ }
2713
+ }
2714
+ }
2715
+
2716
+ private beforeCheck(args: NodeCheckEventArgs): void {
2717
+ if (args.isInteracted) {
2718
+ this.oldValue = this.value ? this.value.slice() : this.value;
2719
+ }
2720
+ }
2721
+
2722
+ private onNodeExpanded(args: NodeExpandEventArgs): void {
2723
+ if (this.hasTemplate && (this as any).portals) {
2724
+ (this as any).portals = [].concat((this.treeObj as any).portals);
2725
+ /* eslint-enable */
2726
+ this.renderReactTemplates();
2727
+ }
2728
+ }
2729
+
2730
+ private updateClearButton(state: boolean): void {
2731
+ if (state) {
2732
+ if (!this.inputWrapper.contains(this.overAllClear)) {
2733
+ this.inputEle.parentElement.insertBefore(this.overAllClear, this.inputEle.nextSibling);
2734
+ } else {
2735
+ removeClass([this.overAllClear], HIDEICON);
2736
+ addClass([this.inputWrapper], SHOW_CLEAR);
2737
+ }
2738
+ } else {
2739
+ addClass([this.overAllClear], HIDEICON);
2740
+ removeClass([this.inputWrapper], SHOW_CLEAR);
2741
+ }
2742
+ if ((this.allowMultiSelection || this.showCheckBox) && this.chipWrapper) {
2743
+ const chipClose: Element[] = selectAll('.' + CHIP_CLOSE, this.chipWrapper);
2744
+ for (let i: number = 0; i < chipClose.length; i++) {
2745
+ if (!state) {
2746
+ addClass([chipClose[i as number]], HIDEICON);
2747
+ } else {
2748
+ removeClass([chipClose[i as number]], HIDEICON);
2749
+ }
2750
+ }
2751
+ }
2752
+ }
2753
+
2754
+ private updateDropDownIconState(state: boolean): void {
2755
+ const spinIcon: Element = select('.' + DDTICON, this.inputWrapper);
2756
+ if (state) {
2757
+ if (!spinIcon) {
2758
+ Input.appendSpan(DROPDOWNICON, this.inputWrapper, this.createElement);
2759
+ } else {
2760
+ removeClass([spinIcon], HIDEICON);
2761
+ }
2762
+ addClass([this.inputWrapper], SHOW_DD_ICON);
2763
+ } else {
2764
+ addClass([spinIcon], HIDEICON);
2765
+ removeClass([this.inputWrapper], SHOW_DD_ICON);
2766
+ }
2767
+ }
2768
+
2769
+ private updateMode(): void {
2770
+ if (this.mode === 'Custom') { return; }
2771
+ if (this.mode !== 'Delimiter') {
2772
+ if (!this.inputWrapper.contains(this.chipWrapper)) {
2773
+ this.createChip();
2774
+ }
2775
+ const isValid: boolean = this.getValidMode();
2776
+ if (this.chipWrapper.classList.contains(HIDEICON) && isValid) {
2777
+ removeClass([this.chipWrapper], HIDEICON);
2778
+ addClass([this.inputWrapper], SHOW_CHIP);
2779
+ } else if (!isValid) {
2780
+ addClass([this.chipWrapper], HIDEICON);
2781
+ removeClass([this.inputWrapper], SHOW_CHIP);
2782
+ }
2783
+ const isValue: boolean = this.value !== null ? (this.value.length !== 0 ? true : false) : false;
2784
+ if (isValid && isValue) {
2785
+ addClass([this.inputEle], CHIP_INPUT);
2786
+ } else {
2787
+ removeClass([this.inputEle], CHIP_INPUT);
2788
+ }
2789
+ } else if (this.inputEle.classList.contains(CHIP_INPUT)) {
2790
+ removeClass([this.inputEle], CHIP_INPUT);
2791
+ if (this.chipWrapper) {
2792
+ addClass([this.chipWrapper], HIDEICON);
2793
+ removeClass([this.inputWrapper], SHOW_CHIP);
2794
+ }
2795
+ }
2796
+ }
2797
+
2798
+ private ensurePlaceHolder(): void {
2799
+ if (isNOU(this.value) || (this.value && this.value.length === 0)) {
2800
+ removeClass([this.inputEle], CHIP_INPUT);
2801
+ if (this.chipWrapper) {
2802
+ addClass([this.chipWrapper], HIDEICON);
2803
+ }
2804
+ }
2805
+ }
2806
+ private ensureClearIconPosition(floatLabelType: FloatLabelType): void {
2807
+ if (floatLabelType !== 'Never') {
2808
+ this.inputWrapper.insertBefore(this.overAllClear, this.inputObj.buttons[0]);
2809
+ }
2810
+ }
2811
+
2812
+ private setMultiSelectValue(newValues: string[]): void {
2813
+ if (!this.isFilteredData) {
2814
+ this.setProperties({ value: this.isFromFilterChange && newValues && newValues.length == 0 ? this.value : newValues }, true);
2815
+ this.isFromFilterChange = false;
2816
+ if (newValues && newValues.length !== 0 && !this.showCheckBox) {
2817
+ this.treeObj.selectedNodes = this.value.slice();
2818
+ this.treeObj.dataBind();
2819
+ }
2820
+ } else {
2821
+ const selectedValues: string[] = isNOU(this.value) ? [] : this.value;
2822
+ for (let i: number = 0; i < newValues.length; i++) {
2823
+ if (isNOU(this.value) || this.value.indexOf(newValues[i as number]) === -1) {
2824
+ selectedValues.push(newValues[i as number]);
2825
+ }
2826
+ }
2827
+ this.setProperties({ value: selectedValues }, true);
2828
+ }
2829
+ }
2830
+
2831
+ private setMultiSelect(): void {
2832
+ if (this.showCheckBox && !this.isDynamicChange) {
2833
+ this.setMultiSelectValue(this.treeObj.checkedNodes.slice());
2834
+ } else {
2835
+ const ddtValue: string[] = this.allowMultiSelection ? (this.showCheckBox ? this.treeObj.checkedNodes
2836
+ : this.treeObj.selectedNodes) : (this.value ? (this.showCheckBox ? this.value : [this.value[0]]) : null);
2837
+ this.setMultiSelectValue(ddtValue);
2838
+ if (this.showCheckBox && this.value !== null) {
2839
+ this.treeObj.checkedNodes = this.value;
2840
+ this.treeObj.dataBind();
2841
+ }
2842
+ }
2843
+ this.selectedText = [];
2844
+ const checkSelection: boolean = this.allowMultiSelection ? true : (this.showCheckBox ? true : false);
2845
+ if (this.inputWrapper.contains(this.chipWrapper) && !checkSelection) {
2846
+ removeClass([this.inputEle], CHIP_INPUT);
2847
+ detach(this.chipWrapper);
2848
+ }
2849
+ const isValid: boolean = this.getValidMode();
2850
+ if (isValid && this.value !== null) {
2851
+ addClass([this.inputEle], CHIP_INPUT);
2852
+ if (this.chipWrapper) {
2853
+ removeClass([this.chipWrapper], HIDEICON);
2854
+ }
2855
+ }
2856
+ const isValue: boolean = this.value ? (this.value.length ? true : false) : false;
2857
+ if (this.chipWrapper && (this.mode === 'Box' && !isValue)) {
2858
+ addClass([this.chipWrapper], HIDEICON);
2859
+ removeClass([this.inputEle], CHIP_INPUT);
2860
+ }
2861
+ this.updateSelectedValues();
2862
+ }
2863
+
2864
+ // eslint-disable-next-line
2865
+ private getSelectedData(value: string): { [key: string]: Object } {
2866
+ // eslint-disable-next-line
2867
+ let data: { [key: string]: Object } = null;
2868
+ if (this.isFilteredData) {
2869
+ for (let i: number = 0; i < this.selectedData.length; i++) {
2870
+ if (getValue(this.treeSettings.loadOnDemand ? this.fields.value : 'id', this.selectedData[i as number]).toString() === value) {
2871
+ data = this.selectedData[i as number];
2872
+ break;
2873
+ }
2874
+ }
2875
+ }
2876
+ if (isNOU(data)) {
2877
+ if (this.treeSettings.loadOnDemand) {
2878
+ data = this.getNodeData(value);
2879
+ } else {
2880
+ data = this.treeObj.getNode(value);
2881
+ }
2882
+ if (!isNOU(data)) { this.selectedData.push(data); }
2883
+ }
2884
+ return data;
2885
+ }
2886
+
2887
+ private getNodeData(id: string): { [key: string]: Object } {
2888
+ let childItems: { [key: string]: Object };
2889
+ if (isNOU(id)) {
2890
+ return childItems;
2891
+ } else if (this.treeDataType === 1) {
2892
+ for (let i: number = 0, objlen: number = this.treeItems.length; i < objlen; i++) {
2893
+ let dataId: Object = getValue(this.fields.value, this.treeItems[i as number]);
2894
+ if (!isNOU(this.treeItems[i as number]) && !isNOU(dataId) && dataId.toString() === id) {
2895
+ return this.treeItems[i as number];
2896
+ }
2897
+ }
2898
+ } else {
2899
+ return this.getChildNodeData(this.treeItems, this.fields, id);
2900
+ }
2901
+ return childItems;
2902
+ }
2903
+
2904
+ private getChildNodeData(obj: { [key: string]: Object }[], mapper: FieldsModel, id: string): { [key: string]: Object } {
2905
+ let newChildItems: { [key: string]: Object };
2906
+ if (isNOU(obj)) {
2907
+ return newChildItems;
2908
+ }
2909
+ for (let i: number = 0, objlen: number = obj.length; i < objlen; i++) {
2910
+ let dataValue: Object = getValue(mapper.value, obj[i as number]);
2911
+ if (obj[i as number] && dataValue && dataValue.toString() === id) {
2912
+ return obj[i as number];
2913
+ } else if (typeof mapper.child === 'string' && !isNOU(getValue(mapper.child, obj[i as number]))) {
2914
+ let childNodeData: Object = getValue(mapper.child, obj[i as number]);
2915
+ newChildItems = this.getChildNodeData(<{ [key: string]: Object }[]>childNodeData, this.getChildMapperFields(mapper), id);
2916
+ if (newChildItems !== undefined) {
2917
+ break;
2918
+ }
2919
+ } else if (this.fields.dataSource instanceof DataManager && !isNOU(getValue('child', obj[i as number]))) {
2920
+ let child: string = 'child';
2921
+ newChildItems = this.getChildNodeData(<{ [key: string]: Object }[]>getValue(child, obj[i as number]), this.getChildMapperFields(mapper), id);
2922
+ if (newChildItems !== undefined) {
2923
+ break;
2924
+ }
2925
+ }
2926
+ }
2927
+ return newChildItems;
2928
+ }
2929
+
2930
+ private getChildMapperFields(mapper: FieldsSettingsModel): FieldsSettingsModel {
2931
+ return (typeof mapper.child === 'string' || isNOU(mapper.child)) ? mapper : mapper.child;
2932
+ }
2933
+
2934
+ private removeSelectedData(value: string, muteOnChange: boolean): void {
2935
+ const selectedValues: string[] = isNOU(this.value) ? [] : this.value.slice();
2936
+ selectedValues.splice(selectedValues.indexOf(value), 1);
2937
+ this.setProperties({ value: selectedValues }, muteOnChange);
2938
+ for (let i: number = 0; i < this.selectedData.length; i++) {
2939
+ if (getValue(this.treeSettings.loadOnDemand ? this.fields.value : 'id', this.selectedData[i as number]).toString() === value) {
2940
+ this.selectedData.splice(i, 1);
2941
+ break;
2942
+ }
2943
+ }
2944
+ }
2945
+
2946
+ private updateSelectedValues(): void {
2947
+ this.dataValue = '';
2948
+ let temp: string;
2949
+ let text: string;
2950
+ let textValue: string = '';
2951
+ // eslint-disable-next-line
2952
+ let selectedData: { [key: string]: Object };
2953
+ this.hiddenElement.innerHTML = '';
2954
+ let hiddenInputValue = '';
2955
+ if ((!this.isChipDelete || this.treeSettings.autoCheck) && (this.inputWrapper.contains(this.chipWrapper))) {
2956
+ this.chipCollection.innerHTML = '';
2957
+ }
2958
+ if (!this.isFilteredData) { this.selectedData = []; }
2959
+ if (!isNOU(this.value)) {
2960
+ for (let i: number = 0, len: number = this.value.length; i < len; i++) {
2961
+ selectedData = this.getSelectedData(this.value[i as number]);
2962
+ text = getValue(this.treeSettings.loadOnDemand ? this.fields.text : 'text', selectedData);
2963
+ this.selectedText.push(text);
2964
+ temp = this.selectedText[this.selectedText.length - 1];
2965
+ if (this.selectedText.length > 1) {
2966
+ this.dataValue += (this.delimiterChar + ' ' + temp);
2967
+ textValue += (',' + temp);
2968
+ } else {
2969
+ this.dataValue += temp;
2970
+ textValue += temp;
2971
+ }
2972
+ if (this.mode !== 'Custom' && this.mode !== 'Delimiter' && (!this.isChipDelete || this.treeSettings.autoCheck) &&
2973
+ (this.allowMultiSelection || this.showCheckBox)) {
2974
+ this.setChipValues(temp, this.value[i as number]);
2975
+ }
2976
+ hiddenInputValue += '<option selected value ="' + this.value[i as number] + '">' +
2977
+ this.selectedText[this.selectedText.length - 1] + '</option>';
2978
+ }
2979
+ if (this.selectedText.length >= 1) {
2980
+ this.setProperties({ text: textValue }, true);
2981
+ }
2982
+ this.hiddenElement.innerHTML = hiddenInputValue;
2983
+ if (this.mode === 'Custom' && (this.allowMultiSelection || this.showCheckBox)) {
2984
+ this.setTagValues();
2985
+ }
2986
+ }
2987
+ const isValid: boolean = this.getValidMode();
2988
+ if (this.mode !== 'Custom' && this.mode !== 'Box' && (this.allowMultiSelection || this.showCheckBox) && !isValid) {
2989
+ if (this.chipWrapper) {
2990
+ addClass([this.chipWrapper], HIDEICON);
2991
+ removeClass([this.inputWrapper], SHOW_CHIP);
2992
+ }
2993
+ }
2994
+ Input.setValue(this.dataValue, this.inputEle, this.floatLabelType);
2995
+ if (textValue === '') {
2996
+ this.setProperties({ text: null }, true);
2997
+ } else {
2998
+ this.setProperties({ text: textValue }, true);
2999
+ }
3000
+ if (this.showClearButton && this.inputFocus) {
3001
+ this.showOverAllClear();
3002
+ }
3003
+ if ((this.allowMultiSelection || this.showCheckBox) && this.popupObj) {
3004
+ this.popupObj.refreshPosition();
3005
+ }
3006
+ this.currentText = this.text;
3007
+ this.currentValue = this.value;
3008
+ }
3009
+ private setChipValues(text: string, value: string): void {
3010
+ if (!this.inputWrapper.contains(this.chipWrapper)) {
3011
+ this.createChip();
3012
+ }
3013
+ const chip: HTMLElement = this.createElement('span', {
3014
+ className: CHIP,
3015
+ attrs: { 'data-value': <string>value }
3016
+ });
3017
+ const chipContent: HTMLElement = this.createElement('span', { className: CHIP_CONTENT });
3018
+ const chipClose: HTMLElement = this.createElement('span', { className: CHIP_CLOSE + ' ' + ICONS });
3019
+ if (this.enableHtmlSanitizer){
3020
+ chipContent.innerText = SanitizeHtmlHelper.sanitize(text);
3021
+ }
3022
+ else { chipContent.innerHTML = text; }
3023
+ chip.appendChild(chipContent);
3024
+ this.chipCollection.appendChild(chip);
3025
+ if (this.showClearButton) {
3026
+ chip.appendChild(chipClose);
3027
+ EventHandler.add(chipClose, 'mousedown', this.removeChip, this);
3028
+ }
3029
+ }
3030
+
3031
+ private setTagValues(): void {
3032
+ if (this.value === null || this.text == null) { return; }
3033
+ if (!this.inputWrapper.contains(this.chipWrapper)) {
3034
+ this.createChip();
3035
+ }
3036
+ if (!this.inputWrapper.classList.contains(SHOW_CHIP)) {
3037
+ addClass([this.inputWrapper], SHOW_CHIP);
3038
+ }
3039
+ const chip: HTMLElement = this.createElement('span', {
3040
+ className: CHIP,
3041
+ });
3042
+ if (!this.inputEle.classList.contains(CHIP_INPUT)) {
3043
+ addClass([this.inputEle], CHIP_INPUT);
3044
+ }
3045
+ if (this.chipWrapper.classList.contains(HIDEICON)) {
3046
+ removeClass([this.chipWrapper], HIDEICON);
3047
+ }
3048
+ const chipContent: HTMLElement = this.createElement('span', { className: CHIP_CONTENT });
3049
+ const template: string | Function = this.customTemplate;
3050
+ const templateId: string = this.customTemplateId;
3051
+ const templatestring: string = 'customTemplate';
3052
+ const compiledString: Function = this.templateComplier(template);
3053
+ let tempArr: Element[] = compiledString({'value': this.value, 'text': this.text}, this, templatestring, templateId, this.isStringTemplate, undefined, chipContent);
3054
+ if (tempArr) {
3055
+ tempArr = Array.prototype.slice.call(tempArr);
3056
+ append(tempArr, chipContent);
3057
+ }
3058
+ chip.appendChild(chipContent);
3059
+ this.chipCollection.appendChild(chip);
3060
+ }
3061
+
3062
+ private setSelectAllWrapper(state: boolean): void {
3063
+ if (this.isFirstRender) {return; }
3064
+ if (state && !this.popupEle.contains(this.checkAllParent) && this.showCheckBox) {
3065
+ this.createSelectAllWrapper();
3066
+ this.popupEle.insertBefore(this.checkAllParent, this.popupDiv);
3067
+ } else if (this.popupEle.contains(this.checkAllParent)) {
3068
+ detach(this.checkAllParent);
3069
+ this.checkAllParent = null;
3070
+ }
3071
+ }
3072
+
3073
+ private setHeaderTemplate(): void {
3074
+ if (this.header) {
3075
+ this.header.innerHTML = '';
3076
+ } else {
3077
+ this.header = this.createElement('div');
3078
+ addClass([this.header], HEADER);
3079
+ }
3080
+ // eslint-disable-next-line
3081
+ const compiledString: Function = this.templateComplier(this.headerTemplate);
3082
+ let tempArr: Element[] = compiledString({}, this, 'headerTemplate', this.headerTemplateId, this.isStringTemplate, undefined, this.header);
3083
+ if (tempArr) {
3084
+ tempArr = Array.prototype.slice.call(tempArr);
3085
+ append(tempArr, this.header);
3086
+ }
3087
+ this.popupEle.insertBefore(this.header, this.checkAllParent ? this.checkAllParent : this.popupDiv);
3088
+ }
3089
+
3090
+ // eslint-disable-next-line
3091
+ private templateComplier(template: string | Function): Function {
3092
+ if (template) {
3093
+ // eslint-disable-next-line
3094
+ let e: Object;
3095
+ try {
3096
+ if (typeof template !== 'function' && document.querySelectorAll(template).length) {
3097
+ return compile(document.querySelector(template).innerHTML.trim());
3098
+ } else {
3099
+ return compile(template);
3100
+ }
3101
+ } catch (e) {
3102
+ return compile(template);
3103
+ }
3104
+ }
3105
+ return compile(template);
3106
+ }
3107
+
3108
+
3109
+ private setFooterTemplate(): void {
3110
+ if (this.footer) {
3111
+ this.footer.innerHTML = '';
3112
+ } else {
3113
+ this.footer = this.createElement('div');
3114
+ addClass([this.footer], FOOTER);
3115
+ }
3116
+ // eslint-disable-next-line
3117
+ const compiledString: Function = this.templateComplier(this.footerTemplate);
3118
+ let tempArr: Element[] = compiledString({}, this, 'footerTemplate', this.footerTemplateId, this.isStringTemplate, undefined, this.footer);
3119
+ if (tempArr) {
3120
+ tempArr = Array.prototype.slice.call(tempArr);
3121
+ append(tempArr, this.footer);
3122
+ }
3123
+ append([this.footer], this.popupEle);
3124
+ }
3125
+
3126
+ private clearAll(e?: MouseEvent): void {
3127
+ if (!this.enabled || this.readonly) {
3128
+ return;
3129
+ }
3130
+ this.resetValue();
3131
+ this.showOverAllClear();
3132
+ if ((this.allowMultiSelection || this.showCheckBox)) {
3133
+ if ( this.popupObj) {
3134
+ this.popupObj.refreshPosition();
3135
+ }
3136
+ if (!this.wrapText) {
3137
+ this.updateOverflowWrapper(true);
3138
+ }
3139
+ }
3140
+ if (e) {
3141
+ this.isClearButtonClick = true;
3142
+ }
3143
+ if (!this.changeOnBlur) {
3144
+ this.triggerChangeEvent(e);
3145
+ }
3146
+ }
3147
+
3148
+ private removeChip(e: MouseEvent): void {
3149
+ if (!this.enabled || this.readonly) {
3150
+ return;
3151
+ }
3152
+ const element: HTMLElement = (<HTMLElement>e.target).parentElement;
3153
+ const value: string = element.getAttribute('data-value');
3154
+ if (this.chipCollection) {
3155
+ if (element) {
3156
+ remove(element);
3157
+ }
3158
+ }
3159
+ this.isChipDelete = true;
3160
+ this.isClearButtonClick = true;
3161
+ this.removeSelectedData(value, true);
3162
+ this.selectedText = [];
3163
+ if (this.allowMultiSelection) {
3164
+ this.treeObj.selectedNodes = this.value.slice();
3165
+ this.updateSelectedValues();
3166
+ }
3167
+ if (this.showCheckBox) {
3168
+ this.treeObj.uncheckAll([value]);
3169
+ this.clearCheckAll();
3170
+ this.setMultiSelect();
3171
+ }
3172
+ this.triggerChangeEvent(e);
3173
+ this.isChipDelete = false;
3174
+ this.ensurePlaceHolder();
3175
+ }
3176
+
3177
+ private resetValue(isDynamicChange?: boolean): void {
3178
+ if (this.value == [] && this.text == null) { return; }
3179
+ Input.setValue(null, this.inputEle, this.floatLabelType);
3180
+ if (!isDynamicChange) {
3181
+ this.oldValue = this.value;
3182
+ this.setProperties({ value: [] }, true);
3183
+ }
3184
+ this.dataValue = null;
3185
+ this.setProperties({ text: null }, true);
3186
+ this.selectedData = [];
3187
+ setValue('selectedNodes', [], this.treeObj);
3188
+ this.hiddenElement.innerHTML = '';
3189
+ if (this.showCheckBox) {
3190
+ this.treeObj.uncheckAll();
3191
+ this.setMultiSelect();
3192
+ this.clearCheckAll();
3193
+ }
3194
+ if (this.oldValue === null && !isDynamicChange) {
3195
+ this.removeValue = true;
3196
+ } else if (isDynamicChange) {
3197
+ this.triggerChangeEvent();
3198
+ }
3199
+ if ((this.allowMultiSelection || this.showCheckBox) && this.chipWrapper) {
3200
+ this.chipCollection.innerHTML = '';
3201
+ if (!this.wrapText) {
3202
+ this.updateOverflowWrapper(true);
3203
+ }
3204
+ this.ensurePlaceHolder();
3205
+ }
3206
+ }
3207
+
3208
+ private clearCheckAll(): void {
3209
+ if (this.showSelectAll && this.value && this.value.length === 0) {
3210
+ this.setLocale(false);
3211
+ }
3212
+ }
3213
+
3214
+ private selectAllItems(state: boolean): void {
3215
+ if (this.showCheckBox) {
3216
+ if (state) {
3217
+ this.isCheckAllCalled = true;
3218
+ this.treeObj.checkAll();
3219
+ }
3220
+ else {
3221
+ this.treeObj.uncheckAll();
3222
+ }
3223
+ this.checkSelectAll = true;
3224
+ } else if (this.allowMultiSelection) {
3225
+ if (!state) {
3226
+ this.treeObj.selectedNodes = [];
3227
+ } else {
3228
+ const li: HTMLElement[] = selectAll('li', this.treeObj.element);
3229
+ let id: string;
3230
+ const arr: string[] = [];
3231
+ for (let i: number = 0; i < li.length; i++) {
3232
+ id = li[i as number].getAttribute('data-uid').toString();
3233
+ arr.push(id);
3234
+ }
3235
+ this.treeObj.selectedNodes = arr;
3236
+ }
3237
+ }
3238
+ this.updateMode();
3239
+ this.setMultiSelect();
3240
+ if (!this.wrapText) {
3241
+ if (state) { this.updateView(); } else{ this.updateOverflowWrapper(true); }
3242
+ }
3243
+ }
3244
+
3245
+ private updateTreeSettings(prop: DropDownTreeModel): void {
3246
+ const value: string = Object.keys(prop.treeSettings)[0];
3247
+ if (value === 'autoCheck') {
3248
+ this.treeObj.autoCheck = this.treeSettings.autoCheck;
3249
+ } else if (value === 'loadOnDemand') {
3250
+ this.treeObj.loadOnDemand = this.treeSettings.loadOnDemand;
3251
+ } else if (value === 'expandOn') {
3252
+ this.treeObj.expandOn = this.treeSettings.expandOn;
3253
+ this.treeObj.dataBind();
3254
+ return;
3255
+ }
3256
+ this.treeObj.dataBind();
3257
+ this.setMultiSelect();
3258
+ this.updateValue(this.value);
3259
+ }
3260
+
3261
+ private updateCheckBoxState(checkBox: boolean): void {
3262
+ if (this.hasTemplate) {
3263
+ this.updateTemplate();
3264
+ }
3265
+ if (!this.wrapText) {
3266
+ this.updateOverflowWrapper(false);
3267
+ }
3268
+ this.treeObj.showCheckBox = checkBox;
3269
+ this.treeObj.dataBind();
3270
+ this.isDynamicChange = true;
3271
+ this.setSelectAllWrapper(this.showSelectAll);
3272
+ if (this.showSelectAll) {
3273
+ this.setLocale();
3274
+ }
3275
+ if (this.showCheckBox) {
3276
+ this.updateMode();
3277
+ }
3278
+ this.setMultiSelect();
3279
+ this.isDynamicChange = false;
3280
+ }
3281
+
3282
+
3283
+ private updateTemplate(): void {
3284
+ if (this.popupObj) {
3285
+ this.clearTemplate();
3286
+ /* eslint-disable */
3287
+ (this as any).portals = [];
3288
+ /* eslint-enable */
3289
+ this.popupObj.destroy();
3290
+ if (this.isPopupOpen) {
3291
+ this.hidePopup();
3292
+ this.isFirstRender = true;
3293
+ this.renderPopup();
3294
+ } else {
3295
+ this.isFirstRender = true;
3296
+ }
3297
+ }
3298
+ }
3299
+
3300
+ private l10nUpdate(actionFailure?: boolean): void {
3301
+ if (this.noRecord) {
3302
+ this.noRecord.innerHTML = '';
3303
+ } else {
3304
+ this.noRecord = this.createElement('div');
3305
+ }
3306
+ if (this.noRecordsTemplate !== 'No Records Found' || this.actionFailureTemplate !== 'The Request Failed') {
3307
+ const template: string | Function = actionFailure ? this.actionFailureTemplate : this.noRecordsTemplate;
3308
+ const templateId: string = actionFailure ? this.actionFailureTemplateId : this.noRecordsTemplateId;
3309
+ const templatestring: string = actionFailure ? 'actionFailureTemplate' : 'noRecordsTemplate';
3310
+ // eslint-disable-next-line
3311
+ const compiledString: Function = this.templateComplier(template);
3312
+ let tempArr: Element[] = compiledString({}, this, templatestring, templateId, this.isStringTemplate, undefined, this.noRecord);
3313
+ if (tempArr) {
3314
+ tempArr = Array.prototype.slice.call(tempArr);
3315
+ append(tempArr, this.noRecord);
3316
+ }
3317
+ } else {
3318
+ // eslint-disable-next-line
3319
+ const l10nLocale: Object = { noRecordsTemplate: 'No Records Found', actionFailureTemplate: 'The Request Failed'};
3320
+ this.l10n = new L10n(this.getLocaleName(), l10nLocale, this.locale);
3321
+ this.noRecord.innerHTML = actionFailure ?
3322
+ this.l10n.getConstant('actionFailureTemplate') : this.l10n.getConstant('noRecordsTemplate');
3323
+ }
3324
+ addClass([this.noRecord], NODATACONTAINER);
3325
+ prepend([this.noRecord], this.popupDiv);
3326
+ }
3327
+
3328
+ private updateRecordTemplate(action?: boolean): void {
3329
+ if (this.treeItems && this.treeItems.length <= 0) {
3330
+ this.l10nUpdate(action);
3331
+ if (this.hasTemplate) {
3332
+ this.updateTemplate();
3333
+ }
3334
+ }
3335
+ }
3336
+
3337
+ private updateOverflowWrapper(state: boolean): void {
3338
+ if (!state) {
3339
+ if (!this.inputWrapper.contains(this.overFlowWrapper)) {
3340
+ this.overFlowWrapper = this.createElement('span', { className: OVERFLOW_VIEW + ' ' + HIDEICON });
3341
+ this.inputWrapper.insertBefore(this.overFlowWrapper, this.hiddenElement);
3342
+ }
3343
+ } else if (this.inputWrapper.contains(this.overFlowWrapper) && state) {
3344
+ this.overFlowWrapper.innerHTML = '';
3345
+ }
3346
+ }
3347
+
3348
+
3349
+ private updateMultiSelection(state: boolean): void {
3350
+ if (!this.wrapText) {
3351
+ this.updateOverflowWrapper(false);
3352
+ }
3353
+ this.treeObj.allowMultiSelection = state;
3354
+ this.treeObj.dataBind();
3355
+ this.updateOption();
3356
+ if (this.allowMultiSelection) {
3357
+ this.updateMode();
3358
+ }
3359
+ this.setMultiSelect();
3360
+ }
3361
+
3362
+ private updateAllowFiltering(state: boolean): void {
3363
+ if (!this.isFirstRender) {
3364
+ if (state) {
3365
+ this.renderFilter();
3366
+ } else {
3367
+ this.destroyFilter();
3368
+ }
3369
+ }
3370
+ }
3371
+
3372
+ private updateFilterPlaceHolder(): void {
3373
+ if (this.filterObj) {
3374
+ this.filterObj.placeholder = this.filterBarPlaceholder;
3375
+ this.filterObj.element.setAttribute('aria-label', this.filterBarPlaceholder);
3376
+ }
3377
+ }
3378
+
3379
+ private updateValue(value: string[]): void {
3380
+ this.isDynamicChange = true;
3381
+ if (isNOU(value) || value.length === 0) {
3382
+ this.resetValue(true);
3383
+ } else {
3384
+ this.setTreeValue();
3385
+ if ((this.allowMultiSelection || this.showCheckBox) && !this.wrapText) {
3386
+ this.updateOverflowWrapper(false);
3387
+ this.updateView();
3388
+ }
3389
+ }
3390
+ this.updateHiddenValue();
3391
+ this.isDynamicChange = false;
3392
+ }
3393
+
3394
+ private updateText(text: string): void {
3395
+ if (isNOU(text)) {
3396
+ this.resetValue();
3397
+ } else {
3398
+ this.setTreeText();
3399
+ if ((this.allowMultiSelection || this.showCheckBox) && !this.wrapText) {
3400
+ this.updateOverflowWrapper(false);
3401
+ this.updateView();
3402
+ }
3403
+ }
3404
+ this.updateHiddenValue();
3405
+ }
3406
+
3407
+ private updateModelMode(): void {
3408
+ const validMode: boolean = this.allowMultiSelection ? true : (this.showCheckBox ? true : false);
3409
+ if (!validMode) { return; }
3410
+ if (!this.wrapText) {
3411
+ const overFlow: Element = select('.' + OVERFLOW_VIEW, this.inputWrapper);
3412
+ if (overFlow) {
3413
+ overFlow.innerHTML = '';
3414
+ }
3415
+ }
3416
+ this.updateMode();
3417
+ this.setMultiSelect();
3418
+ if (!this.wrapText && (this.value && this.value.length !== 0)) {
3419
+ this.updateOverFlowView();
3420
+ addClass([this.inputEle], CHIP_INPUT);
3421
+ if (this.mode === 'Box') {
3422
+ removeClass([this.overFlowWrapper, this.inputWrapper], SHOW_TEXT);
3423
+ } else {
3424
+ addClass([this.overFlowWrapper, this.inputWrapper], SHOW_TEXT);
3425
+ }
3426
+ }
3427
+ }
3428
+
3429
+ private updateOption(): void {
3430
+ if (!this.hiddenElement.hasAttribute('multiple') && (this.allowMultiSelection || this.showCheckBox)) {
3431
+ this.hiddenElement.setAttribute('multiple', '');
3432
+ } else if (this.hiddenElement.hasAttribute('multiple') && (!this.allowMultiSelection && !this.showCheckBox)) {
3433
+ this.hiddenElement.removeAttribute('multiple');
3434
+ }
3435
+ }
3436
+
3437
+ /**
3438
+ * Dynamically change the value of properties.
3439
+ *
3440
+ * @param {DropDownTreeModel} newProp - specifies the newProp value.
3441
+ * @param {DropDownTreeModel} oldProp - specifies the newProp value.
3442
+ * @returns {void}
3443
+ * @private
3444
+ */
3445
+ public onPropertyChanged(newProp: DropDownTreeModel, oldProp: DropDownTreeModel): void {
3446
+ for (const prop of Object.keys(newProp)) {
3447
+ switch (prop) {
3448
+ case 'width': this.setElementWidth(newProp.width);
3449
+ if (this.popupObj) {
3450
+ this.popupObj.element.style.width = this.setWidth();
3451
+ }
3452
+ break;
3453
+ case 'placeholder': Input.setPlaceholder(newProp.placeholder, this.inputEle); break;
3454
+ case 'cssClass': this.setCssClass(newProp.cssClass, oldProp.cssClass); break;
3455
+ case 'enableRtl': this.setEnableRTL(this.enableRtl); break;
3456
+ case 'fields': this.setFields(); break;
3457
+ case 'readonly': Input.setReadonly(newProp.readonly, this.inputEle); break;
3458
+ case 'enabled': this.setEnable(); break;
3459
+ case 'floatLabelType':
3460
+ Input.removeFloating(this.inputObj);
3461
+ Input.addFloating(this.inputEle, newProp.floatLabelType, this.placeholder, this.createElement);
3462
+ this.ensureClearIconPosition(newProp.floatLabelType);
3463
+ break;
3464
+ case 'showClearButton': this.updateClearButton(newProp.showClearButton); break;
3465
+ case 'allowFiltering':
3466
+ this.updateAllowFiltering(newProp.allowFiltering);
3467
+ break;
3468
+ case 'filterBarPlaceholder':
3469
+ this.updateFilterPlaceHolder();
3470
+ break;
3471
+ case 'value':
3472
+ this.oldValue = oldProp.value;
3473
+ this.updateValue(newProp.value); break;
3474
+ case 'text': this.updateText(newProp.text); break;
3475
+ case 'allowMultiSelection': this.updateMultiSelection(newProp.allowMultiSelection); break;
3476
+ case 'mode':
3477
+ if (!this.showCheckBox && !this.allowMultiSelection) { return;}
3478
+ if (this.mode === 'Custom') {
3479
+ if (this.overFlowWrapper) {
3480
+ detach(this.overFlowWrapper);
3481
+ }
3482
+ if (this.chipWrapper) {
3483
+ detach(this.chipWrapper);
3484
+ }
3485
+ this.setTagValues();
3486
+ } else {
3487
+ if (oldProp.mode === 'Custom') { this.updateOverflowWrapper(this.wrapText); }
3488
+ this.updateModelMode();
3489
+ }
3490
+ break;
3491
+ case 'delimiterChar':
3492
+ if (this.mode === 'Box') { return; }
3493
+ if (this.showCheckBox || this.allowMultiSelection) {
3494
+ this.setMultiSelect();
3495
+ }
3496
+ break;
3497
+ case 'selectAllText':
3498
+ if (this.showCheckBox && this.showSelectAll) { this.setLocale(); }
3499
+ break;
3500
+ case 'unSelectAllText':
3501
+ if (this.showCheckBox && this.showSelectAll) { this.setLocale(false); }
3502
+ break;
3503
+ case 'showSelectAll':
3504
+ if (this.showCheckBox) {
3505
+ this.setSelectAllWrapper(newProp.showSelectAll);
3506
+ this.updatePopupHeight();
3507
+ }
3508
+ break;
3509
+ case 'showCheckBox':
3510
+ this.updateCheckBoxState(newProp.showCheckBox);
3511
+ if (!this.wrapText) {
3512
+ this.updateOverflowWrapper(true);
3513
+ }
3514
+ this.updatePopupHeight();
3515
+ this.updateOption();
3516
+ break;
3517
+ case 'treeSettings':
3518
+ this.updateTreeSettings(newProp);
3519
+ break;
3520
+ case 'customTemplate':
3521
+ if (this.mode !== "Custom") { return; }
3522
+ this.chipCollection.innerHTML = "";
3523
+ this.setTagValues();
3524
+ break;
3525
+ case 'sortOrder':
3526
+ if (this.hasTemplate) { this.updateTemplate(); }
3527
+ this.treeObj.sortOrder = newProp.sortOrder;
3528
+ this.treeObj.dataBind();
3529
+ this.updateValue(this.value);
3530
+ break;
3531
+ case 'showDropDownIcon': this.updateDropDownIconState(newProp.showDropDownIcon); break;
3532
+ case 'popupWidth':
3533
+ if (this.popupObj) {
3534
+ this.popupObj.element.style.width = this.setWidth();
3535
+ }
3536
+ break;
3537
+ case 'popupHeight':
3538
+ if (this.popupObj) {
3539
+ this.updatePopupHeight();
3540
+ }
3541
+ break;
3542
+ case 'zIndex':
3543
+ if (this.popupObj) {
3544
+ this.popupObj.zIndex = newProp.zIndex;
3545
+ this.popupObj.dataBind();
3546
+ }
3547
+ break;
3548
+ case 'headerTemplate': this.updateTemplate(); break;
3549
+ case 'footerTemplate': this.updateTemplate(); break;
3550
+ case 'itemTemplate':
3551
+ this.updateTemplate();
3552
+ this.treeObj.nodeTemplate = newProp.itemTemplate;
3553
+ this.treeObj.dataBind();
3554
+ break;
3555
+ case 'noRecordsTemplate': this.updateRecordTemplate(); break;
3556
+ case 'actionFailureTemplate':
3557
+ this.updateRecordTemplate(true);
3558
+ break;
3559
+ case 'htmlAttributes': this.setHTMLAttributes(); break;
3560
+ case 'wrapText':
3561
+ this.updateOverflowWrapper(this.wrapText);
3562
+ if ((this.allowMultiSelection || this.showCheckBox) && !this.wrapText) {
3563
+ this.updateView();
3564
+ } else {
3565
+ addClass([this.overFlowWrapper], HIDEICON);
3566
+ if (this.chipWrapper && this.mode === 'Box') {
3567
+ removeClass([this.chipWrapper], HIDEICON);
3568
+ } else {
3569
+ removeClass([this.inputWrapper], SHOW_CHIP);
3570
+ removeClass([this.inputEle], CHIP_INPUT);
3571
+ }
3572
+ this.ensurePlaceHolder();
3573
+ }
3574
+ break;
3575
+ }
3576
+ }
3577
+ }
3578
+
3579
+ /**
3580
+ * Allows you to clear the selected values from the Dropdown Tree component.
3581
+ *
3582
+ * @method clear
3583
+ * @returns {void}
3584
+ */
3585
+ public clear(): void {
3586
+ this.clearAll();
3587
+ if (this.inputFocus) {
3588
+ this.onFocusOut();
3589
+ } else {
3590
+ if (this.changeOnBlur) {
3591
+ this.triggerChangeEvent();
3592
+ }
3593
+ this.removeValue = false;
3594
+ }
3595
+ }
3596
+
3597
+ /**
3598
+ * Removes the component from the DOM and detaches all its related event handlers. Also, it removes the attributes and classes.
3599
+ *
3600
+ * @method destroy
3601
+ * @returns {void}
3602
+ */
3603
+ public destroy(): void {
3604
+ this.clearTemplate();
3605
+ this.unWireEvents();
3606
+ this.setCssClass(null, this.cssClass);
3607
+ this.setProperties({ text: null }, true);
3608
+ this.treeObj.destroy();
3609
+ this.destroyFilter();
3610
+ if (this.popupObj) {
3611
+ this.popupObj.destroy();
3612
+ detach(this.popupObj.element);
3613
+ }
3614
+ if (this.element.tagName !== this.getDirective()) {
3615
+ this.inputWrapper.parentElement.insertBefore(this.element, this.inputWrapper);
3616
+ }
3617
+ Input.setValue(null, this.inputEle, this.floatLabelType);
3618
+ detach(this.inputWrapper);
3619
+ detach(this.popupDiv);
3620
+ detach(this.hiddenElement);
3621
+ this.element.classList.remove('e-input');
3622
+ if (this.showCheckBox || this.allowMultiSelection) {
3623
+ this.element.classList.remove(CHIP_INPUT);
3624
+ }
3625
+ this.inputObj = null;
3626
+ while (this.hiddenElement.options.length > 0) {
3627
+ this.hiddenElement.remove(0);
3628
+ }
3629
+ this.hiddenElement.innerHTML = '';
3630
+ this.hiddenElement = null;
3631
+ this.inputWrapper = null;
3632
+ this.popupDiv = null;
3633
+ this.tree = null;
3634
+ this.popupObj = null;
3635
+ this.treeObj = null;
3636
+ this.overAllClear = null;
3637
+ this.chipWrapper = null;
3638
+ this.chipCollection = null;
3639
+ this.checkAllParent = null;
3640
+ this.selectAllSpan = null;
3641
+ this.checkBoxElement = null;
3642
+ this.checkWrapper = null;
3643
+ this.popupEle = null;
3644
+ this.header = null;
3645
+ this.footer = null;
3646
+ this.overFlowWrapper = null;
3647
+ this.keyboardModule = null;
3648
+ super.destroy();
3649
+ this.setProperties({ value: [] }, true);
3650
+ }
3651
+
3652
+ private destroyFilter(): void {
3653
+ if (this.filterObj) {
3654
+ this.filterObj.destroy();
3655
+ detach(this.filterObj.element);
3656
+ detach(this.filterContainer);
3657
+ this.filterObj = null;
3658
+ }
3659
+ }
3660
+
3661
+ /**
3662
+ * Ensures visibility of the Dropdown Tree item by using item value or item element.
3663
+ * If many Dropdown Tree items are present, and we are in need to find a particular item, then the `ensureVisible` property
3664
+ * helps you to bring the item to visibility by expanding the Dropdown Tree and scrolling to the specific item.
3665
+ *
3666
+ * @param {string | Element} item - Specifies the value of Dropdown Tree item/ Dropdown Tree item element.
3667
+ * @returns {void}
3668
+ */
3669
+ public ensureVisible(item: string | Element): void {
3670
+ this.treeObj.ensureVisible(item);
3671
+ }
3672
+
3673
+ /**
3674
+ * To get the updated data source of the Dropdown Tree.
3675
+ *
3676
+ * @param {string | Element} item - Specifies the value of Dropdown Tree item/ Dropdown Tree item element
3677
+ * @returns {'{[key: string]: Object }[]'} - returns the updated data source of the Dropdown Tree.
3678
+ */
3679
+ // eslint-disable-next-line
3680
+ public getData(item?: string | Element): { [key: string]: Object }[] {
3681
+ return this.treeObj.getTreeData(item);
3682
+ }
3683
+
3684
+ /**
3685
+ * Close the Dropdown tree pop-up.
3686
+ *
3687
+ * @returns {void}
3688
+ */
3689
+ public hidePopup(): void {
3690
+ const eventArgs: DdtPopupEventArgs = { popup: this.popupObj };
3691
+ this.inputWrapper.classList.remove(ICONANIMATION);
3692
+ if (this.popupEle) {
3693
+ addClass([this.popupEle], DDTHIDEICON);
3694
+ }
3695
+ attributes(this.inputWrapper, { 'aria-expanded': 'false' });
3696
+ if (this.popupObj && this.isPopupOpen) {
3697
+ this.popupObj.hide();
3698
+ if (this.inputFocus) {
3699
+ this.inputWrapper.focus();
3700
+ if (this.allowFiltering) {
3701
+ addClass([this.inputWrapper], [INPUTFOCUS]);
3702
+ }
3703
+ }
3704
+ this.trigger('close', eventArgs);
3705
+ }
3706
+ }
3707
+
3708
+ /**
3709
+ * Based on the state parameter, entire list item will be selected or deselected.
3710
+ *
3711
+ * @param {boolean} state - Unselects/Selects entire Dropdown Tree items.
3712
+ * @returns {void}
3713
+ *
3714
+ */
3715
+ public selectAll(state: boolean): void {
3716
+ this.selectAllItems(state);
3717
+ }
3718
+
3719
+ /**
3720
+ * Opens the popup that displays the Dropdown Tree items.
3721
+ *
3722
+ * @returns {void}
3723
+ */
3724
+ public showPopup(): void {
3725
+ if (!this.enabled || this.readonly || this.isPopupOpen) {
3726
+ return;
3727
+ }
3728
+ this.renderPopup();
3729
+ this.focusIn();
3730
+ }
3731
+
3732
+ /**
3733
+ * Return the module name.
3734
+ *
3735
+ * @private
3736
+ * @returns {string} - returns the module name.
3737
+ */
3738
+ public getModuleName(): string {
3739
+ return 'dropdowntree';
3740
+ }
3741
+ }