@syncfusion/ej2-navigations 17.3.9-beta → 17.3.14-96615

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 (314) hide show
  1. package/.eslintrc.json +244 -0
  2. package/CHANGELOG.md +898 -800
  3. package/README.md +163 -163
  4. package/dist/ej2-navigations.umd.min.js +1 -10
  5. package/dist/ej2-navigations.umd.min.js.map +1 -1
  6. package/dist/es6/ej2-navigations.es2015.js +325 -170
  7. package/dist/es6/ej2-navigations.es2015.js.map +1 -1
  8. package/dist/es6/ej2-navigations.es5.js +455 -300
  9. package/dist/es6/ej2-navigations.es5.js.map +1 -1
  10. package/dist/global/ej2-navigations.min.js +1 -10
  11. package/dist/global/ej2-navigations.min.js.map +1 -1
  12. package/dist/global/index.d.ts +0 -9
  13. package/dist/ts/accordion/accordion.ts +1312 -0
  14. package/dist/ts/common/h-scroll.ts +459 -0
  15. package/dist/ts/common/menu-base.ts +2131 -0
  16. package/dist/ts/common/v-scroll.ts +430 -0
  17. package/dist/ts/context-menu/context-menu.ts +119 -0
  18. package/dist/ts/menu/menu.ts +270 -0
  19. package/dist/ts/sidebar/sidebar.ts +817 -0
  20. package/dist/ts/tab/tab.ts +1761 -0
  21. package/dist/ts/toolbar/toolbar.ts +2076 -0
  22. package/dist/ts/treeview/treeview.ts +5050 -0
  23. package/helpers/e2e/index.js +3 -3
  24. package/license +10 -10
  25. package/package.json +135 -149
  26. package/src/accordion/accordion-model.d.ts +156 -156
  27. package/src/accordion/accordion.d.ts +1 -0
  28. package/src/accordion/accordion.js +40 -41
  29. package/src/common/h-scroll-model.d.ts +5 -5
  30. package/src/common/h-scroll.js +19 -20
  31. package/src/common/menu-base-model.d.ts +157 -157
  32. package/src/common/menu-base.d.ts +19 -0
  33. package/src/common/menu-base.js +94 -24
  34. package/src/common/v-scroll-model.d.ts +5 -5
  35. package/src/common/v-scroll.js +19 -19
  36. package/src/context-menu/context-menu-model.d.ts +15 -15
  37. package/src/context-menu/context-menu.js +19 -19
  38. package/src/menu/menu-model.d.ts +30 -30
  39. package/src/menu/menu.js +19 -19
  40. package/src/sidebar/sidebar-model.d.ts +136 -136
  41. package/src/sidebar/sidebar.js +19 -19
  42. package/src/tab/tab-model.d.ts +215 -215
  43. package/src/tab/tab.d.ts +3 -0
  44. package/src/tab/tab.js +117 -82
  45. package/src/toolbar/toolbar-model.d.ts +175 -175
  46. package/src/toolbar/toolbar.d.ts +1 -0
  47. package/src/toolbar/toolbar.js +30 -24
  48. package/src/treeview/treeview-model.d.ts +323 -323
  49. package/src/treeview/treeview.js +79 -33
  50. package/styles/accordion/_all.scss +2 -2
  51. package/styles/accordion/_bootstrap-dark-definition.scss +69 -69
  52. package/styles/accordion/_bootstrap-definition.scss +76 -76
  53. package/styles/accordion/_bootstrap4-definition.scss +82 -82
  54. package/styles/accordion/_fabric-dark-definition.scss +74 -74
  55. package/styles/accordion/_fabric-definition.scss +78 -78
  56. package/styles/accordion/_highcontrast-definition.scss +106 -106
  57. package/styles/accordion/_highcontrast-light-definition.scss +104 -104
  58. package/styles/accordion/_layout.scss +447 -447
  59. package/styles/accordion/_material-dark-definition.scss +75 -75
  60. package/styles/accordion/_material-definition.scss +72 -72
  61. package/styles/accordion/_theme.scss +479 -479
  62. package/styles/accordion/icons/_bootstrap-dark.scss +17 -17
  63. package/styles/accordion/icons/_bootstrap.scss +17 -17
  64. package/styles/accordion/icons/_bootstrap4.scss +17 -17
  65. package/styles/accordion/icons/_fabric-dark.scss +17 -17
  66. package/styles/accordion/icons/_fabric.scss +17 -17
  67. package/styles/accordion/icons/_highcontrast-light.scss +17 -17
  68. package/styles/accordion/icons/_highcontrast.scss +17 -17
  69. package/styles/accordion/icons/_material-dark.scss +17 -17
  70. package/styles/accordion/icons/_material.scss +17 -17
  71. package/styles/bootstrap-dark.css +7 -9
  72. package/styles/bootstrap.css +7 -9
  73. package/styles/bootstrap4.css +7 -9
  74. package/styles/bootstrap5-dark.css +0 -0
  75. package/styles/bootstrap5-dark.scss +0 -0
  76. package/styles/bootstrap5.css +0 -0
  77. package/styles/bootstrap5.scss +0 -0
  78. package/styles/context-menu/_all.scss +2 -2
  79. package/styles/context-menu/_bootstrap-dark-definition.scss +54 -54
  80. package/styles/context-menu/_bootstrap-definition.scss +52 -52
  81. package/styles/context-menu/_bootstrap4-definition.scss +52 -52
  82. package/styles/context-menu/_fabric-dark-definition.scss +54 -54
  83. package/styles/context-menu/_fabric-definition.scss +52 -52
  84. package/styles/context-menu/_highcontrast-definition.scss +52 -52
  85. package/styles/context-menu/_highcontrast-light-definition.scss +54 -54
  86. package/styles/context-menu/_layout-mixin.scss +175 -175
  87. package/styles/context-menu/_layout.scss +70 -70
  88. package/styles/context-menu/_material-dark-definition.scss +54 -54
  89. package/styles/context-menu/_material-definition.scss +52 -52
  90. package/styles/context-menu/_theme-mixin.scss +59 -59
  91. package/styles/context-menu/_theme.scss +36 -36
  92. package/styles/context-menu/bootstrap-dark.css +0 -1
  93. package/styles/context-menu/bootstrap.css +0 -1
  94. package/styles/context-menu/bootstrap4.css +0 -1
  95. package/styles/context-menu/fabric-dark.css +0 -1
  96. package/styles/context-menu/fabric.css +0 -1
  97. package/styles/context-menu/highcontrast-light.css +0 -1
  98. package/styles/context-menu/highcontrast.css +0 -1
  99. package/styles/context-menu/icons/_bootstrap-dark.scss +30 -30
  100. package/styles/context-menu/icons/_bootstrap.scss +30 -30
  101. package/styles/context-menu/icons/_bootstrap4.scss +30 -30
  102. package/styles/context-menu/icons/_fabric-dark.scss +30 -30
  103. package/styles/context-menu/icons/_fabric.scss +30 -30
  104. package/styles/context-menu/icons/_highcontrast-light.scss +30 -30
  105. package/styles/context-menu/icons/_highcontrast.scss +30 -30
  106. package/styles/context-menu/icons/_material-dark.scss +30 -30
  107. package/styles/context-menu/icons/_material.scss +30 -30
  108. package/styles/context-menu/material-dark.css +0 -1
  109. package/styles/context-menu/material.css +3 -4
  110. package/styles/fabric-dark.css +7 -9
  111. package/styles/fabric.css +7 -9
  112. package/styles/h-scroll/_all.scss +2 -2
  113. package/styles/h-scroll/_bootstrap-dark-definition.scss +49 -49
  114. package/styles/h-scroll/_bootstrap-definition.scss +50 -50
  115. package/styles/h-scroll/_bootstrap4-definition.scss +49 -49
  116. package/styles/h-scroll/_fabric-dark-definition.scss +50 -50
  117. package/styles/h-scroll/_fabric-definition.scss +48 -48
  118. package/styles/h-scroll/_highcontrast-definition.scss +52 -52
  119. package/styles/h-scroll/_highcontrast-light-definition.scss +54 -54
  120. package/styles/h-scroll/_layout.scss +198 -198
  121. package/styles/h-scroll/_material-dark-definition.scss +77 -77
  122. package/styles/h-scroll/_material-definition.scss +77 -77
  123. package/styles/h-scroll/_theme.scss +157 -157
  124. package/styles/h-scroll/icons/_bootstrap-dark.scss +49 -49
  125. package/styles/h-scroll/icons/_bootstrap.scss +49 -49
  126. package/styles/h-scroll/icons/_bootstrap4.scss +49 -49
  127. package/styles/h-scroll/icons/_fabric-dark.scss +49 -49
  128. package/styles/h-scroll/icons/_fabric.scss +49 -49
  129. package/styles/h-scroll/icons/_highcontrast-light.scss +49 -49
  130. package/styles/h-scroll/icons/_highcontrast.scss +49 -49
  131. package/styles/h-scroll/icons/_material-dark.scss +49 -49
  132. package/styles/h-scroll/icons/_material.scss +49 -49
  133. package/styles/highcontrast-light.css +7 -9
  134. package/styles/highcontrast.css +7 -9
  135. package/styles/material-dark.css +7 -9
  136. package/styles/material.css +21 -14
  137. package/styles/menu/_all.scss +2 -2
  138. package/styles/menu/_bootstrap-dark-definition.scss +63 -63
  139. package/styles/menu/_bootstrap-definition.scss +65 -65
  140. package/styles/menu/_bootstrap4-definition.scss +64 -64
  141. package/styles/menu/_fabric-dark-definition.scss +63 -63
  142. package/styles/menu/_fabric-definition.scss +64 -64
  143. package/styles/menu/_highcontrast-definition.scss +65 -65
  144. package/styles/menu/_highcontrast-light-definition.scss +61 -61
  145. package/styles/menu/_layout.scss +638 -638
  146. package/styles/menu/_material-dark-definition.scss +63 -63
  147. package/styles/menu/_material-definition.scss +64 -64
  148. package/styles/menu/_theme.scss +243 -243
  149. package/styles/menu/bootstrap-dark.css +0 -1
  150. package/styles/menu/bootstrap.css +0 -1
  151. package/styles/menu/bootstrap.scss +1 -0
  152. package/styles/menu/bootstrap4.css +0 -1
  153. package/styles/menu/fabric-dark.css +0 -1
  154. package/styles/menu/fabric.css +0 -1
  155. package/styles/menu/fabric.scss +1 -0
  156. package/styles/menu/highcontrast-light.css +0 -1
  157. package/styles/menu/highcontrast.css +0 -1
  158. package/styles/menu/highcontrast.scss +1 -0
  159. package/styles/menu/icons/_bootstrap-dark.scss +127 -127
  160. package/styles/menu/icons/_bootstrap.scss +127 -127
  161. package/styles/menu/icons/_bootstrap4.scss +127 -127
  162. package/styles/menu/icons/_fabric-dark.scss +127 -127
  163. package/styles/menu/icons/_fabric.scss +127 -127
  164. package/styles/menu/icons/_highcontrast-light.scss +127 -127
  165. package/styles/menu/icons/_highcontrast.scss +127 -127
  166. package/styles/menu/icons/_material-dark.scss +127 -127
  167. package/styles/menu/icons/_material.scss +127 -127
  168. package/styles/menu/material-dark.css +0 -1
  169. package/styles/menu/material.css +2 -3
  170. package/styles/menu/material.scss +1 -0
  171. package/styles/sidebar/_all.scss +3 -3
  172. package/styles/sidebar/_bootstrap-dark-definition.scss +4 -4
  173. package/styles/sidebar/_bootstrap-definition.scss +4 -4
  174. package/styles/sidebar/_bootstrap4-definition.scss +4 -4
  175. package/styles/sidebar/_fabric-dark-definition.scss +4 -4
  176. package/styles/sidebar/_fabric-definition.scss +6 -6
  177. package/styles/sidebar/_highcontrast-definition.scss +4 -4
  178. package/styles/sidebar/_highcontrast-light-definition.scss +4 -4
  179. package/styles/sidebar/_icons.scss +1 -1
  180. package/styles/sidebar/_material-dark-definition.scss +4 -4
  181. package/styles/sidebar/_material-definition.scss +6 -6
  182. package/styles/sidebar/_theme.scss +168 -168
  183. package/styles/sidebar/bootstrap-dark.css +0 -1
  184. package/styles/sidebar/bootstrap.css +0 -1
  185. package/styles/sidebar/bootstrap4.css +0 -1
  186. package/styles/sidebar/fabric-dark.css +0 -1
  187. package/styles/sidebar/fabric.css +0 -1
  188. package/styles/sidebar/highcontrast-light.css +0 -1
  189. package/styles/sidebar/highcontrast.css +0 -1
  190. package/styles/sidebar/material-dark.css +0 -1
  191. package/styles/sidebar/material.css +0 -1
  192. package/styles/tab/_all.scss +2 -2
  193. package/styles/tab/_bootstrap-dark-definition.scss +386 -386
  194. package/styles/tab/_bootstrap-definition.scss +396 -396
  195. package/styles/tab/_bootstrap4-definition.scss +401 -401
  196. package/styles/tab/_fabric-dark-definition.scss +394 -394
  197. package/styles/tab/_fabric-definition.scss +410 -410
  198. package/styles/tab/_highcontrast-definition.scss +434 -434
  199. package/styles/tab/_highcontrast-light-definition.scss +423 -423
  200. package/styles/tab/_icons.scss +43 -43
  201. package/styles/tab/_layout.scss +3528 -3521
  202. package/styles/tab/_material-dark-definition.scss +407 -407
  203. package/styles/tab/_material-definition.scss +416 -416
  204. package/styles/tab/_theme.scss +1751 -1751
  205. package/styles/tab/bootstrap-dark.css +7 -2
  206. package/styles/tab/bootstrap.css +7 -2
  207. package/styles/tab/bootstrap4.css +7 -2
  208. package/styles/tab/fabric-dark.css +7 -2
  209. package/styles/tab/fabric.css +7 -2
  210. package/styles/tab/highcontrast-light.css +7 -2
  211. package/styles/tab/highcontrast.css +7 -2
  212. package/styles/tab/icons/_bootstrap-dark.scss +132 -132
  213. package/styles/tab/icons/_bootstrap.scss +132 -132
  214. package/styles/tab/icons/_bootstrap4.scss +132 -132
  215. package/styles/tab/icons/_fabric-dark.scss +132 -132
  216. package/styles/tab/icons/_fabric.scss +132 -132
  217. package/styles/tab/icons/_highcontrast-light.scss +132 -132
  218. package/styles/tab/icons/_highcontrast.scss +132 -132
  219. package/styles/tab/icons/_material-dark.scss +132 -132
  220. package/styles/tab/icons/_material.scss +132 -132
  221. package/styles/tab/material-dark.css +7 -2
  222. package/styles/tab/material.css +7 -2
  223. package/styles/tailwind-dark.css +0 -0
  224. package/styles/tailwind-dark.scss +0 -0
  225. package/styles/tailwind.css +0 -0
  226. package/styles/tailwind.scss +0 -0
  227. package/styles/toolbar/_all.scss +2 -2
  228. package/styles/toolbar/_bootstrap-dark-definition.scss +135 -135
  229. package/styles/toolbar/_bootstrap-definition.scss +134 -134
  230. package/styles/toolbar/_bootstrap4-definition.scss +139 -139
  231. package/styles/toolbar/_fabric-dark-definition.scss +155 -155
  232. package/styles/toolbar/_fabric-definition.scss +139 -139
  233. package/styles/toolbar/_highcontrast-definition.scss +149 -149
  234. package/styles/toolbar/_highcontrast-light-definition.scss +164 -164
  235. package/styles/toolbar/_layout.scss +1460 -1460
  236. package/styles/toolbar/_material-dark-definition.scss +180 -180
  237. package/styles/toolbar/_material-definition.scss +164 -164
  238. package/styles/toolbar/_theme.scss +451 -451
  239. package/styles/toolbar/bootstrap-dark.css +0 -1
  240. package/styles/toolbar/bootstrap.css +0 -1
  241. package/styles/toolbar/bootstrap.scss +1 -0
  242. package/styles/toolbar/bootstrap4.css +0 -1
  243. package/styles/toolbar/fabric-dark.css +0 -1
  244. package/styles/toolbar/fabric.css +0 -1
  245. package/styles/toolbar/fabric.scss +1 -0
  246. package/styles/toolbar/highcontrast-light.css +0 -1
  247. package/styles/toolbar/highcontrast.css +0 -1
  248. package/styles/toolbar/highcontrast.scss +1 -0
  249. package/styles/toolbar/icons/_bootstrap-dark.scss +16 -16
  250. package/styles/toolbar/icons/_bootstrap.scss +16 -16
  251. package/styles/toolbar/icons/_bootstrap4.scss +16 -16
  252. package/styles/toolbar/icons/_fabric-dark.scss +16 -16
  253. package/styles/toolbar/icons/_fabric.scss +16 -16
  254. package/styles/toolbar/icons/_highcontrast-light.scss +16 -16
  255. package/styles/toolbar/icons/_highcontrast.scss +16 -16
  256. package/styles/toolbar/icons/_material-dark.scss +16 -16
  257. package/styles/toolbar/icons/_material.scss +16 -16
  258. package/styles/toolbar/material-dark.css +0 -1
  259. package/styles/toolbar/material.css +0 -1
  260. package/styles/toolbar/material.scss +1 -0
  261. package/styles/treeview/_all.scss +2 -2
  262. package/styles/treeview/_bootstrap-dark-definition.scss +131 -131
  263. package/styles/treeview/_bootstrap-definition.scss +127 -127
  264. package/styles/treeview/_bootstrap4-definition.scss +153 -153
  265. package/styles/treeview/_fabric-dark-definition.scss +130 -130
  266. package/styles/treeview/_fabric-definition.scss +126 -126
  267. package/styles/treeview/_highcontrast-definition.scss +132 -132
  268. package/styles/treeview/_highcontrast-light-definition.scss +137 -137
  269. package/styles/treeview/_layout.scss +551 -551
  270. package/styles/treeview/_material-dark-definition.scss +126 -126
  271. package/styles/treeview/_material-definition.scss +126 -126
  272. package/styles/treeview/_theme.scss +331 -331
  273. package/styles/treeview/bootstrap-dark.css +0 -3
  274. package/styles/treeview/bootstrap.css +0 -3
  275. package/styles/treeview/bootstrap4.css +0 -3
  276. package/styles/treeview/fabric-dark.css +0 -3
  277. package/styles/treeview/fabric.css +0 -3
  278. package/styles/treeview/highcontrast-light.css +0 -3
  279. package/styles/treeview/highcontrast.css +0 -3
  280. package/styles/treeview/icons/_bootstrap-dark.scss +39 -39
  281. package/styles/treeview/icons/_bootstrap.scss +39 -39
  282. package/styles/treeview/icons/_bootstrap4.scss +39 -39
  283. package/styles/treeview/icons/_fabric-dark.scss +43 -43
  284. package/styles/treeview/icons/_fabric.scss +43 -43
  285. package/styles/treeview/icons/_highcontrast-light.scss +43 -43
  286. package/styles/treeview/icons/_highcontrast.scss +43 -43
  287. package/styles/treeview/icons/_material-dark.scss +43 -43
  288. package/styles/treeview/icons/_material.scss +43 -43
  289. package/styles/treeview/material-dark.css +0 -3
  290. package/styles/treeview/material.css +9 -3
  291. package/styles/v-scroll/_all.scss +2 -2
  292. package/styles/v-scroll/_bootstrap-dark-definition.scss +50 -50
  293. package/styles/v-scroll/_bootstrap-definition.scss +49 -49
  294. package/styles/v-scroll/_bootstrap4-definition.scss +49 -49
  295. package/styles/v-scroll/_fabric-dark-definition.scss +51 -51
  296. package/styles/v-scroll/_fabric-definition.scss +50 -50
  297. package/styles/v-scroll/_highcontrast-definition.scss +51 -51
  298. package/styles/v-scroll/_highcontrast-light-definition.scss +52 -52
  299. package/styles/v-scroll/_layout.scss +162 -162
  300. package/styles/v-scroll/_material-dark-definition.scss +78 -78
  301. package/styles/v-scroll/_material-definition.scss +77 -77
  302. package/styles/v-scroll/_theme.scss +133 -133
  303. package/styles/v-scroll/icons/_bootstrap-dark.scss +26 -26
  304. package/styles/v-scroll/icons/_bootstrap.scss +26 -26
  305. package/styles/v-scroll/icons/_bootstrap4.scss +26 -26
  306. package/styles/v-scroll/icons/_fabric-dark.scss +26 -26
  307. package/styles/v-scroll/icons/_fabric.scss +26 -26
  308. package/styles/v-scroll/icons/_highcontrast-light.scss +26 -26
  309. package/styles/v-scroll/icons/_highcontrast.scss +26 -26
  310. package/styles/v-scroll/icons/_material-dark.scss +26 -26
  311. package/styles/v-scroll/icons/_material.scss +26 -26
  312. package/tslint.json +111 -0
  313. package/.gitlab/merge_request_templates/Bug.md +0 -63
  314. package/.gitlab/merge_request_templates/feature.md +0 -39
