forked from EVOgeek/Vmeda.Online
		
	MOBILE-3833 tabs: Fix tab size calculations
This commit is contained in:
		
							parent
							
								
									f56cfa3ab6
								
							
						
					
					
						commit
						b2246a01c5
					
				| @ -22,7 +22,6 @@ import { | |||||||
|     OnDestroy, |     OnDestroy, | ||||||
|     AfterViewInit, |     AfterViewInit, | ||||||
|     ViewChild, |     ViewChild, | ||||||
|     ElementRef, |  | ||||||
|     SimpleChange, |     SimpleChange, | ||||||
| } from '@angular/core'; | } from '@angular/core'; | ||||||
| import { IonSlides } from '@ionic/angular'; | import { IonSlides } from '@ionic/angular'; | ||||||
| @ -34,6 +33,8 @@ import { CoreSettingsHelper } from '@features/settings/services/settings-helper' | |||||||
| import { CoreAriaRoleTab, CoreAriaRoleTabFindable } from './aria-role-tab'; | import { CoreAriaRoleTab, CoreAriaRoleTabFindable } from './aria-role-tab'; | ||||||
| import { CoreEventObserver } from '@singletons/events'; | import { CoreEventObserver } from '@singletons/events'; | ||||||
| import { CoreDom } from '@singletons/dom'; | import { CoreDom } from '@singletons/dom'; | ||||||
|  | import { CoreUtils } from '@services/utils/utils'; | ||||||
|  | import { CoreError } from './errors/error'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Class to abstract some common code for tabs. |  * Class to abstract some common code for tabs. | ||||||
| @ -54,6 +55,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
| 
 | 
 | ||||||
|     tabs: T[] = []; // List of tabs.
 |     tabs: T[] = []; // List of tabs.
 | ||||||
| 
 | 
 | ||||||
|  |     hideTabs = false; | ||||||
|     selected?: string; // Selected tab id.
 |     selected?: string; // Selected tab id.
 | ||||||
|     showPrevButton = false; |     showPrevButton = false; | ||||||
|     showNextButton = false; |     showNextButton = false; | ||||||
| @ -65,10 +67,11 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|         initialSlide: 0, |         initialSlide: 0, | ||||||
|         slidesPerView: 3, |         slidesPerView: 3, | ||||||
|         centerInsufficientSlides: true, |         centerInsufficientSlides: true, | ||||||
|  |         threshold: 10, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     protected slidesElement?: HTMLIonSlidesElement; | ||||||
|     protected initialized = false; |     protected initialized = false; | ||||||
|     protected afterViewInitTriggered = false; |  | ||||||
| 
 | 
 | ||||||
|     protected resizeListener?: CoreEventObserver; |     protected resizeListener?: CoreEventObserver; | ||||||
|     protected isDestroyed = false; |     protected isDestroyed = false; | ||||||
| @ -79,54 +82,41 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
| 
 | 
 | ||||||
|     protected firstSelectedTab?: string; // ID of the first selected tab to control history.
 |     protected firstSelectedTab?: string; // ID of the first selected tab to control history.
 | ||||||
|     protected backButtonFunction: (event: BackButtonEvent) => void; |     protected backButtonFunction: (event: BackButtonEvent) => void; | ||||||
|     protected languageChangedSubscription?: Subscription; |  | ||||||
|     // Swiper 6 documentation: https://swiper6.vercel.app/
 |     // Swiper 6 documentation: https://swiper6.vercel.app/
 | ||||||
|     protected isInTransition = false; // Wether Slides is in transition.
 |     protected isInTransition = false; // Wether Slides is in transition.
 | ||||||
|     protected slidesSwiper: any; // eslint-disable-line @typescript-eslint/no-explicit-any
 |     protected subscriptions: Subscription[] = []; | ||||||
|     protected slidesSwiperLoaded = false; |  | ||||||
| 
 | 
 | ||||||
