\n\n\n","import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, OnDestroy, OnInit } from '@angular/core';\nimport { NavigationEnd, Router } from '@angular/router';\nimport { Subject } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\nimport { TreoAnimations } from '@treo/animations';\nimport { TreoVerticalNavigationComponent } from '@treo/components/navigation/vertical/vertical.component';\nimport { TreoNavigationService } from '@treo/components/navigation/navigation.service';\nimport { TreoNavigationItem } from '@treo/components/navigation/navigation.types';\nimport { EventService } from '@services/events.service';\n\n@Component({\n selector : 'treo-vertical-navigation-collapsable-item',\n templateUrl : './collapsable.component.html',\n styles : [],\n animations : TreoAnimations,\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class TreoVerticalNavigationCollapsableItemComponent implements OnInit, OnDestroy\n{\n // Auto collapse\n @Input()\n autoCollapse: boolean;\n\n // Item\n @Input()\n item: TreoNavigationItem;\n\n // Collapsed\n @HostBinding('class.treo-vertical-navigation-item-collapsed')\n isCollapsed: boolean;\n\n // Expanded\n @HostBinding('class.treo-vertical-navigation-item-expanded')\n isExpanded: boolean;\n\n // Name\n @Input()\n name: string;\n\n // Private\n private _treoVerticalNavigationComponent: TreoVerticalNavigationComponent;\n private _unsubscribeAll: Subject;\n\n /**\n * Constructor\n *\n * @param {ChangeDetectorRef} _changeDetectorRef\n * @param {Router} _router\n * @param {TreoNavigationService} _treoNavigationService\n */\n constructor(\n private _changeDetectorRef: ChangeDetectorRef,\n private _router: Router,\n private _treoNavigationService: TreoNavigationService,\n private _event: EventService\n )\n {\n // Set the private defaults\n this._unsubscribeAll = new Subject();\n\n // Set the defaults\n this.isCollapsed = true;\n this.isExpanded = false;\n }\n\n // -----------------------------------------------------------------------------------------------------\n // @ Lifecycle hooks\n // -----------------------------------------------------------------------------------------------------\n\n /**\n * On init\n */\n ngOnInit(): void\n {\n // Get the parent navigation component\n this._treoVerticalNavigationComponent = this._treoNavigationService.getComponent(this.name);\n\n // If the item has a children that has a matching url with the current url, expand...\n if ( this._hasCurrentUrlAsChildren(this.item, this._router.url) )\n {\n this.expand();\n }\n // Otherwise...\n else\n {\n // If the autoCollapse is on, collapse...\n if ( this.autoCollapse )\n {\n this.collapse();\n }\n }\n\n // Listen for the onCollapsableItemCollapsed from the service\n this._treoVerticalNavigationComponent.onCollapsableItemCollapsed\n .pipe(takeUntil(this._unsubscribeAll))\n .subscribe((collapsedItem) => {\n\n // Check if the collapsed item is null\n if ( collapsedItem === null )\n {\n return;\n }\n\n // Collapse if this is a children of the collapsed item\n if ( this._isChildrenOf(collapsedItem, this.item) )\n {\n this.collapse();\n }\n });\n\n // Listen for the onCollapsableItemExpanded from the service if the autoCollapse is on\n if ( this.autoCollapse )\n {\n this._treoVerticalNavigationComponent.onCollapsableItemExpanded\n .pipe(takeUntil(this._unsubscribeAll))\n .subscribe((expandedItem) => {\n\n // Check if the expanded item is null\n if ( expandedItem === null )\n {\n return;\n }\n\n // Check if this is a parent of the expanded item\n if ( this._isChildrenOf(this.item, expandedItem) )\n {\n return;\n }\n\n // Check if this has a children with a matching url with the current active url\n if ( this._hasCurrentUrlAsChildren(this.item, this._router.url) )\n {\n return;\n }\n\n // Check if this is the expanded item\n if ( this.item === expandedItem )\n {\n return;\n }\n\n // If none of the above conditions are matched, collapse this item\n this.collapse();\n });\n }\n\n // Attach a listener to the NavigationEnd event\n this._router.events\n .pipe(\n filter(event => event instanceof NavigationEnd),\n takeUntil(this._unsubscribeAll)\n )\n .subscribe((event: NavigationEnd) => {\n\n // If the item has a children that has a matching url with the current url, expand...\n if ( this._hasCurrentUrlAsChildren(this.item, event.urlAfterRedirects) )\n {\n this.expand();\n }\n // Otherwise...\n else\n {\n // If the autoCollapse is on, collapse...\n if ( this.autoCollapse )\n {\n this.collapse();\n }\n }\n });\n\n // Subscribe to onRefreshed on the navigation component\n this._treoVerticalNavigationComponent.onRefreshed.pipe(\n takeUntil(this._unsubscribeAll)\n ).subscribe(() => {\n\n this.item.disabled = !!!this._event.eventId;\n\n if (this.item.id === 'config.events' && this._router.url === '/events/details') {\n this.item.disabled = false;\n }\n\n // Mark for check\n this._changeDetectorRef.markForCheck();\n });\n }\n\n /**\n * On destroy\n */\n ngOnDestroy(): void\n {\n // Unsubscribe from all subscriptions\n this._unsubscribeAll.next();\n this._unsubscribeAll.complete();\n }\n\n // -----------------------------------------------------------------------------------------------------\n // @ Private methods\n // -----------------------------------------------------------------------------------------------------\n\n /**\n * Check if the given item has the given url\n * in one of its children\n *\n * @param item\n * @param url\n * @private\n */\n private _hasCurrentUrlAsChildren(item, url): boolean\n {\n const children = item.children;\n\n if ( !children )\n {\n return false;\n }\n\n for ( const child of children )\n {\n if ( child.children )\n {\n if ( this._hasCurrentUrlAsChildren(child, url) )\n {\n return true;\n }\n }\n\n // Check if the item's link is the exact same of the\n // current url\n if ( child.link === url )\n {\n return true;\n }\n\n // If exactMatch is not set for the item, also check\n // if the current url starts with the item's link and\n // continues with a question mark, a pound sign or a\n // slash\n if ( !child.exactMatch && (child.link === url || url.startsWith(child.link + '?') || url.startsWith(child.link + '#') || url.startsWith(child.link + '/')) )\n {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Check if this is a children\n * of the given item\n *\n * @param parent\n * @param item\n * @return {boolean}\n * @private\n */\n private _isChildrenOf(parent, item): boolean\n {\n const children = parent.children;\n\n if ( !children )\n {\n return false;\n }\n\n if ( children.indexOf(item) > -1 )\n {\n return true;\n }\n\n for ( const child of children )\n {\n if ( child.children )\n {\n if ( this._isChildrenOf(child, item) )\n {\n return true;\n }\n }\n }\n\n return false;\n }\n\n // -----------------------------------------------------------------------------------------------------\n // @ Public methods\n // -----------------------------------------------------------------------------------------------------\n\n /**\n * Collapse\n */\n collapse(): void\n {\n // Return if the item is disabled\n if ( this.item.disabled )\n {\n return;\n }\n\n // Return if the item is already collapsed\n if ( this.isCollapsed )\n {\n return;\n }\n\n // Collapse it\n this.isCollapsed = true;\n this.isExpanded = false;\n\n // Mark for check\n this._changeDetectorRef.markForCheck();\n\n // Execute the observable\n this._treoVerticalNavigationComponent.onCollapsableItemCollapsed.next(this.item);\n }\n\n /**\n * Expand\n */\n expand(): void\n {\n // Return if the item is disabled\n if ( this.item.disabled )\n {\n return;\n }\n\n // Return if the item is already expanded\n if ( !this.isCollapsed )\n {\n return;\n }\n\n // Expand it\n this.isCollapsed = false;\n this.isExpanded = true;\n\n // Mark for check\n this._changeDetectorRef.markForCheck();\n\n // Execute the observable\n this._treoVerticalNavigationComponent.onCollapsableItemExpanded.next(this.item);\n }\n\n /**\n * Toggle collapsable\n */\n toggleCollapsable(): void\n {\n // Toggle collapse/expand\n if ( this.isCollapsed )\n {\n this.expand();\n }\n else\n {\n this.collapse();\n }\n }\n\n /**\n * Track by function for ngFor loops\n *\n * @param index\n * @param item\n */\n trackByFn(index: number, item: any): any\n {\n return item.id || index;\n }\n}\n","