@@ -0,0 +1,1312 @@
1
+ import { Component, EventHandler, Property, Event, EmitType, AnimationModel, KeyboardEvents, rippleEffect } from '@syncfusion/ej2-base';
2
+ import { KeyboardEventArgs, BaseEventArgs, Effect, getUniqueID, compile as templateCompiler } from '@syncfusion/ej2-base';
3
+ import { isVisible, closest, attributes, detach, select, isBlazor, addClass, append } from '@syncfusion/ej2-base';
4
+ import { INotifyPropertyChanged, NotifyPropertyChanges, ChildProperty, Collection, Animation } from '@syncfusion/ej2-base';
5
+ import { setStyleAttribute as setStyle, Complex, updateBlazorTemplate } from '@syncfusion/ej2-base';
6
+ import { isNullOrUndefined as isNOU, formatUnit, selectAll } from '@syncfusion/ej2-base';
7
+ import { AccordionModel, AccordionItemModel, AccordionAnimationSettingsModel, AccordionActionSettingsModel } from './accordion-model';
8
+
9
+ /**
10
+ * Specifies the option to expand single or multiple panel at a time.
11
+ */
12
+ export type ExpandMode = 'Single' | 'Multiple';
13
+
14
+ type HTEle = HTMLElement;
15
+ type Str = string;
16
+
17
+ const CLS_ACRDN_ROOT: Str = 'e-acrdn-root';
18
+ const CLS_ROOT: Str = 'e-accordion';
19
+ const CLS_ITEM: Str = 'e-acrdn-item';
20
+ const CLS_ITEMFOCUS: Str = 'e-item-focus';
21
+ const CLS_ITEMHIDE: Str = 'e-hide';
22
+ const CLS_HEADER: Str = 'e-acrdn-header';
23
+ const CLS_HEADERICN: Str = 'e-acrdn-header-icon';
24
+ const CLS_HEADERCTN: Str = 'e-acrdn-header-content';
25
+ const CLS_CONTENT: Str = 'e-acrdn-panel';
26
+ const CLS_CTENT: Str = 'e-acrdn-content';
27
+ const CLS_TOOGLEICN: Str = 'e-toggle-icon';
28
+ const CLS_COLLAPSEICN: Str = 'e-tgl-collapse-icon e-icons';
29
+ const CLS_EXPANDICN: Str = 'e-expand-icon';
30
+ const CLS_RTL: Str = 'e-rtl';
31
+ const CLS_CTNHIDE: Str = 'e-content-hide';
32
+ const CLS_SLCT: Str = 'e-select';
33
+ const CLS_SLCTED: Str = 'e-selected';
34
+ const CLS_ACTIVE: Str = 'e-active';
35
+ const CLS_ANIMATE: Str = 'e-animate';
36
+ const CLS_DISABLE: Str = 'e-overlay';
37
+ const CLS_TOGANIMATE: Str = 'e-toggle-animation';
38
+ const CLS_NEST: Str = 'e-nested';
39
+ const CLS_EXPANDSTATE: Str = 'e-expand-state';
40
+ const CLS_CONTAINER: Str = 'e-accordion-container';
41
+
42
+ interface AcrdnTemplateRef {
43
+ elementRef: AcrdnElementRef;
44
+ }
45
+
46
+ interface AcrdnElementRef {
47
+ nativeElement: AcrdnElementComment;
48
+ }
49
+
50
+ interface AcrdnElementComment {
51
+ childNodes?: NodeList;
52
+ firstChild?: HTMLElement;
53
+ lastChild?: HTMLElement;
54
+ nextElementSibling?: HTMLElement;
55
+ parentElement?: HTMLElement;
56
+ propName?: HTMLElement;
57
+ data?: string;
58
+ }
59
+
60
+ export interface AccordionClickArgs extends BaseEventArgs {
61
+ /** Defines the current Accordion Item Object. */
62
+ item?: AccordionItemModel;
63
+ /**
64
+ * Defines the current Event arguments.
65
+ * @blazorType MouseEventArgs
66
+ */
67
+ originalEvent?: Event;
68
+ }
69
+ export interface ExpandEventArgs extends BaseEventArgs {
70
+ /** Defines the current Accordion Item Object. */
71
+ item?: AccordionItemModel;
72
+ /** Defines the current Accordion Item Element. */
73
+ element?: HTMLElement;
74
+ /** Defines the expand/collapse state. */
75
+ isExpanded?: boolean;
76
+ /** Defines the prevent action. */
77
+ cancel?: boolean;
78
+ /** Defines the Accordion Item Index */
79
+ index?: number;
80
+ /** Defines the Accordion Item Content */
81
+ content?: HTMLElement;
82
+ }
83
+
84
+ export interface ExpandedEventArgs extends BaseEventArgs {
85
+ /** Defines the current Accordion Item Object. */
86
+ item?: AccordionItemModel;
87
+ /** Defines the current Accordion Item Element. */
88
+ element?: HTMLElement;
89
+ /** Defines the expand/collapse state. */
90
+ isExpanded?: boolean;
91
+ /** Defines the Accordion Item Index */
92
+ index?: number;
93
+ /** Defines the Accordion Item Content */
94
+ content?: HTMLElement;
95
+ }
96
+
97
+ export class AccordionActionSettings extends ChildProperty<AccordionActionSettings> {
98
+ /**
99
+ * Specifies the type of animation.
100
+ * @default 'SlideDown'
101
+ * @aspType string
102
+ * @blazorType string
103
+ */
104
+ @Property('SlideDown')
105
+ public effect: 'None' | Effect;
106
+ /**
107
+ * Specifies the duration to animate.
108
+ * @default 400
109
+ */
110
+ @Property(400)
111
+ public duration: number;
112
+ /**
113
+ * Specifies the animation timing function.
114
+ * @default 'linear'
115
+ */
116
+ @Property('linear')
117
+ public easing: string;
118
+ }
119
+
120
+ export class AccordionAnimationSettings extends ChildProperty<AccordionAnimationSettings> {
121
+ /**
122
+ * Specifies the animation to appear while collapsing the Accordion item.
123
+ * @default { effect: 'SlideDown', duration: 400, easing: 'linear' }
124
+ */
125
+ @Complex<AccordionActionSettingsModel>({ effect: 'SlideUp', duration: 400, easing: 'linear' }, AccordionActionSettings)
126
+ public collapse: AccordionActionSettingsModel;
127
+ /**
128
+ * Specifies the animation to appear while expanding the Accordion item.
129
+ * @default { effect: 'SlideDown', duration: 400, easing: 'linear' }
130
+ */
131
+ @Complex<AccordionActionSettingsModel>({ effect: 'SlideDown', duration: 400, easing: 'linear' }, AccordionActionSettings)
132
+ public expand: AccordionActionSettingsModel;
133
+ }
134
+ /**
135
+ * An item object that is used to configure Accordion items.
136
+ */
137
+ export class AccordionItem extends ChildProperty<AccordionItem> {
138
+ /**
139
+ * Sets the text content to be displayed for the Accordion item.
140
+ * You can set the content of the Accordion item using `content` property.
141
+ * It also supports to include the title as `HTML element`, `string`, or `query selector`.
142
+ * ```typescript
143
+ * let accordionObj: Accordion = new Accordion( {
144
+ * items: [
145
+ * { header: 'Accordion Header', content: 'Accordion Content' },
146
+ * { header: '<div>Accordion Header</div>', content: '<div>Accordion Content</div' },
147
+ * { header: '#headerContent', content: '#panelContent' }]
148
+ * });
149
+ * accordionObj.appendTo('#accordion');
150
+ * ```
151
+ * @default null
152
+ */
153
+ @Property(null)
154
+ public content: string;
155
+ /**
156
+ * Sets the header text to be displayed for the Accordion item.
157
+ * You can set the title of the Accordion item using `header` property.
158
+ * It also supports to include the title as `HTML element`, `string`, or `query selector`.
159
+ * ```typescript
160
+ * let accordionObj: Accordion = new Accordion( {
161
+ * items: [
162
+ * { header: 'Accordion Header', content: 'Accordion Content' },
163
+ * { header: '<div>Accordion Header</div>', content: '<div>Accordion Content</div' },
164
+ * { header: '#headerContent', content: '#panelContent' }]
165
+ * });
166
+ * accordionObj.appendTo('#accordion');
167
+ * ```
168
+ * @default null
169
+ */
170
+ @Property(null)
171
+ public header: string;
172
+ /**
173
+ * Defines single/multiple classes (separated by a space) are to be used for Accordion item customization.
174
+ * @default null
175
+ */
176
+ @Property(null)
177
+ public cssClass: string;
178
+ /**
179
+ * Defines an icon with the given custom CSS class that is to be rendered before the header text.
180
+ * Add the css classes to the `iconCss` property and write the css styles to the defined class to set images/icons.
181
+ * Adding icon is applicable only to the header.
182
+ * ```typescript
183
+ * let accordionObj: Accordion = new Accordion( {
184
+ * items: [
185
+ * { header: 'Accordion Header', iconCss: 'e-app-icon' }]
186
+ * });
187
+ * accordionObj.appendTo('#accordion');
188
+ * ```
189
+ * ```css
190
+ * .e-app-icon::before {
191
+ * content: "\e710";
192
+ * }
193
+ * ```
194
+ * @default null
195
+ */
196
+ @Property(null)
197
+ public iconCss: string;
198
+ /**
199
+ * Sets the expand (true) or collapse (false) state of the Accordion item. By default, all the items are in a collapsed state.
200
+ * @default false
201
+ */
202
+ @Property(false)
203
+ public expanded: Boolean;
204
+ }
205
+
206
+ /**
207
+ * The Accordion is a vertically collapsible content panel that displays one or more panels at a time within the available space.
208
+ * ```html
209
+ * <div id='accordion'/>
210
+ * <script>
211
+ * var accordionObj = new Accordion();
212
+ * accordionObj.appendTo('#accordion');
213
+ * </script>
214
+ * ```
215
+ */
216
+ @NotifyPropertyChanges
217
+ export class Accordion extends Component<HTMLElement> implements INotifyPropertyChanged {
218
+ private lastActiveItemId: string;
219
+ private trgtEle: HTEle;
220
+ private ctrlTem: HTEle;
221
+ private keyModule: KeyboardEvents;
222
+ private expandedItems: number[];
223
+ private initExpand: number[];
224
+ private isNested: Boolean;
225
+ private isDestroy: Boolean;
226
+ private templateEle: string[];
227
+ private isAngular: boolean;
228
+ private headerTemplateFn: Function;
229
+ private itemTemplateFn: Function;
230
+ /**
231
+ * Contains the keyboard configuration of the Accordion.
232
+ */
233
+ private keyConfigs: { [key: string]: Str } = {
234
+ moveUp: 'uparrow',
235
+ moveDown: 'downarrow',
236
+ enter: 'enter',
237
+ space: 'space',
238
+ home: 'home',
239
+ end: 'end',
240
+ };
241
+
242
+ /**
243
+ * An array of item that is used to specify Accordion items.
244
+ * ```typescript
245
+ * let accordionObj: Accordion = new Accordion( {
246
+ * items: [
247
+ * { header: 'Accordion Header', content: 'Accordion Content' }]
248
+ * });
249
+ * accordionObj.appendTo('#accordion');
250
+ * ```
251
+ * @default []
252
+ */
253
+ @Collection<AccordionItemModel>([], AccordionItem)
254
+ public items: AccordionItemModel[];
255
+ /**
256
+ * Specifies the datasource for the accordion items.
257
+ * @isdatamanager false
258
+ * @default []
259
+ */
260
+ @Property([])
261
+ public dataSource: Object[];
262
+ /**
263
+ * Specifies the template option for accordion items.
264
+ * @default null
265
+ */
266
+ @Property()
267
+ public itemTemplate: string;
268
+ /**
269
+ * Specifies the header title template option for accordion items.
270
+ * @default null
271
+ */
272
+ @Property()
273
+ public headerTemplate: string;
274
+ /**
275
+ * Specifies the width of the Accordion in pixels/number/percentage. Number value is considered as pixels.
276
+ * @default '100%'
277
+ */
278
+ @Property('100%')
279
+ public width: string | number;
280
+ /**
281
+ * Specifies the height of the Accordion in pixels/number/percentage. Number value is considered as pixels.
282
+ * @default 'auto'
283
+ */
284
+ @Property('auto')
285
+ public height: string | number;
286
+ /**
287
+ * Specifies the options to expand single or multiple panel at a time.
288
+ * The possible values are:
289
+ * - Single: Sets to expand only one Accordion item at a time.
290
+ * - Multiple: Sets to expand more than one Accordion item at a time.
291
+ * @default 'Multiple'
292
+ */
293
+ @Property('Multiple')
294
+ public expandMode: ExpandMode;
295
+ /**
296
+ * Specifies the animation configuration settings for expanding and collapsing the panel.
297
+ * @default { expand: { effect: 'SlideDown', duration: 400, easing: 'linear' },
298
+ * collapse: { effect: 'SlideUp', duration: 400, easing: 'linear' }}
299
+ */
300
+ @Complex<AccordionAnimationSettingsModel>({}, AccordionAnimationSettings)
301
+ public animation: AccordionAnimationSettingsModel;
302
+ /**
303
+ * The event will be fired while clicking anywhere within the Accordion.
304
+ * @event
305
+ * @blazorProperty 'Clicked'
306
+ */
307
+ @Event()
308
+ public clicked: EmitType<AccordionClickArgs>;
309
+ /**
310
+ * The event will be fired before the item gets collapsed/expanded.
311
+ * @event
312
+ * @blazorProperty 'Expanding'
313
+ */
314
+ @Event()
315
+ public expanding: EmitType<ExpandEventArgs>;
316
+ /**
317
+ * The event will be fired after the item gets collapsed/expanded.
318
+ * @event
319
+ * @blazorProperty 'Expanded'
320
+ */
321
+ @Event()
322
+ public expanded: EmitType<ExpandedEventArgs>;
323
+ /**
324
+ * The event will be fired once the control rendering is completed.
325
+ * @event
326
+ * @blazorProperty 'Created'
327
+ */
328
+ @Event()
329
+ public created: EmitType<Event>;
330
+ /**
331
+ * The event will be fired when the control gets destroyed.
332
+ * @event
333
+ * @blazorProperty 'Destroyed'
334
+ */
335
+ @Event()
336
+ public destroyed: EmitType<Event>;
337
+
338
+ /**
339
+ * Initializes a new instance of the Accordion class.
340
+ * @param options - Specifies Accordion model properties as options.
341
+ * @param element - Specifies the element that is rendered as an Accordion.
342
+ */
343
+ constructor(options?: AccordionModel, element?: string | HTMLElement) {
344
+ super(options, <HTEle | Str>element);
345
+ }
346
+ /**
347
+ * Removes the control from the DOM and also removes all its related events.
348
+ * @returns void
349
+ */
350
+ public destroy(): void {
351
+ let ele: HTEle = this.element;
352
+ super.destroy();
353
+ this.unwireEvents();
354
+ this.isDestroy = true;
355
+ this.restoreContent(null);
356
+ while (ele.firstElementChild) {
357
+ ele.removeChild(ele.firstElementChild); }
358
+ if (this.trgtEle) {
359
+ while (this.ctrlTem.firstElementChild) {
360
+ ele.appendChild(this.ctrlTem.firstElementChild); } }
361
+ ele.classList.remove(CLS_ACRDN_ROOT);
362
+ ele.removeAttribute('style');
363
+ ['aria-disabled', 'aria-multiselectable', 'role', 'data-ripple'].forEach((attrb: string): void => {
364
+ this.element.removeAttribute(attrb);
365
+ });
366
+ }
367
+ protected preRender(): void {
368
+ let nested: Element = closest(this.element, '.' + CLS_CONTENT);
369
+ this.isNested = false;
370
+ this.templateEle = [];
371
+ if (!this.isDestroy) {
372
+ this.isDestroy = false; }
373
+ if (!isNOU(nested)) {
374
+ nested.classList.add(CLS_NEST);
375
+ this.isNested = true;
376
+ } else {
377
+ this.element.classList.add(CLS_ACRDN_ROOT);
378
+ }
379
+ if (this.enableRtl) {
380
+ this.add(this.element, CLS_RTL);
381
+ }
382
+ if (!this.enablePersistence || isNOU(this.expandedItems)) {
383
+ this.expandedItems = []; }
384
+ }
385
+ private add(ele: HTEle, val: Str): void {
386
+ ele.classList.add(val);
387
+ }
388
+ private remove(ele: HTEle, val: Str): void {
389
+ ele.classList.remove(val);
390
+ }
391
+ /**
392
+ * To initialize the control rendering
393
+ * @private
394
+ */
395
+ protected render(): void {
396
+ this.initializeheaderTemplate();
397
+ this.initializeItemTemplate();
398
+ this.initialize();
399
+ this.renderControl();
400
+ this.wireEvents();
401
+ this.renderComplete();
402
+ }
403
+ private initialize(): void {
404
+ let width: Str = formatUnit(this.width);
405
+ let height: Str = formatUnit(this.height);
406
+ setStyle(this.element, {'width': width, 'height': height});
407
+ let ariaAttr: { [key: string]: Str } = {
408
+ 'aria-disabled': 'false', 'role': 'presentation', 'aria-multiselectable' : 'true'
409
+ };
410
+ if (this.expandedItems.length > 0 ) {
411
+ this.initExpand = this.expandedItems;
412
+ }
413
+ attributes(this.element, ariaAttr);
414
+ if (this.expandMode === 'Single') {
415
+ this.element.setAttribute('aria-multiselectable', 'false');
416
+ }
417
+ }
418
+ private renderControl(): void {
419
+ this.trgtEle = (this.element.children.length > 0) ? <HTEle>select('div', this.element) : null;
420
+ this.renderItems();
421
+ this.initItemExpand();
422
+ }
423
+ private unwireEvents(): void {
424
+ EventHandler.remove(this.element, 'click', this.clickHandler);
425
+ if (!isNOU(this.keyModule)) {
426
+ this.keyModule.destroy(); }
427
+ }
428
+ private wireEvents(): void {
429
+ EventHandler.add(this.element, 'click', this.clickHandler, this);
430
+ if (!this.isNested && !this.isDestroy) {
431
+ rippleEffect(this.element, { selector: '.' + CLS_HEADER}); }
432
+ if (!this.isNested) {
433
+ this.keyModule = new KeyboardEvents(
434
+ this.element,
435
+ {
436
+ keyAction: this.keyActionHandler.bind(this),
437
+ keyConfigs: this.keyConfigs,
438
+ eventName: 'keydown'
439
+ }); }
440
+ }
441
+ private templateParser(template: string): Function {
442
+ if (template) {
443
+ try {
444
+ if (document.querySelectorAll(template).length) {
445
+ return templateCompiler(document.querySelector(template).innerHTML.trim());
446
+ }
447
+ } catch (error) {
448
+ return templateCompiler(template);
449
+ }
450
+ }
451
+ return undefined;
452
+ }
453
+ private initializeheaderTemplate(): void {
454
+ if (this.headerTemplate) {
455
+ this.headerTemplateFn = this.templateParser(this.headerTemplate);
456
+ }
457
+ }
458
+ private initializeItemTemplate(): void {
459
+ if (this.itemTemplate) {
460
+ this.itemTemplateFn = this.templateParser(this.itemTemplate);
461
+ }
462
+ }
463
+ private getheaderTemplate(): Function {
464
+ return this.headerTemplateFn;
465
+ }
466
+ private getItemTemplate(): Function {
467
+ return this.itemTemplateFn;
468
+ }
469
+ private updateContentBlazorTemplate(item?: AccordionItemModel, index?: number): void {
470
+ if (this.itemTemplate && isBlazor() && !this.isStringTemplate) {
471
+ updateBlazorTemplate(this.element.id + '_itemTemplate', 'ItemTemplate', this, false);
472
+ }
473
+ if (item && item.content && isBlazor() && !this.isStringTemplate && item.content.indexOf('<div>Blazor') === 0) {
474
+ updateBlazorTemplate(this.element.id + index + '_content', 'ContentTemplate', item);
475
+ }
476
+ }
477
+ private updateHeaderBlazorTemplate(item?: AccordionItemModel, index?: number): void {
478
+ if (this.headerTemplate && isBlazor() && !this.isStringTemplate) {
479
+ updateBlazorTemplate(this.element.id + '_headerTemplate', 'HeaderTemplate', this, false);
480
+ }
481
+ if (item && item.header && isBlazor() && !this.isStringTemplate && item.header.indexOf('<div>Blazor') === 0) {
482
+ updateBlazorTemplate(this.element.id + index + '_header', 'HeaderTemplate', item);
483
+ }
484
+ }
485
+ private focusIn(e: FocusEvent): void {
486
+ (<HTEle>e.target).parentElement.classList.add(CLS_ITEMFOCUS);
487
+ }
488
+ private focusOut(e: FocusEvent): void {
489
+ (<HTEle>e.target).parentElement.classList.remove(CLS_ITEMFOCUS);
490
+ }
491
+ private ctrlTemplate(): void {
492
+ this.ctrlTem = <HTEle>this.element.cloneNode(true);
493
+ let innerEles: HTMLCollection;
494
+ let rootEle: HTMLElement = <HTMLElement>select('.' + CLS_CONTAINER, this.element);
495
+ if (rootEle) {
496
+ innerEles = rootEle.children as HTMLCollection;
497
+ } else {
498
+ innerEles = this.element.children as HTMLCollection;
499
+ }
500
+ let items: AccordionItemModel[] = [];
501
+ /* tslint:disable */
502
+ [].slice.call(innerEles).forEach((el: HTEle) => {
503
+ items.push({
504
+ header: (el.childElementCount > 0 && el.children[0]) ? (el.children[0]) as any : '' ,
505
+ content: (el.childElementCount > 1 && el.children[1]) ? (el.children[1]) as any : ''
506
+ });
507
+ el.parentNode.removeChild(el);
508
+ });
509
+ /* tslint:enable */
510
+ if (rootEle) {
511
+ this.element.removeChild(rootEle);
512
+ }
513
+ this.setProperties({ items: items }, true);
514
+ }
515
+ private toggleIconGenerate(): HTEle {
516
+ let tglIcon: HTEle = this.createElement('div', {className: CLS_TOOGLEICN});
517
+ let hdrColIcon: HTEle = this.createElement('span', {className: CLS_COLLAPSEICN });
518
+ tglIcon.appendChild(hdrColIcon);
519
+ return tglIcon;
520
+ }
521
+ private initItemExpand(): void {
522
+ let len: number = this.initExpand.length;
523
+ if (len === 0 ) {
524
+ return; }
525
+ if (this.expandMode === 'Single') {
526
+ this.expandItem(true, this.initExpand[len - 1]);
527
+ } else {
528
+ for (let i: number = 0; i < len; i++) {
529
+ this.expandItem(true, this.initExpand[i]); } }
530
+ }
531
+ private renderItems(): void {
532
+ let ele: HTEle = this.element;
533
+ let innerItem: HTEle;
534
+ let innerDataSourceItem: HTEle;
535
+ if (isNOU(this.initExpand)) {
536
+ this.initExpand = [];
537
+ }
538
+ if (!isNOU(this.trgtEle)) {
539
+ this.ctrlTemplate();
540
+ }
541
+ if (this.dataSource.length > 0) {
542
+ this.dataSource.forEach((item: object, index: number) => {
543
+ innerDataSourceItem = this.renderInnerItem(item, index);
544
+ ele.appendChild(innerDataSourceItem);
545
+ if (innerDataSourceItem.childElementCount > 0) {
546
+ EventHandler.add(innerDataSourceItem.querySelector('.' + CLS_HEADER), 'focus', this.focusIn, this);
547
+ EventHandler.add(innerDataSourceItem.querySelector('.' + CLS_HEADER), 'blur', this.focusOut, this);
548
+ }
549
+ });
550
+ this.updateHeaderBlazorTemplate();
551
+ } else {
552
+ let items: AccordionItem[] = <AccordionItem[]>this.items;
553
+ if (ele && items.length > 0) {
554
+ items.forEach((item: AccordionItem, index: number) => {
555
+ innerItem = this.renderInnerItem(item, index);
556
+ ele.appendChild(innerItem);
557
+ this.updateHeaderBlazorTemplate(item, index);
558
+ if (innerItem.childElementCount > 0) {
559
+ EventHandler.add(innerItem.querySelector('.' + CLS_HEADER), 'focus', this.focusIn, this);
560
+ EventHandler.add(innerItem.querySelector('.' + CLS_HEADER), 'blur', this.focusOut, this);
561
+ }
562
+ });
563
+ }
564
+ }
565
+ }
566
+ private clickHandler(e: Event): void {
567
+ let trgt: HTEle = <HTEle>e.target;
568
+ let items: Object[] = this.getItems();
569
+ let eventArgs: AccordionClickArgs = { };
570
+ let index: number;
571
+ let tglIcon: HTEle;
572
+ let acrdEle: HTEle = <HTEle>closest(trgt, '.' + CLS_ROOT);
573
+ if (acrdEle !== this.element) {
574
+ return; }
575
+ trgt.classList.add('e-target');
576
+ let acrdnItem: HTEle = <HTEle>closest(trgt, '.' + CLS_ITEM);
577
+ let acrdnHdr: HTEle = <HTEle>closest(trgt, '.' + CLS_HEADER);
578
+ let acrdnCtn: HTEle = <HTEle>closest(trgt, '.' + CLS_CONTENT);
579
+ if (acrdnItem && (isNOU(acrdnHdr) || isNOU(acrdnCtn))) {
580
+ acrdnHdr = <HTEle>acrdnItem.children[0];
581
+ acrdnCtn = <HTEle>acrdnItem.children[1]; }
582
+ if (acrdnHdr) {
583
+ tglIcon = <HTEle> select('.' + CLS_TOOGLEICN, acrdnHdr); }
584
+ let acrdnCtnItem: HTEle;
585
+ if (acrdnHdr) {
586
+ acrdnCtnItem = <HTEle>closest(acrdnHdr, '.' + CLS_ITEM); } else if (acrdnCtn) {
587
+ acrdnCtnItem = <HTEle>closest(acrdnCtn, '.' + CLS_ITEM); }
588
+ let acrdActive: HTEle[] = [];
589
+ index = this.getIndexByItem(acrdnItem);
590
+ if (acrdnCtnItem) {
591
+ eventArgs.item = items[this.getIndexByItem(acrdnCtnItem)]; }
592
+ eventArgs.originalEvent = e;
593
+ let ctnCheck: Boolean = !isNOU(tglIcon) && acrdnItem.childElementCount <= 1;
594
+ if (ctnCheck && (isNOU(acrdnCtn) || !isNOU(select('.' + CLS_HEADER + ' .' + CLS_TOOGLEICN, acrdnCtnItem )))) {
595
+ acrdnItem.appendChild(this.contentRendering(index));
596
+ this.updateContentBlazorTemplate(eventArgs.item, index);
597
+ this.ariaAttrUpdate(acrdnItem);
598
+ }
599
+ this.trigger('clicked', eventArgs);
600
+ let cntclkCheck: boolean = (acrdnCtn && !isNOU(select('.e-target', acrdnCtn)));
601
+ let inlineAcrdnSel: string = '.' + CLS_CONTENT + ' .' + CLS_ROOT;
602
+ let inlineEleAcrdn: boolean = acrdnCtn && !isNOU(select('.' + CLS_ROOT, acrdnCtn)) && isNOU(closest(trgt , inlineAcrdnSel )) ;
603
+ let nestContCheck: boolean = acrdnCtn && isNOU(select('.' + CLS_ROOT, acrdnCtn)) || !(closest(trgt , '.' + CLS_ROOT) === this.element);
604
+ cntclkCheck = cntclkCheck && (inlineEleAcrdn || nestContCheck);
605
+ trgt.classList.remove('e-target');
606
+ if (trgt.classList.contains(CLS_CONTENT) || trgt.classList.contains(CLS_CTENT) || cntclkCheck) {
607
+ return; }
608
+ let acrdcontainer: HTMLElement = <HTMLElement>this.element.querySelector('.' + CLS_CONTAINER);
609
+ let acrdnchild: HTMLCollection = (acrdcontainer) ? acrdcontainer.children : this.element.children;
610
+ [].slice.call(acrdnchild).forEach((el: HTEle) => {
611
+ if (el.classList.contains(CLS_ACTIVE)) { acrdActive.push(el); }
612
+ });
613
+ let acrdAniEle: HTEle[] = [].slice.call(this.element.querySelectorAll('.' + CLS_ITEM + ' [' + CLS_ANIMATE + ']'));
614
+ if (acrdAniEle.length > 0) {
615
+ for (let el of acrdAniEle) {
616
+ acrdActive.push(el.parentElement);
617
+ }
618
+ }
619
+ let sameContentCheck: boolean = acrdActive.indexOf(acrdnCtnItem) !== -1 && acrdnCtn.getAttribute('e-animate') === 'true';
620
+ let sameHeader: boolean = false;
621
+ if (!isNOU(acrdnItem) && !isNOU(acrdnHdr) ) {
622
+ let acrdnCtn: HTEle = <HTEle>select('.' + CLS_CONTENT, acrdnItem);
623
+ let acrdnRoot: HTEle = <HTEle>closest(acrdnItem, '.' + CLS_ACRDN_ROOT);
624
+ let expandState: HTEle = <HTEle>acrdnRoot.querySelector('.' + CLS_EXPANDSTATE);
625
+ if (isNOU(acrdnCtn) ) {
626
+ return; }
627
+ sameHeader = (expandState === acrdnItem);
628
+ if (isVisible(acrdnCtn) && (!sameContentCheck || acrdnCtnItem.classList.contains(CLS_SLCTED))) {
629
+ this.collapse(acrdnCtn);
630
+ } else {
631
+ if ((acrdActive.length > 0) && this.expandMode === 'Single' && !sameContentCheck) {
632
+ acrdActive.forEach( (el: HTEle) => {
633
+ this.collapse(<HTEle>select('.' + CLS_CONTENT, el));
634
+ el.classList.remove(CLS_EXPANDSTATE);
635
+ });
636
+ }
637
+ this.expand(acrdnCtn);
638
+ }
639
+ if (!isNOU(expandState) && !sameHeader ) {
640
+ expandState.classList.remove(CLS_EXPANDSTATE); }
641
+ }
642
+ }
643
+ private eleMoveFocus(action: Str, root: HTEle, trgt: HTEle): void {
644
+ let clst: HTEle;
645
+ let clstItem: HTEle = <HTEle>closest(trgt, '.' + CLS_ITEM);
646
+ if (trgt === root) {
647
+ clst = <HTEle>((action === 'moveUp' ? trgt.lastElementChild : trgt).querySelector('.' + CLS_HEADER));
648
+ } else if (trgt.classList.contains(CLS_HEADER)) {
649
+ clstItem = <HTEle>(action === 'moveUp' ? clstItem.previousElementSibling : clstItem.nextElementSibling );
650
+ if (clstItem) {
651
+ clst = <HTEle>select('.' + CLS_HEADER, clstItem);
652
+ }
653
+ }
654
+ if (clst) {
655
+ clst.focus();
656
+ }
657
+ }
658
+ private keyActionHandler(e: KeyboardEventArgs): void {
659
+ let trgt: HTEle = <HTEle>e.target;
660
+ let header: HTEle = <HTEle>closest(e.target as HTEle, CLS_HEADER);
661
+ if (isNOU(header) && !trgt.classList.contains(CLS_ROOT) && !trgt.classList.contains(CLS_HEADER)) {
662
+ return; }
663
+ let clst: HTEle;
664
+ let root: HTEle = this.element;
665
+ let content: HTEle;
666
+ switch (e.action) {
667
+ case 'moveUp':
668
+ this.eleMoveFocus(e.action, root, trgt);
669
+ break;
670
+ case 'moveDown':
671
+ this.eleMoveFocus(e.action, root, trgt);
672
+ break;
673
+ case 'space':
674
+ case 'enter':
675
+ content = trgt.nextElementSibling as HTEle;
676
+ if (!isNOU(content) && content.classList.contains(CLS_CONTENT)) {
677
+ if (content.getAttribute('e-animate') !== 'true') {
678
+ trgt.click(); }} else {
679
+ trgt.click();
680
+ }
681
+ break;
682
+ case 'home':
683
+ case 'end':
684
+ clst = e.action === 'home' ? <HTEle>root.firstElementChild.children[0] : <HTEle>root.lastElementChild.children[0];
685
+ clst.focus();
686
+ break;
687
+ }
688
+ }
689
+ private headerEleGenerate(): HTEle {
690
+ let header: HTEle = this.createElement('div', { className: CLS_HEADER, id: getUniqueID('acrdn_header') });
691
+ let items: Object[] = this.getItems();
692
+ let ariaAttr: { [key: string]: Str } = {
693
+ 'tabindex': '0', 'role': 'heading', 'aria-selected': 'false',
694
+ 'aria-disabled': 'false', 'aria-level': items.length.toString()
695
+ };
696
+ attributes(header, ariaAttr);
697
+ return header;
698
+ }
699
+ private renderInnerItem(item: AccordionItemModel, index: number): HTEle {
700
+ let innerEle: HTEle;
701
+ innerEle = this.createElement('div', { className: CLS_ITEM });
702
+ innerEle.id = getUniqueID('acrdn_item');
703
+ attributes(innerEle, { 'aria-expanded': 'false' });
704
+ if (this.headerTemplate) {
705
+ let ctnEle: HTEle = this.headerEleGenerate();
706
+ let hdrEle: HTEle = this.createElement('div', { className: CLS_HEADERCTN });
707
+ ctnEle.appendChild(hdrEle);
708
+ append(this.getheaderTemplate()(item, this, 'headerTemplate', this.element.id + '_headerTemplate', false), hdrEle);
709
+ innerEle.appendChild(ctnEle);
710
+ ctnEle.appendChild(this.toggleIconGenerate());
711
+ this.add(innerEle, CLS_SLCT);
712
+ return innerEle;
713
+ }
714
+ if (item.header && this.angularnativeCondiCheck(item, 'header')) {
715
+ let ctnEle: HTEle = this.headerEleGenerate();
716
+ let hdrEle: HTEle = this.createElement('div', { className: CLS_HEADERCTN});
717
+ ctnEle.appendChild(hdrEle);
718
+ ctnEle.appendChild(this.fetchElement(hdrEle, item.header, index, true));
719
+ innerEle.appendChild(ctnEle);
720
+ }
721
+ let hdr: HTEle = <HTEle>select('.' + CLS_HEADER, innerEle);
722
+ if (item.expanded && !isNOU(index) && (!this.enablePersistence)) {
723
+ if (this.initExpand.indexOf(index) === -1) {
724
+ this.initExpand.push(index); }
725
+ }
726
+ if (item.cssClass) {
727
+ let acrdnClass: string = item.cssClass;
728
+ let arcdnClassList: string[] = [];
729
+ arcdnClassList = acrdnClass.split(' ');
730
+ arcdnClassList.forEach((el: string): void => {
731
+ addClass([innerEle], el);
732
+ });
733
+ }
734
+ if (item.iconCss) {
735
+ let hdrIcnEle: HTEle = this.createElement('div', { className: CLS_HEADERICN });
736
+ let icon: HTEle = this.createElement('span', { className: item.iconCss + ' e-icons' });
737
+ hdrIcnEle.appendChild(icon);
738
+ if (isNOU(hdr)) {
739
+ hdr = this.headerEleGenerate();
740
+ hdr.appendChild(hdrIcnEle);
741
+ innerEle.appendChild(hdr);
742
+ } else {
743
+ hdr.insertBefore(hdrIcnEle, hdr.childNodes[0]); }
744
+ }
745
+ if (item.content && this.angularnativeCondiCheck(item, 'content')) {
746
+ let hdrIcon: HTEle = this.toggleIconGenerate();
747
+ if (isNOU(hdr)) {
748
+ hdr = this.headerEleGenerate();
749
+ innerEle.appendChild(hdr);
750
+ }
751
+ hdr.appendChild(hdrIcon);
752
+ this.add(innerEle, CLS_SLCT);
753
+ }
754
+ return innerEle;
755
+ }
756
+
757
+ private angularnativeCondiCheck(item: AccordionItemModel, prop: string): boolean {
758
+ let property: string = prop === 'content' ? item.content : item.header;
759
+ let content: AcrdnTemplateRef = (property as Object) as AcrdnTemplateRef;
760
+ if (this.isAngular && !isNOU(content.elementRef) ) {
761
+ let data: string = content.elementRef.nativeElement.data;
762
+ if (isNOU(data) || data === '' || (data.indexOf('bindings=') === -1) ) {
763
+ return true;
764
+ }
765
+ let parseddata: { [key: string]: string } = JSON.parse(content.elementRef.nativeElement.data.replace('bindings=', ''));
766
+ if (!isNOU(parseddata) && parseddata['ng-reflect-ng-if'] === 'false' ) {
767
+ return false;
768
+ } else {
769
+ return true;
770
+ }
771
+ } else {
772
+ return true;
773
+ }
774
+ }
775
+
776
+ private fetchElement(ele: HTEle, value: Str, index: number, isHeader: boolean): HTEle {
777
+ let templateFn: Function;
778
+ let temString: Str;
779
+ try {
780
+ if (document.querySelectorAll(value).length) {
781
+ let eleVal: HTEle = <HTEle>document.querySelector(value);
782
+ temString = eleVal.outerHTML.trim();
783
+ ele.appendChild(eleVal);
784
+ eleVal.style.display = '';
785
+ }
786
+ } catch (e) {
787
+ if (typeof (value) === 'string' && isBlazor() && value.indexOf('<div>Blazor') !== 0) {
788
+ ele.innerHTML = value;
789
+ /* tslint:disable */
790
+ } else if (!isNOU(this.trgtEle) && ((value as any) instanceof (HTMLElement))) {
791
+ ele.appendChild(value as any);
792
+ (<HTMLElement>ele.firstElementChild).style.display = '';
793
+ /* tslint:enable */
794
+ } else {
795
+ templateFn = templateCompiler(value);
796
+ }
797
+ }
798
+ let tempArray: HTEle[];
799
+ if (!isNOU(templateFn)) {
800
+ let templateProps: string;
801
+ if (ele.classList.contains(CLS_HEADERCTN)) {
802
+ templateProps = this.element.id + index + '_header';
803
+ } else if (ele.classList.contains(CLS_CTENT)) {
804
+ templateProps = this.element.id + index + '_content';
805
+ }
806
+ tempArray = templateFn({}, null, null, templateProps, this.isStringTemplate);
807
+ }
808
+ if (!isNOU(tempArray) && tempArray.length > 0 && !(isNOU(tempArray[0].tagName) && tempArray.length === 1) ) {
809
+ [].slice.call(tempArray).forEach((el: HTEle): void => {
810
+ if (!isNOU(el.tagName)) {
811
+ el.style.display = '';
812
+ }
813
+ ele.appendChild(el);
814
+ });
815
+ } else if (ele.childElementCount === 0) {
816
+ ele.innerHTML = value;
817
+ }
818
+ if (!isNOU(temString)) {
819
+ if (this.templateEle.indexOf(value) === -1) {
820
+ this.templateEle.push(value);
821
+ }
822
+ }
823
+ return ele;
824
+ }
825
+ private ariaAttrUpdate(itemEle: HTEle): void {
826
+ let header: Element = select('.' + CLS_HEADER, itemEle);
827
+ let content: Element = select('.' + CLS_CONTENT, itemEle);
828
+ header.setAttribute('aria-controls', content.id);
829
+ content.setAttribute('aria-labelledby', header.id);
830
+ content.setAttribute('role', 'definition');
831
+ }
832
+ private contentRendering(index: number): HTEle {
833
+ let itemcnt: HTEle = this.createElement('div', { className: CLS_CONTENT + ' ' + CLS_CTNHIDE, id: getUniqueID('acrdn_panel') });
834
+ attributes(itemcnt, { 'aria-hidden': 'true' });
835
+ let ctn: HTEle = this.createElement('div', { className: CLS_CTENT });
836
+ if (this.dataSource.length > 0) {
837
+ append(this.getItemTemplate()(this.dataSource[index], this, 'itemTemplate', this.element.id + '_itemTemplate', false), ctn);
838
+ itemcnt.appendChild(ctn);
839
+ } else {
840
+ itemcnt.appendChild(this.fetchElement(ctn, this.items[index].content, index, false));
841
+ }
842
+ return itemcnt;
843
+ }
844
+ private expand(trgt: HTEle): void {
845
+ let eventArgs: ExpandEventArgs;
846
+ let items: Object[] = this.getItems();
847
+ let trgtItemEle: HTEle = <HTEle>closest(trgt, '.' + CLS_ITEM);
848
+ if (isNOU(trgt) || (isVisible(trgt) && trgt.getAttribute('e-animate') !== 'true' ) || trgtItemEle.classList.contains(CLS_DISABLE)) {
849
+ return; }
850
+ let acrdnRoot: HTEle = <HTEle>closest(trgtItemEle, '.' + CLS_ACRDN_ROOT);
851
+ let expandState: HTEle = <HTEle>acrdnRoot.querySelector('.' + CLS_EXPANDSTATE);
852
+ let animation: AnimationModel = {
853
+ name: <Effect>this.animation.expand.effect,
854
+ duration: this.animation.expand.duration,
855
+ timingFunction: this.animation.expand.easing
856
+ };
857
+ let icon: HTEle = <HTEle>select('.' + CLS_TOOGLEICN, trgtItemEle).firstElementChild;
858
+ eventArgs = { element: trgtItemEle,
859
+ item: items[this.getIndexByItem(trgtItemEle)],
860
+ index: this.getIndexByItem(trgtItemEle),
861
+ content: trgtItemEle.querySelector('.' + CLS_CONTENT),
862
+ isExpanded: true };
863
+ let eff: string = animation.name;
864
+ this.trigger('expanding', eventArgs, (expandArgs: ExpandEventArgs) => {
865
+ if (!expandArgs.cancel) {
866
+ icon.classList.add(CLS_TOGANIMATE);
867
+ this.expandedItemsPush(trgtItemEle);
868
+ if (!isNOU(expandState)) {
869
+ expandState.classList.remove(CLS_EXPANDSTATE); }
870
+ trgtItemEle.classList.add(CLS_EXPANDSTATE);
871
+ if ((animation.name === <Effect>'None')) {
872
+ this.expandProgress('begin', icon, trgt, trgtItemEle, expandArgs);
873
+ this.expandProgress('end', icon, trgt, trgtItemEle, expandArgs);
874
+ } else {
875
+ this.expandAnimation(eff, icon, trgt, trgtItemEle, animation, expandArgs);
876
+ }
877
+ }
878
+ });
879
+ }
880
+ private expandAnimation (ef: Str, icn: HTEle, trgt: HTEle, trgtItemEle: HTEle, animate: AnimationModel, args: ExpandEventArgs ): void {
881
+ let height: number;
882
+ let trgtHgt: number;
883
+ this.lastActiveItemId = trgtItemEle.id;
884
+ if (ef === 'SlideDown') {
885
+ animate.begin = () => {
886
+ this.expandProgress('begin', icn, trgt, trgtItemEle, args);
887
+ trgt.style.position = 'absolute';
888
+ height = trgtItemEle.offsetHeight;
889
+ trgtHgt = trgt.offsetHeight;
890
+ trgt.style.maxHeight = (trgt.offsetHeight) + 'px';
891
+ trgtItemEle.style.maxHeight = '';
892
+ };
893
+ animate.progress = () => {
894
+ trgtItemEle.style.minHeight = (height + trgt.offsetHeight) + 'px';
895
+ };
896
+ animate.end = () => {
897
+ setStyle(trgt, { 'position': '', 'maxHeight': '' });
898
+ trgtItemEle.style.minHeight = '';
899
+ this.expandProgress('end', icn, trgt, trgtItemEle, args);
900
+ };
901
+ } else {
902
+ animate.begin = () => {
903
+ this.expandProgress('begin', icn, trgt, trgtItemEle, args); };
904
+ animate.end = () => {
905
+ this.expandProgress('end', icn, trgt, trgtItemEle, args); };
906
+ }
907
+ new Animation(animate).animate(trgt);
908
+ }
909
+ private expandProgress(progress: string, icon: HTEle, trgt: HTEle, trgtItemEle: HTEle, eventArgs: ExpandEventArgs ): void {
910
+ this.remove(trgt, CLS_CTNHIDE);
911
+ this.add(trgtItemEle, CLS_SLCTED);
912
+ this.add(icon , CLS_EXPANDICN);
913
+ if (progress === 'end') {
914
+ this.add(trgtItemEle, CLS_ACTIVE);
915
+ trgt.setAttribute('aria-hidden', 'false');
916
+ attributes (trgtItemEle, {'aria-expanded': 'true' });
917
+ attributes (trgt.previousElementSibling, { 'aria-selected': 'true'});
918
+ icon.classList.remove(CLS_TOGANIMATE);
919
+ this.trigger('expanded' , eventArgs);
920
+ }
921
+ }
922
+ private expandedItemsPush(item: HTEle): void {
923
+ let index: number = this.getIndexByItem(item);
924
+ if (this.expandedItems.indexOf(index) === -1) {
925
+ this.expandedItems.push (index); }
926
+ }
927
+ private getIndexByItem(item: HTEle): number {
928
+ let itemEle: HTEle[] = this.getItemElements();
929
+ return [].slice.call(itemEle).indexOf(item);
930
+ }
931
+ private getItemElements(): HTEle[] {
932
+ let itemEle: HTEle[] = [];
933
+ let itemCollection: HTMLCollection = this.element.children;
934
+ [].slice.call(itemCollection).forEach((el: HTEle) => {
935
+ if (el.classList.contains(CLS_ITEM)) { itemEle.push(el); }
936
+ });
937
+ return itemEle;
938
+ }
939
+ private expandedItemsPop(item: HTEle): void {
940
+ let index: number = this.getIndexByItem(item);
941
+ this.expandedItems.splice(this.expandedItems.indexOf(index), 1);
942
+ }
943
+ private collapse(trgt: HTEle): void {
944
+ let eventArgs: ExpandEventArgs;
945
+ let items: Object[] = this.getItems();
946
+ let trgtItemEle: HTEle = <HTEle>closest(trgt, '.' + CLS_ITEM);
947
+ if (isNOU(trgt) || !isVisible(trgt) || trgtItemEle.classList.contains(CLS_DISABLE)) { return; }
948
+ let animation: AnimationModel = {
949
+ name: <Effect>this.animation.collapse.effect,
950
+ duration: this.animation.collapse.duration,
951
+ timingFunction: this.animation.collapse.easing,
952
+ };
953
+ let icon: HTEle = <HTEle>select('.' + CLS_TOOGLEICN, trgtItemEle).firstElementChild;
954
+ eventArgs = { element: trgtItemEle,
955
+ item: items[this.getIndexByItem(trgtItemEle)],
956
+ index: this.getIndexByItem(trgtItemEle),
957
+ content: trgtItemEle.querySelector('.' + CLS_CONTENT),
958
+ isExpanded: false };
959
+ let eff: string = animation.name;
960
+ this.trigger('expanding', eventArgs, (expandArgs: ExpandEventArgs) => {
961
+ if (!expandArgs.cancel) {
962
+ this.expandedItemsPop(trgtItemEle);
963
+ trgtItemEle.classList.add(CLS_EXPANDSTATE);
964
+ icon.classList.add(CLS_TOGANIMATE);
965
+ if ((animation.name === <Effect>'None')) {
966
+ this.collapseProgress('begin', icon, trgt, trgtItemEle, expandArgs);
967
+ this.collapseProgress('end', icon, trgt, trgtItemEle, expandArgs);
968
+ } else {
969
+ this.collapseAnimation(eff, trgt, trgtItemEle, icon, animation, expandArgs);
970
+ }
971
+ }
972
+ });
973
+ }
974
+ private collapseAnimation (ef: Str, trgt: HTEle, trgtItEl: HTEle, icn: HTEle, animate: AnimationModel, args: ExpandEventArgs ): void {
975
+ let height: number;
976
+ let trgtHeight: number;
977
+ let itemHeight: number;
978
+ let remain: number;
979
+ this.lastActiveItemId = trgtItEl.id;
980
+ if (ef === 'SlideUp') {
981
+ animate.begin = () => {
982
+ itemHeight = trgtItEl.offsetHeight;
983
+ trgtItEl.style.minHeight = itemHeight + 'px';
984
+ trgt.style.position = 'absolute';
985
+ height = trgtItEl.offsetHeight;
986
+ trgtHeight = trgt.offsetHeight;
987
+ trgt.style.maxHeight = trgtHeight + 'px';
988
+ this.collapseProgress('begin', icn, trgt, trgtItEl, args);
989
+ };
990
+ animate.progress = () => {
991
+ remain = ((height - (trgtHeight - trgt.offsetHeight)));
992
+ if (remain < itemHeight) {
993
+ trgtItEl.style.minHeight = remain + 'px'; }
994
+ };
995
+ animate.end = () => {
996
+ trgt.style.display = 'none';
997
+ this.collapseProgress('end', icn, trgt, trgtItEl, args);
998
+ trgtItEl.style.minHeight = '';
999
+ setStyle(trgt, { 'position': '', 'maxHeight': '', 'display': '' });
1000
+ };
1001
+ } else {
1002
+ animate.begin = () => {
1003
+ this.collapseProgress('begin', icn, trgt, trgtItEl, args); };
1004
+ animate.end = () => {
1005
+ this.collapseProgress('end', icn, trgt, trgtItEl, args); };
1006
+ }
1007
+ new Animation(animate).animate(trgt);
1008
+ }
1009
+ private collapseProgress(progress: string, icon: HTEle, trgt: HTEle, trgtItemEle: HTEle, eventArgs: ExpandEventArgs ): void {
1010
+ this.remove(icon , CLS_EXPANDICN);
1011
+ this.remove(trgtItemEle, CLS_SLCTED);
1012
+ if (progress === 'end') {
1013
+ this.add(trgt, CLS_CTNHIDE);
1014
+ icon.classList.remove(CLS_TOGANIMATE);
1015
+ this.remove(trgtItemEle, CLS_ACTIVE);
1016
+ trgt.setAttribute('aria-hidden', 'true');
1017
+ attributes (trgtItemEle, {'aria-expanded': 'false' });
1018
+ attributes (trgt.previousElementSibling, { 'aria-selected': 'false'});
1019
+ this.trigger('expanded' , eventArgs);
1020
+ }
1021
+ }
1022
+ /**
1023
+ * Returns the current module name.
1024
+ * @returns string
1025
+ * @private
1026
+ */
1027
+ protected getModuleName(): string {
1028
+ return 'accordion';
1029
+ }
1030
+ private itemAttribUpdate(): void {
1031
+ let items: Object[] = this.getItems();
1032
+ let itemEle: HTEle[] = this.getItemElements();
1033
+ let itemLen: number = items.length;
1034
+ itemEle.forEach((ele: HTEle): void => {
1035
+ select('.' + CLS_HEADER, ele).setAttribute('aria-level', '' + itemLen);
1036
+ });
1037
+ }
1038
+ private getItems(): Object[] {
1039
+ let items: AccordionItemModel[] | Object[];
1040
+ if (this.itemTemplate && this.headerTemplate) {
1041
+ items = this.dataSource;
1042
+ } else {
1043
+ items = this.items;
1044
+ }
1045
+ return items;
1046
+ }
1047
+ /**
1048
+ * Adds new item to the Accordion with the specified index of the Accordion.
1049
+ * @param {AccordionItemModel | Object} item - Item array that is to be added to the Accordion.
1050
+ * @param {number} index - Number value that determines where the item should be added.
1051
+ * By default, item is added at the last index if the index is not specified.
1052
+ * @returns void
1053
+ */
1054
+ public addItem (item: AccordionItemModel | Object, index?: number): void {
1055
+ let ele: HTEle = this.element;
1056
+ let itemEle: HTEle[] = this.getItemElements();
1057
+ let items: Object[] = this.getItems();
1058
+ if (isNOU(index)) {
1059
+ index = items.length; }
1060
+ if (ele.childElementCount >= index) {
1061
+ items.splice(index, 0, item);
1062
+ let innerItemEle: HTEle = this.renderInnerItem(item, index);
1063
+ if (ele.childElementCount === index) {
1064
+ ele.appendChild(innerItemEle);
1065
+ } else {
1066
+ ele.insertBefore(innerItemEle, itemEle[index]);
1067
+ }
1068
+ this.updateHeaderBlazorTemplate();
1069
+ EventHandler.add(innerItemEle.querySelector('.' + CLS_HEADER), 'focus', this.focusIn, this);
1070
+ EventHandler.add(innerItemEle.querySelector('.' + CLS_HEADER), 'blur', this.focusOut, this);
1071
+ this.itemAttribUpdate();
1072
+ }
1073
+ this.expandedItems = [];
1074
+ this.expandedItemRefresh(ele);
1075
+ if (item && (item as AccordionItemModel).expanded) {
1076
+ this.expandItem(true, index);
1077
+ }
1078
+ }
1079
+ private expandedItemRefresh(ele: HTEle): void {
1080
+ let itemEle: HTEle[] = this.getItemElements();
1081
+ [].slice.call(itemEle).forEach( (el: HTEle) => {
1082
+ if (el.classList.contains(CLS_SLCTED)) {
1083
+ this.expandedItemsPush(el);
1084
+ }
1085
+ });
1086
+ }
1087
+ /**
1088
+ * Dynamically removes item from Accordion.
1089
+ * @param {number} index - Number value that determines which item should be removed.
1090
+ * @returns void.
1091
+ */
1092
+ public removeItem(index: number): void {
1093
+ let itemEle: HTEle[] = this.getItemElements();
1094
+ let ele: HTEle = <HTEle>itemEle[index];
1095
+ let items: Object[] = this.getItems();
1096
+ if (isNOU(ele)) { return; }
1097
+ this.restoreContent(index);
1098
+ detach(ele);
1099
+ items.splice(index, 1);
1100
+ this.itemAttribUpdate();
1101
+ this.expandedItems = [];
1102
+ this.expandedItemRefresh(this.element);
1103
+ }
1104
+ /**
1105
+ * Sets focus to the specified index item header in Accordion.
1106
+ * @param {number} index - Number value that determines which item should be focused.
1107
+ * @returns void.
1108
+ */
1109
+ public select(index: number): void {
1110
+ let itemEle: HTEle[] = this.getItemElements();
1111
+ let ele: HTEle = <HTEle>itemEle[index];
1112
+ if (isNOU(ele) || isNOU(select('.' + CLS_HEADER, ele))) {
1113
+ return; }
1114
+ (<HTEle>ele.children[0]).focus();
1115
+ }
1116
+ /**
1117
+ * Shows or hides the specified item from Accordion.
1118
+ * @param {number} index - Number value that determines which item should be hidden/shown.
1119
+ * @param {Boolean} isHidden - Boolean value that determines the action either hide (true) or show (false). Default value is false.
1120
+ * If the `isHidden` value is false, the item is shown or else item it is hidden.
1121
+ * @returns void.
1122
+ */
1123
+ public hideItem(index: number, isHidden?: Boolean): void {
1124
+ let itemEle: HTEle[] = this.getItemElements();
1125
+ let ele: HTEle = <HTEle>itemEle[index];
1126
+ if (isNOU(ele)) {
1127
+ return; }
1128
+ if (isNOU(isHidden)) {
1129
+ isHidden = true; }
1130
+ isHidden ? this.add(ele, CLS_ITEMHIDE ) : this.remove(ele, CLS_ITEMHIDE );
1131
+ }
1132
+ /**
1133
+ * Enables/Disables the specified Accordion item.
1134
+ * @param {number} index - Number value that determines which item should be enabled/disabled.
1135
+ * @param {boolean} isEnable - Boolean value that determines the action as enable (true) or disable (false).
1136
+ * If the `isEnable` value is true, the item is enabled or else it is disabled.
1137
+ * @returns void.
1138
+ */
1139
+ public enableItem(index: number, isEnable: boolean): void {
1140
+ let itemEle: HTEle[] = this.getItemElements();
1141
+ let ele: HTEle = <HTEle>itemEle[index];
1142
+ if (isNOU(ele)) {
1143
+ return; }
1144
+ let eleHeader: HTEle = <HTEle>ele.firstElementChild;
1145
+ if (isEnable) {
1146
+ this.remove(ele, CLS_DISABLE );
1147
+ attributes(eleHeader, {'tabindex': '0', 'aria-disabled': 'false'});
1148
+ eleHeader.focus();
1149
+ } else {
1150
+ if (ele.classList.contains(CLS_ACTIVE)) {
1151
+ this.expandItem(false, index);
1152
+ this.eleMoveFocus('movedown', this.element, eleHeader); }
1153
+ this.add(ele, CLS_DISABLE );
1154
+ eleHeader.setAttribute('aria-disabled', 'true');
1155
+ eleHeader.removeAttribute('tabindex');
1156
+ }
1157
+ }
1158
+ /**
1159
+ * Expands/Collapses the specified Accordion item.
1160
+ * @param {boolean} isExpand - Boolean value that determines the action as expand or collapse.
1161
+ * @param {number} index - Number value that determines which item should be expanded/collapsed.`index` is optional parameter.
1162
+ * Without Specifying index, based on the `isExpand` value all Accordion item can be expanded or collapsed.
1163
+ * @returns void.
1164
+ */
1165
+ public expandItem(isExpand: boolean, index?: number): void {
1166
+ let root: HTEle = this.element;
1167
+ let itemEle: HTEle[] = this.getItemElements();
1168
+ if (isNOU(index)) {
1169
+ if (this.expandMode === 'Single' && isExpand) {
1170
+ let ele: HTEle = <HTEle>itemEle[itemEle.length - 1];
1171
+ this.itemExpand(isExpand, ele, this.getIndexByItem(ele));
1172
+ } else {
1173
+ let item: HTMLElement = <HTMLElement>select('#' + this.lastActiveItemId, this.element);
1174
+ [].slice.call(itemEle).forEach( (el: HTEle) => {
1175
+ this.itemExpand(isExpand, el, this.getIndexByItem(el));
1176
+ el.classList.remove(CLS_EXPANDSTATE);
1177
+ });
1178
+ let expandedItem: Element = select('.' + CLS_EXPANDSTATE, this.element);
1179
+ if (expandedItem) { expandedItem.classList.remove(CLS_EXPANDSTATE); }
1180
+ if (item) { item.classList.add(CLS_EXPANDSTATE); }
1181
+ }
1182
+ } else {
1183
+ let ele: HTEle = <HTEle>itemEle[index];
1184
+ if (isNOU(ele) || !ele.classList.contains(CLS_SLCT) || (ele.classList.contains(CLS_ACTIVE) && isExpand)) {
1185
+ return; } else {
1186
+ if (this.expandMode === 'Single') {
1187
+ this.expandItem(false); }
1188
+ this.itemExpand(isExpand, ele, index);
1189
+ }
1190
+ }
1191
+ }
1192
+ private itemExpand(isExpand: Boolean , ele: HTEle, index: number): void {
1193
+ let ctn: HTEle = <HTEle>ele.children[1];
1194
+ let items: Object[] = this.getItems();
1195
+ if (ele.classList.contains(CLS_DISABLE)) {
1196
+ return; }
1197
+ if (isNOU(ctn) && isExpand) {
1198
+ ctn = this.contentRendering(index);
1199
+ ele.appendChild(ctn);
1200
+ this.updateContentBlazorTemplate(items[index], index);
1201
+ this.ariaAttrUpdate(ele);
1202
+ } else if (isNOU(ctn)) {
1203
+ return;
1204
+ }
1205
+ isExpand ? this.expand(ctn) : this.collapse(ctn);
1206
+ }
1207
+ private destroyItems(): void {
1208
+ this.restoreContent(null);
1209
+ [].slice.call(this.element.querySelectorAll('.' + CLS_ITEM)).forEach ((el: HTEle) => {
1210
+ detach(el); });
1211
+ }
1212
+ private restoreContent(index: number): void {
1213
+ let ctnElePos: HTMLElement;
1214
+ if (isNOU(index)) { ctnElePos = this.element;
1215
+ } else {
1216
+ ctnElePos = <HTMLElement> this.element.querySelectorAll('.' + CLS_ITEM)[index];
1217
+ }
1218
+ this.templateEle.forEach((eleStr: Str): void => {
1219
+ if (!isNOU(ctnElePos.querySelector(eleStr))) {
1220
+ (<HTEle>document.body.appendChild(ctnElePos.querySelector(eleStr))).style.display = 'none'; }
1221
+ });
1222
+ }
1223
+ private updateItem(item: HTEle, index: number): void {
1224
+ if (!isNOU(item)) {
1225
+ let items: Object[] = this.getItems();
1226
+ let itemObj: Object = items[index];
1227
+ items.splice(index, 1);
1228
+ this.restoreContent(index);
1229
+ detach(item);
1230
+ this.addItem(itemObj, index);
1231
+ }
1232
+ }
1233
+ protected getPersistData(): string {
1234
+ let keyEntity: string[] = ['expandedItems'];
1235
+ return this.addOnPersist(keyEntity);
1236
+ }
1237
+ /**
1238
+ * Gets called when the model property changes.The data that describes the old and new values of the property that changed.
1239
+ * @param {AccordionModel} newProp
1240
+ * @param {AccordionModel} oldProp
1241
+ * @returns void
1242
+ * @private
1243
+ */
1244
+ public onPropertyChanged(newProp: AccordionModel, oldProp: AccordionModel): void {
1245
+ let acrdn: HTEle = this.element;
1246
+ let isRefresh: boolean = false;
1247
+ for (let prop of Object.keys(newProp)) {
1248
+ switch (prop) {
1249
+ case 'items':
1250
+ if (!(newProp.items instanceof Array && oldProp.items instanceof Array)) {
1251
+ let changedProp: Object[] = Object.keys(newProp.items);
1252
+ for (let j: number = 0; j < changedProp.length; j++) {
1253
+ let index: number = parseInt(Object.keys(newProp.items)[j], 10);
1254
+ let property: Str = Object.keys(newProp.items[index])[0];
1255
+ let item: HTEle = <HTEle> selectAll('.' + CLS_ITEM, this.element)[index];
1256
+ let oldVal: Str = Object(oldProp.items[index])[property];
1257
+ let newVal: Str = Object(newProp.items[index])[property];
1258
+ let temp: Str = property;
1259
+ if (temp === 'header' || temp === 'iconCss' || temp === 'expanded' || ((temp === 'content') && (oldVal === ''))) {
1260
+ this.updateItem(item, index);
1261
+ }
1262
+ if (property === 'cssClass' && !isNOU(item)) {
1263
+ item.classList.remove(oldVal);
1264
+ item.classList.add(newVal);
1265
+ }
1266
+ if (property === 'content' && !isNOU(item) && item.children.length === 2) {
1267
+ if (item.classList.contains(CLS_SLCTED)) { this.expandItem(false, index); }
1268
+ detach(item.querySelector('.' + CLS_CONTENT));
1269
+ }
1270
+ }
1271
+ } else {
1272
+ isRefresh = true;
1273
+ }
1274
+ break;
1275
+ case 'dataSource':
1276
+ isRefresh = true;
1277
+ break;
1278
+ case 'headerTemplate':
1279
+ this.initializeheaderTemplate();
1280
+ isRefresh = true;
1281
+ break;
1282
+ case 'itemTemplate':
1283
+ this.initializeItemTemplate();
1284
+ isRefresh = true;
1285
+ break;
1286
+ case 'enableRtl':
1287
+ newProp.enableRtl ? this.add(acrdn, CLS_RTL) : this.remove(acrdn, CLS_RTL);
1288
+ break;
1289
+ case 'height':
1290
+ setStyle(this.element, { 'height': formatUnit(newProp.height) });
1291
+ break;
1292
+ case 'width':
1293
+ setStyle(this.element, { 'width': formatUnit(newProp.width) });
1294
+ break;
1295
+ case 'expandMode':
1296
+ if (newProp.expandMode === 'Single') {
1297
+ this.element.setAttribute('aria-multiselectable', 'false');
1298
+ if (this.expandedItems.length > 1) {
1299
+ this.expandItem(false); }
1300
+ } else {
1301
+ this.element.setAttribute('aria-multiselectable', 'true');
1302
+ }
1303
+ break;
1304
+ }
1305
+ }
1306
+ if (isRefresh) {
1307
+ this.destroyItems();
1308
+ this.renderItems();
1309
+ this.initItemExpand();
1310
+ }
1311
+ }
1312
+ }