mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-10 00:27:41 +08:00
feature(angular): action-sheet, alert, loading, toast
This commit is contained in:
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';
|
||||
Reference in New Issue
Block a user