@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,1761 @@
1
+ import { Component, Property, Event, EmitType, closest, Collection, Complex, attributes, detach, Instance } from '@syncfusion/ej2-base';
2
+ import { INotifyPropertyChanged, NotifyPropertyChanges, ChildProperty, AnimationOptions, select, isVisible } from '@syncfusion/ej2-base';
3
+ import { KeyboardEvents, KeyboardEventArgs, MouseEventArgs, Effect, Browser, formatUnit, DomElements, L10n } from '@syncfusion/ej2-base';
4
+ import { setStyleAttribute as setStyle, isNullOrUndefined as isNOU, selectAll, addClass, removeClass, remove } from '@syncfusion/ej2-base';
5
+ import { EventHandler, rippleEffect, Touch, SwipeEventArgs, compile, Animation, AnimationModel, BaseEventArgs } from '@syncfusion/ej2-base';
6
+ import { updateBlazorTemplate, resetBlazorTemplate, isBlazor, getRandomId } from '@syncfusion/ej2-base';
7
+ import { Popup, PopupModel } from '@syncfusion/ej2-popups';
8
+ import { Toolbar, OverflowMode, ClickEventArgs } from '../toolbar/toolbar';
9
+ import { TabModel, TabItemModel, HeaderModel, TabActionSettingsModel, TabAnimationSettingsModel } from './tab-model';
10
+
11
+ type HTEle = HTMLElement;
12
+ type Str = string;
13
+
14
+ /**
15
+ * Options to set the orientation of Tab header.
16
+ */
17
+ export type HeaderPosition = 'Top' | 'Bottom' | 'Left' | 'Right';
18
+ /**
19
+ * Options to set the content element height adjust modes.
20
+ */
21
+ export type HeightStyles = 'None' | 'Auto' | 'Content' | 'Fill';
22
+
23
+ const CLS_TAB: string = 'e-tab';
24
+ const CLS_HEADER: string = 'e-tab-header';
25
+ const CLS_BLA_TEM: string = 'blazor-template';
26
+ const CLS_CONTENT: string = 'e-content';
27
+ const CLS_NEST: string = 'e-nested';
28
+ const CLS_ITEMS: string = 'e-items';
29
+ const CLS_ITEM: string = 'e-item';
30
+ const CLS_TEMPLATE: string = 'e-template';
31
+ const CLS_RTL: string = 'e-rtl';
32
+ const CLS_ACTIVE: string = 'e-active';
33
+ const CLS_DISABLE: string = 'e-disable';
34
+ const CLS_HIDDEN: string = 'e-hidden';
35
+ const CLS_FOCUS: string = 'e-focused';
36
+ const CLS_ICONS: string = 'e-icons';
37
+ const CLS_ICON: string = 'e-icon';
38
+ const CLS_ICON_TAB: string = 'e-icon-tab';
39
+ const CLS_ICON_CLOSE: string = 'e-close-icon';
40
+ const CLS_CLOSE_SHOW: string = 'e-close-show';
41
+ const CLS_TEXT: string = 'e-tab-text';
42
+ const CLS_INDICATOR: string = 'e-indicator';
43
+ const CLS_WRAP: string = 'e-tab-wrap';
44
+ const CLS_TEXT_WRAP: string = 'e-text-wrap';
45
+ const CLS_TAB_ICON: string = 'e-tab-icon';
46
+ const CLS_TB_ITEMS: string = 'e-toolbar-items';
47
+ const CLS_TB_ITEM: string = 'e-toolbar-item';
48
+ const CLS_TB_POP: string = 'e-toolbar-pop';
49
+ const CLS_TB_POPUP: string = 'e-toolbar-popup';
50
+ const CLS_HOR_NAV: string = 'e-hor-nav';
51
+ const CLS_POPUP_OPEN: string = 'e-popup-open';
52
+ const CLS_POPUP_CLOSE: string = 'e-popup-close';
53
+ const CLS_PROGRESS: string = 'e-progress';
54
+ const CLS_IGNORE: string = 'e-ignore';
55
+ const CLS_OVERLAY: string = 'e-overlay';
56
+ const CLS_HSCRCNT: string = 'e-hscroll-content';
57
+ const CLS_VSCRCNT: string = 'e-vscroll-content';
58
+ const CLS_HORIZONTAL: string = 'e-horizontal';
59
+ const CLS_VTAB: string = 'e-vertical-tab';
60
+ const CLS_VERTICAL: string = 'e-vertical';
61
+ const CLS_VLEFT: string = 'e-vertical-left';
62
+ const CLS_VRIGHT: string = 'e-vertical-right';
63
+ const CLS_HBOTTOM: string = 'e-horizontal-bottom';
64
+ const CLS_FILL: string = 'e-fill-mode';
65
+
66
+ export interface SelectEventArgs extends BaseEventArgs {
67
+ /** Defines the previous Tab item element. */
68
+ previousItem: HTMLElement;
69
+ /** Defines the previous Tab item index. */
70
+ previousIndex: number;
71
+ /** Defines the selected Tab item element. */
72
+ selectedItem: HTMLElement;
73
+ /** Defines the selected Tab item index. */
74
+ selectedIndex: number;
75
+ /** Defines the content selection done through swiping. */
76
+ isSwiped: boolean;
77
+ /** Defines the prevent action. */
78
+ cancel?: boolean;
79
+ /** Defines the selected content. */
80
+ selectedContent: HTMLElement;
81
+ }
82
+ export interface SelectingEventArgs extends SelectEventArgs {
83
+ /** Defines the selecting Tab item element. */
84
+ selectingItem: HTMLElement;
85
+ /** Defines the selecting Tab item index. */
86
+ selectingIndex: number;
87
+ /** Defines the selecting Tab item content. */
88
+ selectingContent: HTMLElement;
89
+ }
90
+ export interface RemoveEventArgs extends BaseEventArgs {
91
+ /** Defines the removed Tab item element. */
92
+ removedItem: HTMLElement;
93
+ /** Defines the removed Tab item index. */
94
+ removedIndex: number;
95
+ /** Defines the prevent action. */
96
+ cancel?: boolean;
97
+ }
98
+ export interface AddEventArgs extends BaseEventArgs {
99
+ /** Defines the added Tab item element */
100
+ addedItems: TabItemModel[];
101
+ /** Defines the prevent action. */
102
+ cancel?: boolean;
103
+ }
104
+ export class TabActionSettings extends ChildProperty<TabActionSettings> {
105
+ /**
106
+ * Specifies the animation effect for displaying Tab content.
107
+ * @default 'SlideLeftIn'
108
+ * @aspType string
109
+ * @blazorType string
110
+ */
111
+ @Property('SlideLeftIn')
112
+ public effect: 'None' | Effect;
113
+ /**
114
+ * Specifies the time duration to transform content.
115
+ * @default 600
116
+ */
117
+ @Property(600)
118
+ public duration: number;
119
+ /**
120
+ * Specifies easing effect applied while transforming content.
121
+ * @default 'ease'
122
+ */
123
+ @Property('ease')
124
+ public easing: string;
125
+ }
126
+ export class TabAnimationSettings extends ChildProperty<TabAnimationSettings> {
127
+ /**
128
+ * Specifies the animation to appear while moving to previous Tab content.
129
+ * @default { effect: 'SlideLeftIn', duration: 600, easing: 'ease' }
130
+ */
131
+ @Complex<TabActionSettingsModel>({ effect: 'SlideLeftIn', duration: 600, easing: 'ease' }, TabActionSettings)
132
+ public previous: TabActionSettingsModel;
133
+ /**
134
+ * Specifies the animation to appear while moving to next Tab content.
135
+ * @default { effect: 'SlideRightIn', duration: 600, easing: 'ease' }
136
+ */
137
+ @Complex<TabActionSettingsModel>({ effect: 'SlideRightIn', duration: 600, easing: 'ease' }, TabActionSettings)
138
+ public next: TabActionSettingsModel;
139
+ }
140
+ /**
141
+ * Objects used for configuring the Tab item header properties.
142
+ */
143
+ export class Header extends ChildProperty<Header> {
144
+ /**
145
+ * Specifies the display text of the Tab item header.
146
+ * @default ''
147
+ */
148
+ @Property('')
149
+ public text: string | HTMLElement;
150
+ /**
151
+ * Specifies the icon class that is used to render an icon in the Tab header.
152
+ * @default ''
153
+ */
154
+ @Property('')
155
+ public iconCss: string;
156
+ /**
157
+ * Options for positioning the icon in the Tab item header. This property depends on `iconCss` property.
158
+ * The possible values are:
159
+ * - Left: Places the icon to the `left` of the item.
160
+ * - Top: Places the icon on the `top` of the item.
161
+ * - Right: Places the icon to the `right` end of the item.
162
+ * - Bottom: Places the icon at the `bottom` of the item.
163
+ * @default 'left'
164
+ */
165
+ @Property('left')
166
+ public iconPosition: string;
167
+ }
168
+ /**
169
+ * An array of object that is used to configure the Tab.
170
+ */
171
+ export class TabItem extends ChildProperty<TabItem> {
172
+ /**
173
+ * The object used for configuring the Tab item header properties.
174
+ * @default {}
175
+ */
176
+ @Complex<HeaderModel>({}, Header)
177
+ public header: HeaderModel;
178
+ /**
179
+ * Specifies the header text of Tab item.
180
+ * @default null
181
+ */
182
+ @Property(null)
183
+ public headerTemplate: string;
184
+ /**
185
+ * Specifies the content of Tab item, that is displayed when concern item header is selected.
186
+ * @default ''
187
+ */
188
+ @Property('')
189
+ public content: string | HTMLElement;
190
+ /**
191
+ * Sets the CSS classes to the Tab item to customize its styles.
192
+ * @default ''
193
+ */
194
+ @Property('')
195
+ public cssClass: string;
196
+ /**
197
+ * Sets true to disable user interactions of the Tab item.
198
+ * @default false
199
+ */
200
+ @Property(false)
201
+ public disabled: boolean;
202
+ }
203
+ /**
204
+ * Tab is a content panel to show multiple contents in a single space, one at a time.
205
+ * Each Tab item has an associated content, that will be displayed based on the active Tab header item.
206
+ * ```html
207
+ * <div id="tab"></div>
208
+ * <script>
209
+ * var tabObj = new Tab();
210
+ * tab.appendTo("#tab");
211
+ * </script>
212
+ * ```
213
+ */
214
+ @NotifyPropertyChanges
215
+ export class Tab extends Component<HTMLElement> implements INotifyPropertyChanged {
216
+ private hdrEle: HTEle;
217
+ private cntEle: HTEle;
218
+ private tbObj: Toolbar;
219
+ public tabId: string;
220
+ private tbItems: HTEle;
221
+ private tbItem: HTEle[];
222
+ private tbPop: HTEle;
223
+ private isTemplate: boolean;
224
+ private isPopup: boolean;
225
+ private isReplace: boolean;
226
+ private prevIndex: number;
227
+ private prevItem: HTEle;
228
+ private popEle: DomElements;
229
+ private actEleId: string;
230
+ private bdrLine: HTEle;
231
+ private popObj: Popup;
232
+ private btnCls: HTEle;
233
+ private cnt: string;
234
+ private show: object = {};
235
+ private hide: object = {};
236
+ private enableAnimation: boolean;
237
+ private keyModule: KeyboardEvents;
238
+ private tabKeyModule: KeyboardEvents;
239
+ private touchModule: Touch;
240
+ private animateOptions: AnimationOptions = {};
241
+ private animObj: Animation = new Animation(this.animateOptions);
242
+ private maxHeight: number = 0;
243
+ private title: Str = 'Close';
244
+ private initRender: boolean;
245
+ private prevActiveEle: string;
246
+ private lastIndex: number = 0;
247
+ private isSwipeed: boolean;
248
+ private isNested: boolean;
249
+ private itemIndexArray: string[];
250
+ private templateEle: string[];
251
+ private scrCntClass: string;
252
+ private isAdd: boolean = false;
253
+ private content: HTEle;
254
+ private selectedID: string;
255
+ private selectingID: string;
256
+ private isIconAlone: boolean = false;
257
+ private resizeContext: EventListenerObject = this.refreshActElePosition.bind(this);
258
+ /**
259
+ * Contains the keyboard configuration of the Tab.
260
+ */
261
+ private keyConfigs: { [key: string]: Str } = {
262
+ tab: 'tab',
263
+ home: 'home',
264
+ end: 'end',
265
+ enter: 'enter',
266
+ space: 'space',
267
+ delete: 'delete',
268
+ moveLeft: 'leftarrow',
269
+ moveRight: 'rightarrow',
270
+ moveUp: 'uparrow',
271
+ moveDown: 'downarrow'
272
+ };
273
+ /**
274
+ * An array of object that is used to configure the Tab component.
275
+ * ```typescript
276
+ * let tabObj: Tab = new Tab( {
277
+ * items: [
278
+ * { header: { text: 'TabItem1' }, content: 'Tab Item1 Content' },
279
+ * { header: { text: 'TabItem2' }, content: 'Tab Item2 Content' }
280
+ * ]
281
+ * });
282
+ * tabObj.appendTo('#tab');
283
+ * ```
284
+ * @default []
285
+ */
286
+ @Collection<TabItemModel>([], TabItem)
287
+ public items: TabItemModel[];
288
+ /**
289
+ * Specifies the width of the Tab component. Default, Tab width sets based on the width of its parent.
290
+ * @default '100%'
291
+ */
292
+ @Property('100%')
293
+ public width: string | number;
294
+ /**
295
+ * Specifies the height of the Tab component. By default, Tab height is set based on the height of its parent.
296
+ * To use height property, heightAdjustMode must be set to 'None'.
297
+ * @default 'auto'
298
+ */
299
+ @Property('auto')
300
+ public height: string | number;
301
+ /**
302
+ * Sets the CSS classes to root element of the Tab that helps to customize component styles.
303
+ * @default ''
304
+ */
305
+ @Property('')
306
+ public cssClass: string;
307
+ /**
308
+ * Specifies the index for activating the current Tab item.
309
+ * ```typescript
310
+ * let tabObj: Tab = new Tab( {
311
+ * selectedItem: 1,
312
+ * items: [
313
+ * { header: { text: 'TabItem1' }, content: 'Tab Item1 Content' },
314
+ * { header: { text: 'TabItem2' }, content: 'Tab Item2 Content' }
315
+ * ]
316
+ * });
317
+ * tabObj.appendTo('#tab');
318
+ * ```
319
+ * @default 0
320
+ */
321
+ @Property(0)
322
+ public selectedItem: number;
323
+ /**
324
+ * Specifies the orientation of Tab header.
325
+ * The possible values are:
326
+ * - Top: Places the Tab header on the top.
327
+ * - Bottom: Places the Tab header at the bottom.
328
+ * - Left: Places the Tab header on the left.
329
+ * - Right: Places the Tab header at the right.
330
+ * @default 'Top'
331
+ */
332
+ @Property('Top')
333
+ public headerPlacement: HeaderPosition;
334
+ /**
335
+ * Specifies the height style for Tab content.
336
+ * The possible values are:
337
+ * - None: Based on the given height property, the content panel height is set.
338
+ * - Auto: Tallest panel height of a given Tab content is set to all the other panels.
339
+ * - Content: Based on the corresponding content height, the content panel height is set.
340
+ * - Fill: Based on the parent height, the content panel height is set.
341
+ * @default 'Content'
342
+ */
343
+ @Property('Content')
344
+ public heightAdjustMode: HeightStyles;
345
+ /**
346
+ * Specifies the Tab display mode when Tab content exceeds the viewing area.
347
+ * The possible modes are:
348
+ * - Scrollable: All the elements are displayed in a single line with horizontal scrolling enabled.
349
+ * - Popup: Tab container holds the items that can be placed within the available space and rest of the items are moved to the popup.
350
+ * If the popup content overflows the height of the page, the rest of the elements can be viewed by scrolling the popup.
351
+ * @default 'Scrollable'
352
+ */
353
+ @Property('Scrollable')
354
+ public overflowMode: OverflowMode;
355
+ /**
356
+ * Enable or disable persisting component's state between page reloads.
357
+ * If enabled, following list of states will be persisted.
358
+ * 1. selectedItem
359
+ * @default false
360
+ */
361
+ @Property(false)
362
+ public enablePersistence: boolean;
363
+ /**
364
+ * Specifies whether to show the close button for header items to remove the item from the Tab.
365
+ * @default false
366
+ */
367
+ @Property(false)
368
+ public showCloseButton: boolean;
369
+ /**
370
+ * Specifies the scrolling distance in scroller.
371
+ * @default null
372
+ */
373
+ @Property()
374
+ public scrollStep: number;
375
+ /**
376
+ * Specifies the animation configuration settings while showing the content of the Tab.
377
+ * @default
378
+ * { previous: { effect: 'SlideLeftIn', duration: 600, easing: 'ease' },
379
+ * next: { effect: 'SlideRightIn', duration: 600, easing: 'ease' } }
380
+ */
381
+ @Complex<TabAnimationSettingsModel>({}, TabAnimationSettings)
382
+ public animation: TabAnimationSettingsModel;
383
+ /**
384
+ * The event will be fired once the component rendering is completed.
385
+ * @event
386
+ * @blazorProperty 'Created'
387
+ */
388
+ @Event()
389
+ public created: EmitType<Event>;
390
+ /**
391
+ * The event will be fired before adding the item to the Tab.
392
+ * @event
393
+ * @blazorProperty 'Adding'
394
+ */
395
+ @Event()
396
+ public adding: EmitType<AddEventArgs>;
397
+ /**
398
+ * The event will be fired after adding the item to the Tab.
399
+ * @event
400
+ * @blazorProperty 'Added'
401
+ */
402
+ @Event()
403
+ public added: EmitType<AddEventArgs>;
404
+ /**
405
+ * The event will be fired before the item gets selected.
406
+ * @event
407
+ * @blazorProperty 'Selecting'
408
+ */
409
+ @Event()
410
+ public selecting: EmitType<SelectingEventArgs>;
411
+ /**
412
+ * The event will be fired after the item gets selected.
413
+ * @event
414
+ * @blazorProperty 'Selected'
415
+ */
416
+ @Event()
417
+ public selected: EmitType<SelectEventArgs>;
418
+ /**
419
+ * The event will be fired before removing the item from the Tab.
420
+ * @event
421
+ * @blazorProperty 'Removing'
422
+ */
423
+ @Event()
424
+ public removing: EmitType<RemoveEventArgs>;
425
+ /**
426
+ * The event will be fired after removing the item from the Tab.
427
+ * @event
428
+ * @blazorProperty 'Removed'
429
+ */
430
+ @Event()
431
+ public removed: EmitType<RemoveEventArgs>;
432
+ /**
433
+ * The event will be fired when the component gets destroyed.
434
+ * @event
435
+ * @blazorProperty 'Destroyed'
436
+ */
437
+ @Event()
438
+ public destroyed: EmitType<Event>;
439
+ /**
440
+ * Removes the component from the DOM and detaches all its related event handlers, attributes and classes.
441
+ * @returns void
442
+ */
443
+ public destroy(): void {
444
+ if (!isNOU(this.tbObj)) {
445
+ this.tbObj.destroy();
446
+ }
447
+ this.unWireEvents();
448
+ ['role', 'aria-disabled', 'aria-activedescendant', 'tabindex', 'aria-orientation'].forEach((val: string): void => {
449
+ this.element.removeAttribute(val);
450
+ });
451
+ this.expTemplateContent();
452
+ if (!this.isTemplate) {
453
+ while (this.element.firstElementChild) {
454
+ remove(this.element.firstElementChild);
455
+ }
456
+ } else {
457
+ let cntEle: Element = select('.' + CLS_TAB + ' > .' + CLS_CONTENT, this.element);
458
+ this.element.classList.remove(CLS_TEMPLATE);
459
+ if (!isNOU(cntEle)) { cntEle.innerHTML = this.cnt; }
460
+ }
461
+ super.destroy();
462
+ this.trigger('destroyed');
463
+ }
464
+ /**
465
+ * Initialize component
466
+ * @private
467
+ */
468
+ protected preRender(): void {
469
+ let nested: Element = closest(this.element, '.' + CLS_CONTENT);
470
+ this.prevIndex = 0;
471
+ this.isNested = false;
472
+ this.isPopup = false;
473
+ this.initRender = true;
474
+ this.isSwipeed = false;
475
+ this.itemIndexArray = [];
476
+ this.templateEle = [];
477
+ if (!isNOU(nested)) {
478
+ nested.parentElement.classList.add(CLS_NEST);
479
+ this.isNested = true;
480
+ }
481
+ let name: Str = Browser.info.name;
482
+ let css: Str = (name === 'msie') ? 'e-ie' : (name === 'edge') ? 'e-edge' : (name === 'safari') ? 'e-safari' : '';
483
+ setStyle(this.element, { 'width': formatUnit(this.width), 'height': formatUnit(this.height) });
484
+ this.setCssClass(this.element, this.cssClass, true);
485
+ attributes(this.element, { role: 'tablist', 'aria-disabled': 'false', 'aria-activedescendant': '' });
486
+ this.setCssClass(this.element, css, true);
487
+ this.updatePopAnimationConfig();
488
+ }
489
+ /**
490
+ * Initializes a new instance of the Tab class.
491
+ * @param options - Specifies Tab model properties as options.
492
+ * @param element - Specifies the element that is rendered as a Tab.
493
+ */
494
+ constructor(options?: TabModel, element?: string | HTMLElement) {
495
+ super(options, <HTEle | Str>element);
496
+ }
497
+ /**
498
+ * Initialize the component rendering
499
+ * @private
500
+ */
501
+ protected render(): void {
502
+ this.btnCls = this.createElement('span', { className: CLS_ICONS + ' ' + CLS_ICON_CLOSE, attrs: { title: this.title } });
503
+ this.tabId = this.element.id.length > 0 ? ('-' + this.element.id) : getRandomId();
504
+ this.renderContainer();
505
+ this.wireEvents();
506
+ this.initRender = false;
507
+ if (isBlazor()) {
508
+ this.renderComplete();
509
+ }
510
+ }
511
+ private renderContainer(): void {
512
+ let ele: HTEle = this.element;
513
+ if (this.items.length > 0 && ele.children.length === 0) {
514
+ ele.appendChild(this.createElement('div', { className: CLS_CONTENT }));
515
+ this.setOrientation(this.headerPlacement, this.createElement('div', { className: CLS_HEADER }));
516
+ this.isTemplate = false;
517
+ } else if (this.element.children.length > 0) {
518
+ this.isTemplate = true;
519
+ ele.classList.add(CLS_TEMPLATE);
520
+ let header: HTEle = <HTEle>ele.querySelector('.' + CLS_HEADER);
521
+ if (header && this.headerPlacement === 'Bottom') {
522
+ this.setOrientation(this.headerPlacement, header);
523
+ }
524
+ }
525
+ if (!isNOU(select('.' + CLS_HEADER, this.element)) && !isNOU(select('.' + CLS_CONTENT, this.element))) {
526
+ this.renderHeader();
527
+ this.tbItems = <HTEle>select('.' + CLS_HEADER + ' .' + CLS_TB_ITEMS, this.element);
528
+ if (!isNOU(this.tbItems)) { rippleEffect(this.tbItems, { selector: '.e-tab-wrap' }); }
529
+ this.renderContent();
530
+ if (selectAll('.' + CLS_TB_ITEM, this.element).length > 0) {
531
+ let scrCnt: HTEle;
532
+ this.tbItems = <HTEle>select('.' + CLS_HEADER + ' .' + CLS_TB_ITEMS, this.element);
533
+ this.bdrLine = this.createElement('div', { className: CLS_INDICATOR + ' ' + CLS_HIDDEN + ' ' + CLS_IGNORE });
534
+ scrCnt = <HTEle>select('.' + this.scrCntClass, this.tbItems);
535
+ if (!isNOU(scrCnt)) {
536
+ scrCnt.insertBefore(this.bdrLine, scrCnt.firstChild);
537
+ } else {
538
+ this.tbItems.insertBefore(this.bdrLine, this.tbItems.firstChild);
539
+ }
540
+ this.setContentHeight(true);
541
+ this.select(this.selectedItem);
542
+ }
543
+ this.setRTL(this.enableRtl);
544
+ }
545
+ }
546
+ private renderHeader(): void {
547
+ let hdrPlace: HeaderPosition = this.headerPlacement;
548
+ let tabItems: Object[] = [];
549
+ this.hdrEle = this.getTabHeader();
550
+ this.addVerticalClass();
551
+ if (!this.isTemplate) {
552
+ tabItems = this.parseObject(this.items, 0);
553
+ } else {
554
+ if (this.element.children.length > 1 && this.element.children[1].classList.contains(CLS_HEADER)) {
555
+ this.setProperties({ headerPlacement: 'Bottom' }, true);
556
+ }
557
+ let count: number = this.hdrEle.children.length;
558
+ let hdrItems: string[] = [];
559
+ for (let i: number = 0; i < count; i++) {
560
+ hdrItems.push(this.hdrEle.children.item(i).innerHTML);
561
+ }
562
+ if (count > 0) {
563
+ while (this.hdrEle.firstElementChild) {
564
+ detach(this.hdrEle.firstElementChild);
565
+ }
566
+ let tabItems: HTMLElement = this.createElement('div', { className: CLS_ITEMS });
567
+ this.hdrEle.appendChild(tabItems);
568
+ hdrItems.forEach((item: string, index: number) => {
569
+ this.lastIndex = index;
570
+ let attr: object = {
571
+ className: CLS_ITEM, id: CLS_ITEM + this.tabId + '_' + index,
572
+ attrs: { role: 'tab', 'aria-controls': CLS_CONTENT + this.tabId + '_' + index, 'aria-selected': 'false' }
573
+ };
574
+ let txt: Str = this.createElement('span', {
575
+ className: CLS_TEXT, innerHTML: item, attrs: { 'role': 'presentation' }
576
+ }).outerHTML;
577
+ let cont: Str = this.createElement('div', {
578
+ className: CLS_TEXT_WRAP, innerHTML: txt + this.btnCls.outerHTML
579
+ }).outerHTML;
580
+ let wrap: HTEle = this.createElement('div', { className: CLS_WRAP, innerHTML: cont, attrs: { tabIndex: '-1' } });
581
+ tabItems.appendChild(this.createElement('div', attr));
582
+ selectAll('.' + CLS_ITEM, tabItems)[index].appendChild(wrap);
583
+ });
584
+ }
585
+ }
586
+ this.tbObj = new Toolbar({
587
+ width: (hdrPlace === 'Left' || hdrPlace === 'Right') ? 'auto' : '100%',
588
+ height: (hdrPlace === 'Left' || hdrPlace === 'Right') ? '100%' : 'auto',
589
+ overflowMode: this.overflowMode,
590
+ items: (tabItems.length !== 0) ? tabItems : [],
591
+ clicked: this.clickHandler.bind(this),
592
+ scrollStep: this.scrollStep
593
+ });
594
+ this.tbObj.isStringTemplate = true;
595
+ this.tbObj.createElement = this.createElement;
596
+ this.tbObj.appendTo(<HTEle>this.hdrEle);
597
+ attributes(this.hdrEle, { 'aria-label': 'tab-header' });
598
+ for (let i: number = 0; i < this.items.length; i++) {
599
+ let item: TabItemModel = this.items[i];
600
+ if (item.headerTemplate && isBlazor() && !this.isStringTemplate &&
601
+ (<string>item.headerTemplate).indexOf('<div>Blazor') === 0) {
602
+ updateBlazorTemplate(this.element.id + i + '_' + 'headerTemplate', 'HeaderTemplate', item);
603
+ }
604
+ }
605
+ this.updateOrientationAttribute();
606
+ this.setCloseButton(this.showCloseButton);
607
+ }
608
+ private renderContent(): void {
609
+ this.cntEle = <HTEle>select('.' + CLS_CONTENT, this.element);
610
+ let hdrItem: HTEle[] = selectAll('.' + CLS_TB_ITEM, this.element);
611
+ if (this.isTemplate) {
612
+ this.cnt = (this.cntEle.children.length > 0) ? this.cntEle.innerHTML : '';
613
+ let contents: HTMLCollection = this.cntEle.children;
614
+ for (let i: number = 0; i < hdrItem.length; i++) {
615
+ if (contents.length - 1 >= i) {
616
+ contents.item(i).className += CLS_ITEM;
617
+ attributes(contents.item(i), { 'role': 'tabpanel', 'aria-labelledby': CLS_ITEM + this.tabId + '_' + i });
618
+ contents.item(i).id = CLS_CONTENT + this.tabId + '_' + i;
619
+ }
620
+ }
621
+ }
622
+ }
623
+ private reRenderItems(): void {
624
+ this.renderContainer();
625
+ if (!isNOU(this.cntEle)) {
626
+ this.touchModule = new Touch(this.cntEle, { swipe: this.swipeHandler.bind(this) });
627
+ }
628
+ }
629
+ private parseObject(items: TabItemModel[], index: number): object[] {
630
+ let tbCount: number = selectAll('.' + CLS_TB_ITEM, this.element).length;
631
+ let tItems: Object[] = [];
632
+ let txtWrapEle: HTEle;
633
+ let spliceArray: number[] = [];
634
+ let i: number = 0;
635
+ items.forEach((item: TabItemModel, i: number) => {
636
+ let pos: Str = (isNOU(item.header) || isNOU(item.header.iconPosition)) ? '' : item.header.iconPosition;
637
+ let css: Str = (isNOU(item.header) || isNOU(item.header.iconCss)) ? '' : item.header.iconCss;
638
+ if ((isNOU(item.headerTemplate)) && (isNOU(item.header) || isNOU(item.header.text) ||
639
+ (((<string>item.header.text).length === 0)) && (css === ''))) {
640
+ spliceArray.push(i);
641
+ return;
642
+ }
643
+ let txt: Str | HTEle = item.headerTemplate || item.header.text;
644
+ this.lastIndex = ((tbCount === 0) ? i : ((this.isReplace) ? (index + i) : (this.lastIndex + 1)));
645
+ let disabled: Str = (item.disabled) ? ' ' + CLS_DISABLE + ' ' + CLS_OVERLAY : '';
646
+ txtWrapEle = this.createElement('div', { className: CLS_TEXT, attrs: { 'role': 'presentation' } });
647
+ let tHtml: Str = ((txt instanceof Object) ? (<HTEle>txt).outerHTML : txt);
648
+ let txtEmpty: boolean = (!isNOU(tHtml) && tHtml !== '');
649
+ if (!isNOU((<HTEle>txt).tagName)) {
650
+ txtWrapEle.appendChild(txt as HTEle);
651
+ } else {
652
+ this.headerTextCompile(txtWrapEle, txt as string, i);
653
+ }
654
+ let tEle: HTEle;
655
+ let icon: HTEle = this.createElement('span', {
656
+ className: CLS_ICONS + ' ' + CLS_TAB_ICON + ' ' + CLS_ICON + '-' + pos + ' ' + css
657
+ });
658
+ let tCont: HTEle = this.createElement('div', { className: CLS_TEXT_WRAP });
659
+ tCont.appendChild(txtWrapEle);
660
+ if ((txt !== '' && txt !== undefined) && css !== '') {
661
+ if ((pos === 'left' || pos === 'top')) {
662
+ tCont.insertBefore(icon, tCont.firstElementChild);
663
+ } else {
664
+ tCont.appendChild(icon);
665
+ }
666
+ tEle = txtWrapEle;
667
+ this.isIconAlone = false;
668
+ } else {
669
+ tEle = ((css === '') ? txtWrapEle : icon);
670
+ if (tEle === icon) {
671
+ detach(txtWrapEle);
672
+ tCont.appendChild(icon);
673
+ this.isIconAlone = true;
674
+ }
675
+ }
676
+ let wrapAttrs: { [key: string]: string } = (item.disabled) ? {} : { tabIndex: '-1' };
677
+ tCont.appendChild(this.btnCls.cloneNode(true));
678
+ let wrap: HTEle = this.createElement('div', { className: CLS_WRAP, attrs: wrapAttrs });
679
+ wrap.appendChild(tCont);
680
+ if (this.itemIndexArray === []) {
681
+ this.itemIndexArray.push(CLS_ITEM + this.tabId + '_' + this.lastIndex);
682
+ } else {
683
+ this.itemIndexArray.splice((index + i), 0, CLS_ITEM + this.tabId + '_' + this.lastIndex);
684
+ }
685
+ let attrObj: Object = {
686
+ id: CLS_ITEM + this.tabId + '_' + this.lastIndex, role: 'tab', 'aria-selected': 'false'
687
+ };
688
+ let tItem: { [key: string]: {} } = { htmlAttributes: attrObj, template: wrap };
689
+ tItem.cssClass = item.cssClass + ' ' + disabled + ' ' + ((css !== '') ? 'e-i' + pos : '') + ' ' + ((!txtEmpty) ? CLS_ICON : '');
690
+ if (pos === 'top' || pos === 'bottom') { this.element.classList.add('e-vertical-icon'); }
691
+ tItems.push(tItem);
692
+ i++;
693
+ });
694
+ if (!this.isAdd) {
695
+ spliceArray.forEach((spliceItemIndex: number) => {
696
+ this.items.splice(spliceItemIndex, 1);
697
+ });
698
+ }
699
+ (this.isIconAlone) ? this.element.classList.add(CLS_ICON_TAB) : this.element.classList.remove(CLS_ICON_TAB);
700
+ return tItems;
701
+ }
702
+ private removeActiveClass(): void {
703
+ let tabHeader: HTMLElement = this.getTabHeader();
704
+ if (tabHeader) {
705
+ let tabItems: HTMLElement[] = selectAll('.' + CLS_TB_ITEM + '.' + CLS_ACTIVE, tabHeader);
706
+ [].slice.call(tabItems).forEach((node: HTMLElement) => node.classList.remove(CLS_ACTIVE));
707
+ }
708
+ }
709
+ private checkPopupOverflow(ele: HTEle): boolean {
710
+ this.tbPop = <HTEle>select('.' + CLS_TB_POP, this.element);
711
+ let popIcon: HTEle = (<HTEle>select('.e-hor-nav', this.element));
712
+ let tbrItems: HTEle = (<HTEle>select('.' + CLS_TB_ITEMS, this.element));
713
+ let lastChild: HTEle = <HTMLElement>tbrItems.lastChild;
714
+ let isOverflow: boolean = false;
715
+ if (!this.isVertical() && ((this.enableRtl && ((popIcon.offsetLeft + popIcon.offsetWidth) > tbrItems.offsetLeft))
716
+ || (!this.enableRtl && popIcon.offsetLeft < tbrItems.offsetWidth))) {
717
+ isOverflow = true;
718
+ } else if (this.isVertical() && (popIcon.offsetTop < lastChild.offsetTop + lastChild.offsetHeight)) {
719
+ isOverflow = true;
720
+ }
721
+ if (isOverflow) {
722
+ ele.classList.add(CLS_TB_POPUP);
723
+ this.tbPop.insertBefore(<Node>ele.cloneNode(true), selectAll('.' + CLS_TB_POPUP, this.tbPop)[0]);
724
+ ele.outerHTML = '';
725
+ }
726
+ return true;
727
+ }
728
+ private popupHandler(target: HTEle): number {
729
+ let ripEle: HTEle = <HTEle>target.querySelector('.e-ripple-element');
730
+ if (!isNOU(ripEle)) {
731
+ ripEle.outerHTML = '';
732
+ target.querySelector('.' + CLS_WRAP).classList.remove('e-ripple');
733
+ }
734
+ this.tbItem = selectAll('.' + CLS_TB_ITEMS + ' .' + CLS_TB_ITEM, this.hdrEle);
735
+ let lastChild: HTEle = <HTEle>this.tbItem[this.tbItem.length - 1];
736
+ if (this.tbItem.length !== 0) {
737
+ target.classList.remove(CLS_TB_POPUP);
738
+ target.removeAttribute('style');
739
+ this.tbItems.appendChild(target.cloneNode(true));
740
+ this.actEleId = target.id;
741
+ target.outerHTML = '';
742
+ if (this.checkPopupOverflow(lastChild)) {
743
+ let prevEle: HTEle = <HTEle>(<HTEle>this.tbItems.lastChild).previousElementSibling;
744
+ this.checkPopupOverflow(prevEle);
745
+ }
746
+ this.isPopup = true;
747
+ }
748
+ return selectAll('.' + CLS_TB_ITEM, this.tbItems).length - 1;
749
+ }
750
+ private updateOrientationAttribute(): void {
751
+ attributes(this.element, { 'aria-orientation': (this.isVertical() ? 'vertical' : 'horizontal') });
752
+ }
753
+ private setCloseButton(val: boolean): void {
754
+ let trg: Element = select('.' + CLS_HEADER, this.element);
755
+ (val === true) ? trg.classList.add(CLS_CLOSE_SHOW) : trg.classList.remove(CLS_CLOSE_SHOW);
756
+ this.tbObj.refreshOverflow();
757
+ this.refreshActElePosition();
758
+ }
759
+ private prevCtnAnimation(prev: number, current: number): AnimationModel {
760
+ let animation: AnimationModel;
761
+ let checkRTL: boolean = this.enableRtl || this.element.classList.contains(CLS_RTL);
762
+ if (this.isPopup || prev <= current) {
763
+ if (this.animation.previous.effect === 'SlideLeftIn') {
764
+ animation = {
765
+ name: 'SlideLeftOut',
766
+ duration: this.animation.previous.duration, timingFunction: this.animation.previous.easing
767
+ };
768
+ } else {
769
+ animation = null;
770
+ }
771
+ } else {
772
+ if (this.animation.next.effect === 'SlideRightIn') {
773
+ animation = {
774
+ name: 'SlideRightOut',
775
+ duration: this.animation.next.duration, timingFunction: this.animation.next.easing
776
+ };
777
+ } else { animation = null; }
778
+ }
779
+ return animation;
780
+ }
781
+ private triggerPrevAnimation(oldCnt: HTEle, prevIndex: number): void {
782
+ let animateObj: AnimationModel = this.prevCtnAnimation(prevIndex, this.selectedItem);
783
+ if (!isNOU(animateObj)) {
784
+ animateObj.begin = () => {
785
+ setStyle(oldCnt, { 'position': 'absolute' });
786
+ oldCnt.classList.add(CLS_PROGRESS);
787
+ oldCnt.classList.add('e-view');
788
+ };
789
+ animateObj.end = () => {
790
+ oldCnt.style.display = 'none';
791
+ oldCnt.classList.remove(CLS_ACTIVE);
792
+ oldCnt.classList.remove(CLS_PROGRESS);
793
+ oldCnt.classList.remove('e-view');
794
+ setStyle(oldCnt, { 'display': '', 'position': '' });
795
+ if (oldCnt.childNodes.length === 0 && !this.isTemplate) {
796
+ detach(oldCnt);
797
+ }
798
+ };
799
+ new Animation(animateObj).animate(oldCnt);
800
+ } else {
801
+ oldCnt.classList.remove(CLS_ACTIVE);
802
+ }
803
+ }
804
+ private triggerAnimation(id: Str, value: boolean): void {
805
+ let prevIndex: number = this.prevIndex;
806
+ let itemCollection: HTMLElement[] = [].slice.call(this.element.querySelector('.' + CLS_CONTENT).children);
807
+ let oldCnt: HTEle;
808
+ itemCollection.forEach((item: HTEle) => {
809
+ if (item.id === this.prevActiveEle) {
810
+ oldCnt = item;
811
+ }
812
+ });
813
+ let prevEle: HTEle = this.tbItem[prevIndex];
814
+ let no: Str = this.extIndex(this.tbItem[this.selectedItem].id);
815
+ let newCnt: HTEle = this.getTrgContent(this.cntEle, no);
816
+ if (isNOU(oldCnt) && !isNOU(prevEle)) {
817
+ let idNo: Str = this.extIndex(prevEle.id);
818
+ oldCnt = this.getTrgContent(this.cntEle, idNo);
819
+ }
820
+ this.prevActiveEle = newCnt.id;
821
+ if (this.initRender || value === false || this.animation === {} || isNOU(this.animation)) {
822
+ if (oldCnt && oldCnt !== newCnt) { oldCnt.classList.remove(CLS_ACTIVE); }
823
+ return;
824
+ }
825
+ let cnt: HTEle = <HTEle>select('.' + CLS_CONTENT, this.element);
826
+ let animateObj: AnimationModel;
827
+ if (this.prevIndex > this.selectedItem && !this.isPopup) {
828
+ let openEff: Effect = <Effect>this.animation.previous.effect;
829
+ animateObj = {
830
+ name: <Effect>((openEff === <Effect>'None') ? '' : ((openEff !== <Effect>'SlideLeftIn') ? openEff : 'SlideLeftIn')),
831
+ duration: this.animation.previous.duration,
832
+ timingFunction: this.animation.previous.easing
833
+ };
834
+ } else if (this.isPopup || this.prevIndex < this.selectedItem || this.prevIndex === this.selectedItem) {
835
+ let clsEff: Effect = <Effect>this.animation.next.effect;
836
+ animateObj = {
837
+ name: <Effect>((clsEff === <Effect>'None') ? '' : ((clsEff !== <Effect>'SlideRightIn') ? clsEff : 'SlideRightIn')),
838
+ duration: this.animation.next.duration,
839
+ timingFunction: this.animation.next.easing
840
+ };
841
+ }
842
+ animateObj.progress = () => {
843
+ cnt.classList.add(CLS_PROGRESS); this.setActiveBorder();
844
+ };
845
+ animateObj.end = () => {
846
+ cnt.classList.remove(CLS_PROGRESS);
847
+ newCnt.classList.add(CLS_ACTIVE);
848
+ };
849
+ if (!this.initRender && !isNOU(oldCnt)) {
850
+ this.triggerPrevAnimation(oldCnt, prevIndex);
851
+ }
852
+ this.isPopup = false;
853
+ if (animateObj.name === <Effect>'') {
854
+ newCnt.classList.add(CLS_ACTIVE);
855
+ } else {
856
+ new Animation(animateObj).animate(newCnt);
857
+ }
858
+ }
859
+ private keyPressed(trg: HTEle): void {
860
+ let trgParent: HTEle = <HTEle>closest(trg, '.' + CLS_HEADER + ' .' + CLS_TB_ITEM);
861
+ let trgIndex: number = this.getEleIndex(trgParent);
862
+ if (!isNOU(this.popEle) && trg.classList.contains('e-hor-nav')) {
863
+ (this.popEle.classList.contains(CLS_POPUP_OPEN)) ? this.popObj.hide(this.hide) : this.popObj.show(this.show);
864
+ } else if (trg.classList.contains('e-scroll-nav')) {
865
+ trg.click();
866
+ } else {
867
+ if (!isNOU(trgParent) && trgParent.classList.contains(CLS_ACTIVE) === false) {
868
+ this.select(trgIndex);
869
+ if (!isNOU(this.popEle)) {
870
+ this.popObj.hide(this.hide);
871
+ }
872
+ }
873
+ }
874
+ }
875
+ private getTabHeader(): HTMLElement {
876
+ let headers: HTMLElement[] = [].slice.call(this.element.children).filter((e: HTMLElement) => e.classList.contains(CLS_HEADER));
877
+ if (headers.length > 0) {
878
+ return headers[0];
879
+ } else {
880
+ let wrap: HTMLElement = [].slice.call(this.element.children).filter((e: HTMLElement) => !e.classList.contains(CLS_BLA_TEM))[0];
881
+ if (!wrap) {
882
+ return undefined;
883
+ }
884
+ return [].slice.call(wrap.children).filter((e: HTMLElement) => e.classList.contains(CLS_HEADER))[0];
885
+ }
886
+ }
887
+ private getEleIndex(item: HTEle): number {
888
+ return Array.prototype.indexOf.call(selectAll('.' + CLS_TB_ITEM, this.getTabHeader()), item);
889
+ }
890
+ private extIndex(id: string): string {
891
+ return id.replace(CLS_ITEM + this.tabId + '_', '');
892
+ }
893
+ private expTemplateContent(): void {
894
+ this.templateEle.forEach((eleStr: Str): void => {
895
+ if (!isNOU(this.element.querySelector(eleStr))) {
896
+ (<HTEle>document.body.appendChild(this.element.querySelector(eleStr))).style.display = 'none';
897
+ }
898
+ });
899
+ }
900
+ private templateCompile(ele: HTEle, cnt: Str, index: number): void {
901
+ let tempEle: HTEle = this.createElement('div');
902
+ this.compileElement(tempEle, cnt, 'content', index);
903
+ if (tempEle.childNodes.length !== 0) {
904
+ ele.appendChild(tempEle);
905
+ let item: TabItemModel = this.items[index];
906
+ if (!isNOU(item)) {
907
+ if (item.content && isBlazor() && !this.isStringTemplate && (<string>item.content).indexOf('<div>Blazor') === 0) {
908
+ updateBlazorTemplate(this.element.id + index + '_' + 'content', 'ContentTemplate', item);
909
+ }
910
+ }
911
+ }
912
+ }
913
+ private compileElement(ele: HTEle, val: string, prop: string, index: number): void {
914
+ let templateFn: Function;
915
+ if (typeof val === 'string' && isBlazor() && val.indexOf('<div>Blazor') !== 0) {
916
+ val = val.trim();
917
+ ele.innerHTML = val;
918
+ } else {
919
+ templateFn = compile(val);
920
+ }
921
+ let templateFUN: HTMLElement[];
922
+ if (!isNOU(templateFn)) {
923
+ if (isBlazor() && !this.isStringTemplate && val.indexOf('<div>Blazor') === 0) {
924
+ templateFUN = templateFn({}, this, prop, this.element.id + index + '_' + prop, this.isStringTemplate);
925
+ } else {
926
+ templateFUN = templateFn({}, this, prop);
927
+ }
928
+ }
929
+ if (!isNOU(templateFn) && templateFUN.length > 0) {
930
+ [].slice.call(templateFUN).forEach((el: HTEle): void => {
931
+ ele.appendChild(el);
932
+ });
933
+ }
934
+ }
935
+ private headerTextCompile(element: HTEle, text: string, index: number): void {
936
+ this.compileElement(element, text, 'headerTemplate', index);
937
+ }
938
+ private getContent(ele: HTEle, cnt: Str | HTEle, callType: string, index: number): void {
939
+ let eleStr: Str;
940
+ if (typeof cnt === 'string' || isNOU((<HTEle>cnt).innerHTML)) {
941
+ if ((<Str>cnt)[0] === '.' || (<Str>cnt)[0] === '#') {
942
+ if (document.querySelectorAll(<string>cnt).length) {
943
+ let eleVal: HTEle = <HTEle>document.querySelector(<string>cnt);
944
+ eleStr = eleVal.outerHTML.trim();
945
+ if (callType === 'clone') {
946
+ ele.appendChild(eleVal.cloneNode(true));
947
+ } else {
948
+ ele.appendChild(eleVal);
949
+ eleVal.style.display = '';
950
+ }
951
+ } else {
952
+ this.templateCompile(ele, <Str>cnt, index);
953
+ }
954
+ } else {
955
+ this.templateCompile(ele, <Str>cnt, index);
956
+ }
957
+ } else {
958
+ ele.appendChild(cnt);
959
+ }
960
+ if (!isNOU(eleStr)) {
961
+ if (this.templateEle.indexOf(cnt.toString()) === -1) {
962
+ this.templateEle.push(cnt.toString());
963
+ }
964
+ }
965
+ }
966
+ private getTrgContent(cntEle: HTEle, no: Str): HTEle {
967
+ let ele: HTEle;
968
+ if (this.element.classList.contains(CLS_NEST)) {
969
+ ele = <HTEle>select('.' + CLS_NEST + '> .' + CLS_CONTENT + ' > #' + CLS_CONTENT + this.tabId + '_' + no, this.element);
970
+ } else { ele = this.findEle(cntEle.children, CLS_CONTENT + this.tabId + '_' + no); }
971
+ return ele;
972
+ }
973
+ private findEle(items: HTMLCollection, key: Str): HTEle {
974
+ let ele: HTEle;
975
+ for (let i: number = 0; i < items.length; i++) {
976
+ if (items[i].id === key) { ele = <HTEle>items[i]; break; }
977
+ }
978
+ return ele;
979
+ }
980
+ private isVertical(): boolean {
981
+ let isVertical: boolean = (this.headerPlacement === 'Left' || this.headerPlacement === 'Right') ? true : false;
982
+ this.scrCntClass = (isVertical) ? CLS_VSCRCNT : CLS_HSCRCNT;
983
+ return isVertical;
984
+ }
985
+ private addVerticalClass(): void {
986
+ if (this.isVertical()) {
987
+ let tbPos: string = (this.headerPlacement === 'Left') ? CLS_VLEFT : CLS_VRIGHT;
988
+ addClass([this.hdrEle], [CLS_VERTICAL, tbPos]);
989
+ this.element.classList.add(CLS_VTAB);
990
+ }
991
+ if (this.headerPlacement === 'Bottom') {
992
+ this.hdrEle.classList.add(CLS_HBOTTOM);
993
+ }
994
+ }
995
+ private updatePopAnimationConfig(): void {
996
+ this.show = { name: (this.isVertical() ? 'FadeIn' : 'SlideDown'), duration: 100 };
997
+ this.hide = { name: (this.isVertical() ? 'FadeOut' : 'SlideUp'), duration: 100 };
998
+ }
999
+ private changeOrientation(place: Str): void {
1000
+ this.setOrientation(place, this.hdrEle);
1001
+ let isVertical: boolean = this.hdrEle.classList.contains(CLS_VERTICAL) ? true : false;
1002
+ removeClass([this.element], [CLS_VTAB]);
1003
+ removeClass([this.hdrEle], [CLS_VERTICAL, CLS_VLEFT, CLS_VRIGHT]);
1004
+ if (isVertical !== this.isVertical()) {
1005
+ this.tbObj.setProperties({ height: (this.isVertical() ? '100%' : 'auto'), width: (this.isVertical() ? 'auto' : '100%') }, true);
1006
+ this.tbObj.changeOrientation();
1007
+ this.updatePopAnimationConfig();
1008
+ }
1009
+ this.addVerticalClass();
1010
+ this.updateOrientationAttribute();
1011
+ this.select(this.selectedItem);
1012
+ }
1013
+ private setOrientation(place: Str, ele: HTEle): void {
1014
+ let headerPos: number = Array.prototype.indexOf.call(this.element.children, ele);
1015
+ let contentPos: number = Array.prototype.indexOf.call(this.element.children, this.element.querySelector('.' + CLS_CONTENT));
1016
+ if (place === 'Bottom' && (contentPos > headerPos)) {
1017
+ this.element.appendChild(ele);
1018
+ } else {
1019
+ this.element.insertBefore(ele, select('.' + CLS_CONTENT, this.element));
1020
+ }
1021
+ }
1022
+ private setCssClass(ele: HTEle, cls: Str, val: boolean): void {
1023
+ if (cls === '') { return; }
1024
+ let list: Str[] = cls.split(' ');
1025
+ for (let i: number = 0; i < list.length; i++) {
1026
+ if (val) {
1027
+ ele.classList.add(list[i]);
1028
+ } else {
1029
+ ele.classList.remove(list[i]);
1030
+ }
1031
+ }
1032
+ }
1033
+ private setContentHeight(val: boolean): void {
1034
+ if (this.element.classList.contains(CLS_FILL)) {
1035
+ removeClass([this.element], [CLS_FILL]);
1036
+ }
1037
+ if (isNOU(this.cntEle)) { return; }
1038
+ let hdrEle: HTEle = this.getTabHeader();
1039
+ if (this.heightAdjustMode === 'None') {
1040
+ if (this.height === 'auto') {
1041
+ return;
1042
+ } else {
1043
+ if (!this.isVertical()) {
1044
+ setStyle(this.cntEle, { 'height': (this.element.offsetHeight - hdrEle.offsetHeight) + 'px' });
1045
+ }
1046
+ }
1047
+ } else if (this.heightAdjustMode === 'Fill') {
1048
+ addClass([this.element], [CLS_FILL]);
1049
+ setStyle(this.element, { 'height': '100%' });
1050
+ setStyle(this.cntEle, { 'height': '100%' });
1051
+ } else if (this.heightAdjustMode === 'Auto') {
1052
+ let cnt: HTEle[] = selectAll('.' + CLS_CONTENT + ' > .' + CLS_ITEM, this.element);
1053
+ if (this.isTemplate === true) {
1054
+ for (let i: number = 0; i < cnt.length; i++) {
1055
+ cnt[i].setAttribute('style', 'display:block; visibility: visible');
1056
+ this.maxHeight = Math.max(this.maxHeight, this.getHeight(cnt[i]));
1057
+ cnt[i].style.removeProperty('display');
1058
+ cnt[i].style.removeProperty('visibility');
1059
+ }
1060
+ } else {
1061
+ this.cntEle = <HTEle>select('.' + CLS_CONTENT, this.element);
1062
+ if (val === true) {
1063
+ this.cntEle.appendChild(this.createElement('div', {
1064
+ id: (CLS_CONTENT + this.tabId + '_' + 0), className: CLS_ITEM + ' ' + CLS_ACTIVE,
1065
+ attrs: { 'role': 'tabpanel', 'aria-labelledby': CLS_ITEM + this.tabId + '_' + 0 }
1066
+ }));
1067
+ }
1068
+ let ele: HTEle = <HTEle>this.cntEle.children.item(0);
1069
+ for (let i: number = 0; i < this.items.length; i++) {
1070
+ this.getContent(ele, this.items[i].content, 'clone', i);
1071
+ this.maxHeight = Math.max(this.maxHeight, this.getHeight(ele));
1072
+ while (ele.firstChild) { ele.removeChild(ele.firstChild); }
1073
+ }
1074
+ this.clearTemplate(['content']);
1075
+ this.templateEle = [];
1076
+ this.getContent(ele, this.items[0].content, 'render', 0);
1077
+ ele.classList.remove(CLS_ACTIVE);
1078
+ }
1079
+ setStyle(this.cntEle, { 'height': this.maxHeight + 'px' });
1080
+ } else {
1081
+ setStyle(this.cntEle, { 'height': 'auto' });
1082
+ }
1083
+ }
1084
+ private getHeight(ele: HTEle): number {
1085
+ let cs: CSSStyleDeclaration = window.getComputedStyle(ele);
1086
+ return ele.offsetHeight + parseFloat(cs.getPropertyValue('padding-top')) + parseFloat(cs.getPropertyValue('padding-bottom')) +
1087
+ parseFloat(cs.getPropertyValue('margin-top')) + parseFloat(cs.getPropertyValue('margin-bottom'));
1088
+ }
1089
+ private setActiveBorder(): void {
1090
+ let bar: HTEle;
1091
+ let scrollCnt: HTEle;
1092
+ let trgHdrEle: Element = this.getTabHeader();
1093
+ let trg: HTEle = <HTEle>select('.' + CLS_TB_ITEM + '.' + CLS_ACTIVE, trgHdrEle);
1094
+ if (trg === null) { return; }
1095
+ let root: HTEle = <HTEle>closest(trg, '.' + CLS_TAB);
1096
+ if (this.element !== root) { return; }
1097
+ this.tbItems = <HTEle>select('.' + CLS_TB_ITEMS, trgHdrEle);
1098
+ bar = <HTEle>select('.' + CLS_INDICATOR, trgHdrEle);
1099
+ scrollCnt = <HTEle>select('.' + CLS_TB_ITEMS + ' .' + this.scrCntClass, trgHdrEle);
1100
+ if (this.isVertical()) {
1101
+ setStyle(bar, { 'left': '', 'right': '' });
1102
+ let tbHeight: number = (isNOU(scrollCnt)) ? this.tbItems.offsetHeight : scrollCnt.offsetHeight;
1103
+ if (tbHeight !== 0) {
1104
+ setStyle(bar, { 'top': trg.offsetTop + 'px', 'height': trg.offsetHeight + 'px' });
1105
+ } else {
1106
+ setStyle(bar, { 'top': 0, 'height': 0 });
1107
+ }
1108
+ } else {
1109
+ setStyle(bar, { 'top': '', 'height': '' });
1110
+ let tbWidth: number = (isNOU(scrollCnt)) ? this.tbItems.offsetWidth : scrollCnt.offsetWidth;
1111
+ if (tbWidth !== 0) {
1112
+ setStyle(bar, { 'left': trg.offsetLeft + 'px', 'right': tbWidth - (trg.offsetLeft + trg.offsetWidth) + 'px' });
1113
+ } else {
1114
+ setStyle(bar, { 'left': 'auto', 'right': 'auto' });
1115
+ }
1116
+ }
1117
+ if (!isNOU(this.bdrLine)) { this.bdrLine.classList.remove(CLS_HIDDEN); }
1118
+ }
1119
+ private setActive(value: number): void {
1120
+ this.tbItem = selectAll('.' + CLS_TB_ITEM, this.getTabHeader());
1121
+ let trg: HTEle = this.tbItem[value];
1122
+ if (value >= 0) { this.setProperties({ selectedItem: value }, true); }
1123
+ if (value < 0 || isNaN(value) || this.tbItem.length === 0 ) { return; }
1124
+ if ( trg.classList.contains(CLS_ACTIVE)) {
1125
+ this.setActiveBorder();
1126
+ return; }
1127
+ if (!this.isTemplate) {
1128
+ let prev: HTEle = this.tbItem[this.prevIndex];
1129
+ if (!isNOU(prev)) { prev.removeAttribute('aria-controls'); }
1130
+ attributes(trg, { 'aria-controls': CLS_CONTENT + this.tabId + '_' + value }); }
1131
+ let id: Str = trg.id;
1132
+ this.removeActiveClass();
1133
+ trg.classList.add(CLS_ACTIVE);
1134
+ trg.setAttribute('aria-selected', 'true');
1135
+ let no: number = Number(this.extIndex(id));
1136
+ if (isNOU(this.prevActiveEle)) {
1137
+ this.prevActiveEle = CLS_CONTENT + this.tabId + '_' + no;
1138
+ }
1139
+ attributes(this.element, { 'aria-activedescendant': id });
1140
+ if (this.isTemplate) {
1141
+ if (select('.' + CLS_CONTENT, this.element).children.length > 0) {
1142
+ let trg: HTEle = this.findEle(select('.' + CLS_CONTENT, this.element).children, CLS_CONTENT + this.tabId + '_' + no);
1143
+ if (!isNOU(trg)) { trg.classList.add(CLS_ACTIVE); }
1144
+ this.triggerAnimation(id, this.enableAnimation);
1145
+ }
1146
+ } else {
1147
+ this.cntEle = <HTEle> select('.' + CLS_TAB + ' > .' + CLS_CONTENT, this.element);
1148
+ let item: HTEle = this.getTrgContent(this.cntEle, this.extIndex(id));
1149
+ if (isNOU(item)) {
1150
+ this.cntEle.appendChild(this.createElement('div', {
1151
+ id: CLS_CONTENT + this.tabId + '_' + this.extIndex(id), className: CLS_ITEM + ' ' + CLS_ACTIVE,
1152
+ attrs: { role: 'tabpanel', 'aria-labelledby': CLS_ITEM + this.tabId + '_' + this.extIndex(id) }
1153
+ }));
1154
+ let eleTrg: HTEle = this.getTrgContent(this.cntEle, this.extIndex(id));
1155
+ let itemIndex: number = Array.prototype.indexOf.call(this.itemIndexArray, trg.id);
1156
+ this.getContent(eleTrg, this.items[itemIndex].content, 'render', itemIndex);
1157
+ } else {
1158
+ item.classList.add(CLS_ACTIVE);
1159
+ }
1160
+ this.triggerAnimation(id, this.enableAnimation);
1161
+ }
1162
+ this.setActiveBorder();
1163
+ let curActItem: HTEle = <HTEle> select('.' + CLS_HEADER + ' #' + id, this.element);
1164
+ this.refreshItemVisibility(curActItem);
1165
+ if (!this.initRender) {
1166
+ (<HTEle> curActItem.firstChild).focus();
1167
+ }
1168
+ let eventArg: SelectEventArgs = {
1169
+ previousItem: this.prevItem,
1170
+ previousIndex: this.prevIndex,
1171
+ selectedItem: trg,
1172
+ selectedIndex: value,
1173
+ selectedContent: <HTEle>select('#' + CLS_CONTENT + this.tabId + '_' + this.selectingID, this.content),
1174
+ isSwiped: this.isSwipeed
1175
+ };
1176
+ if (!this.initRender || this.selectedItem !== 0 ) {
1177
+ this.trigger('selected', eventArg); }
1178
+ }
1179
+ private setItems(items: object[]): void {
1180
+ this.isReplace = true;
1181
+ this.tbItems = <HTEle>select('.' + CLS_TB_ITEMS, this.getTabHeader());
1182
+ this.tbObj.items = this.parseObject(items, 0);
1183
+ this.tbObj.dataBind();
1184
+ this.isReplace = false;
1185
+ }
1186
+ private setRTL(value: boolean): void {
1187
+ this.tbObj.enableRtl = value;
1188
+ this.tbObj.dataBind();
1189
+ this.setCssClass(this.element, CLS_RTL, value);
1190
+ this.refreshActiveBorder();
1191
+ }
1192
+ private refreshActiveBorder(): void {
1193
+ if (!isNOU(this.bdrLine)) { this.bdrLine.classList.add(CLS_HIDDEN); }
1194
+ this.setActiveBorder();
1195
+ }
1196
+ private showPopup(config: object): void {
1197
+ let tbPop: HTEle = <HTEle>select('.e-popup.e-toolbar-pop', this.hdrEle);
1198
+ if (tbPop.classList.contains('e-popup-close')) {
1199
+ let tbPopObj: Popup = (<PopupModel>(tbPop && (<Instance>tbPop).ej2_instances[0])) as Popup;
1200
+ tbPopObj.position.X = (this.headerPlacement === 'Left') ? 'left' : 'right';
1201
+ tbPopObj.dataBind();
1202
+ tbPopObj.show(config);
1203
+ }
1204
+ }
1205
+ private wireEvents(): void {
1206
+ window.addEventListener('resize', this.resizeContext);
1207
+ EventHandler.add(this.element, 'mouseover', this.hoverHandler, this);
1208
+ EventHandler.add(this.element, 'keydown', this.spaceKeyDown, this);
1209
+ if (!isNOU(this.cntEle)) { this.touchModule = new Touch(this.cntEle, { swipe: this.swipeHandler.bind(this) }); }
1210
+ this.keyModule = new KeyboardEvents(this.element, { keyAction: this.keyHandler.bind(this), keyConfigs: this.keyConfigs });
1211
+ this.tabKeyModule = new KeyboardEvents(this.element, {
1212
+ keyAction: this.keyHandler.bind(this),
1213
+ keyConfigs: { openPopup: 'shift+f10', tab: 'tab', shiftTab: 'shift+tab' },
1214
+ eventName: 'keydown'
1215
+ });
1216
+ }
1217
+ private unWireEvents(): void {
1218
+ this.keyModule.destroy();
1219
+ this.tabKeyModule.destroy();
1220
+ if (!isNOU(this.cntEle)) { this.touchModule.destroy(); }
1221
+ window.removeEventListener('resize', this.resizeContext);
1222
+ EventHandler.remove(this.element, 'mouseover', this.hoverHandler);
1223
+ EventHandler.remove(this.element, 'keydown', this.spaceKeyDown);
1224
+ this.element.classList.remove(CLS_RTL);
1225
+ this.element.classList.remove(CLS_FOCUS);
1226
+ }
1227
+ private clickHandler(args: ClickEventArgs): void {
1228
+ this.element.classList.remove(CLS_FOCUS);
1229
+ let trg: HTEle = <HTEle>args.originalEvent.target;
1230
+ let trgParent: HTEle = <HTEle>closest(trg, '.' + CLS_TB_ITEM);
1231
+ let trgIndex: number = this.getEleIndex(trgParent);
1232
+ if (trg.classList.contains(CLS_ICON_CLOSE)) {
1233
+ this.removeTab(trgIndex);
1234
+ } else if (this.isVertical() && closest(trg, '.' + CLS_HOR_NAV)) {
1235
+ this.showPopup(this.show);
1236
+ } else {
1237
+ this.isPopup = false;
1238
+ if (!isNOU(trgParent) && trgIndex !== this.selectedItem) { this.select(trgIndex); }
1239
+ }
1240
+ }
1241
+ private swipeHandler(e: SwipeEventArgs): void {
1242
+ if (e.velocity < 3 && isNOU(e.originalEvent.changedTouches)) { return; }
1243
+ this.isSwipeed = true;
1244
+ if (e.swipeDirection === 'Right' && this.selectedItem !== 0) {
1245
+ for (let k: number = this.selectedItem - 1; k >= 0; k--) {
1246
+ if (!this.tbItem[k].classList.contains(CLS_HIDDEN)) {
1247
+ this.select(k);
1248
+ break;
1249
+ }
1250
+ }
1251
+ } else if (e.swipeDirection === 'Left' && (this.selectedItem !== selectAll('.' + CLS_TB_ITEM, this.element).length - 1)) {
1252
+ for (let i: number = this.selectedItem + 1; i < this.tbItem.length; i++) {
1253
+ if (!this.tbItem[i].classList.contains(CLS_HIDDEN)) {
1254
+ this.select(i);
1255
+ break;
1256
+ }
1257
+ }
1258
+ }
1259
+ this.isSwipeed = false;
1260
+ }
1261
+ private spaceKeyDown(e: KeyboardEvent): void {
1262
+ if ((e.keyCode === 32 && e.which === 32) || (e.keyCode === 35 && e.which === 35)) {
1263
+ let clstHead: HTEle = <HTEle>closest(<Element>e.target, '.' + CLS_HEADER);
1264
+ if (!isNOU(clstHead)) {
1265
+ e.preventDefault();
1266
+ }
1267
+ }
1268
+ }
1269
+ private keyHandler(e: KeyboardEventArgs): void {
1270
+ if (this.element.classList.contains(CLS_DISABLE)) { return; }
1271
+ this.element.classList.add(CLS_FOCUS);
1272
+ let trg: HTEle = <HTEle>e.target;
1273
+ let tabHeader: HTMLElement = this.getTabHeader();
1274
+ let actEle: HTEle = <HTEle>select('.' + CLS_ACTIVE, tabHeader);
1275
+ this.popEle = <DomElements>select('.' + CLS_TB_POP, tabHeader);
1276
+ if (!isNOU(this.popEle)) { this.popObj = <Popup>this.popEle.ej2_instances[0]; }
1277
+ switch (e.action) {
1278
+ case 'space':
1279
+ case 'enter':
1280
+ if (trg.parentElement.classList.contains(CLS_DISABLE)) { return; }
1281
+ if (e.action === 'enter' && trg.classList.contains('e-hor-nav')) {
1282
+ this.showPopup(this.show);
1283
+ break;
1284
+ }
1285
+ this.keyPressed(trg);
1286
+ break;
1287
+ case 'tab':
1288
+ case 'shiftTab':
1289
+ if (trg.classList.contains(CLS_WRAP)
1290
+ && (<HTEle>closest(trg, '.' + CLS_TB_ITEM)).classList.contains(CLS_ACTIVE) === false) {
1291
+ trg.setAttribute('tabindex', '-1');
1292
+ }
1293
+ if (this.popObj && isVisible(this.popObj.element)) {
1294
+ this.popObj.hide(this.hide);
1295
+ }
1296
+ actEle.children.item(0).setAttribute('tabindex', '0');
1297
+ break;
1298
+ case 'moveLeft':
1299
+ case 'moveRight':
1300
+ let item: HTEle = <HTEle>closest(document.activeElement, '.' + CLS_TB_ITEM);
1301
+ if (!isNOU(item)) { this.refreshItemVisibility(item); }
1302
+ break;
1303
+ case 'openPopup':
1304
+ e.preventDefault();
1305
+ if (!isNOU(this.popEle) && this.popEle.classList.contains(CLS_POPUP_CLOSE)) { this.popObj.show(this.show); }
1306
+ break;
1307
+ case 'delete':
1308
+ let trgParent: HTEle = <HTEle>closest(trg, '.' + CLS_TB_ITEM);
1309
+ if (this.showCloseButton === true && !isNOU(trgParent)) {
1310
+ let nxtSib: HTEle = <HTEle>trgParent.nextSibling;
1311
+ if (!isNOU(nxtSib) && nxtSib.classList.contains(CLS_TB_ITEM)) { (<HTEle>nxtSib.firstChild).focus(); }
1312
+ this.removeTab(this.getEleIndex(trgParent));
1313
+ }
1314
+ this.setActiveBorder();
1315
+ break;
1316
+ }
1317
+ }
1318
+ private refreshActElePosition(): void {
1319
+ let activeEle: Element = select('.' + CLS_TB_ITEM + '.' + CLS_TB_POPUP + '.' + CLS_ACTIVE, this.element);
1320
+ if (!isNOU(activeEle)) {
1321
+ this.select(this.getEleIndex(<HTEle>activeEle));
1322
+ }
1323
+ this.refreshActiveBorder();
1324
+ }
1325
+ private refreshItemVisibility(target: HTEle): void {
1326
+ let scrCnt: HTEle = <HTEle>select('.' + this.scrCntClass, this.tbItems);
1327
+ if (!this.isVertical() && !isNOU(scrCnt)) {
1328
+ let scrBar: HTEle = <HTEle>select('.e-hscroll-bar', this.tbItems);
1329
+ let scrStart: number = scrBar.scrollLeft;
1330
+ let scrEnd: number = scrStart + scrBar.offsetWidth;
1331
+ let eleStart: number = target.offsetLeft;
1332
+ let eleWidth: number = target.offsetWidth;
1333
+ let eleEnd: number = target.offsetLeft + target.offsetWidth;
1334
+ if ((scrStart < eleStart) && (scrEnd < eleEnd)) {
1335
+ let eleViewRange: number = scrEnd - eleStart;
1336
+ scrBar.scrollLeft = scrStart + (eleWidth - eleViewRange);
1337
+ } else {
1338
+ if ((scrStart > eleStart) && (scrEnd > eleEnd)) {
1339
+ let eleViewRange: number = eleEnd - scrStart;
1340
+ scrBar.scrollLeft = scrStart - (eleWidth - eleViewRange);
1341
+ }
1342
+ }
1343
+ } else { return; }
1344
+ }
1345
+ private hoverHandler(e: MouseEventArgs): void {
1346
+ let trg: HTEle = <HTEle>e.target;
1347
+ if (!isNOU(trg.classList) && trg.classList.contains(CLS_ICON_CLOSE)) {
1348
+ trg.setAttribute('title', new L10n('tab', { closeButtonTitle: this.title }, this.locale).getConstant('closeButtonTitle'));
1349
+ }
1350
+ }
1351
+ private evalOnPropertyChangeItems(newProp: TabModel, oldProp: TabModel): void {
1352
+ if (!(newProp.items instanceof Array && oldProp.items instanceof Array)) {
1353
+ let changedProp: Object[] = Object.keys(newProp.items);
1354
+ for (let i: number = 0; i < changedProp.length; i++) {
1355
+ let index: number = parseInt(Object.keys(newProp.items)[i], 10);
1356
+ let property: Str = Object.keys(newProp.items[index])[0];
1357
+ let oldVal: Str = Object(oldProp.items[index])[property];
1358
+ let newVal: Str | Object = Object(newProp.items[index])[property];
1359
+ let hdrItem: HTEle = <HTEle>select('.' + CLS_TB_ITEMS + ' #' + CLS_ITEM + this.tabId + '_' + index, this.element);
1360
+ let cntItem: HTEle = <HTEle>select('.' + CLS_CONTENT + ' #' + CLS_CONTENT + this.tabId + '_' + index, this.element);
1361
+ if (property === 'header' || property === 'headerTemplate') {
1362
+ let icon: Str | Object = (isNOU(this.items[index].header) ||
1363
+ isNOU(this.items[index].header.iconCss)) ? '' : this.items[index].header.iconCss;
1364
+ let textVal: Str | Object = this.items[index].headerTemplate || this.items[index].header.text;
1365
+ if ((textVal === '') && (icon === '')) {
1366
+ this.removeTab(index);
1367
+ } else {
1368
+ let arr: Object[] = [];
1369
+ arr.push(<TabItemModel>this.items[index]);
1370
+ this.items.splice(index, 1);
1371
+ this.itemIndexArray.splice(index, 1);
1372
+ this.tbObj.items.splice(index, 1);
1373
+ let isHiddenEle: Boolean = hdrItem.classList.contains(CLS_HIDDEN);
1374
+ detach(hdrItem);
1375
+ this.isReplace = true;
1376
+ this.addTab(arr, index);
1377
+ if (isHiddenEle) { this.hideTab(index); }
1378
+ this.isReplace = false;
1379
+ }
1380
+ }
1381
+ if (property === 'content' && !isNOU(cntItem)) {
1382
+ let strVal: Boolean = typeof newVal === 'string' || isNOU((<HTEle>newVal).innerHTML);
1383
+ if (strVal && ((<Str>newVal)[0] === '.' || (<Str>newVal)[0] === '#') && (<Str>newVal).length) {
1384
+ let eleVal: HTEle = <HTEle>document.querySelector(<Str>newVal);
1385
+ cntItem.appendChild(eleVal);
1386
+ eleVal.style.display = '';
1387
+ } else if (newVal === '' && oldVal[0] === '#') {
1388
+ (<HTEle>document.body.appendChild(this.element.querySelector(oldVal))).style.display = 'none';
1389
+ cntItem.innerHTML = <Str>newVal;
1390
+ } else { cntItem.innerHTML = <Str>newVal; }
1391
+ }
1392
+ if (property === 'cssClass') {
1393
+ if (!isNOU(hdrItem)) {
1394
+ hdrItem.classList.remove(oldVal);
1395
+ hdrItem.classList.add(<Str>newVal);
1396
+ }
1397
+ if (!isNOU(cntItem)) {
1398
+ cntItem.classList.remove(oldVal);
1399
+ cntItem.classList.add(<Str>newVal);
1400
+ }
1401
+ }
1402
+ if (property === 'disabled') { this.enableTab(index, ((newVal === true) ? false : true)); }
1403
+ }
1404
+ } else {
1405
+ this.lastIndex = 0;
1406
+ if (isNOU(this.tbObj)) {
1407
+ this.reRenderItems();
1408
+ } else {
1409
+ let items: TabItemModel[] = newProp.items;
1410
+ for (let i: number = 0; i < items.length; i++) {
1411
+ this.resetBlazorTemplates(items[i], i);
1412
+ }
1413
+ this.setItems(<TabItemModel[]>newProp.items);
1414
+ if (this.templateEle.length > 0) { this.expTemplateContent(); }
1415
+ this.templateEle = [];
1416
+ let selectElement: HTEle = <HTEle>select('.' + CLS_TAB + ' > .' + CLS_CONTENT, this.element);
1417
+ while (selectElement.firstElementChild) {
1418
+ detach(selectElement.firstElementChild);
1419
+ }
1420
+ this.select(this.selectedItem);
1421
+ }
1422
+ }
1423
+ }
1424
+
1425
+ private resetBlazorTemplates(item: TabItemModel, index: number): void {
1426
+ if (!isBlazor()) {
1427
+ return;
1428
+ }
1429
+ if (item.headerTemplate && !this.isStringTemplate && (item.headerTemplate).indexOf('<div>Blazor') === 0) {
1430
+ resetBlazorTemplate(this.element.id + index + '_' + 'headerTemplate', 'HeaderTemplate');
1431
+ }
1432
+ if (item.content && !this.isStringTemplate && (<string>item.content).indexOf('<div>Blazor') === 0) {
1433
+ resetBlazorTemplate(this.element.id + index + '_' + 'content', 'ContentTemplate');
1434
+ }
1435
+ }
1436
+
1437
+ /**
1438
+ * Enables or disables the specified Tab item. On passing value as `false`, the item will be disabled.
1439
+ * @param {number} index - Index value of target Tab item.
1440
+ * @param {boolean} value - Boolean value that determines whether the command should be enabled or disabled.
1441
+ * By default, isEnable is true.
1442
+ * @returns void.
1443
+ */
1444
+ public enableTab(index: number, value: boolean): void {
1445
+ let tbItems: HTEle = selectAll('.' + CLS_TB_ITEM, this.element)[index];
1446
+ if (isNOU(tbItems)) { return; }
1447
+ if (value === true) {
1448
+ tbItems.classList.remove(CLS_DISABLE, CLS_OVERLAY);
1449
+ (<HTEle>tbItems.firstChild).setAttribute('tabindex', '-1');
1450
+ } else {
1451
+ tbItems.classList.add(CLS_DISABLE, CLS_OVERLAY);
1452
+ (<HTEle>tbItems.firstChild).removeAttribute('tabindex');
1453
+ if (tbItems.classList.contains(CLS_ACTIVE)) { this.select(index + 1); }
1454
+ }
1455
+ if (!isNOU(this.items[index])) {
1456
+ this.items[index].disabled = !value;
1457
+ this.dataBind();
1458
+ }
1459
+ tbItems.setAttribute('aria-disabled', (value === true) ? 'false' : 'true');
1460
+ }
1461
+ /**
1462
+ * Adds new items to the Tab that accepts an array as Tab items.
1463
+ * @param {TabItemsModel[]} items - An array of item that is added to the Tab.
1464
+ * @param {number} index - Number value that determines where the items to be added. By default, index is 0.
1465
+ * @returns void.
1466
+ */
1467
+ public addTab(items: TabItemModel[], index?: number): void {
1468
+ let addArgs: AddEventArgs = { addedItems: items, cancel: false };
1469
+ if (!this.isReplace) {
1470
+ this.trigger('adding', addArgs, (tabAddingArgs: AddEventArgs) => {
1471
+ if (!tabAddingArgs.cancel) { this.addingTabContent(items, index); }
1472
+ });
1473
+ } else {
1474
+ this.addingTabContent(items, index);
1475
+ }
1476
+ }
1477
+ private addingTabContent(items: TabItemModel[], index?: number): void {
1478
+ let lastEleIndex: number = 0;
1479
+ this.hdrEle = <HTEle>select('.' + CLS_HEADER, this.element);
1480
+ if (isNOU(this.hdrEle)) {
1481
+ this.items = items;
1482
+ this.reRenderItems();
1483
+ } else {
1484
+ let itemsCount: number = selectAll('.' + CLS_TB_ITEM, this.element).length;
1485
+ if (itemsCount !== 0) { lastEleIndex = this.lastIndex + 1; }
1486
+ if (isNOU(index)) { index = itemsCount - 1; }
1487
+ if (itemsCount < index || index < 0 || isNaN(index)) { return; }
1488
+ if (itemsCount === 0 && !isNOU(this.hdrEle)) { this.hdrEle.style.display = ''; }
1489
+ if (!isNOU(this.bdrLine)) { this.bdrLine.classList.add(CLS_HIDDEN); }
1490
+ this.tbItems = <HTEle>select('.' + CLS_TB_ITEMS, this.getTabHeader());
1491
+ this.isAdd = true;
1492
+ let tabItems: object[] = this.parseObject(items, index);
1493
+ this.isAdd = false;
1494
+ let i: number = 0;
1495
+ let textValue: string | HTEle;
1496
+ items.forEach((item: TabItemModel, place: number) => {
1497
+ textValue = item.headerTemplate || item.header.text;
1498
+ if (!(isNOU(item.headerTemplate || item.header) ||
1499
+ isNOU(textValue) || ((<string>textValue).length === 0) && isNOU(item.header.iconCss))) {
1500
+ this.items.splice((index + i), 0, item);
1501
+ i++;
1502
+ }
1503
+ if (this.isTemplate && !isNOU(item.header) && !isNOU(item.header.text)) {
1504
+ let no: number = lastEleIndex + place;
1505
+ let ele: HTEle = this.createElement('div', {
1506
+ id: CLS_CONTENT + this.tabId + '_' + no, className: CLS_ITEM,
1507
+ attrs: { role: 'tabpanel', 'aria-labelledby': CLS_ITEM + this.tabId + '_' + no }
1508
+ });
1509
+ this.cntEle.insertBefore(ele, this.cntEle.children[(index + place)]);
1510
+ let eleTrg: HTEle = this.getTrgContent(this.cntEle, no.toString());
1511
+ this.getContent(eleTrg, item.content, 'render', index);
1512
+ }
1513
+ });
1514
+ this.tbObj.addItems(tabItems, index);
1515
+ if (!this.isReplace) {
1516
+ this.trigger('added', { addedItems: items });
1517
+ }
1518
+ if (this.selectedItem === index) { this.select(index); } else { this.setActiveBorder(); }
1519
+ }
1520
+ }
1521
+ /**
1522
+ * Removes the items in the Tab from the specified index.
1523
+ * @param {number} index - Index of target item that is going to be removed.
1524
+ * @returns void.
1525
+ */
1526
+ public removeTab(index: number): void {
1527
+ let trg: HTEle = selectAll('.' + CLS_TB_ITEM, this.element)[index];
1528
+ if (isNOU(trg)) {
1529
+ return;
1530
+ }
1531
+ let removeArgs: RemoveEventArgs = { removedItem: trg, removedIndex: index, cancel: false };
1532
+ this.trigger('removing', removeArgs, (tabRemovingArgs: RemoveEventArgs) => {
1533
+ if (!tabRemovingArgs.cancel) {
1534
+ this.resetBlazorTemplates(this.items[index], index);
1535
+ this.tbObj.removeItems(index);
1536
+ this.items.splice(index, 1);
1537
+ this.itemIndexArray.splice(index, 1);
1538
+ this.refreshActiveBorder();
1539
+ let cntTrg: HTEle =
1540
+ <HTEle>select('#' + CLS_CONTENT + this.tabId + '_' + this.extIndex(trg.id), select('.' + CLS_CONTENT, this.element));
1541
+ if (!isNOU(cntTrg)) { detach(cntTrg); }
1542
+ this.trigger('removed', tabRemovingArgs);
1543
+ if (trg.classList.contains(CLS_ACTIVE)) {
1544
+ // tslint:disable-next-line:max-line-length
1545
+ index = (index > selectAll('.' + CLS_TB_ITEM + ':not(.' + CLS_TB_POPUP + ')', this.element).length - 1) ? index - 1 : index;
1546
+ this.enableAnimation = false;
1547
+ this.selectedItem = index;
1548
+ this.select(index);
1549
+ }
1550
+ if (selectAll('.' + CLS_TB_ITEM, this.element).length === 0) { this.hdrEle.style.display = 'none'; }
1551
+ this.enableAnimation = true;
1552
+ }
1553
+ });
1554
+ }
1555
+ /**
1556
+ * Shows or hides the Tab that is in the specified index.
1557
+ * @param {number} index - Index value of target item.
1558
+ * @param {boolean} value - Based on this Boolean value, item will be hide (false) or show (true). By default, value is true.
1559
+ * @returns void.
1560
+ */
1561
+ public hideTab(index: number, value?: boolean): void {
1562
+ let items: HTMLElement[];
1563
+ let item: HTEle = selectAll('.' + CLS_TB_ITEM, this.element)[index];
1564
+ if (isNOU(item)) { return; }
1565
+ if (isNOU(value)) { value = true; }
1566
+ this.bdrLine.classList.add(CLS_HIDDEN);
1567
+ if (value === true) {
1568
+ item.classList.add(CLS_HIDDEN);
1569
+ items = selectAll('.' + CLS_TB_ITEM + ':not(.' + CLS_HIDDEN + ')', this.tbItems);
1570
+ if (items.length !== 0 && item.classList.contains(CLS_ACTIVE)) {
1571
+ if (index !== 0) {
1572
+ for (let i: number = index - 1; i >= 0; i--) {
1573
+ if (!this.tbItem[i].classList.contains(CLS_HIDDEN)) {
1574
+ this.select(i);
1575
+ break;
1576
+ } else if (i === 0) {
1577
+ for (let k: number = index + 1; k < this.tbItem.length; k++) {
1578
+ if (!this.tbItem[k].classList.contains(CLS_HIDDEN)) {
1579
+ this.select(k);
1580
+ break;
1581
+ }
1582
+ }
1583
+ }
1584
+ }
1585
+ } else {
1586
+ for (let k: number = index + 1; k < this.tbItem.length; k++) {
1587
+ if (!this.tbItem[k].classList.contains(CLS_HIDDEN)) {
1588
+ this.select(k);
1589
+ break;
1590
+ }
1591
+ }
1592
+ }
1593
+ } else if (items.length === 0) {
1594
+ this.element.classList.add(CLS_HIDDEN);
1595
+ }
1596
+ } else {
1597
+ this.element.classList.remove(CLS_HIDDEN);
1598
+ items = selectAll('.' + CLS_TB_ITEM + ':not(.' + CLS_HIDDEN + ')', this.tbItems);
1599
+ if (items.length === 0) { this.select(index); }
1600
+ item.classList.remove(CLS_HIDDEN);
1601
+ }
1602
+ this.setActiveBorder();
1603
+ item.setAttribute('aria-hidden', '' + value);
1604
+ }
1605
+ /**
1606
+ * Specifies the index or HTMLElement to select an item from the Tab.
1607
+ * @param {number | HTMLElement} args - Index or DOM element is used for selecting an item from the Tab.
1608
+ * @returns void.
1609
+ */
1610
+ public select(args: number | HTEle): void {
1611
+ let tabHeader: HTMLElement = this.getTabHeader();
1612
+ this.tbItems = <HTEle>select('.' + CLS_TB_ITEMS, tabHeader);
1613
+ this.tbItem = selectAll('.' + CLS_TB_ITEM, tabHeader);
1614
+ this.content = <HTEle>select('.' + CLS_CONTENT, this.element);
1615
+ this.prevItem = this.tbItem[this.prevIndex];
1616
+ if (isNOU(this.selectedItem) || (this.selectedItem < 0) || (this.tbItem.length <= this.selectedItem) || isNaN(this.selectedItem)) {
1617
+ this.selectedItem = 0;
1618
+ } else {
1619
+ this.selectedID = this.extIndex(this.tbItem[this.selectedItem].id);
1620
+ }
1621
+ let trg: HTEle = this.tbItem[args as number];
1622
+ if (isNOU(trg)) {
1623
+ this.selectedID = '0';
1624
+ } else {
1625
+ this.selectingID = this.extIndex(trg.id);
1626
+ }
1627
+ if (!isNOU(this.prevItem) && !this.prevItem.classList.contains(CLS_DISABLE)) {
1628
+ this.prevItem.children.item(0).setAttribute('tabindex', '-1');
1629
+ }
1630
+ let eventArg: SelectingEventArgs = {
1631
+ previousItem: this.prevItem,
1632
+ previousIndex: this.prevIndex,
1633
+ selectedItem: this.tbItem[this.selectedItem],
1634
+ selectedIndex: this.selectedItem,
1635
+ selectedContent: !isNOU(this.content) ?
1636
+ <HTEle>select('#' + CLS_CONTENT + this.tabId + '_' + this.selectedID, this.content) : null,
1637
+ selectingItem: trg,
1638
+ selectingIndex: args as number,
1639
+ selectingContent: !isNOU(this.content) ?
1640
+ <HTEle>select('#' + CLS_CONTENT + this.tabId + '_' + this.selectingID, this.content) : null,
1641
+ isSwiped: this.isSwipeed,
1642
+ cancel: false
1643
+ };
1644
+ if (!this.initRender || this.selectedItem !== 0) {
1645
+ this.trigger('selecting', eventArg, (selectArgs: SelectingEventArgs) => {
1646
+ if (!selectArgs.cancel) {
1647
+ this.selectingContent(args);
1648
+ }
1649
+ });
1650
+ } else {
1651
+ this.selectingContent(args);
1652
+ }
1653
+ }
1654
+
1655
+ private selectingContent(args: number | HTEle): void {
1656
+ if (typeof args === 'number') {
1657
+ if (!isNOU(this.tbItem[args]) && this.tbItem[<number>args].classList.contains(CLS_DISABLE)) {
1658
+ for (let i: number = <number>args + 1; i < this.items.length; i++) {
1659
+ if (this.items[i].disabled === false) {
1660
+ args = i; break;
1661
+ } else { args = 0; }
1662
+ }
1663
+ }
1664
+ if (this.tbItem.length > args && args >= 0 && !isNaN(args)) {
1665
+ this.prevIndex = this.selectedItem;
1666
+ if (this.tbItem[args].classList.contains(CLS_TB_POPUP)) {
1667
+ this.setActive(this.popupHandler(this.tbItem[args]));
1668
+ } else {
1669
+ this.setActive(args);
1670
+ }
1671
+ } else {
1672
+ this.setActive(0);
1673
+ }
1674
+ } else if (args instanceof (HTMLElement)) {
1675
+ this.setActive(this.getEleIndex(args));
1676
+ }
1677
+ }
1678
+ /**
1679
+ * Specifies the value to disable/enable the Tab component.
1680
+ * When set to `true`, the component will be disabled.
1681
+ * @param {boolean} value - Based on this Boolean value, Tab will be enabled (false) or disabled (true).
1682
+ * @returns void.
1683
+ */
1684
+ public disable(value: boolean): void {
1685
+ this.setCssClass(this.element, CLS_DISABLE, value);
1686
+ this.element.setAttribute('aria-disabled', '' + value);
1687
+ }
1688
+ /**
1689
+ * Get the properties to be maintained in the persisted state.
1690
+ * @returns string
1691
+ */
1692
+ protected getPersistData(): string {
1693
+ return this.addOnPersist(['selectedItem', 'actEleId']);
1694
+ }
1695
+ /**
1696
+ * Returns the current module name.
1697
+ * @returns string
1698
+ * @private
1699
+ */
1700
+ protected getModuleName(): string {
1701
+ return 'tab';
1702
+ }
1703
+ /**
1704
+ * Gets called when the model property changes.The data that describes the old and new values of the property that changed.
1705
+ * @param {TabModel} newProp
1706
+ * @param {TabModel} oldProp
1707
+ * @returns void
1708
+ * @private
1709
+ */
1710
+ public onPropertyChanged(newProp: TabModel, oldProp: TabModel): void {
1711
+ for (let prop of Object.keys(newProp)) {
1712
+ switch (prop) {
1713
+ case 'width':
1714
+ setStyle(this.element, { width: formatUnit(newProp.width) });
1715
+ break;
1716
+ case 'height':
1717
+ setStyle(this.element, { height: formatUnit(newProp.height) });
1718
+ this.setContentHeight(false);
1719
+ break;
1720
+ case 'cssClass':
1721
+ if (oldProp.cssClass !== '') {
1722
+ this.setCssClass(this.element, oldProp.cssClass, false);
1723
+ this.setCssClass(this.element, newProp.cssClass, true);
1724
+ } else {
1725
+ this.setCssClass(this.element, newProp.cssClass, true);
1726
+ }
1727
+ break;
1728
+ case 'items':
1729
+ this.evalOnPropertyChangeItems(newProp, oldProp);
1730
+ break;
1731
+ case 'showCloseButton':
1732
+ this.setCloseButton(newProp.showCloseButton);
1733
+ break;
1734
+ case 'selectedItem':
1735
+ this.selectedItem = oldProp.selectedItem;
1736
+ this.select(newProp.selectedItem);
1737
+ break;
1738
+ case 'headerPlacement':
1739
+ this.changeOrientation(newProp.headerPlacement);
1740
+ break;
1741
+ case 'enableRtl':
1742
+ this.setRTL(newProp.enableRtl);
1743
+ break;
1744
+ case 'overflowMode':
1745
+ this.tbObj.overflowMode = newProp.overflowMode;
1746
+ this.tbObj.dataBind();
1747
+ this.refreshActElePosition();
1748
+ break;
1749
+ case 'heightAdjustMode':
1750
+ this.setContentHeight(false);
1751
+ this.select(this.selectedItem);
1752
+ break;
1753
+ case 'scrollStep':
1754
+ if (this.tbObj) {
1755
+ this.tbObj.scrollStep = this.scrollStep;
1756
+ }
1757
+ break;
1758
+ }
1759
+ }
1760
+ }
1761
+ }