|     tabAction: CoreTabsRoleTab<T>; |     tabAction: CoreTabsRoleTab<T>; | ||||||
| 
 | 
 | ||||||
|     constructor( |     constructor() { | ||||||
|         protected element: ElementRef, |  | ||||||
|     ) { |  | ||||||
|         this.backButtonFunction = this.backButtonClicked.bind(this); |         this.backButtonFunction = this.backButtonClicked.bind(this); | ||||||
| 
 | 
 | ||||||
|         this.tabAction = new CoreTabsRoleTab(this); |         this.tabAction = new CoreTabsRoleTab(this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Component being initialized. |      * @inheritdoc | ||||||
|      */ |      */ | ||||||
|     ngOnInit(): void { |     async ngOnInit(): Promise<void> { | ||||||
|         this.direction = Platform.isRTL ? 'rtl' : 'ltr'; |         this.direction = Platform.isRTL ? 'rtl' : 'ltr'; | ||||||
| 
 | 
 | ||||||
|         // Change the side when the language changes.
 |         // Change the side when the language changes.
 | ||||||
|         this.languageChangedSubscription = Translate.onLangChange.subscribe(() => { |         this.subscriptions.push(Translate.onLangChange.subscribe(() => { | ||||||
|             setTimeout(() => { |             setTimeout(() => { | ||||||
|                 this.direction = Platform.isRTL ? 'rtl' : 'ltr'; |                 this.direction = Platform.isRTL ? 'rtl' : 'ltr'; | ||||||
|             }); |             }); | ||||||
|         }); |         })); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * View has been initialized. |      * @inheritdoc | ||||||
|      */ |      */ | ||||||
|     async ngAfterViewInit(): Promise<void> { |     ngAfterViewInit(): void { | ||||||
|         if (this.isDestroyed) { |         if (this.isDestroyed) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         this.afterViewInitTriggered = true; |         this.init(); | ||||||
| 
 |  | ||||||
|         if (!this.initialized && this.hideUntil) { |  | ||||||
|             // Tabs should be shown, initialize them.
 |  | ||||||
|             await this.initializeTabs(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         this.resizeListener = CoreDom.onWindowResize(() => { |  | ||||||
|             this.windowResized(); |  | ||||||
|         }); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -134,14 +124,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|      */ |      */ | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 |     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||||
|     ngOnChanges(changes: Record<string, SimpleChange>): void { |     ngOnChanges(changes: Record<string, SimpleChange>): void { | ||||||
|         // Wait for ngAfterViewInit so it works in the case that each tab has its own component.
 |         this.init(); | ||||||
|         if (!this.initialized && this.hideUntil && this.afterViewInitTriggered) { |  | ||||||
|             // Tabs should be shown, initialize them.
 |  | ||||||
|             // Use a setTimeout so child components update their inputs before initializing the tabs.
 |  | ||||||
|             setTimeout(() => { |  | ||||||
|                 this.initializeTabs(); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -206,6 +189,16 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         this.numTabsShown = this.tabs.reduce((prev: number, current) => current.enabled ? prev + 1 : prev, 0); | ||||||
|  | 
 | ||||||
|  |         if (this.numTabsShown <= 1) { | ||||||
|  |             this.hideTabs = true; | ||||||
|  | 
 | ||||||
|  |             // Only one, nothing to do here.
 | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         this.hideTabs = false; | ||||||
|  | 
 | ||||||
|         await this.calculateMaxSlides(); |         await this.calculateMaxSlides(); | ||||||
| 
 | 
 | ||||||
|         await this.updateSlides(); |         await this.updateSlides(); | ||||||
| @ -233,28 +226,81 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Initialize the tabs, determining the first tab to be shown. |      * Init the component. | ||||||
|      */ |      */ | ||||||
|     protected async initializeTabs(): Promise<void> { |     protected async init(): Promise<void> { | ||||||
|         // Initialize slider.
 |         if (!this.hideUntil) { | ||||||
|         this.slidesSwiper = await this.slides?.getSwiper(); |             // Hidden, do nothing.
 | ||||||
|         this.slidesSwiper.once('progress', () => { |  | ||||||
|             this.slidesSwiperLoaded = true; |  | ||||||
|             this.calculateSlides(); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         const selectedTab = this.calculateInitialTab(); |  | ||||||
|         if (!selectedTab) { |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         this.firstSelectedTab = selectedTab.id!; |         try { | ||||||
|         this.selectTab(this.firstSelectedTab); |             await this.initializeSlider(); | ||||||
|  |             await this.initializeTabs(); | ||||||
|  |         } catch { | ||||||
|  |             // Something went wrong, ignore.
 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Initialize the slider elements. | ||||||
|  |      */ | ||||||
|  |     protected async initializeSlider(): Promise<void> { | ||||||
|  |         if (this.initialized) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (this.slidesElement) { | ||||||
|  |             // Already initializated, await for ready.
 | ||||||
|  |             await this.slidesElement.componentOnReady(); | ||||||
|  | 
 | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!this.slides) { | ||||||
|  |             await CoreUtils.nextTick(); | ||||||
|  |         } | ||||||
|  |         const slidesSwiper = await this.slides?.getSwiper(); | ||||||
|  |         if (!slidesSwiper || !this.slides) { | ||||||
|  |             throw new CoreError('Swiper not found, will try on next change.'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.slidesElement = <HTMLIonSlidesElement>slidesSwiper.el; | ||||||
|  |         await this.slidesElement.componentOnReady(); | ||||||
| 
 | 
 | ||||||
|         this.initialized = true; |         this.initialized = true; | ||||||
| 
 | 
 | ||||||
|  |         // Subscribe to changes.
 | ||||||
|  |         this.subscriptions.push(this.slides.ionSlideDidChange.subscribe(() => { | ||||||
|  |             this.slideChanged(); | ||||||
|  |         })); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Initialize the tabs, determining the first tab to be shown. | ||||||
|  |      */ | ||||||
|  |     protected async initializeTabs(): Promise<void> { | ||||||
|  |         if (!this.initialized || !this.slidesElement) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         const selectedTab = this.calculateInitialTab(); | ||||||
|  |         if (!selectedTab) { | ||||||
|  |             // No enabled tabs, return.
 | ||||||
|  |             throw new CoreError('No enabled tabs.'); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.firstSelectedTab = selectedTab.id; | ||||||
|  |         if (this.firstSelectedTab !== undefined) { | ||||||
|  |             this.selectTab(this.firstSelectedTab); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         // Check which arrows should be shown.
 |         // Check which arrows should be shown.
 | ||||||
|         this.calculateSlides(); |         this.calculateSlides(); | ||||||
|  | 
 | ||||||
|  |         this.resizeListener = CoreDom.onWindowResize(() => { | ||||||
|  |             this.calculateSlides(); | ||||||
|  |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -277,7 +323,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|      * Method executed when the slides are changed. |      * Method executed when the slides are changed. | ||||||
|      */ |      */ | ||||||
|     async slideChanged(): Promise<void> { |     async slideChanged(): Promise<void> { | ||||||
|         if (!this.slidesSwiperLoaded) { |         if (!this.slidesElement) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -302,17 +348,15 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|      * Updates the number of slides to show. |      * Updates the number of slides to show. | ||||||
|      */ |      */ | ||||||
|     protected async updateSlides(): Promise<void> { |     protected async updateSlides(): Promise<void> { | ||||||
|         this.numTabsShown = this.tabs.reduce((prev: number, current) => current.enabled ? prev + 1 : prev, 0); |         if (!this.slides) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         this.slidesOpts = { ...this.slidesOpts, slidesPerView: Math.min(this.maxSlides, this.numTabsShown) }; |         this.slidesOpts = { ...this.slidesOpts, slidesPerView: Math.min(this.maxSlides, this.numTabsShown) }; | ||||||
| 
 | 
 | ||||||
|         this.slideChanged(); |         await this.slideChanged(); | ||||||
| 
 | 
 | ||||||
|         // @todo: This call to update() can trigger JS errors in the console if tabs are re-loaded and there's only 1 tab.
 |         await this.slides.update(); | ||||||
|         // For some reason, swiper.slides is undefined inside the Slides class, and the swiper is marked as destroyed.
 |  | ||||||
|         // Changing *ngIf="hideUntil" to [hidden] doesn't solve the issue, and it causes another error to be raised.
 |  | ||||||
|         // This can be tested in lesson as a student, play a lesson and go back to the entry page.
 |  | ||||||
|         await this.slides!.update(); |  | ||||||
| 
 | 
 | ||||||
|         if (!this.hasSliddenToInitial && this.selectedIndex && this.selectedIndex >= this.slidesOpts.slidesPerView) { |         if (!this.hasSliddenToInitial && this.selectedIndex && this.selectedIndex >= this.slidesOpts.slidesPerView) { | ||||||
|             this.hasSliddenToInitial = true; |             this.hasSliddenToInitial = true; | ||||||
| @ -320,7 +364,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
| 
 | 
 | ||||||
|             setTimeout(() => { |             setTimeout(() => { | ||||||
|                 if (this.shouldSlideToInitial) { |                 if (this.shouldSlideToInitial) { | ||||||
|                     this.slides!.slideTo(this.selectedIndex, 0); |                     this.slides?.slideTo(this.selectedIndex, 0); | ||||||
|                     this.shouldSlideToInitial = false; |                     this.shouldSlideToInitial = false; | ||||||
|                 } |                 } | ||||||
|             }, 400); |             }, 400); | ||||||
| @ -339,17 +383,23 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|      * Calculate the number of slides that can fit on the screen. |      * Calculate the number of slides that can fit on the screen. | ||||||
|      */ |      */ | ||||||
|     protected async calculateMaxSlides(): Promise<void> { |     protected async calculateMaxSlides(): Promise<void> { | ||||||
|         if (!this.slidesSwiperLoaded) { |         if (!this.slidesElement || !this.slides) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         this.maxSlides = 3; |         this.maxSlides = 3; | ||||||
|         let width = this.slidesSwiper.width; |         await CoreUtils.nextTick(); | ||||||
|         if (!width) { |  | ||||||
|             this.slidesSwiper.updateSize(); |  | ||||||
|             width = this.slidesSwiper.width; |  | ||||||
| 
 | 
 | ||||||
|  |         let width: number = this.slidesElement.getBoundingClientRect().width; | ||||||
|  |         if (!width) { | ||||||
|  |             const slidesSwiper = await this.slides.getSwiper(); | ||||||
|  | 
 | ||||||
|  |             await slidesSwiper.updateSize(); | ||||||
|  |             await CoreUtils.nextTick(); | ||||||
|  | 
 | ||||||
|  |             width = slidesSwiper.width; | ||||||
|             if (!width) { |             if (!width) { | ||||||
|  | 
 | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @ -456,12 +506,12 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (this.selected) { |         if (this.selected && this.slides) { | ||||||
|             // Check if we need to slide to the tab because it's not visible.
 |             // Check if we need to slide to the tab because it's not visible.
 | ||||||
|             const firstVisibleTab = await this.slides!.getActiveIndex(); |             const firstVisibleTab = await this.slides.getActiveIndex(); | ||||||
|             const lastVisibleTab = firstVisibleTab + this.slidesOpts.slidesPerView - 1; |             const lastVisibleTab = firstVisibleTab + this.slidesOpts.slidesPerView - 1; | ||||||
|             if (index < firstVisibleTab || index > lastVisibleTab) { |             if (index < firstVisibleTab || index > lastVisibleTab) { | ||||||
|                 await this.slides!.slideTo(index, 0, true); |                 await this.slides.slideTo(index, 0, true); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| @ -470,9 +520,9 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const ok = await this.loadTab(tabToSelect); |         const suceeded = await this.loadTab(tabToSelect); | ||||||
| 
 | 
 | ||||||
|         if (ok !== false) { |         if (suceeded !== false) { | ||||||
|             this.tabSelected(tabToSelect, index); |             this.tabSelected(tabToSelect, index); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -503,15 +553,6 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Adapt tabs to a window resize. |  | ||||||
|      */ |  | ||||||
|     protected windowResized(): void { |  | ||||||
|         setTimeout(() => { |  | ||||||
|             this.calculateSlides(); |  | ||||||
|         }, 200); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Component destroyed. |      * Component destroyed. | ||||||
|      */ |      */ | ||||||
| @ -519,7 +560,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | |||||||
|         this.isDestroyed = true; |         this.isDestroyed = true; | ||||||
| 
 | 
 | ||||||
|         this.resizeListener?.off(); |         this.resizeListener?.off(); | ||||||
|         this.languageChangedSubscription?.unsubscribe(); |         this.subscriptions.forEach((subscription) => subscription.unsubscribe()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| @ -541,8 +582,8 @@ class CoreTabsRoleTab<T extends CoreTabBase> extends CoreAriaRoleTab<CoreTabsBas | |||||||
|      */ |      */ | ||||||
|     getSelectableTabs(): CoreAriaRoleTabFindable[] { |     getSelectableTabs(): CoreAriaRoleTabFindable[] { | ||||||
|         return this.componentInstance.tabs.filter((tab) => tab.enabled).map((tab) => ({ |         return this.componentInstance.tabs.filter((tab) => tab.enabled).map((tab) => ({ | ||||||
|             id: tab.id!, |             id: tab.id || '', | ||||||
|             findIndex: tab.id!, |             findIndex: tab.id || '', | ||||||
|         })); |         })); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -6,10 +6,9 @@ | |||||||
|                 <ion-icon *ngIf="showPrevButton" name="fas-chevron-left" [attr.aria-label]="'core.previous' | translate"></ion-icon> |                 <ion-icon *ngIf="showPrevButton" name="fas-chevron-left" [attr.aria-label]="'core.previous' | translate"></ion-icon> | ||||||
|             </ion-col> |             </ion-col> | ||||||
|             <ion-col class="ion-no-padding" size="10"> |             <ion-col class="ion-no-padding" size="10"> | ||||||
|                 <ion-slides (ionSlideDidChange)="slideChanged()" [options]="slidesOpts" [dir]="direction" role="tablist" |                 <ion-slides [options]="slidesOpts" [dir]="direction" role="tablist" [attr.aria-label]="description"> | ||||||
|                     [attr.aria-label]="description"> |  | ||||||
|                     <ng-container *ngFor="let tab of tabs"> |                     <ng-container *ngFor="let tab of tabs"> | ||||||
|                         <ion-slide role="presentation" [id]="tab.id! + '-tab'" class="tab-slide" tabindex="-1" |                         <ion-slide role="presentation" class="tab-slide" [id]=" tab.id! + '-tab'" tabindex="-1" | ||||||
|                             [class.selected]="selected == tab.id"> |                             [class.selected]="selected == tab.id"> | ||||||
|                             <ion-tab-button (ionTabButtonClick)="selectTab(tab.id, $event)" (keydown)="tabAction.keyDown($event)" |                             <ion-tab-button (ionTabButtonClick)="selectTab(tab.id, $event)" (keydown)="tabAction.keyDown($event)" | ||||||
|                                 (keyup)="tabAction.keyUp(tab.id, $event)" [tab]="tab.page" [layout]="layout" class="{{tab.class}}" |                                 (keyup)="tabAction.keyUp(tab.id, $event)" [tab]="tab.page" [layout]="layout" class="{{tab.class}}" | ||||||
|  | |||||||
| @ -70,7 +70,7 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent<CoreTabsOutle | |||||||
|     protected existsInNavigationStack = false; |     protected existsInNavigationStack = false; | ||||||
| 
 | 
 | ||||||
|     constructor(element: ElementRef) { |     constructor(element: ElementRef) { | ||||||
|         super(element); |         super(); | ||||||
| 
 | 
 | ||||||
|         CoreComponentsRegistry.register(element.nativeElement, this); |         CoreComponentsRegistry.register(element.nativeElement, this); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -5,10 +5,9 @@ | |||||||
|             <ion-icon *ngIf="showPrevButton" name="fas-chevron-left" [attr.aria-label]="'core.previous' | translate"></ion-icon> |             <ion-icon *ngIf="showPrevButton" name="fas-chevron-left" [attr.aria-label]="'core.previous' | translate"></ion-icon> | ||||||
|         </ion-col> |         </ion-col> | ||||||
|         <ion-col class="ion-no-padding" size="10"> |         <ion-col class="ion-no-padding" size="10"> | ||||||
|             <ion-slides (ionSlideDidChange)="slideChanged()" [options]="slidesOpts" [dir]="direction" role="tablist" |             <ion-slides [options]="slidesOpts" [dir]="direction" role="tablist" [attr.aria-label]="description"> | ||||||
|                 [attr.aria-label]="description"> |  | ||||||
|                 <ng-container *ngFor="let tab of tabs"> |                 <ng-container *ngFor="let tab of tabs"> | ||||||
|                     <ion-slide *ngIf="tab.enabled" role="presentation" [hidden]="!hideUntil" class="tab-slide" [id]="tab.id! + '-tab'" |                     <ion-slide *ngIf="tab.enabled" role="presentation" class="tab-slide" [id]="tab.id! + '-tab'" | ||||||
|                         [class.selected]="selected == tab.id"> |                         [class.selected]="selected == tab.id"> | ||||||
|                         <ion-tab-button (click)="selectTab(tab.id, $event)" (keydown)="tabAction.keyDown($event)" |                         <ion-tab-button (click)="selectTab(tab.id, $event)" (keydown)="tabAction.keyDown($event)" | ||||||
|                             (keyup)="tabAction.keyUp(tab.id, $event)" class="{{tab.class}}" [layout]="layout" role="tab" |                             (keyup)="tabAction.keyUp(tab.id, $event)" class="{{tab.class}}" [layout]="layout" role="tab" | ||||||
|  | |||||||
| @ -65,7 +65,7 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase { | |||||||
|         return this.isEnabled; |         return this.isEnabled; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Input() id?: string; // An ID to identify the tab.
 |     @Input() id = ''; // An ID to identify the tab.
 | ||||||
|     @Output() ionSelect: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); |     @Output() ionSelect: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); | ||||||
| 
 | 
 | ||||||
|     @ContentChild(TemplateRef) template?: TemplateRef<unknown>; // Template defined by the content.
 |     @ContentChild(TemplateRef) template?: TemplateRef<unknown>; // Template defined by the content.
 | ||||||
| @ -82,7 +82,7 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase { | |||||||
|         element: ElementRef, |         element: ElementRef, | ||||||
|     ) { |     ) { | ||||||
|         this.element = element.nativeElement; |         this.element = element.nativeElement; | ||||||
| 
 |         this.id = this.id || 'core-tab-' + CoreUtils.getUniqueId('CoreTabComponent'); | ||||||
|         this.element.setAttribute('role', 'tabpanel'); |         this.element.setAttribute('role', 'tabpanel'); | ||||||
|         this.element.setAttribute('tabindex', '0'); |         this.element.setAttribute('tabindex', '0'); | ||||||
|         this.element.setAttribute('aria-hidden', 'true'); |         this.element.setAttribute('aria-hidden', 'true'); | ||||||
| @ -92,7 +92,6 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase { | |||||||
|      * Component being initialized. |      * Component being initialized. | ||||||
|      */ |      */ | ||||||
|     ngOnInit(): void { |     ngOnInit(): void { | ||||||
|         this.id = this.id || 'core-tab-' + CoreUtils.getUniqueId('CoreTabComponent'); |  | ||||||
|         this.element.setAttribute('aria-labelledby', this.id + '-tab'); |         this.element.setAttribute('aria-labelledby', this.id + '-tab'); | ||||||
|         this.element.setAttribute('id', this.id); |         this.element.setAttribute('id', this.id); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ | |||||||
|             ion-tab-button { |             ion-tab-button { | ||||||
|                 max-width: 100%; |                 max-width: 100%; | ||||||
|                 ion-label { |                 ion-label { | ||||||
|                     font-size: 16px; |                     font-size: 14px; | ||||||
|                     font-weight: 400; |                     font-weight: 400; | ||||||
|                     text-overflow: ellipsis; |                     text-overflow: ellipsis; | ||||||
|                     white-space: nowrap; |                     white-space: nowrap; | ||||||
| @ -109,8 +109,3 @@ | |||||||
|         position: relative; |         position: relative; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| :host-context(.ios) { |  | ||||||
|     --height: 53px; |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -51,12 +51,6 @@ export class CoreTabsComponent extends CoreTabsBaseComponent<CoreTabComponent> i | |||||||
| 
 | 
 | ||||||
|     protected originalTabsContainer?: HTMLElement; // The container of the original tabs. It will include each tab's content.
 |     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. |      * View has been initialized. | ||||||
|      */ |      */ | ||||||
| @ -84,7 +78,7 @@ export class CoreTabsComponent extends CoreTabsBaseComponent<CoreTabComponent> i | |||||||
|      */ |      */ | ||||||
|     addTab(tab: CoreTabComponent): void { |     addTab(tab: CoreTabComponent): void { | ||||||
|         // Check if tab is already in the list.
 |         // Check if tab is already in the list.
 | ||||||
|         if (this.getTabIndex(tab.id!) == -1) { |         if (this.getTabIndex(tab.id) === -1) { | ||||||
|             this.tabs.push(tab); |             this.tabs.push(tab); | ||||||
|             this.sortTabs(); |             this.sortTabs(); | ||||||
| 
 | 
 | ||||||
| @ -100,7 +94,7 @@ export class CoreTabsComponent extends CoreTabsBaseComponent<CoreTabComponent> i | |||||||
|      * @param tab The tab to remove. |      * @param tab The tab to remove. | ||||||
|      */ |      */ | ||||||
|     removeTab(tab: CoreTabComponent): void { |     removeTab(tab: CoreTabComponent): void { | ||||||
|         const index = this.getTabIndex(tab.id!); |         const index = this.getTabIndex(tab.id); | ||||||
|         this.tabs.splice(index, 1); |         this.tabs.splice(index, 1); | ||||||
| 
 | 
 | ||||||
|         this.calculateSlides(); |         this.calculateSlides(); | ||||||
|  | |||||||
| @ -131,6 +131,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { | |||||||
|         } catch (error) { |         } catch (error) { | ||||||
|             CoreDomUtils.showErrorModal(error); |             CoreDomUtils.showErrorModal(error); | ||||||
|             CoreNavigator.back(); |             CoreNavigator.back(); | ||||||
|  |             this.loaded = true; | ||||||
| 
 | 
 | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @ -224,9 +225,9 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { | |||||||
|         // Select the tab if needed.
 |         // Select the tab if needed.
 | ||||||
|         this.firstTabName = undefined; |         this.firstTabName = undefined; | ||||||
|         if (tabToLoad) { |         if (tabToLoad) { | ||||||
|             setTimeout(() => { |             await CoreUtils.nextTick(); | ||||||
|                 this.tabsComponent?.selectByIndex(tabToLoad!); | 
 | ||||||
|             }); |             this.tabsComponent?.selectByIndex(tabToLoad); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user