@syncfusion/ej2-dropdowns 18.2.44-4568 → 18.2.44-4569

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