mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-07 23:16:52 +08:00
refactor(loading): update loading controller and element to match other overlays
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
import { Component, Listen, Method } from '@stencil/core';
|
import { Component, Listen, Method } from '@stencil/core';
|
||||||
import { Loading, LoadingEvent, LoadingOptions } from '../../index';
|
import { LoadingEvent, LoadingOptions } from '../../index';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -8,13 +8,13 @@ import { Loading, LoadingEvent, LoadingOptions } from '../../index';
|
|||||||
export class LoadingController {
|
export class LoadingController {
|
||||||
private ids = 0;
|
private ids = 0;
|
||||||
private loadingResolves: {[loadingId: string]: Function} = {};
|
private loadingResolves: {[loadingId: string]: Function} = {};
|
||||||
private loadings: Loading[] = [];
|
private loadings: HTMLIonLoadingElement[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a loading overlay and pass options to it
|
* Create a loading overlay and pass options to it
|
||||||
*/
|
*/
|
||||||
@Method()
|
@Method()
|
||||||
create(opts?: LoadingOptions): Promise<Loading> {
|
create(opts?: LoadingOptions): Promise<HTMLIonLoadingElement> {
|
||||||
// create ionic's wrapping ion-loading component
|
// create ionic's wrapping ion-loading component
|
||||||
const loading = document.createElement('ion-loading');
|
const loading = document.createElement('ion-loading');
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ export class LoadingController {
|
|||||||
appRoot.appendChild(loading as any);
|
appRoot.appendChild(loading as any);
|
||||||
|
|
||||||
// store the resolve function to be called later up when the loading loads
|
// store the resolve function to be called later up when the loading loads
|
||||||
return new Promise<Loading>(resolve => {
|
return new Promise<HTMLIonLoadingElement>(resolve => {
|
||||||
this.loadingResolves[loading.loadingId] = resolve;
|
this.loadingResolves[loading.loadingId] = resolve;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ export class LoadingController {
|
|||||||
|
|
||||||
@Listen('body:ionLoadingDidLoad')
|
@Listen('body:ionLoadingDidLoad')
|
||||||
protected didLoad(ev: LoadingEvent) {
|
protected didLoad(ev: LoadingEvent) {
|
||||||
const loading = ev.detail.loading;
|
const loading = ev.target as HTMLIonLoadingElement;
|
||||||
const loadingResolve = this.loadingResolves[loading.loadingId];
|
const loadingResolve = this.loadingResolves[loading.loadingId];
|
||||||
if (loadingResolve) {
|
if (loadingResolve) {
|
||||||
loadingResolve(loading);
|
loadingResolve(loading);
|
||||||
@ -52,13 +52,13 @@ export class LoadingController {
|
|||||||
|
|
||||||
@Listen('body:ionLoadingWillPresent')
|
@Listen('body:ionLoadingWillPresent')
|
||||||
protected willPresent(ev: LoadingEvent) {
|
protected willPresent(ev: LoadingEvent) {
|
||||||
this.loadings.push(ev.detail.loading);
|
this.loadings.push(ev.target as HTMLIonLoadingElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Listen('body:ionLoadingWillDismiss, body:ionLoadingDidUnload')
|
@Listen('body:ionLoadingWillDismiss, body:ionLoadingDidUnload')
|
||||||
protected willDismiss(ev: LoadingEvent) {
|
protected willDismiss(ev: LoadingEvent) {
|
||||||
const index = this.loadings.indexOf(ev.detail.loading);
|
const index = this.loadings.indexOf(ev.target as HTMLIonLoadingElement);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
this.loadings.splice(index, 1);
|
this.loadings.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,17 @@
|
|||||||
import { Animation, AnimationBuilder, AnimationController, Config } from '../../index';
|
import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core';
|
||||||
import { Component, Element, Event, EventEmitter, Listen, Prop, State } from '@stencil/core';
|
|
||||||
|
import {
|
||||||
|
Animation,
|
||||||
|
AnimationBuilder,
|
||||||
|
AnimationController,
|
||||||
|
Config,
|
||||||
|
OverlayDismissEvent,
|
||||||
|
OverlayDismissEventDetail
|
||||||
|
} from '../../index';
|
||||||
|
import { domControllerAsync, playAnimationAsync } from '../../utils/helpers';
|
||||||
import { createThemedClasses } from '../../utils/theme';
|
import { createThemedClasses } from '../../utils/theme';
|
||||||
|
|
||||||
|
|
||||||
import iosEnterAnimation from './animations/ios.enter';
|
import iosEnterAnimation from './animations/ios.enter';
|
||||||
import iosLeaveAnimation from './animations/ios.leave';
|
import iosLeaveAnimation from './animations/ios.leave';
|
||||||
import mdEnterAnimation from './animations/md.enter';
|
import mdEnterAnimation from './animations/md.enter';
|
||||||
@ -30,32 +40,32 @@ export class Loading {
|
|||||||
/**
|
/**
|
||||||
* @output {LoadingEvent} Emitted after the loading has loaded.
|
* @output {LoadingEvent} Emitted after the loading has loaded.
|
||||||
*/
|
*/
|
||||||
@Event() ionLoadingDidLoad: EventEmitter;
|
@Event() ionLoadingDidLoad: EventEmitter<LoadingEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {LoadingEvent} Emitted after the loading has presented.
|
* @output {LoadingEvent} Emitted after the loading has presented.
|
||||||
*/
|
*/
|
||||||
@Event() ionLoadingDidPresent: EventEmitter;
|
@Event() ionLoadingDidPresent: EventEmitter<LoadingEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {LoadingEvent} Emitted before the loading has presented.
|
* @output {LoadingEvent} Emitted before the loading has presented.
|
||||||
*/
|
*/
|
||||||
@Event() ionLoadingWillPresent: EventEmitter;
|
@Event() ionLoadingWillPresent: EventEmitter<LoadingEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {LoadingEvent} Emitted before the loading has dismissed.
|
* @output {LoadingEvent} Emitted before the loading has dismissed.
|
||||||
*/
|
*/
|
||||||
@Event() ionLoadingWillDismiss: EventEmitter;
|
@Event() ionLoadingWillDismiss: EventEmitter<LoadingDismissEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {LoadingEvent} Emitted after the loading has dismissed.
|
* @output {LoadingEvent} Emitted after the loading has dismissed.
|
||||||
*/
|
*/
|
||||||
@Event() ionLoadingDidDismiss: EventEmitter;
|
@Event() ionLoadingDidDismiss: EventEmitter<LoadingDismissEventDetail>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @output {LoadingEvent} Emitted after the loading has unloaded.
|
* @output {LoadingEvent} Emitted after the loading has unloaded.
|
||||||
*/
|
*/
|
||||||
@Event() ionLoadingDidUnload: EventEmitter;
|
@Event() ionLoadingDidUnload: EventEmitter<LoadingEventDetail>;
|
||||||
|
|
||||||
@State() private showSpinner: boolean = null;
|
@State() private showSpinner: boolean = null;
|
||||||
@State() private spinner: string;
|
@State() private spinner: string;
|
||||||
@ -103,16 +113,16 @@ export class Loading {
|
|||||||
*/
|
*/
|
||||||
@Prop() leaveAnimation: AnimationBuilder;
|
@Prop() leaveAnimation: AnimationBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles whether animation should occur or not
|
||||||
|
*/
|
||||||
|
@Prop() animate: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Present a loading overlay after it has been created
|
* Present a loading overlay after it has been created
|
||||||
*/
|
*/
|
||||||
|
@Method()
|
||||||
present() {
|
present() {
|
||||||
return new Promise<void>(resolve => {
|
|
||||||
this._present(resolve);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _present(resolve: Function) {
|
|
||||||
if (this.animation) {
|
if (this.animation) {
|
||||||
this.animation.destroy();
|
this.animation.destroy();
|
||||||
this.animation = null;
|
this.animation = null;
|
||||||
@ -124,22 +134,26 @@ export class Loading {
|
|||||||
const animationBuilder = this.enterAnimation || this.config.get('loadingEnter', this.mode === 'ios' ? iosEnterAnimation : mdEnterAnimation);
|
const animationBuilder = this.enterAnimation || this.config.get('loadingEnter', this.mode === 'ios' ? iosEnterAnimation : mdEnterAnimation);
|
||||||
|
|
||||||
// build the animation and kick it off
|
// build the animation and kick it off
|
||||||
this.animationCtrl.create(animationBuilder, this.el).then(animation => {
|
// build the animation and kick it off
|
||||||
|
return this.animationCtrl.create(animationBuilder, this.el).then(animation => {
|
||||||
this.animation = animation;
|
this.animation = animation;
|
||||||
|
if (!this.animate) {
|
||||||
animation.onFinish((a: any) => {
|
// if the duration is 0, it won't actually animate I don't think
|
||||||
a.destroy();
|
// TODO - validate this
|
||||||
this.componentDidEnter();
|
this.animation = animation.duration(0);
|
||||||
resolve();
|
}
|
||||||
|
return playAnimationAsync(animation);
|
||||||
}).play();
|
}).then((animation) => {
|
||||||
|
animation.destroy();
|
||||||
|
this.componentDidEnter();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dismiss a loading indicator programatically
|
* Dismiss a loading indicator programatically
|
||||||
*/
|
*/
|
||||||
dismiss() {
|
@Method()
|
||||||
|
dismiss(data?: any, role?: string) {
|
||||||
clearTimeout(this.durationTimeout);
|
clearTimeout(this.durationTimeout);
|
||||||
|
|
||||||
if (this.animation) {
|
if (this.animation) {
|
||||||
@ -147,27 +161,25 @@ export class Loading {
|
|||||||
this.animation = null;
|
this.animation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise(resolve => {
|
this.ionLoadingWillDismiss.emit({
|
||||||
this.ionLoadingWillDismiss.emit({ loading: this });
|
data,
|
||||||
|
role
|
||||||
|
});
|
||||||
|
|
||||||
// get the user's animation fn if one was provided
|
const animationBuilder = this.leaveAnimation || this.config.get('loadingLeave', this.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation);
|
||||||
const animationBuilder = this.leaveAnimation || this.config.get('loadingLeave', this.mode === 'ios' ? iosLeaveAnimation : mdLeaveAnimation);
|
|
||||||
|
|
||||||
// build the animation and kick it off
|
return this.animationCtrl.create(animationBuilder, this.el).then(animation => {
|
||||||
this.animationCtrl.create(animationBuilder, this.el).then(animation => {
|
this.animation = animation;
|
||||||
this.animation = animation;
|
return playAnimationAsync(animation);
|
||||||
|
}).then((animation) => {
|
||||||
animation.onFinish((a: any) => {
|
animation.destroy();
|
||||||
a.destroy();
|
return domControllerAsync(Context.dom.write, () => {
|
||||||
this.ionLoadingDidDismiss.emit({ loading: this });
|
this.el.parentNode.removeChild(this.el);
|
||||||
|
});
|
||||||
Context.dom.write(() => {
|
}).then(() => {
|
||||||
this.el.parentNode.removeChild(this.el);
|
this.ionLoadingDidDismiss.emit({
|
||||||
});
|
data,
|
||||||
|
role
|
||||||
resolve();
|
|
||||||
|
|
||||||
}).play();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -273,10 +285,20 @@ export interface LoadingOptions {
|
|||||||
translucent?: boolean;
|
translucent?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingEvent extends Event {
|
export interface LoadingEvent extends CustomEvent {
|
||||||
detail: {
|
detail: LoadingEventDetail;
|
||||||
loading: Loading;
|
}
|
||||||
};
|
|
||||||
|
export interface LoadingEventDetail {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoadingDismissEventDetail extends OverlayDismissEventDetail {
|
||||||
|
// keep this just for the sake of static types and potential future extensions
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoadingDismissEvent extends OverlayDismissEvent {
|
||||||
|
// keep this just for the sake of static types and potential future extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@ -56,21 +56,21 @@
|
|||||||
</ion-page>
|
</ion-page>
|
||||||
</ion-app>
|
</ion-app>
|
||||||
<script>
|
<script>
|
||||||
function presentLoading() {
|
async function presentLoading() {
|
||||||
var loadingController = document.querySelector('ion-loading-controller');
|
const loadingController = document.querySelector('ion-loading-controller');
|
||||||
loadingController.create({
|
await loadingController.componentOnReady();
|
||||||
|
const loadingElement = await loadingController.create({
|
||||||
message: 'Hellooo',
|
message: 'Hellooo',
|
||||||
duration: 2000
|
duration: 2000
|
||||||
}).then(loading => {
|
|
||||||
loading.present();
|
|
||||||
});
|
});
|
||||||
|
return await loadingElement.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
function presentLoadingWithOptions(opts) {
|
async function presentLoadingWithOptions(opts) {
|
||||||
var loadingController = document.querySelector('ion-loading-controller');
|
const loadingController = document.querySelector('ion-loading-controller');
|
||||||
loadingController.create(opts).then(loading => {
|
await loadingController.componentOnReady();
|
||||||
loading.present();
|
const loadingElement = await loadingController.create(opts);
|
||||||
});
|
return await loadingElement.present();
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user