MOBILE-3565 components: Implement loading component
parent
072c05c268
commit
a6bf6afe7a
|
@ -13,18 +13,24 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
|
||||
import { CoreIconComponent } from './icon/icon';
|
||||
import { CoreLoadingComponent } from './loading/loading';
|
||||
import { CoreShowPasswordComponent } from './show-password/show-password';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CoreIconComponent,
|
||||
CoreLoadingComponent,
|
||||
CoreShowPasswordComponent,
|
||||
],
|
||||
imports: [],
|
||||
imports: [
|
||||
IonicModule,
|
||||
],
|
||||
exports: [
|
||||
CoreIconComponent,
|
||||
CoreLoadingComponent,
|
||||
CoreShowPasswordComponent,
|
||||
],
|
||||
})
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<div class="core-loading-container" *ngIf="!hideUntil" role="status"> <!-- @todo [@coreShowHideAnimation] -->
|
||||
<span class="core-loading-spinner">
|
||||
<ion-spinner></ion-spinner>
|
||||
<p class="core-loading-message" *ngIf="message" role="status">{{message}}</p>
|
||||
</span>
|
||||
</div>
|
||||
<div #content class="core-loading-content" [id]="uniqueId" [attr.aria-busy]="hideUntil">
|
||||
<ng-content *ngIf="hideUntil">
|
||||
</ng-content> <!-- @todo [@coreShowHideAnimation] -->
|
||||
</div>
|
|
@ -0,0 +1,67 @@
|
|||
ion-app.app-root {
|
||||
core-loading {
|
||||
// @todo @include core-transition(height, 200ms);
|
||||
|
||||
.core-loading-container {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding-top: 10px;
|
||||
clear: both;
|
||||
/* @todo @include darkmode() {
|
||||
color: $core-dark-text-color;
|
||||
} */
|
||||
}
|
||||
|
||||
.core-loading-content {
|
||||
display: inline;
|
||||
padding-bottom: 1px; /* This makes height be real */
|
||||
}
|
||||
|
||||
&.core-loading-noheight .core-loading-content {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&.safe-area-page {
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
|
||||
> .core-loading-content > *:not[padding],
|
||||
> .core-loading-content-loading > *:not[padding] {
|
||||
// @todo @include safe-area-padding-horizontal(0px, 0px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-content > core-loading,
|
||||
ion-content > .scroll-content > core-loading,
|
||||
core-tab core-loading,
|
||||
.core-loading-center {
|
||||
position: static !important;
|
||||
}
|
||||
|
||||
.scroll-content > core-loading,
|
||||
ion-content > .scroll-content > core-loading,
|
||||
core-tab core-loading,
|
||||
.core-loading-center,
|
||||
core-loading.core-loading-loaded {
|
||||
position: relative;
|
||||
|
||||
> .core-loading-container {
|
||||
position: absolute;
|
||||
// @todo @include position(0, 0, 0, 0);
|
||||
display: table;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
clear: both;
|
||||
|
||||
.core-loading-spinner {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
// (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, OnInit, OnChanges, SimpleChange, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
|
||||
|
||||
import { CoreEvents, CoreEventsProvider } from '@services/events';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { Translate } from '@singletons/core.singletons';
|
||||
|
||||
/**
|
||||
* Component to show a loading spinner and message while data is being loaded.
|
||||
*
|
||||
* It will show a spinner with a message and hide all the content until 'hideUntil' variable is set to a truthy value (!!hideUntil).
|
||||
* If 'message' isn't set, default message "Loading" is shown.
|
||||
* 'message' attribute accepts hardcoded strings, variables, filters, etc. E.g. [message]="'core.loading' | translate".
|
||||
*
|
||||
* Usage:
|
||||
* <core-loading [message]="loadingMessage" [hideUntil]="dataLoaded">
|
||||
* <!-- CONTENT TO HIDE UNTIL LOADED -->
|
||||
* </core-loading>
|
||||
*
|
||||
* IMPORTANT: Due to how ng-content works in Angular, the content of core-loading will be executed as soon as your view
|
||||
* is loaded, even if the content hidden. So if you have the following code:
|
||||
* <core-loading [hideUntil]="dataLoaded"><my-component></my-component></core-loading>
|
||||
*
|
||||
* The component "my-component" will be initialized immediately, even if dataLoaded is false, but it will be hidden. If you want
|
||||
* your component to be initialized only if dataLoaded is true, then you should use ngIf:
|
||||
* <core-loading [hideUntil]="dataLoaded"><my-component *ngIf="dataLoaded"></my-component></core-loading>
|
||||
*/
|
||||
@Component({
|
||||
selector: 'core-loading',
|
||||
templateUrl: 'core-loading.html',
|
||||
styleUrls: ['loading.scss'],
|
||||
// @todo animations: [coreShowHideAnimation],
|
||||
})
|
||||
export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit {
|
||||
|
||||
@Input() hideUntil: unknown; // Determine when should the contents be shown.
|
||||
@Input() message?: string; // Message to show while loading.
|
||||
@ViewChild('content') content: ElementRef;
|
||||
|
||||
protected uniqueId: string;
|
||||
protected element: HTMLElement; // Current element.
|
||||
|
||||
constructor(element: ElementRef) {
|
||||
this.element = element.nativeElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component being initialized.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
// Calculate the unique ID.
|
||||
this.uniqueId = 'core-loading-content-' + CoreUtils.instance.getUniqueId('CoreLoadingComponent');
|
||||
|
||||
if (!this.message) {
|
||||
// Default loading message.
|
||||
this.message = Translate.instance.instant('core.loading');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View has been initialized.
|
||||
*/
|
||||
ngAfterViewInit(): void {
|
||||
// Add class if loaded on init.
|
||||
if (this.hideUntil) {
|
||||
this.element.classList.add('core-loading-loaded');
|
||||
this.content?.nativeElement.classList.add('core-loading-content');
|
||||
} else {
|
||||
this.content?.nativeElement.classList.remove('core-loading-content');
|
||||
this.content?.nativeElement.classList.add('core-loading-content-loading');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component input changed.
|
||||
*
|
||||
* @param changes Changes.
|
||||
*/
|
||||
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
||||
if (changes.hideUntil) {
|
||||
if (this.hideUntil) {
|
||||
setTimeout(() => {
|
||||
// Content is loaded so, center the spinner on the content itself.
|
||||
this.element.classList.add('core-loading-loaded');
|
||||
setTimeout(() => {
|
||||
// Change CSS to force calculate height.
|
||||
this.content?.nativeElement.classList.add('core-loading-content');
|
||||
this.content?.nativeElement.classList.remove('core-loading-content-loading');
|
||||
}, 500);
|
||||
});
|
||||
} else {
|
||||
this.element.classList.remove('core-loading-loaded');
|
||||
this.content?.nativeElement.classList.remove('core-loading-content');
|
||||
this.content?.nativeElement.classList.add('core-loading-content-loading');
|
||||
}
|
||||
|
||||
// Trigger the event after a timeout since the elements inside ngIf haven't been added to DOM yet.
|
||||
setTimeout(() => {
|
||||
CoreEvents.instance.trigger(CoreEventsProvider.CORE_LOADING_CHANGED, {
|
||||
loaded: !!this.hideUntil,
|
||||
uniqueId: this.uniqueId,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue