2018-01-12 11:27:57 +00:00
|
|
|
// (C) Copyright 2015 Martin Dougiamas
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
|
2018-01-19 08:00:59 +00:00
|
|
|
import { Component, Input, Output, EventEmitter, OnInit, OnChanges, AfterViewInit, ViewChild, ElementRef,
|
|
|
|
SimpleChange } from '@angular/core';
|
2018-01-12 11:27:57 +00:00
|
|
|
import { CoreTabComponent } from './tab';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This component displays some tabs that usually share data between them.
|
|
|
|
*
|
|
|
|
* If your tabs don't share any data then you should probably use ion-tabs. This component doesn't use different ion-nav
|
|
|
|
* for each tab, so it will not load pages.
|
|
|
|
*
|
|
|
|
* Example usage:
|
|
|
|
*
|
|
|
|
* <core-tabs selectedIndex="1">
|
|
|
|
* <core-tab [title]="'core.courses.timeline' | translate" (ionSelect)="switchTab('timeline')">
|
2018-01-19 14:41:14 +00:00
|
|
|
* <ng-template> <!-- This ng-template is required, @see CoreTabComponent. -->
|
|
|
|
* <!-- Tab contents. -->
|
|
|
|
* </ng-template>
|
2018-01-12 11:27:57 +00:00
|
|
|
* </core-tab>
|
|
|
|
* </core-tabs>
|
|
|
|
*
|
|
|
|
* Obviously, the tab contents will only be shown if that tab is selected.
|
|
|
|
*/
|
|
|
|
@Component({
|
|
|
|
selector: 'core-tabs',
|
|
|
|
templateUrl: 'tabs.html'
|
|
|
|
})
|
2018-01-19 08:00:59 +00:00
|
|
|
export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
2018-01-12 11:27:57 +00:00
|
|
|
@Input() selectedIndex?: number = 0; // Index of the tab to select.
|
2018-01-19 08:00:59 +00:00
|
|
|
@Input() hideUntil: boolean; // Determine when should the contents be shown.
|
2018-01-12 11:27:57 +00:00
|
|
|
@Output() ionChange: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); // Emitted when the tab changes.
|
|
|
|
@ViewChild('originalTabs') originalTabsRef: ElementRef;
|
|
|
|
|
|
|
|
tabs: CoreTabComponent[] = []; // List of tabs.
|
|
|
|
selected: number; // Selected tab number.
|
|
|
|
protected originalTabsContainer: HTMLElement; // The container of the original tabs. It will include each tab's content.
|
2018-01-19 08:00:59 +00:00
|
|
|
protected initialized = false;
|
|
|
|
protected afterViewInitTriggered = false;
|
2018-01-12 11:27:57 +00:00
|
|
|
|
|
|
|
constructor() {}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Component being initialized.
|
|
|
|
*/
|
|
|
|
ngOnInit() {
|
|
|
|
this.originalTabsContainer = this.originalTabsRef.nativeElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* View has been initialized.
|
|
|
|
*/
|
|
|
|
ngAfterViewInit() {
|
2018-01-19 08:00:59 +00:00
|
|
|
this.afterViewInitTriggered = true;
|
|
|
|
if (!this.initialized && this.hideUntil) {
|
|
|
|
// Tabs should be shown, initialize them.
|
|
|
|
this.initializeTabs();
|
2018-01-12 11:27:57 +00:00
|
|
|
}
|
2018-01-19 08:00:59 +00:00
|
|
|
}
|
2018-01-12 11:27:57 +00:00
|
|
|
|
2018-01-19 08:00:59 +00:00
|
|
|
/**
|
|
|
|
* Detect changes on input properties.
|
|
|
|
*/
|
|
|
|
ngOnChanges(changes: {[name: string]: SimpleChange}) {
|
|
|
|
// We need to wait for ngAfterViewInit because we need core-tab components to be executed.
|
|
|
|
if (!this.initialized && this.hideUntil && this.afterViewInitTriggered) {
|
|
|
|
// Tabs should be shown, initialize them.
|
|
|
|
// Use a setTimeout so child core-tab update their inputs before initializing the tabs.
|
|
|
|
setTimeout(() => {
|
|
|
|
this.initializeTabs();
|
|
|
|
});
|
2018-01-12 11:27:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a new tab if it isn't already in the list of tabs.
|
|
|
|
*
|
|
|
|
* @param {CoreTabComponent} tab The tab to add.
|
|
|
|
*/
|
|
|
|
addTab(tab: CoreTabComponent) : void {
|
|
|
|
// Check if tab is already in the list.
|
|
|
|
if (this.getIndex(tab) == -1) {
|
|
|
|
this.tabs.push(tab);
|
|
|
|
this.sortTabs();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the index of tab.
|
|
|
|
*
|
|
|
|
* @param {any} tab [description]
|
|
|
|
* @return {number} [description]
|
|
|
|
*/
|
|
|
|
getIndex(tab: any) : number {
|
|
|
|
for (let i = 0; i < this.tabs.length; i++) {
|
|
|
|
let t = this.tabs[i];
|
|
|
|
if (t === tab || (typeof t.id != 'undefined' && t.id === tab.id)) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the current selected tab.
|
|
|
|
*
|
|
|
|
* @return {CoreTabComponent} Selected tab.
|
|
|
|
*/
|
|
|
|
getSelected() : CoreTabComponent {
|
|
|
|
return this.tabs[this.selected];
|
|
|
|
}
|
|
|
|
|
2018-01-19 08:00:59 +00:00
|
|
|
/**
|
|
|
|
* Initialize the tabs, determining the first tab to be shown.
|
|
|
|
*/
|
|
|
|
protected initializeTabs() : void {
|
|
|
|
let selectedIndex = this.selectedIndex || 0,
|
|
|
|
selectedTab = this.tabs[selectedIndex];
|
|
|
|
|
|
|
|
if (!selectedTab.enabled || !selectedTab.show) {
|
|
|
|
// The tab is not enabled or not shown. Get the first tab that is enabled.
|
|
|
|
selectedTab = this.tabs.find((tab, index) => {
|
|
|
|
if (tab.enabled && tab.show) {
|
|
|
|
selectedIndex = index;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
if (selectedTab) {
|
|
|
|
this.selectTab(selectedIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.initialized = true;
|
|
|
|
}
|
|
|
|
|
2018-01-12 11:27:57 +00:00
|
|
|
/**
|
|
|
|
* Remove a tab from the list of tabs.
|
|
|
|
*
|
|
|
|
* @param {CoreTabComponent} tab The tab to remove.
|
|
|
|
*/
|
|
|
|
removeTab(tab: CoreTabComponent) : void {
|
|
|
|
const index = this.getIndex(tab);
|
|
|
|
this.tabs.splice(index, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Select a certain tab.
|
|
|
|
*
|
|
|
|
* @param {number} index The index of the tab to select.
|
|
|
|
*/
|
|
|
|
selectTab(index: number) : void {
|
|
|
|
if (index == this.selected) {
|
|
|
|
// Already selected.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index < 0 || index >= this.tabs.length) {
|
|
|
|
// Index isn't valid, select the first one.
|
|
|
|
index = 0;
|
|
|
|
}
|
|
|
|
|
2018-01-19 14:41:14 +00:00
|
|
|
const currentTab = this.getSelected(),
|
2018-01-12 11:27:57 +00:00
|
|
|
newTab = this.tabs[index];
|
|
|
|
|
|
|
|
if (!newTab.enabled || !newTab.show) {
|
|
|
|
// The tab isn't enabled or shown, stop.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-19 14:41:14 +00:00
|
|
|
if (currentTab) {
|
2018-01-12 11:27:57 +00:00
|
|
|
// Unselect previous selected tab.
|
2018-01-19 14:41:14 +00:00
|
|
|
currentTab.unselectTab();
|
2018-01-12 11:27:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this.selected = index;
|
2018-01-19 14:41:14 +00:00
|
|
|
newTab.selectTab();
|
2018-01-12 11:27:57 +00:00
|
|
|
this.ionChange.emit(newTab);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort the tabs, keeping the same order as in the original list.
|
|
|
|
*/
|
|
|
|
protected sortTabs() {
|
|
|
|
if (this.originalTabsContainer) {
|
|
|
|
let newTabs = [],
|
|
|
|
newSelected;
|
|
|
|
|
|
|
|
this.tabs.forEach((tab, index) => {
|
|
|
|
let originalIndex = Array.prototype.indexOf.call(this.originalTabsContainer.children, tab.element);
|
|
|
|
if (originalIndex != -1) {
|
|
|
|
newTabs[originalIndex] = tab;
|
|
|
|
if (this.selected == index) {
|
|
|
|
newSelected = originalIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.tabs = newTabs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|