tabs.mjs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { Directive, ElementRef, EventEmitter, HostListener, Output, ViewChild, } from '@angular/core';
  2. import * as i0 from "@angular/core";
  3. import * as i1 from "../../providers/nav-controller";
  4. // eslint-disable-next-line @angular-eslint/directive-class-suffix
  5. export class IonTabs {
  6. navCtrl;
  7. tabsInner;
  8. /**
  9. * Emitted before the tab view is changed.
  10. */
  11. ionTabsWillChange = new EventEmitter();
  12. /**
  13. * Emitted after the tab view is changed.
  14. */
  15. ionTabsDidChange = new EventEmitter();
  16. tabBarSlot = 'bottom';
  17. hasTab = false;
  18. selectedTab;
  19. leavingTab;
  20. constructor(navCtrl) {
  21. this.navCtrl = navCtrl;
  22. }
  23. ngAfterViewInit() {
  24. /**
  25. * Developers must pass at least one ion-tab
  26. * inside of ion-tabs if they want to use a
  27. * basic tab-based navigation without the
  28. * history stack or URL updates associated
  29. * with the router.
  30. */
  31. const firstTab = this.tabs.length > 0 ? this.tabs.first : undefined;
  32. if (firstTab) {
  33. this.hasTab = true;
  34. this.setActiveTab(firstTab.tab);
  35. this.tabSwitch();
  36. }
  37. }
  38. ngAfterContentInit() {
  39. this.detectSlotChanges();
  40. }
  41. ngAfterContentChecked() {
  42. this.detectSlotChanges();
  43. }
  44. /**
  45. * @internal
  46. */
  47. onStackWillChange({ enteringView, tabSwitch }) {
  48. const stackId = enteringView.stackId;
  49. if (tabSwitch && stackId !== undefined) {
  50. this.ionTabsWillChange.emit({ tab: stackId });
  51. }
  52. }
  53. /**
  54. * @internal
  55. */
  56. onStackDidChange({ enteringView, tabSwitch }) {
  57. const stackId = enteringView.stackId;
  58. if (tabSwitch && stackId !== undefined) {
  59. if (this.tabBar) {
  60. this.tabBar.selectedTab = stackId;
  61. }
  62. this.ionTabsDidChange.emit({ tab: stackId });
  63. }
  64. }
  65. /**
  66. * When a tab button is clicked, there are several scenarios:
  67. * 1. If the selected tab is currently active (the tab button has been clicked
  68. * again), then it should go to the root view for that tab.
  69. *
  70. * a. Get the saved root view from the router outlet. If the saved root view
  71. * matches the tabRootUrl, set the route view to this view including the
  72. * navigation extras.
  73. * b. If the saved root view from the router outlet does
  74. * not match, navigate to the tabRootUrl. No navigation extras are
  75. * included.
  76. *
  77. * 2. If the current tab tab is not currently selected, get the last route
  78. * view from the router outlet.
  79. *
  80. * a. If the last route view exists, navigate to that view including any
  81. * navigation extras
  82. * b. If the last route view doesn't exist, then navigate
  83. * to the default tabRootUrl
  84. */
  85. select(tabOrEvent) {
  86. const isTabString = typeof tabOrEvent === 'string';
  87. const tab = isTabString ? tabOrEvent : tabOrEvent.detail.tab;
  88. /**
  89. * If the tabs are not using the router, then
  90. * the tab switch logic is handled by the tabs
  91. * component itself.
  92. */
  93. if (this.hasTab) {
  94. this.setActiveTab(tab);
  95. this.tabSwitch();
  96. return;
  97. }
  98. const alreadySelected = this.outlet.getActiveStackId() === tab;
  99. const tabRootUrl = `${this.outlet.tabsPrefix}/${tab}`;
  100. /**
  101. * If this is a nested tab, prevent the event
  102. * from bubbling otherwise the outer tabs
  103. * will respond to this event too, causing
  104. * the app to get directed to the wrong place.
  105. */
  106. if (!isTabString) {
  107. tabOrEvent.stopPropagation();
  108. }
  109. if (alreadySelected) {
  110. const activeStackId = this.outlet.getActiveStackId();
  111. const activeView = this.outlet.getLastRouteView(activeStackId);
  112. // If on root tab, do not navigate to root tab again
  113. if (activeView?.url === tabRootUrl) {
  114. return;
  115. }
  116. const rootView = this.outlet.getRootView(tab);
  117. const navigationExtras = rootView && tabRootUrl === rootView.url && rootView.savedExtras;
  118. return this.navCtrl.navigateRoot(tabRootUrl, {
  119. ...navigationExtras,
  120. animated: true,
  121. animationDirection: 'back',
  122. });
  123. }
  124. else {
  125. const lastRoute = this.outlet.getLastRouteView(tab);
  126. /**
  127. * If there is a lastRoute, goto that, otherwise goto the fallback url of the
  128. * selected tab
  129. */
  130. const url = lastRoute?.url || tabRootUrl;
  131. const navigationExtras = lastRoute?.savedExtras;
  132. return this.navCtrl.navigateRoot(url, {
  133. ...navigationExtras,
  134. animated: true,
  135. animationDirection: 'back',
  136. });
  137. }
  138. }
  139. setActiveTab(tab) {
  140. const tabs = this.tabs;
  141. const selectedTab = tabs.find((t) => t.tab === tab);
  142. if (!selectedTab) {
  143. console.error(`[Ionic Error]: Tab with id: "${tab}" does not exist`);
  144. return;
  145. }
  146. this.leavingTab = this.selectedTab;
  147. this.selectedTab = selectedTab;
  148. this.ionTabsWillChange.emit({ tab });
  149. selectedTab.el.active = true;
  150. }
  151. tabSwitch() {
  152. const { selectedTab, leavingTab } = this;
  153. if (this.tabBar && selectedTab) {
  154. this.tabBar.selectedTab = selectedTab.tab;
  155. }
  156. if (leavingTab?.tab !== selectedTab?.tab) {
  157. if (leavingTab?.el) {
  158. leavingTab.el.active = false;
  159. }
  160. }
  161. if (selectedTab) {
  162. this.ionTabsDidChange.emit({ tab: selectedTab.tab });
  163. }
  164. }
  165. getSelected() {
  166. if (this.hasTab) {
  167. return this.selectedTab?.tab;
  168. }
  169. return this.outlet.getActiveStackId();
  170. }
  171. /**
  172. * Detects changes to the slot attribute of the tab bar.
  173. *
  174. * If the slot attribute has changed, then the tab bar
  175. * should be relocated to the new slot position.
  176. */
  177. detectSlotChanges() {
  178. this.tabBars.forEach((tabBar) => {
  179. // el is a protected attribute from the generated component wrapper
  180. const currentSlot = tabBar.el.getAttribute('slot');
  181. if (currentSlot !== this.tabBarSlot) {
  182. this.tabBarSlot = currentSlot;
  183. this.relocateTabBar();
  184. }
  185. });
  186. }
  187. /**
  188. * Relocates the tab bar to the new slot position.
  189. */
  190. relocateTabBar() {
  191. /**
  192. * `el` is a protected attribute from the generated component wrapper.
  193. * To avoid having to manually create the wrapper for tab bar, we
  194. * cast the tab bar to any and access the protected attribute.
  195. */
  196. const tabBar = this.tabBar.el;
  197. if (this.tabBarSlot === 'top') {
  198. /**
  199. * A tab bar with a slot of "top" should be inserted
  200. * at the top of the container.
  201. */
  202. this.tabsInner.nativeElement.before(tabBar);
  203. }
  204. else {
  205. /**
  206. * A tab bar with a slot of "bottom" or without a slot
  207. * should be inserted at the end of the container.
  208. */
  209. this.tabsInner.nativeElement.after(tabBar);
  210. }
  211. }
  212. /** @nocollapse */ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: IonTabs, deps: [{ token: i1.NavController }], target: i0.ɵɵFactoryTarget.Directive });
  213. /** @nocollapse */ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: IonTabs, selector: "ion-tabs", outputs: { ionTabsWillChange: "ionTabsWillChange", ionTabsDidChange: "ionTabsDidChange" }, host: { listeners: { "ionTabButtonClick": "select($event)" } }, viewQueries: [{ propertyName: "tabsInner", first: true, predicate: ["tabsInner"], descendants: true, read: ElementRef, static: true }], ngImport: i0 });
  214. }
  215. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: IonTabs, decorators: [{
  216. type: Directive,
  217. args: [{
  218. selector: 'ion-tabs',
  219. }]
  220. }], ctorParameters: function () { return [{ type: i1.NavController }]; }, propDecorators: { tabsInner: [{
  221. type: ViewChild,
  222. args: ['tabsInner', { read: ElementRef, static: true }]
  223. }], ionTabsWillChange: [{
  224. type: Output
  225. }], ionTabsDidChange: [{
  226. type: Output
  227. }], select: [{
  228. type: HostListener,
  229. args: ['ionTabButtonClick', ['$event']]
  230. }] } });
  231. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFicy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL2NvbW1vbi9zcmMvZGlyZWN0aXZlcy9uYXZpZ2F0aW9uL3RhYnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUdMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLFlBQVksRUFDWixNQUFNLEVBQ04sU0FBUyxHQUdWLE1BQU0sZUFBZSxDQUFDOzs7QUFTdkIsa0VBQWtFO0FBQ2xFLE1BQU0sT0FBZ0IsT0FBTztJQTJCUDtJQWpCd0MsU0FBUyxDQUE2QjtJQUVsRzs7T0FFRztJQUNPLGlCQUFpQixHQUFHLElBQUksWUFBWSxFQUFtQixDQUFDO0lBQ2xFOztPQUVHO0lBQ08sZ0JBQWdCLEdBQUcsSUFBSSxZQUFZLEVBQW1CLENBQUM7SUFFekQsVUFBVSxHQUFHLFFBQVEsQ0FBQztJQUV0QixNQUFNLEdBQUcsS0FBSyxDQUFDO0lBQ2YsV0FBVyxDQUFtQjtJQUM5QixVQUFVLENBQU87SUFFekIsWUFBb0IsT0FBc0I7UUFBdEIsWUFBTyxHQUFQLE9BQU8sQ0FBZTtJQUFHLENBQUM7SUFFOUMsZUFBZTtRQUNiOzs7Ozs7V0FNRztRQUNILE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUVwRSxJQUFJLFFBQVEsRUFBRTtZQUNaLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO1lBQ25CLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ2hDLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztTQUNsQjtJQUNILENBQUM7SUFFRCxrQkFBa0I7UUFDaEIsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7SUFDM0IsQ0FBQztJQUVELHFCQUFxQjtRQUNu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VnRCLE9BQU87a0JBSjVCLFNBQVM7bUJBQUM7b0JBQ1QsUUFBUSxFQUFFLFVBQVU7aUJBQ3JCO29HQVk2RCxTQUFTO3NCQUFwRSxTQUFTO3VCQUFDLFdBQVcsRUFBRSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFLaEQsaUJBQWlCO3NCQUExQixNQUFNO2dCQUlHLGdCQUFnQjtzQkFBekIsTUFBTTtnQkErRVAsTUFBTTtzQkFETCxZQUFZO3VCQUFDLG1CQUFtQixFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWZ0ZXJDb250ZW50Q2hlY2tlZCxcbiAgQWZ0ZXJDb250ZW50SW5pdCxcbiAgRGlyZWN0aXZlLFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgT3V0cHV0LFxuICBWaWV3Q2hpbGQsXG4gIEFmdGVyVmlld0luaXQsXG4gIFF1ZXJ5TGlzdCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IE5hdkNvbnRyb2xsZXIgfSBmcm9tICcuLi8uLi9wcm92aWRlcnMvbmF2LWNvbnRyb2xsZXInO1xuXG5pbXBvcnQgeyBTdGFja0RpZENoYW5nZUV2ZW50LCBTdGFja1dpbGxDaGFuZ2VFdmVudCB9IGZyb20gJy4vc3RhY2stdXRpbHMnO1xuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdpb24tdGFicycsXG59KVxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC9kaXJlY3RpdmUtY2xhc3Mtc3VmZml4XG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgSW9uVGFicyBpbXBsZW1lbnRzIEFmdGVyVmlld0luaXQsIEFmdGVyQ29udGVudEluaXQsIEFmdGVyQ29udGVudENoZWNrZWQge1xuICAvKipcbiAgICogTm90ZTogVGhlc2UgbXVzdCBiZSByZWRlY2xhcmVkIG9uIGVhY2ggY2hpbGQgY2xhc3Mgc2luY2UgaXQgbmVlZHNcbiAgICogYWNjZXNzIHRvIGdlbmVyYXRlZCBjb21wb25lbnRzIHN1Y2ggYXMgSW9uUm91dGVyT3V0bGV0IGFuZCBJb25UYWJCYXIuXG4gICAqL1xuICBhYnN0cmFjdCBvdXRsZXQ6IGFueTtcbiAgYWJzdHJhY3QgdGFiQmFyOiBhbnk7XG4gIGFic3RyYWN0IHRhYkJhcnM6IFF1ZXJ5TGlzdDxhbnk+O1xuICBhYnN0cmFjdCB0YWJzOiBRdWVyeUxpc3Q8YW55PjtcblxuICBAVmlld0NoaWxkKCd0YWJzSW5uZXInLCB7IHJlYWQ6IEVsZW1lbnRSZWYsIHN0YXRpYzogdHJ1ZSB9KSB0YWJzSW5uZXI6IEVsZW1lbnRSZWY8SFRNTERpdkVsZW1lbnQ+O1xuXG4gIC8qKlxuICAgKiBFbWl0dGVkIGJlZm9yZSB0aGUgdGFiIHZpZXcgaXMgY2hhbmdlZC5cbiAgICovXG4gIEBPdXRwdXQoKSBpb25UYWJzV2lsbENoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8eyB0YWI6IHN0cmluZyB9PigpO1xuICAvKipcbiAgICogRW1pdHRlZCBhZnRlciB0aGUgdGFiIHZpZXcgaXMgY2hhbmdlZC5cbiAgICovXG4gIEBPdXRwdXQoKSBpb25UYWJzRGlkQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjx7IHRhYjogc3RyaW5nIH0+KCk7XG5cbiAgcHJpdmF0ZSB0YWJCYXJTbG90ID0gJ2JvdHRvbSc7XG5cbiAgcHJpdmF0ZSBoYXNUYWIgPSBmYWxzZTtcbiAgcHJpdmF0ZSBzZWxlY3RlZFRhYj86IHsgdGFiOiBzdHJpbmcgfTtcbiAgcHJpdmF0ZSBsZWF2aW5nVGFiPzogYW55O1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgbmF2Q3RybDogTmF2Q29udHJvbGxlcikge31cblxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgLyoqXG4gICAgICogRGV2ZWxvcGVycyBtdXN0IHBhc3MgYXQgbGVhc3Qgb25lIGlvbi10YWJcbiAgICAgKiBpbnNpZGUgb2YgaW9uLXRhYnMgaWYgdGhleSB3YW50IHRvIHVzZSBhXG4gICAgICogYmFzaWMgdGFiLWJhc2VkIG5hdmlnYXRpb24gd2l0aG91dCB0aGVcbiAgICAgKiBoaXN0b3J5IHN0YWNrIG9yIFVSTCB1cGRhdGVzIGFzc29jaWF0ZWRcbiAgICAgKiB3aXRoIHRoZSByb3V0ZXIuXG4gICAgICovXG4gICAgY29uc3QgZmlyc3RUYWIgPSB0aGlzLnRhYnMubGVuZ3RoID4gMCA/IHRoaXMudGFicy5maXJzdCA6IHVuZGVmaW5lZDtcblxuICAgIGlmIChmaXJzdFRhYikge1xuICAgICAgdGhpcy5oYXNUYWIgPSB0cnVlO1xuICAgICAgdGhpcy5zZXRBY3RpdmVUYWIoZmlyc3RUYWIudGFiKTtcbiAgICAgIHRoaXMudGFiU3dpdGNoKCk7XG4gICAgfVxuICB9XG5cbiAgbmdBZnRlckNvbnRlbnRJbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZGV0ZWN0U2xvdENoYW5nZXMoKTtcbiAgfVxuXG4gIG5nQWZ0ZXJDb250ZW50Q2hlY2tlZCgpOiB2b2lkIHtcbiAgICB0aGlzLmRldGVjdFNsb3RDaGFuZ2VzKCk7XG4gIH1cblxuICAvKipcbiAgICogQGludGVybmFsXG4gICAqL1xuICBvblN0YWNrV2lsbENoYW5nZSh7IGVudGVyaW5nVmlldywgdGFiU3dpdGNoIH06IFN0YWNrV2lsbENoYW5nZUV2ZW50KTogdm9pZCB7XG4gICAgY29uc3Qgc3RhY2tJZCA9IGVudGVyaW5nVmlldy5zdGFja0lkO1xuICAgIGlmICh0YWJTd2l0Y2ggJiYgc3RhY2tJZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLmlvblRhYnNXaWxsQ2hhbmdlLmVtaXQoeyB0YWI6IHN0YWNrSWQgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgb25TdGFja0RpZENoYW5nZSh7IGVudGVyaW5nVmlldywgdGFiU3dpdGNoIH06IFN0YWNrRGlkQ2hhbmdlRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBzdGFja0lkID0gZW50ZXJpbmdWaWV3LnN0YWNrSWQ7XG4gICAgaWYgKHRhYlN3aXRjaCAmJiBzdGFja0lkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmICh0aGlzLnRhYkJhcikge1xuICAgICAgICB0aGlzLnRhYkJhci5zZWxlY3RlZFRhYiA9IHN0YWNrSWQ7XG4gICAgICB9XG4gICAgICB0aGlzLmlvblRhYnNEaWRDaGFuZ2UuZW1pdCh7IHRhYjogc3RhY2tJZCB9KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogV2hlbiBhIHRhYiBidXR0b24gaXMgY2xpY2tlZCwgdGhlcmUgYXJlIHNldmVyYWwgc2NlbmFyaW9zOlxuICAgKiAxLiBJZiB0aGUgc2VsZWN0ZWQgdGFiIGlzIGN1cnJlbnRseSBhY3RpdmUgKHRoZSB0YWIgYnV0dG9uIGhhcyBiZWVuIGNsaWNrZWRcbiAgICogICAgYWdhaW4pLCB0aGVuIGl0IHNob3VsZCBnbyB0byB0aGUgcm9vdCB2aWV3IGZvciB0aGF0IHRhYi5cbiAgICpcbiAgICogICBhLiBHZXQgdGhlIHNhdmVkIHJvb3QgdmlldyBmcm9tIHRoZSByb3V0ZXIgb3V0bGV0LiBJZiB0aGUgc2F2ZWQgcm9vdCB2aWV3XG4gICAqICAgICAgbWF0Y2hlcyB0aGUgdGFiUm9vdFVybCwgc2V0IHRoZSByb3V0ZSB2aWV3IHRvIHRoaXMgdmlldyBpbmNsdWRpbmcgdGhlXG4gICAqICAgICAgbmF2aWdhdGlvbiBleHRyYXMuXG4gICAqICAgYi4gSWYgdGhlIHNhdmVkIHJvb3QgdmlldyBmcm9tIHRoZSByb3V0ZXIgb3V0bGV0IGRvZXNcbiAgICogICAgICBub3QgbWF0Y2gsIG5hdmlnYXRlIHRvIHRoZSB0YWJSb290VXJsLiBObyBuYXZpZ2F0aW9uIGV4dHJhcyBhcmVcbiAgICogICAgICBpbmNsdWRlZC5cbiAgICpcbiAgICogMi4gSWYgdGhlIGN1cnJlbnQgdGFiIHRhYiBpcyBub3QgY3VycmVudGx5IHNlbGVjdGVkLCBnZXQgdGhlIGxhc3Qgcm91dGVcbiAgICogICAgdmlldyBmcm9tIHRoZSByb3V0ZXIgb3V0bGV0LlxuICAgKlxuICAgKiAgIGEuIElmIHRoZSBsYXN0IHJvdXRlIHZpZXcgZXhpc3RzLCBuYXZpZ2F0ZSB0byB0aGF0IHZpZXcgaW5jbHVkaW5nIGFueVxuICAgKiAgICAgIG5hdmlnYXRpb24gZXh0cmFzXG4gICAqICAgYi4gSWYgdGhlIGxhc3Qgcm91dGUgdmlldyBkb2Vzbid0IGV4aXN0LCB0aGVuIG5hdmlnYXRlXG4gICAqICAgICAgdG8gdGhlIGRlZmF1bHQgdGFiUm9vdFVybFxuICAgKi9cbiAgQEhvc3RMaXN0ZW5lcignaW9uVGFiQnV0dG9uQ2xpY2snLCBbJyRldmVudCddKVxuICBzZWxlY3QodGFiT3JFdmVudDogc3RyaW5nIHwgQ3VzdG9tRXZlbnQpOiBQcm9taXNlPGJvb2xlYW4+IHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCBpc1RhYlN0cmluZyA9IHR5cGVvZiB0YWJPckV2ZW50ID09PSAnc3RyaW5nJztcbiAgICBjb25zdCB0YWIgPSBpc1RhYlN0cmluZyA/IHRhYk9yRXZlbnQgOiAodGFiT3JFdmVudCBhcyBDdXN0b21FdmVudCkuZGV0YWlsLnRhYjtcblxuICAgIC8qKlxuICAgICAqIElmIHRoZSB0YWJzIGFyZSBub3QgdXNpbmcgdGhlIHJvdXRlciwgdGhlblxuICAgICAqIHRoZSB0YWIgc3dpdGNoIGxvZ2ljIGlzIGhhbmRsZWQgYnkgdGhlIHRhYnNcbiAgICAgKiBjb21wb25lbnQgaXRzZWxmLlxuICAgICAqL1xuICAgIGlmICh0aGlzLmhhc1RhYikge1xuICAgICAgdGhpcy5zZXRBY3RpdmVUYWIodGFiKTtcbiAgICAgIHRoaXMudGFiU3dpdGNoKCk7XG5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBhbHJlYWR5U2VsZWN0ZWQgPSB0aGlzLm91dGxldC5nZXRBY3RpdmVTdGFja0lkKCkgPT09IHRhYjtcbiAgICBjb25zdCB0YWJSb290VXJsID0gYCR7dGhpcy5vdXRsZXQudGFic1ByZWZpeH0vJHt0YWJ9YDtcblxuICAgIC8qKlxuICAgICAqIElmIHRoaXMgaXMgYSBuZXN0ZWQgdGFiLCBwcmV2ZW50IHRoZSBldmVudFxuICAgICAqIGZyb20gYnViYmxpbmcgb3RoZXJ3aXNlIHRoZSBvdXRlciB0YWJzXG4gICAgICogd2lsbCByZXNwb25kIHRvIHRoaXMgZXZlbnQgdG9vLCBjYXVzaW5nXG4gICAgICogdGhlIGFwcCB0byBnZXQgZGlyZWN0ZWQgdG8gdGhlIHdyb25nIHBsYWNlLlxuICAgICAqL1xuICAgIGlmICghaXNUYWJTdHJpbmcpIHtcbiAgICAgICh0YWJPckV2ZW50IGFzIEN1c3RvbUV2ZW50KS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICB9XG5cbiAgICBpZiAoYWxyZWFkeVNlbGVjdGVkKSB7XG4gICAgICBjb25zdCBhY3RpdmVTdGFja0lkID0gdGhpcy5vdXRsZXQuZ2V0QWN0aXZlU3RhY2tJZCgpO1xuICAgICAgY29uc3QgYWN0aXZlVmlldyA9IHRoaXMub3V0bGV0LmdldExhc3RSb3V0ZVZpZXcoYWN0aXZlU3RhY2tJZCk7XG5cbiAgICAgIC8vIElmIG9uIHJvb3QgdGFiLCBkbyBub3QgbmF2aWdhdGUgdG8gcm9vdCB0YWIgYWdhaW5cbiAgICAgIGlmIChhY3RpdmVWaWV3Py51cmwgPT09IHRhYlJvb3RVcmwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBjb25zdCByb290VmlldyA9IHRoaXMub3V0bGV0LmdldFJvb3RWaWV3KHRhYik7XG4gICAgICBjb25zdCBuYXZpZ2F0aW9uRXh0cmFzID0gcm9vdFZpZXcgJiYgdGFiUm9vdFVybCA9PT0gcm9vdFZpZXcudXJsICYmIHJvb3RWaWV3LnNhdmVkRXh0cmFzO1xuICAgICAgcmV0dXJuIHRoaXMubmF2Q3RybC5uYXZpZ2F0ZVJvb3QodGFiUm9vdFVybCwge1xuICAgICAgICAuLi5uYXZpZ2F0aW9uRXh0cmFzLFxuICAgICAgICBhbmltYXRlZDogdHJ1ZSxcbiAgICAgICAgYW5pbWF0aW9uRGlyZWN0aW9uOiAnYmFjaycsXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbGFzdFJvdXRlID0gdGhpcy5vdXRsZXQuZ2V0TGFzdFJvdXRlVmlldyh0YWIpO1xuICAgICAgLyoqXG4gICAgICAgKiBJZiB0aGVyZSBpcyBhIGxhc3RSb3V0ZSwgZ290byB0aGF0LCBvdGhlcndpc2UgZ290byB0aGUgZmFsbGJhY2sgdXJsIG9mIHRoZVxuICAgICAgICogc2VsZWN0ZWQgdGFiXG4gICAgICAgKi9cbiAgICAgIGNvbnN0IHVybCA9IGxhc3RSb3V0ZT8udXJsIHx8IHRhYlJvb3RVcmw7XG4gICAgICBjb25zdCBuYXZpZ2F0aW9uRXh0cmFzID0gbGFzdFJvdXRlPy5zYXZlZEV4dHJhcztcblxuICAgICAgcmV0dXJuIHRoaXMubmF2Q3RybC5uYXZpZ2F0ZVJvb3QodXJsLCB7XG4gICAgICAgIC4uLm5hdmlnYXRpb25FeHRyYXMsXG4gICAgICAgIGFuaW1hdGVkOiB0cnVlLFxuICAgICAgICBhbmltYXRpb25EaXJlY3Rpb246ICdiYWNrJyxcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc2V0QWN0aXZlVGFiKHRhYjogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgdGFicyA9IHRoaXMudGFicztcbiAgICBjb25zdCBzZWxlY3RlZFRhYiA9IHRhYnMuZmluZCgodDogYW55KSA9PiB0LnRhYiA9PT0gdGFiKTtcblxuICAgIGlmICghc2VsZWN0ZWRUYWIpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoYFtJb25pYyBFcnJvcl06IFRhYiB3aXRoIGlkOiBcIiR7dGFifVwiIGRvZXMgbm90IGV4aXN0YCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5sZWF2aW5nVGFiID0gdGhpcy5zZWxlY3RlZFRhYjtcbiAgICB0aGlzLnNlbGVjdGVkVGFiID0gc2VsZWN0ZWRUYWI7XG5cbiAgICB0aGlzLmlvblRhYnNXaWxsQ2hhbmdlLmVtaXQoeyB0YWIgfSk7XG5cbiAgICBzZWxlY3RlZFRhYi5lbC5hY3RpdmUgPSB0cnVlO1xuICB9XG5cbiAgcHJpdmF0ZSB0YWJTd2l0Y2goKTogdm9pZCB7XG4gICAgY29uc3QgeyBzZWxlY3RlZFRhYiwgbGVhdmluZ1RhYiB9ID0gdGhpcztcblxuICAgIGlmICh0aGlzLnRhYkJhciAmJiBzZWxlY3RlZFRhYikge1xuICAgICAgdGhpcy50YWJCYXIuc2VsZWN0ZWRUYWIgPSBzZWxlY3RlZFRhYi50YWI7XG4gICAgfVxuXG4gICAgaWYgKGxlYXZpbmdUYWI/LnRhYiAhPT0gc2VsZWN0ZWRUYWI/LnRhYikge1xuICAgICAgaWYgKGxlYXZpbmdUYWI/LmVsKSB7XG4gICAgICAgIGxlYXZpbmdUYWIuZWwuYWN0aXZlID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHNlbGVjdGVkVGFiKSB7XG4gICAgICB0aGlzLmlvblRhYnNEaWRDaGFuZ2UuZW1pdCh7IHRhYjogc2VsZWN0ZWRUYWIudGFiIH0pO1xuICAgIH1cbiAgfVxuXG4gIGdldFNlbGVjdGVkKCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKHRoaXMuaGFzVGFiKSB7XG4gICAgICByZXR1cm4gdGhpcy5zZWxlY3RlZFRhYj8udGFiO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLm91dGxldC5nZXRBY3RpdmVTdGFja0lkKCk7XG4gIH1cblxuICAvKipcbiAgICogRGV0ZWN0cyBjaGFuZ2VzIHRvIHRoZSBzbG90IGF0dHJpYnV0ZSBvZiB0aGUgdGFiIGJhci5cbiAgICpcbiAgICogSWYgdGhlIHNsb3QgYXR0cmlidXRlIGhhcyBjaGFuZ2VkLCB0aGVuIHRoZSB0YWIgYmFyXG4gICAqIHNob3VsZCBiZSByZWxvY2F0ZWQgdG8gdGhlIG5ldyBzbG90IHBvc2l0aW9uLlxuICAgKi9cbiAgcHJpdmF0ZSBkZXRlY3RTbG90Q2hhbmdlcygpOiB2b2lkIHtcbiAgICB0aGlzLnRhYkJhcnMuZm9yRWFjaCgodGFiQmFyOiBhbnkpID0+IHtcbiAgICAgIC8vIGVsIGlzIGEgcHJvdGVjdGVkIGF0dHJpYnV0ZSBmcm9tIHRoZSBnZW5lcmF0ZWQgY29tcG9uZW50IHdyYXBwZXJcbiAgICAgIGNvbnN0IGN1cnJlbnRTbG90ID0gdGFiQmFyLmVsLmdldEF0dHJpYnV0ZSgnc2xvdCcpO1xuXG4gICAgICBpZiAoY3VycmVudFNsb3QgIT09IHRoaXMudGFiQmFyU2xvdCkge1xuICAgICAgICB0aGlzLnRhYkJhclNsb3QgPSBjdXJyZW50U2xvdDtcbiAgICAgICAgdGhpcy5yZWxvY2F0ZVRhYkJhcigpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbG9jYXRlcyB0aGUgdGFiIGJhciB0byB0aGUgbmV3IHNsb3QgcG9zaXRpb24uXG4gICAqL1xuICBwcml2YXRlIHJlbG9jYXRlVGFiQmFyKCk6IHZvaWQge1xuICAgIC8qKlxuICAgICAqIGBlbGAgaXMgYSBwcm90ZWN0ZWQgYXR0cmlidXRlIGZyb20gdGhlIGdlbmVyYXRlZCBjb21wb25lbnQgd3JhcHBlci5cbiAgICAgKiBUbyBhdm9pZCBoYXZpbmcgdG8gbWFudWFsbHkgY3JlYXRlIHRoZSB3cmFwcGVyIGZvciB0YWIgYmFyLCB3ZVxuICAgICAqIGNhc3QgdGhlIHRhYiBiYXIgdG8gYW55IGFuZCBhY2Nlc3MgdGhlIHByb3RlY3RlZCBhdHRyaWJ1dGUuXG4gICAgICovXG4gICAgY29uc3QgdGFiQmFyID0gKHRoaXMudGFiQmFyIGFzIGFueSkuZWwgYXMgSFRNTEVsZW1lbnQ7XG5cbiAgICBpZiAodGhpcy50YWJCYXJTbG90ID09PSAndG9wJykge1xuICAgICAgLyoqXG4gICAgICAgKiBBIHRhYiBiYXIgd2l0aCBhIHNsb3Qgb2YgXCJ0b3BcIiBzaG91bGQgYmUgaW5zZXJ0ZWRcbiAgICAgICAqIGF0IHRoZSB0b3Agb2YgdGhlIGNvbnRhaW5lci5cbiAgICAgICAqL1xuICAgICAgdGhpcy50YWJzSW5uZXIubmF0aXZlRWxlbWVudC5iZWZvcmUodGFiQmFyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLyoqXG4gICAgICAgKiBBIHRhYiBiYXIgd2l0aCBhIHNsb3Qgb2YgXCJib3R0b21cIiBvciB3aXRob3V0IGEgc2xvdFxuICAgICAgICogc2hvdWxkIGJlIGluc2VydGVkIGF0IHRoZSBlbmQgb2YgdGhlIGNvbnRhaW5lci5cbiAgICAgICAqL1xuICAgICAgdGhpcy50YWJzSW5uZXIubmF0aXZlRWxlbWVudC5hZnRlcih0YWJCYXIpO1xuICAgIH1cbiAgfVxufVxuIl19