refactor(loading): update loading controller and element to match other overlays

This commit is contained in:
Dan Bucholtz
2017-12-02 00:25:22 -06:00
parent ece30bb35a
commit 0a7d827df7
3 changed files with 85 additions and 63 deletions

View File

@ -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);
} }

View File

@ -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 {

View File

@ -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>