mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 04:14:21 +08:00
feature(angular): action-sheet, alert, loading, toast
This commit is contained in:
60
packages/angular/src/components/ion-nav.ts
Normal file
60
packages/angular/src/components/ion-nav.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
OnInit,
|
||||
ReflectiveInjector,
|
||||
ViewContainerRef,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
|
||||
import { PublicNav } from '@ionic/core';
|
||||
|
||||
import { getProviders } from '../di/di';
|
||||
import { AngularFrameworkDelegate } from '../providers/angular-framework-delegate';
|
||||
import { AngularViewController } from '../types/angular-view-controller';
|
||||
|
||||
@Component({
|
||||
selector: 'ion-nav',
|
||||
template: `
|
||||
<div #viewport class="ng-nav-viewport"></div>
|
||||
`
|
||||
})
|
||||
export class IonNavDelegate implements OnInit {
|
||||
|
||||
@ViewChild('viewport', { read: ViewContainerRef}) viewport: ViewContainerRef;
|
||||
|
||||
constructor(private changeDetection: ChangeDetectorRef, private angularFrameworkDelegate: AngularFrameworkDelegate) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const controllerElement = document.querySelector('ion-nav-controller') as any;
|
||||
controllerElement.delegate = this;
|
||||
}
|
||||
|
||||
attachViewToDom(nav: PublicNav, enteringView: AngularViewController): Promise<any> {
|
||||
|
||||
const componentProviders = ReflectiveInjector.resolve(getProviders(nav.element as HTMLIonNavElement));
|
||||
return this.angularFrameworkDelegate.attachViewToDom(enteringView.component, this.viewport, componentProviders, this.changeDetection).then((angularMountingData) => {
|
||||
|
||||
enteringView.componentFactory = angularMountingData.componentFactory;
|
||||
enteringView.injector = angularMountingData.childInjector;
|
||||
enteringView.componentRef = angularMountingData.componentRef;
|
||||
enteringView.instance = angularMountingData.componentRef.instance;
|
||||
enteringView.angularHostElement = angularMountingData.componentRef.location.nativeElement;
|
||||
enteringView.element = angularMountingData.componentRef.location.nativeElement.querySelector('ion-page');
|
||||
});
|
||||
}
|
||||
|
||||
removeViewFromDom(_nav: PublicNav, viewController: AngularViewController) {
|
||||
return this.angularFrameworkDelegate.removeViewFromDom((viewController as any).componentRef).then(() => {
|
||||
viewController.componentFactory = null;
|
||||
viewController.injector = null;
|
||||
viewController.componentRef = null;
|
||||
viewController.instance = null;
|
||||
viewController.angularHostElement = null;
|
||||
viewController.element = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
37
packages/angular/src/di/di.ts
Normal file
37
packages/angular/src/di/di.ts
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
import { InjectionToken } from '@angular/core';
|
||||
|
||||
import { App } from '../providers/app';
|
||||
import { NavController } from '../providers/nav-controller';
|
||||
|
||||
export const NavControllerToken = new InjectionToken<any>('NavControllerToken');
|
||||
export const ViewControllerToken = new InjectionToken<any>('ViewControllerToken');
|
||||
export const AppToken = new InjectionToken<any>('AppToken');
|
||||
|
||||
export function getProviders(element: HTMLIonNavElement) {
|
||||
return [
|
||||
{
|
||||
provide: NavControllerToken, useValue: element
|
||||
},
|
||||
|
||||
{
|
||||
provide: NavController, useFactory: provideNavControllerInjectable, deps: [NavControllerToken]
|
||||
},
|
||||
|
||||
{
|
||||
provide: AppToken, useValue: null,
|
||||
},
|
||||
{
|
||||
provide: App, useFactory: provideAppInjectable, deps: [AppToken]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export function provideNavControllerInjectable(element: HTMLIonNavElement) {
|
||||
return new NavController(element);
|
||||
}
|
||||
|
||||
export function provideAppInjectable() {
|
||||
const element = document.querySelector('ion-app');
|
||||
return new App(element);
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
ComponentFactoryResolver,
|
||||
Directive,
|
||||
ElementRef,
|
||||
Injector,
|
||||
InjectionToken,
|
||||
NgZone,
|
||||
OnInit,
|
||||
ReflectiveInjector,
|
||||
ViewContainerRef,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
|
||||
import { PublicNav, PublicViewController } from '@ionic/core';
|
||||
|
||||
import { App } from '../providers/app';
|
||||
|
||||
import { NavController as InjectableNavController } from '../providers/nav-controller';
|
||||
|
||||
@Component({
|
||||
selector: 'ion-nav',
|
||||
template: `
|
||||
<div #viewport class="ng-nav-viewport"></div>
|
||||
`
|
||||
})
|
||||
export class IonNavDelegate {
|
||||
|
||||
@ViewChild('viewport', { read: ViewContainerRef}) viewport: ViewContainerRef;
|
||||
|
||||
constructor(private crf: ComponentFactoryResolver, private changeDetection: ChangeDetectorRef, private zone: NgZone, private injector: Injector) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const controllerElement = document.querySelector('ion-nav-controller') as any;
|
||||
controllerElement.delegate = this;
|
||||
}
|
||||
|
||||
attachViewToDom(nav: PublicNav, enteringView: PublicViewController): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.zone.run(() => {
|
||||
|
||||
const componentProviders = ReflectiveInjector.resolve([
|
||||
{
|
||||
provide: NavControllerToken, useValue: nav.element,
|
||||
},
|
||||
{
|
||||
provide: InjectableNavController, useFactory: provideNavControllerInjectable, deps: [NavControllerToken]
|
||||
},
|
||||
|
||||
{
|
||||
provide: AppToken, useValue: null,
|
||||
},
|
||||
{
|
||||
provide: App, useFactory: provideAppInjectable, deps: [AppToken]
|
||||
}
|
||||
]);
|
||||
|
||||
const componentFactory = this.crf.resolveComponentFactory(enteringView.component);
|
||||
|
||||
const childInjector = ReflectiveInjector.fromResolvedProviders(componentProviders, this.viewport.parentInjector);
|
||||
const componentRef = componentFactory.create(childInjector, []);
|
||||
this.viewport.insert(componentRef.hostView, this.viewport.length);
|
||||
this.changeDetection.detectChanges();
|
||||
|
||||
|
||||
(enteringView as any).componentFactory = componentFactory;
|
||||
(enteringView as any).childInjector = childInjector;
|
||||
(enteringView as any).componentRef = componentRef;
|
||||
enteringView.instance = componentRef.instance;
|
||||
(enteringView as any).angularHostElement = componentRef.location.nativeElement;
|
||||
enteringView.element = componentRef.location.nativeElement.querySelector('ion-page');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeViewFromDom(nav: PublicNav, viewController: PublicViewController) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.zone.run(() => {
|
||||
|
||||
(viewController as any).componentRef.destroy();
|
||||
// (nav.element as HTMLElement).removeChild(viewController.angularHostElement);
|
||||
|
||||
(viewController as any).componentFactory = null;
|
||||
(viewController as any).childInjector = null;
|
||||
(viewController as any).componentRef = null;
|
||||
viewController.instance = null;
|
||||
(viewController as any).angularHostElement = null;
|
||||
viewController.element = null;
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const NavControllerToken = new InjectionToken<any>('NavControllerToken');
|
||||
export const ViewControllerToken = new InjectionToken<any>('ViewControllerToken');
|
||||
export const AppToken = new InjectionToken<any>('AppToken');
|
||||
|
||||
export function provideNavControllerInjectable(element: any) {
|
||||
return new InjectableNavController(element);
|
||||
}
|
||||
|
||||
export function provideAppInjectable() {
|
||||
return new App();
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
export { IonNavDelegate } from './directives/ion-nav';
|
||||
export { IonNavDelegate } from './components/ion-nav';
|
||||
export { IonicAngularModule } from './module';
|
||||
|
||||
|
||||
export { ActionSheetController, ActionSheetProxy } from './providers/action-sheet-controller';
|
||||
export { AlertController, AlertProxy } from './providers/alert-controller';
|
||||
export { App } from './providers/app';
|
||||
export { LoadingController, LoadingProxy } from './providers/loading-controller';
|
||||
export { NavController } from './providers/nav-controller';
|
||||
|
||||
export { ToastController, ToastProxy } from './providers/toast-controller';
|
@ -9,9 +9,15 @@ import { RadioValueAccessor } from './control-value-accessors/radio-value-access
|
||||
import { SelectValueAccessor } from './control-value-accessors/select-value-accessor';
|
||||
import { TextValueAccessor } from './control-value-accessors/text-value-accessor';
|
||||
|
||||
import { IonNavDelegate } from './directives/ion-nav';
|
||||
|
||||
import { IonNavDelegate } from './components/ion-nav';
|
||||
|
||||
/* Providers */
|
||||
import { ActionSheetController } from './providers/action-sheet-controller';
|
||||
import { AlertController } from './providers/alert-controller';
|
||||
import { AngularFrameworkDelegate } from './providers/angular-framework-delegate';
|
||||
import { LoadingController } from './providers/loading-controller';
|
||||
import { ToastController } from './providers/toast-controller';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@ -30,14 +36,18 @@ import { AlertController } from './providers/alert-controller';
|
||||
],
|
||||
schemas: [
|
||||
CUSTOM_ELEMENTS_SCHEMA
|
||||
]
|
||||
],
|
||||
})
|
||||
export class IonicAngularModule {
|
||||
static forRoot(): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: IonicAngularModule,
|
||||
providers: [
|
||||
AlertController
|
||||
AlertController,
|
||||
ActionSheetController,
|
||||
AngularFrameworkDelegate,
|
||||
LoadingController,
|
||||
ToastController
|
||||
]
|
||||
};
|
||||
}
|
||||
|
104
packages/angular/src/providers/action-sheet-controller.ts
Normal file
104
packages/angular/src/providers/action-sheet-controller.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActionSheetDismissEvent, ActionSheetOptions } from '@ionic/core';
|
||||
|
||||
import { ensureElementInBody, hydrateElement } from '../util/util';
|
||||
|
||||
let actionSheetId = 0;
|
||||
|
||||
@Injectable()
|
||||
export class ActionSheetController {
|
||||
create(opts?: ActionSheetOptions): ActionSheetProxy {
|
||||
return getActionSheetProxy(opts);
|
||||
}
|
||||
}
|
||||
|
||||
export function getActionSheetProxy(opts: ActionSheetOptions){
|
||||
return {
|
||||
id: actionSheetId++,
|
||||
state: PRESENTING,
|
||||
opts: opts,
|
||||
present: function() { return present(this)},
|
||||
dismiss: function() { return dismiss(this)},
|
||||
onDidDismiss: function(callback: (data: any, role: string) => void) {
|
||||
(this as ActionSheetProxyInternal).onDidDismissHandler = callback;
|
||||
},
|
||||
onWillDismiss: function(callback: (data: any, role: string) => void) {
|
||||
(this as ActionSheetProxyInternal).onWillDismissHandler = callback;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function present(actionSheetProxy: ActionSheetProxyInternal): Promise<any> {
|
||||
actionSheetProxy.state = PRESENTING;
|
||||
return loadOverlay(actionSheetProxy.opts).then((actionSheetElement: HTMLIonActionSheetElement) => {
|
||||
actionSheetProxy.element = actionSheetElement;
|
||||
|
||||
const onDidDismissHandler = (event: ActionSheetDismissEvent) => {
|
||||
actionSheetElement.removeEventListener(ION_ACTION_SHEET_DID_DISMISS_EVENT, onDidDismissHandler);
|
||||
if (actionSheetProxy.onDidDismissHandler) {
|
||||
actionSheetProxy.onDidDismissHandler(event.detail.data, event.detail.role);
|
||||
}
|
||||
};
|
||||
|
||||
const onWillDismissHandler = (event: ActionSheetDismissEvent) => {
|
||||
actionSheetElement.removeEventListener(ION_ACTION_SHEET_WILL_DISMISS_EVENT, onWillDismissHandler);
|
||||
if (actionSheetProxy.onWillDismissHandler) {
|
||||
actionSheetProxy.onWillDismissHandler(event.detail.data, event.detail.role);
|
||||
}
|
||||
};
|
||||
|
||||
actionSheetElement.addEventListener(ION_ACTION_SHEET_DID_DISMISS_EVENT, onDidDismissHandler);
|
||||
actionSheetElement.addEventListener(ION_ACTION_SHEET_WILL_DISMISS_EVENT, onWillDismissHandler);
|
||||
|
||||
if (actionSheetProxy.state === PRESENTING) {
|
||||
return actionSheetElement.present();
|
||||
}
|
||||
|
||||
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
|
||||
// attribute before it could async load and present itself.
|
||||
// with that in mind, just return null to make the TS compiler happy
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
export function dismiss(actionSheetProxy: ActionSheetProxyInternal): Promise<any> {
|
||||
actionSheetProxy.state = DISMISSING;
|
||||
if (actionSheetProxy.element) {
|
||||
if (actionSheetProxy.state === DISMISSING) {
|
||||
return actionSheetProxy.element.dismiss();
|
||||
}
|
||||
}
|
||||
// either we're not in the dismissing state
|
||||
// or we're calling this before the element is created
|
||||
// so just return a resolved promise
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export function loadOverlay(opts: ActionSheetOptions): Promise<HTMLIonActionSheetElement> {
|
||||
const element = ensureElementInBody('ion-action-sheet-controller') as HTMLIonActionSheetControllerElement;
|
||||
return hydrateElement(element).then(() => {
|
||||
return element.create(opts);
|
||||
});
|
||||
}
|
||||
|
||||
export interface ActionSheetProxy {
|
||||
present(): Promise<void>
|
||||
dismiss(): Promise<void>
|
||||
onDidDismiss(callback: (data: any, role: string) => void): void;
|
||||
onWillDismiss(callback: (data: any, role: string) => void): void;
|
||||
}
|
||||
|
||||
export interface ActionSheetProxyInternal extends ActionSheetProxy {
|
||||
id: number;
|
||||
opts: ActionSheetOptions;
|
||||
state: number;
|
||||
element: HTMLIonActionSheetElement;
|
||||
onDidDismissHandler?: (data: any, role: string) => void;
|
||||
onWillDismissHandler?: (data: any, role: string) => void;
|
||||
}
|
||||
|
||||
export const PRESENTING = 1;
|
||||
export const DISMISSING = 2;
|
||||
|
||||
const ION_ACTION_SHEET_DID_DISMISS_EVENT = 'ionActionSheetDidDismiss';
|
||||
const ION_ACTION_SHEET_WILL_DISMISS_EVENT = 'ionActionSheetWillDismiss';
|
@ -53,6 +53,11 @@ export function present(alertProxy: AlertProxyInternal): Promise<any> {
|
||||
if (alertProxy.state === PRESENTING) {
|
||||
return alertElement.present();
|
||||
}
|
||||
|
||||
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
|
||||
// attribute before it could async load and present itself.
|
||||
// with that in mind, just return null to make the TS compiler happy
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@ -69,7 +74,7 @@ export function dismiss(alertProxy: AlertProxyInternal): Promise<any> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export function loadOverlay(opts: AlertOptions) {
|
||||
export function loadOverlay(opts: AlertOptions): Promise<HTMLIonAlertElement> {
|
||||
const element = ensureElementInBody('ion-alert-controller') as HTMLIonAlertControllerElement;
|
||||
return hydrateElement(element).then(() => {
|
||||
return element.create(opts);
|
||||
|
60
packages/angular/src/providers/angular-framework-delegate.ts
Normal file
60
packages/angular/src/providers/angular-framework-delegate.ts
Normal file
@ -0,0 +1,60 @@
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
ComponentFactoryResolver,
|
||||
ComponentRef,
|
||||
Injectable,
|
||||
Injector,
|
||||
NgZone,
|
||||
ReflectiveInjector,
|
||||
Type,
|
||||
ViewContainerRef,
|
||||
} from '@angular/core';
|
||||
|
||||
import { ComponentFactory } from '@angular/core/src/linker/component_factory';
|
||||
|
||||
@Injectable()
|
||||
export class AngularFrameworkDelegate {
|
||||
|
||||
constructor(private crf: ComponentFactoryResolver, private zone: NgZone) {
|
||||
}
|
||||
|
||||
attachViewToDom(componentToMount: Type<any>, viewport: ViewContainerRef, providers: any, changeDetection: ChangeDetectorRef): Promise<AngularMountingData> {
|
||||
|
||||
return new Promise((resolve) => {
|
||||
this.zone.run(() => {
|
||||
const mountingData = attachViewToDom(this.crf, componentToMount, viewport, providers, changeDetection);
|
||||
resolve(mountingData);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeViewFromDom(componentRef: ComponentRef<any>): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
this.zone.run(() => {
|
||||
componentRef.destroy();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function attachViewToDom(crf: ComponentFactoryResolver, componentToMount: Type<any>, viewport: ViewContainerRef, providers: any, changeDetection: ChangeDetectorRef): AngularMountingData{
|
||||
const componentFactory = crf.resolveComponentFactory(componentToMount);
|
||||
const componentProviders = ReflectiveInjector.resolve(providers);
|
||||
const childInjector = ReflectiveInjector.fromResolvedProviders(componentProviders, viewport.parentInjector);
|
||||
const componentRef = componentFactory.create(childInjector, []);
|
||||
viewport.insert(componentRef.hostView, viewport.length);
|
||||
changeDetection.detectChanges();
|
||||
|
||||
return {
|
||||
componentFactory,
|
||||
childInjector: childInjector,
|
||||
componentRef: componentRef
|
||||
}
|
||||
}
|
||||
|
||||
export interface AngularMountingData {
|
||||
componentFactory: ComponentFactory<any>;
|
||||
childInjector: Injector;
|
||||
componentRef: ComponentRef<any>;
|
||||
}
|
@ -1,13 +1,8 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { NavContainer } from '@ionic/core';
|
||||
import { hydrateElement } from '../util/util';
|
||||
|
||||
@Injectable()
|
||||
export class App {
|
||||
|
||||
private element: HTMLIonAppElement;
|
||||
constructor() {
|
||||
this.element = document.querySelector('ion-app') as HTMLIonAppElement;
|
||||
constructor(public _element: HTMLIonAppElement) {
|
||||
}
|
||||
|
||||
setTitle(title: string) {
|
||||
@ -15,30 +10,46 @@ export class App {
|
||||
}
|
||||
|
||||
isScrolling(): boolean {
|
||||
if (this.element.isScrolling) {
|
||||
return this.element.isScrolling();
|
||||
}
|
||||
return false;
|
||||
return isScrollingImpl(this);
|
||||
}
|
||||
|
||||
getRootNavs(): NavContainer[] {
|
||||
if (this.element.getRootNavs) {
|
||||
return this.element.getRootNavs();
|
||||
}
|
||||
return [];
|
||||
return getRootNavsImpl(this);
|
||||
}
|
||||
|
||||
getActiveNavs(rootNavId?: number): NavContainer[] {
|
||||
if (this.element.getActiveNavs) {
|
||||
return this.element.getActiveNavs(rootNavId);
|
||||
}
|
||||
return [];
|
||||
return getActiveNavsImpl(this, rootNavId);
|
||||
}
|
||||
|
||||
getNavByIdOrName(nameOrId: number | string): NavContainer {
|
||||
if (this.element.getNavByIdOrName) {
|
||||
return this.element.getNavByIdOrName(nameOrId);
|
||||
}
|
||||
return null;
|
||||
return getNavByIdOrNameImpl(this, nameOrId);
|
||||
}
|
||||
}
|
||||
|
||||
export function isScrollingImpl(app: App) {
|
||||
if (app._element && app._element.isScrolling) {
|
||||
return app._element.isScrolling();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getRootNavsImpl(app: App) {
|
||||
if (app._element && app._element.getRootNavs) {
|
||||
return app._element.getRootNavs();
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function getActiveNavsImpl(app: App, rootNavId?: number): NavContainer[] {
|
||||
if (app._element && app._element.getActiveNavs) {
|
||||
return app._element.getActiveNavs(rootNavId);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function getNavByIdOrNameImpl(app: App, nameOrId: number | string): NavContainer {
|
||||
if (app._element && app._element.getNavByIdOrName) {
|
||||
return app._element.getNavByIdOrName(nameOrId);
|
||||
}
|
||||
return null;
|
||||
}
|
104
packages/angular/src/providers/loading-controller.ts
Normal file
104
packages/angular/src/providers/loading-controller.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { LoadingDismissEvent, LoadingOptions } from '@ionic/core';
|
||||
|
||||
import { ensureElementInBody, hydrateElement } from '../util/util';
|
||||
|
||||
let loadingId = 0;
|
||||
|
||||
@Injectable()
|
||||
export class LoadingController {
|
||||
create(opts?: LoadingOptions): LoadingProxy {
|
||||
return getLoadingProxy(opts);
|
||||
}
|
||||
}
|
||||
|
||||
export function getLoadingProxy(opts: LoadingOptions){
|
||||
return {
|
||||
id: loadingId++,
|
||||
state: PRESENTING,
|
||||
opts: opts,
|
||||
present: function() { return present(this)},
|
||||
dismiss: function() { return dismiss(this)},
|
||||
onDidDismiss: function(callback: (data: any, role: string) => void) {
|
||||
(this as LoadingProxyInternal).onDidDismissHandler = callback;
|
||||
},
|
||||
onWillDismiss: function(callback: (data: any, role: string) => void) {
|
||||
(this as LoadingProxyInternal).onWillDismissHandler = callback;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function present(loadingProxy: LoadingProxyInternal): Promise<any> {
|
||||
loadingProxy.state = PRESENTING;
|
||||
return loadOverlay(loadingProxy.opts).then((loadingElement: HTMLIonLoadingElement) => {
|
||||
loadingProxy.element = loadingElement;
|
||||
|
||||
const onDidDismissHandler = (event: LoadingDismissEvent) => {
|
||||
loadingElement.removeEventListener(ION_LOADING_DID_DISMISS_EVENT, onDidDismissHandler);
|
||||
if (loadingProxy.onDidDismissHandler) {
|
||||
loadingProxy.onDidDismissHandler(event.detail.data, event.detail.role);
|
||||
}
|
||||
};
|
||||
|
||||
const onWillDismissHandler = (event: LoadingDismissEvent) => {
|
||||
loadingElement.removeEventListener(ION_LOADING_WILL_DISMISS_EVENT, onWillDismissHandler);
|
||||
if (loadingProxy.onWillDismissHandler) {
|
||||
loadingProxy.onWillDismissHandler(event.detail.data, event.detail.role);
|
||||
}
|
||||
};
|
||||
|
||||
loadingElement.addEventListener(ION_LOADING_DID_DISMISS_EVENT, onDidDismissHandler);
|
||||
loadingElement.addEventListener(ION_LOADING_WILL_DISMISS_EVENT, onWillDismissHandler);
|
||||
|
||||
if (loadingProxy.state === PRESENTING) {
|
||||
return loadingElement.present();
|
||||
}
|
||||
|
||||
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
|
||||
// attribute before it could async load and present itself.
|
||||
// with that in mind, just return null to make the TS compiler happy
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
export function dismiss(loadingProxy: LoadingProxyInternal): Promise<any> {
|
||||
loadingProxy.state = DISMISSING;
|
||||
if (loadingProxy.element) {
|
||||
if (loadingProxy.state === DISMISSING) {
|
||||
return loadingProxy.element.dismiss();
|
||||
}
|
||||
}
|
||||
// either we're not in the dismissing state
|
||||
// or we're calling this before the element is created
|
||||
// so just return a resolved promise
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export function loadOverlay(opts: LoadingOptions): Promise<HTMLIonLoadingElement> {
|
||||
const element = ensureElementInBody('ion-loading-controller') as HTMLIonLoadingControllerElement;
|
||||
return hydrateElement(element).then(() => {
|
||||
return element.create(opts);
|
||||
});
|
||||
}
|
||||
|
||||
export interface LoadingProxy {
|
||||
present(): Promise<void>
|
||||
dismiss(): Promise<void>
|
||||
onDidDismiss(callback: (data: any, role: string) => void): void;
|
||||
onWillDismiss(callback: (data: any, role: string) => void): void;
|
||||
}
|
||||
|
||||
export interface LoadingProxyInternal extends LoadingProxy {
|
||||
id: number;
|
||||
opts: LoadingOptions;
|
||||
state: number;
|
||||
element: HTMLIonLoadingElement;
|
||||
onDidDismissHandler?: (data: any, role: string) => void;
|
||||
onWillDismissHandler?: (data: any, role: string) => void;
|
||||
}
|
||||
|
||||
export const PRESENTING = 1;
|
||||
export const DISMISSING = 2;
|
||||
|
||||
const ION_LOADING_DID_DISMISS_EVENT = 'ionLoadingDidDismiss';
|
||||
const ION_LOADING_WILL_DISMISS_EVENT = 'ionLoadingWillDismiss';
|
@ -1,4 +1,3 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { NavOptions, PublicNav, PublicViewController } from '@ionic/core';
|
||||
import { hydrateElement } from '../util/util';
|
||||
|
||||
|
104
packages/angular/src/providers/toast-controller.ts
Normal file
104
packages/angular/src/providers/toast-controller.ts
Normal file
@ -0,0 +1,104 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ToastDismissEvent, ToastOptions } from '@ionic/core';
|
||||
|
||||
import { ensureElementInBody, hydrateElement } from '../util/util';
|
||||
|
||||
let toastId = 0;
|
||||
|
||||
@Injectable()
|
||||
export class ToastController {
|
||||
create(opts?: ToastOptions): ToastProxy {
|
||||
return getToastProxy(opts);
|
||||
}
|
||||
}
|
||||
|
||||
export function getToastProxy(opts: ToastOptions){
|
||||
return {
|
||||
id: toastId++,
|
||||
state: PRESENTING,
|
||||
opts: opts,
|
||||
present: function() { return present(this)},
|
||||
dismiss: function() { return dismiss(this)},
|
||||
onDidDismiss: function(callback: (data: any, role: string) => void) {
|
||||
(this as ToastProxyInternal).onDidDismissHandler = callback;
|
||||
},
|
||||
onWillDismiss: function(callback: (data: any, role: string) => void) {
|
||||
(this as ToastProxyInternal).onWillDismissHandler = callback;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function present(toastProxy: ToastProxyInternal): Promise<any> {
|
||||
toastProxy.state = PRESENTING;
|
||||
return loadOverlay(toastProxy.opts).then((toastElement: HTMLIonToastElement) => {
|
||||
toastProxy.element = toastElement;
|
||||
|
||||
const onDidDismissHandler = (event: ToastDismissEvent) => {
|
||||
toastElement.removeEventListener(ION_TOAST_DID_DISMISS_EVENT, onDidDismissHandler);
|
||||
if (toastProxy.onDidDismissHandler) {
|
||||
toastProxy.onDidDismissHandler(event.detail.data, event.detail.role);
|
||||
}
|
||||
};
|
||||
|
||||
const onWillDismissHandler = (event: ToastDismissEvent) => {
|
||||
toastElement.removeEventListener(ION_TOAST_WILL_DISMISS_EVENT, onWillDismissHandler);
|
||||
if (toastProxy.onWillDismissHandler) {
|
||||
toastProxy.onWillDismissHandler(event.detail.data, event.detail.role);
|
||||
}
|
||||
};
|
||||
|
||||
toastElement.addEventListener(ION_TOAST_DID_DISMISS_EVENT, onDidDismissHandler);
|
||||
toastElement.addEventListener(ION_TOAST_WILL_DISMISS_EVENT, onWillDismissHandler);
|
||||
|
||||
if (toastProxy.state === PRESENTING) {
|
||||
return toastElement.present();
|
||||
}
|
||||
|
||||
// we'll only ever get here if someone tried to dismiss the overlay or mess with it's internal state
|
||||
// attribute before it could async load and present itself.
|
||||
// with that in mind, just return null to make the TS compiler happy
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
export function dismiss(toastProxy: ToastProxyInternal): Promise<any> {
|
||||
toastProxy.state = DISMISSING;
|
||||
if (toastProxy.element) {
|
||||
if (toastProxy.state === DISMISSING) {
|
||||
return toastProxy.element.dismiss();
|
||||
}
|
||||
}
|
||||
// either we're not in the dismissing state
|
||||
// or we're calling this before the element is created
|
||||
// so just return a resolved promise
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export function loadOverlay(opts: ToastOptions): Promise<HTMLIonToastElement> {
|
||||
const element = ensureElementInBody('ion-toast-controller') as HTMLIonToastControllerElement;
|
||||
return hydrateElement(element).then(() => {
|
||||
return element.create(opts);
|
||||
});
|
||||
}
|
||||
|
||||
export interface ToastProxy {
|
||||
present(): Promise<void>
|
||||
dismiss(): Promise<void>
|
||||
onDidDismiss(callback: (data: any, role: string) => void): void;
|
||||
onWillDismiss(callback: (data: any, role: string) => void): void;
|
||||
}
|
||||
|
||||
export interface ToastProxyInternal extends ToastProxy {
|
||||
id: number;
|
||||
opts: ToastOptions;
|
||||
state: number;
|
||||
element: HTMLIonToastElement;
|
||||
onDidDismissHandler?: (data: any, role: string) => void;
|
||||
onWillDismissHandler?: (data: any, role: string) => void;
|
||||
}
|
||||
|
||||
export const PRESENTING = 1;
|
||||
export const DISMISSING = 2;
|
||||
|
||||
const ION_TOAST_DID_DISMISS_EVENT = 'ionToastDidDismiss';
|
||||
const ION_TOAST_WILL_DISMISS_EVENT = 'ionToastWillDismiss';
|
16
packages/angular/src/types/angular-view-controller.ts
Normal file
16
packages/angular/src/types/angular-view-controller.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import {
|
||||
ComponentFactory,
|
||||
ComponentRef,
|
||||
Injector
|
||||
} from '@angular/core';
|
||||
|
||||
import { PublicViewController } from '@ionic/core';
|
||||
|
||||
export interface AngularViewController extends PublicViewController {
|
||||
componentFactory?: ComponentFactory<any>;
|
||||
injector?: Injector;
|
||||
componentRef?: ComponentRef<any>;
|
||||
instance?: any;
|
||||
angularHostElement?: HTMLElement;
|
||||
|
||||
}
|
Reference in New Issue
Block a user