MOBILE-2430 tabs: Add tab sliding effect
parent
eb36ee048c
commit
19269f36f9
|
@ -25,7 +25,7 @@
|
|||
<!-- Content. -->
|
||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
|
||||
|
||||
<core-tabs [selectedIndex]="selectedTab">
|
||||
<core-tabs [hideUntil]="loaded" [selectedIndex]="selectedTab">
|
||||
<!-- Page contents. -->
|
||||
<core-tab [title]="'addon.mod_wiki.viewpage' | translate" icon="document">
|
||||
<ng-template>
|
||||
|
|
|
@ -1,12 +1,26 @@
|
|||
<core-loading [hideUntil]="hideUntil" class="core-loading-center">
|
||||
<div class="core-tabs-bar" #topTabs [hidden]="!tabs || tabs.length < 2">
|
||||
<ion-row>
|
||||
<ion-col class="col-with-arrow" (click)="slidePrev()" no-padding col-1>
|
||||
<ion-icon *ngIf="showPrevButton" name="arrow-back"></ion-icon>
|
||||
</ion-col>
|
||||
<ion-col no-padding col-10>
|
||||
<ion-slides (ionSlideDidChange)="slideChanged()" [slidesPerView]="slidesShown">
|
||||
<ng-container *ngFor="let tab of tabs; let idx = index">
|
||||
<a *ngIf="tab.show" [attr.aria-selected]="selected == idx" (click)="selectTab(idx)">
|
||||
<ion-slide *ngIf="tab.show">
|
||||
<a [attr.aria-selected]="selected == idx" (click)="selectTab(idx)" class="tab-slide">
|
||||
<core-icon *ngIf="tab.icon" [name]="tab.icon"></core-icon>
|
||||
<span *ngIf="tab.title">{{ tab.title }}</span>
|
||||
<ion-badge *ngIf="tab.badge" [color]="tab.badgeStyle" class="tab-badge">{{tab.badge}}</ion-badge>
|
||||
</a>
|
||||
</ion-slide>
|
||||
</ng-container>
|
||||
</ion-slides>
|
||||
</ion-col>
|
||||
<ion-col class="col-with-arrow" (click)="slideNext()" no-padding col-1>
|
||||
<ion-icon *ngIf="showNextButton" name="arrow-forward"></ion-icon>
|
||||
</ion-col>
|
||||
</ion-row>
|
||||
</div>
|
||||
<div class="core-tabs-content-container" #originalTabs>
|
||||
<ng-content></ng-content>
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
width: 100%;
|
||||
background: $core-top-tabs-background;
|
||||
|
||||
> a {
|
||||
.row {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
a.tab-slide {
|
||||
@extend .tab-button;
|
||||
|
||||
background: $core-top-tabs-background;
|
||||
|
@ -20,9 +24,25 @@
|
|||
border-bottom: 2px solid $core-top-tabs-color-active !important;
|
||||
}
|
||||
}
|
||||
|
||||
ion-col {
|
||||
text-align: center;
|
||||
font-size: 1.6rem;
|
||||
line-height: 1.6rem;
|
||||
|
||||
&.col-with-arrow {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
ion-icon {
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.md .core-tabs-bar > a {
|
||||
.md .core-tabs-bar a.tab-slide {
|
||||
// @extend .tabs-md .tab-button;
|
||||
min-height: $tabs-md-tab-min-height;
|
||||
|
||||
|
@ -30,7 +50,7 @@
|
|||
color: $tabs-md-tab-text-color;
|
||||
}
|
||||
|
||||
.ios .core-tabs-bar > a {
|
||||
.ios .core-tabs-bar a.tab-slide {
|
||||
// @extend .tabs-ios .tab-button;
|
||||
max-width: $tabs-ios-tab-max-width;
|
||||
min-height: $tabs-ios-tab-min-height;
|
||||
|
@ -40,7 +60,7 @@
|
|||
color: $tabs-ios-tab-text-color;
|
||||
}
|
||||
|
||||
.wp .core-tabs-bar > a {
|
||||
.wp .core-tabs-bar a.tab-slide {
|
||||
//@extend .tabs-wp .tab-button;
|
||||
@include border-radius(0);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
SimpleChange
|
||||
} from '@angular/core';
|
||||
import { CoreTabComponent } from './tab';
|
||||
import { Content } from 'ionic-angular';
|
||||
import { Content, Slides } from 'ionic-angular';
|
||||
|
||||
/**
|
||||
* This component displays some tabs that usually share data between them.
|
||||
|
@ -48,9 +48,16 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
|||
@Output() ionChange: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); // Emitted when the tab changes.
|
||||
@ViewChild('originalTabs') originalTabsRef: ElementRef;
|
||||
@ViewChild('topTabs') topTabs: ElementRef;
|
||||
@ViewChild(Slides) slides: Slides;
|
||||
|
||||
tabs: CoreTabComponent[] = []; // List of tabs.
|
||||
selected: number; // Selected tab number.
|
||||
showPrevButton: boolean;
|
||||
showNextButton: boolean;
|
||||
maxSlides = 3;
|
||||
slidesShown = this.maxSlides;
|
||||
numTabsShown = 0;
|
||||
|
||||
protected originalTabsContainer: HTMLElement; // The container of the original tabs. It will include each tab's content.
|
||||
protected initialized = false;
|
||||
protected afterViewInitTriggered = false;
|
||||
|
@ -77,10 +84,16 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
|||
*/
|
||||
ngAfterViewInit(): void {
|
||||
this.afterViewInitTriggered = true;
|
||||
|
||||
if (!this.initialized && this.hideUntil) {
|
||||
// Tabs should be shown, initialize them.
|
||||
this.initializeTabs();
|
||||
}
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
this.calculateMaxSlides();
|
||||
this.updateSlides();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,6 +120,7 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
|||
if (this.getIndex(tab) == -1) {
|
||||
this.tabs.push(tab);
|
||||
this.sortTabs();
|
||||
this.updateSlides();
|
||||
|
||||
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.
|
||||
|
@ -190,9 +204,72 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
|||
}
|
||||
}
|
||||
|
||||
// Check which arrows should be shown
|
||||
this.calculateMaxSlides();
|
||||
this.updateSlides();
|
||||
|
||||
this.initialized = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method executed when the slides are changed.
|
||||
*/
|
||||
slideChanged(): void {
|
||||
const currentIndex = this.slides.getActiveIndex();
|
||||
if (this.slidesShown >= this.numTabsShown) {
|
||||
this.showPrevButton = false;
|
||||
this.showNextButton = false;
|
||||
} else if (typeof currentIndex !== 'undefined') {
|
||||
this.showPrevButton = currentIndex > 0;
|
||||
this.showNextButton = currentIndex < this.numTabsShown - this.slidesShown;
|
||||
} else {
|
||||
this.showPrevButton = false;
|
||||
this.showNextButton = this.numTabsShown > this.slidesShown;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update slides.
|
||||
*/
|
||||
protected updateSlides(): void {
|
||||
this.numTabsShown = this.tabs.reduce((prev: number, current: any) => {
|
||||
return current.show ? prev + 1 : prev;
|
||||
}, 0);
|
||||
|
||||
this.slidesShown = Math.min(this.maxSlides, this.numTabsShown);
|
||||
this.slides.update();
|
||||
this.slides.resize();
|
||||
|
||||
this.slideChanged();
|
||||
}
|
||||
|
||||
protected calculateMaxSlides(): void {
|
||||
if (this.slides && this.slides.renderedWidth) {
|
||||
this.maxSlides = Math.floor(this.slides.renderedWidth / 120);
|
||||
|
||||
return;
|
||||
}
|
||||
this.maxSlides = 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that shows the next slide.
|
||||
*/
|
||||
slideNext(): void {
|
||||
if (this.showNextButton) {
|
||||
this.slides.slideNext();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that shows the previous slide.
|
||||
*/
|
||||
slidePrev(): void {
|
||||
if (this.showPrevButton) {
|
||||
this.slides.slidePrev();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide the tabs. This is used when the user is scrolling inside a tab.
|
||||
*
|
||||
|
@ -221,6 +298,8 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
|||
removeTab(tab: CoreTabComponent): void {
|
||||
const index = this.getIndex(tab);
|
||||
this.tabs.splice(index, 1);
|
||||
|
||||
this.updateSlides();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -252,6 +331,10 @@ export class CoreTabsComponent implements OnInit, AfterViewInit, OnChanges {
|
|||
currentTab.unselectTab();
|
||||
}
|
||||
|
||||
if (this.selected) {
|
||||
this.slides.slideTo(index);
|
||||
}
|
||||
|
||||
this.selected = index;
|
||||
newTab.selectTab();
|
||||
this.ionChange.emit(newTab);
|
||||
|
|
Loading…
Reference in New Issue