// (C) Copyright 2015 Moodle Pty Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { Component, Input, AfterViewInit, ViewChild, ElementRef, } from '@angular/core'; import { CoreTabsBaseComponent } from '@classes/tabs'; import { CoreTabComponent } from './tab'; /** * This component displays some top scrollable tabs that will autohide on vertical scroll. * Unlike core-tabs-outlet, this component does NOT use Angular router. * * Example usage: * * * * * * * * */ @Component({ selector: 'core-tabs', templateUrl: 'core-tabs.html', styleUrls: ['tabs.scss'], }) export class CoreTabsComponent extends CoreTabsBaseComponent implements AfterViewInit { @Input() parentScrollable = false; // Determine if the scroll should be in the parent content or the tab itself. @ViewChild('originalTabs') originalTabsRef?: ElementRef; protected originalTabsContainer?: HTMLElement; // The container of the original tabs. It will include each tab's content. constructor( element: ElementRef, ) { super(element); } /** * View has been initialized. */ async ngAfterViewInit(): Promise { super.ngAfterViewInit(); if (this.isDestroyed) { return; } this.tabsElement = this.element.nativeElement; this.originalTabsContainer = this.originalTabsRef?.nativeElement; } /** * Initialize the tabs, determining the first tab to be shown. */ protected async initializeTabs(): Promise { await super.initializeTabs(); // @todo: Is this still needed? // if (this.content) { // if (!this.parentScrollable) { // // Parent scroll element (if core-tabs is inside a ion-content). // const scroll = await this.content.getScrollElement(); // if (scroll) { // scroll.classList.add('no-scroll'); // } // } else { // this.originalTabsContainer?.classList.add('no-scroll'); // } // } } /** * Add a new tab if it isn't already in the list of tabs. * * @param tab The tab to add. */ addTab(tab: CoreTabComponent): void { // Check if tab is already in the list. if (this.getTabIndex(tab.id!) == -1) { this.tabs.push(tab); this.sortTabs(); setTimeout(() => { this.calculateSlides(); }); if (this.initialized && this.tabs.length > 1 && this.tabBarHeight == 0) { // Calculate the tabBarHeight again now that there is more than 1 tab and the bar will be seen. // Use timeout to wait for the view to be rendered. 0 ms should be enough, use 50 to be sure. setTimeout(() => { this.calculateTabBarHeight(); }, 50); } } } /** * Remove a tab from the list of tabs. * * @param tab The tab to remove. */ removeTab(tab: CoreTabComponent): void { const index = this.getTabIndex(tab.id!); this.tabs.splice(index, 1); this.calculateSlides(); } /** * Load the tab. * * @param tabToSelect Tab to load. * @return Promise resolved with true if tab is successfully loaded. */ protected async loadTab(tabToSelect: CoreTabComponent): Promise { const currentTab = this.getSelected(); currentTab?.unselectTab(); tabToSelect.selectTab(); return true; } /** * Sort the tabs, keeping the same order as in the original list. */ protected sortTabs(): void { if (!this.originalTabsContainer) { return; } const newTabs: CoreTabComponent[] = []; this.tabs.forEach((tab) => { const originalIndex = Array.prototype.indexOf.call(this.originalTabsContainer?.children, tab.element); if (originalIndex != -1) { newTabs[originalIndex] = tab; } }); this.tabs = newTabs; } /** * Function to call when the visibility of a tab has changed. */ tabVisibilityChanged(): void { this.calculateSlides(); } }