mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 18:17:31 +08:00
@ -1,33 +1,15 @@
|
||||
import { Component, Listen, Method, Prop } from '@stencil/core';
|
||||
import { Component, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { ActionSheetOptions, OverlayController } from '../../interface';
|
||||
import { createOverlay, dismissOverlay, getTopOverlay, removeLastOverlay } from '../../utils/overlays';
|
||||
import { createOverlay, dismissOverlay, getOverlay } from '../../utils/overlays';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-action-sheet-controller'
|
||||
})
|
||||
export class ActionSheetController implements OverlayController {
|
||||
|
||||
private actionSheets = new Map<number, HTMLIonActionSheetElement>();
|
||||
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
@Listen('body:ionActionSheetWillPresent')
|
||||
protected actionSheetWillPresent(ev: any) {
|
||||
this.actionSheets.set(ev.target.overlayId, ev.target);
|
||||
}
|
||||
|
||||
@Listen('body:ionActionSheetWillDismiss')
|
||||
@Listen('body:ionActionSheetDidUnload')
|
||||
protected actionSheetWillDismiss(ev: any) {
|
||||
this.actionSheets.delete(ev.target.overlayId);
|
||||
}
|
||||
|
||||
@Listen('body:keyup.escape')
|
||||
protected escapeKeyUp() {
|
||||
removeLastOverlay(this.actionSheets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an action sheet overlay with action sheet options.
|
||||
*/
|
||||
@ -41,7 +23,7 @@ export class ActionSheetController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
dismiss(data?: any, role?: string, actionSheetId = -1) {
|
||||
return dismissOverlay(data, role, this.actionSheets, actionSheetId);
|
||||
return dismissOverlay(this.doc, data, role, 'ion-action-sheet', actionSheetId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,6 +31,6 @@ export class ActionSheetController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
getTop(): HTMLIonActionSheetElement {
|
||||
return getTopOverlay(this.actionSheets);
|
||||
return getOverlay(this.doc, 'ion-action-sheet') as HTMLIonActionSheetElement;
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,15 @@
|
||||
import { Component, Listen, Method, Prop } from '@stencil/core';
|
||||
import { Component, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { AlertOptions, OverlayController } from '../../interface';
|
||||
import { createOverlay, dismissOverlay, getTopOverlay, removeLastOverlay } from '../../utils/overlays';
|
||||
import { createOverlay, dismissOverlay, getOverlay } from '../../utils/overlays';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-alert-controller'
|
||||
})
|
||||
export class AlertController implements OverlayController {
|
||||
|
||||
private alerts = new Map<number, HTMLIonAlertElement>();
|
||||
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
@Listen('body:ionAlertWillPresent')
|
||||
protected alertWillPresent(ev: any) {
|
||||
this.alerts.set(ev.target.overlayId, ev.target);
|
||||
}
|
||||
|
||||
@Listen('body:ionAlertWillDismiss')
|
||||
@Listen('body:ionAlertDidUnload')
|
||||
protected alertWillDismiss(ev: any) {
|
||||
this.alerts.delete(ev.target.overlayId);
|
||||
}
|
||||
|
||||
@Listen('body:keyup.escape')
|
||||
protected escapeKeyUp() {
|
||||
removeLastOverlay(this.alerts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an alert overlay with alert options
|
||||
*/
|
||||
@ -41,7 +23,7 @@ export class AlertController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
dismiss(data?: any, role?: string, alertId = -1) {
|
||||
return dismissOverlay(data, role, this.alerts, alertId);
|
||||
return dismissOverlay(this.doc, data, role, 'ion-alert', alertId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,6 +31,6 @@ export class AlertController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
getTop(): HTMLIonAlertElement {
|
||||
return getTopOverlay(this.alerts);
|
||||
return getOverlay(this.doc, 'ion-alert') as HTMLIonAlertElement;
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,15 @@
|
||||
import { Component, Listen, Method, Prop } from '@stencil/core';
|
||||
import { Component, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { LoadingOptions, OverlayController } from '../../interface';
|
||||
import { createOverlay, dismissOverlay, getTopOverlay, removeLastOverlay } from '../../utils/overlays';
|
||||
import { createOverlay, dismissOverlay, getOverlay } from '../../utils/overlays';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-loading-controller'
|
||||
})
|
||||
export class LoadingController implements OverlayController {
|
||||
|
||||
private loadings = new Map<number, HTMLIonLoadingElement>();
|
||||
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
@Listen('body:ionLoadingWillPresent')
|
||||
protected loadingWillPresent(ev: any) {
|
||||
this.loadings.set(ev.target.overlayId, ev.target);
|
||||
}
|
||||
|
||||
@Listen('body:ionLoadingWillDismiss')
|
||||
@Listen('body:ionLoadingDidUnload')
|
||||
protected loadingWillDismiss(ev: any) {
|
||||
this.loadings.delete(ev.target.overlayId);
|
||||
}
|
||||
|
||||
@Listen('body:keyup.escape')
|
||||
protected escapeKeyUp() {
|
||||
removeLastOverlay(this.loadings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a loading overlay with loading options.
|
||||
*/
|
||||
@ -41,7 +23,7 @@ export class LoadingController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
dismiss(data?: any, role?: string, loadingId = -1) {
|
||||
return dismissOverlay(data, role, this.loadings, loadingId);
|
||||
return dismissOverlay(this.doc, data, role, 'ion-loading', loadingId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,6 +31,6 @@ export class LoadingController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
getTop(): HTMLIonLoadingElement {
|
||||
return getTopOverlay(this.loadings);
|
||||
return getOverlay(this.doc, 'ion-loading') as HTMLIonLoadingElement;
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,15 @@
|
||||
import { Component, Listen, Method, Prop } from '@stencil/core';
|
||||
import { Component, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { ModalOptions, OverlayController } from '../../interface';
|
||||
import { createOverlay, dismissOverlay, getTopOverlay, removeLastOverlay } from '../../utils/overlays';
|
||||
import { createOverlay, dismissOverlay, getOverlay } from '../../utils/overlays';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-modal-controller'
|
||||
})
|
||||
export class ModalController implements OverlayController {
|
||||
|
||||
private modals = new Map<number, HTMLIonModalElement>();
|
||||
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
@Listen('body:ionModalWillPresent')
|
||||
protected modalWillPresent(ev: any) {
|
||||
this.modals.set(ev.target.overlayId, ev.target);
|
||||
}
|
||||
|
||||
@Listen('body:ionModalWillDismiss')
|
||||
@Listen('body:ionModalDidUnload')
|
||||
protected modalWillDismiss(ev: any) {
|
||||
this.modals.delete(ev.target.overlayId);
|
||||
}
|
||||
|
||||
@Listen('body:keyup.escape')
|
||||
protected escapeKeyUp() {
|
||||
removeLastOverlay(this.modals);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a modal overlay with modal options.
|
||||
*/
|
||||
@ -41,7 +23,7 @@ export class ModalController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
dismiss(data?: any, role?: string, modalId = -1) {
|
||||
return dismissOverlay(data, role, this.modals, modalId);
|
||||
return dismissOverlay(this.doc, data, role, 'ion-modal', modalId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,6 +31,6 @@ export class ModalController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
getTop(): HTMLIonModalElement {
|
||||
return getTopOverlay(this.modals);
|
||||
return getOverlay(this.doc, 'ion-modal') as HTMLIonModalElement;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Component, Listen, Method, Prop } from '@stencil/core';
|
||||
import { Component, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { OverlayController, PickerOptions } from '../../interface';
|
||||
import { createOverlay, dismissOverlay, getTopOverlay, removeLastOverlay } from '../../utils/overlays';
|
||||
import { createOverlay, dismissOverlay, getOverlay } from '../../utils/overlays';
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
@ -9,26 +9,8 @@ import { createOverlay, dismissOverlay, getTopOverlay, removeLastOverlay } from
|
||||
})
|
||||
export class PickerController implements OverlayController {
|
||||
|
||||
private pickers = new Map<number, HTMLIonPickerElement>();
|
||||
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
@Listen('body:ionPickerWillPresent')
|
||||
protected pickerWillPresent(ev: any) {
|
||||
this.pickers.set(ev.target.overlayId, ev.target);
|
||||
}
|
||||
|
||||
@Listen('body:ionPickerWillDismiss')
|
||||
@Listen('body:ionPickerDidUnload')
|
||||
protected pickerWillDismiss(ev: any) {
|
||||
this.pickers.delete(ev.target.overlayId);
|
||||
}
|
||||
|
||||
@Listen('body:keyup.escape')
|
||||
protected escapeKeyUp() {
|
||||
removeLastOverlay(this.pickers);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a picker overlay with picker options.
|
||||
*/
|
||||
@ -42,7 +24,7 @@ export class PickerController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
dismiss(data?: any, role?: string, pickerId = -1) {
|
||||
return dismissOverlay(data, role, this.pickers, pickerId);
|
||||
return dismissOverlay(this.doc, data, role, 'ion-picker', pickerId);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -50,6 +32,6 @@ export class PickerController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
getTop(): HTMLIonPickerElement {
|
||||
return getTopOverlay(this.pickers);
|
||||
return getOverlay(this.doc, 'ion-picker') as HTMLIonPickerElement;
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,15 @@
|
||||
import { Component, Listen, Method, Prop } from '@stencil/core';
|
||||
import { Component, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { OverlayController, PopoverOptions } from '../../interface';
|
||||
import { createOverlay, dismissOverlay, getTopOverlay, removeLastOverlay } from '../../utils/overlays';
|
||||
import { createOverlay, dismissOverlay, getOverlay } from '../../utils/overlays';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-popover-controller'
|
||||
})
|
||||
export class PopoverController implements OverlayController {
|
||||
|
||||
private popovers = new Map<number, HTMLIonPopoverElement>();
|
||||
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
@Listen('body:ionPopoverWillPresent')
|
||||
protected popoverWillPresent(ev: any) {
|
||||
this.popovers.set(ev.target.overlayId, ev.target);
|
||||
}
|
||||
|
||||
@Listen('body:ionPopoverWillDismiss')
|
||||
@Listen('body:ionPopoverDidUnload')
|
||||
protected popoverWillDismiss(ev: any) {
|
||||
this.popovers.delete(ev.target.overlayId);
|
||||
}
|
||||
|
||||
@Listen('body:keyup.escape')
|
||||
protected escapeKeyUp() {
|
||||
removeLastOverlay(this.popovers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a popover overlay with popover options.
|
||||
*/
|
||||
@ -41,7 +23,7 @@ export class PopoverController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
dismiss(data?: any, role?: string, popoverId = -1) {
|
||||
return dismissOverlay(data, role, this.popovers, popoverId);
|
||||
return dismissOverlay(this.doc, data, role, 'ion-popover', popoverId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,6 +31,6 @@ export class PopoverController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
getTop(): HTMLIonPopoverElement {
|
||||
return getTopOverlay(this.popovers);
|
||||
return getOverlay(this.doc, 'ion-popover') as HTMLIonPopoverElement;
|
||||
}
|
||||
}
|
||||
|
@ -1,33 +1,15 @@
|
||||
import { Component, Listen, Method, Prop } from '@stencil/core';
|
||||
import { Component, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { OverlayController, ToastOptions } from '../../interface';
|
||||
import { createOverlay, dismissOverlay, getTopOverlay, removeLastOverlay } from '../../utils/overlays';
|
||||
import { createOverlay, dismissOverlay, getOverlay } from '../../utils/overlays';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-toast-controller'
|
||||
})
|
||||
export class ToastController implements OverlayController {
|
||||
|
||||
private toasts = new Map<number, HTMLIonToastElement>();
|
||||
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
@Listen('body:ionToastWillPresent')
|
||||
protected toastWillPresent(ev: any) {
|
||||
this.toasts.set(ev.target.overlayId, ev.target);
|
||||
}
|
||||
|
||||
@Listen('body:ionToastWillDismiss')
|
||||
@Listen('body:ionToastDidUnload')
|
||||
protected toastWillDismiss(ev: any) {
|
||||
this.toasts.delete(ev.target.overlayId);
|
||||
}
|
||||
|
||||
@Listen('body:keyup.escape')
|
||||
protected escapeKeyUp() {
|
||||
removeLastOverlay(this.toasts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a toast overlay with toast options.
|
||||
*/
|
||||
@ -41,7 +23,7 @@ export class ToastController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
dismiss(data?: any, role?: string, toastId = -1) {
|
||||
return dismissOverlay(data, role, this.toasts, toastId);
|
||||
return dismissOverlay(this.doc, data, role, 'ion-toast', toastId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,6 +31,6 @@ export class ToastController implements OverlayController {
|
||||
*/
|
||||
@Method()
|
||||
getTop(): HTMLIonToastElement {
|
||||
return getTopOverlay(this.toasts);
|
||||
return getOverlay(this.doc, 'ion-toast') as HTMLIonToastElement;
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ export interface OverlayController {
|
||||
|
||||
export interface HTMLIonOverlayElement extends HTMLStencilElement {
|
||||
overlayId: number;
|
||||
backdropDismiss?: boolean;
|
||||
|
||||
dismiss(data?: any, role?: string): Promise<void>;
|
||||
}
|
||||
|
||||
export type OverlayMap = Map<number, HTMLIonOverlayElement>;
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { AnimationBuilder, HTMLIonOverlayElement, IonicConfig, OverlayInterface, OverlayMap } from '../interface';
|
||||
import { AnimationBuilder, HTMLIonOverlayElement, IonicConfig, OverlayInterface } from '../interface';
|
||||
|
||||
let lastId = 1;
|
||||
let lastId = 0;
|
||||
|
||||
export function createOverlay<T extends HTMLIonOverlayElement & Required<B>, B>(element: T, opts: B): Promise<T> {
|
||||
const doc = element.ownerDocument;
|
||||
connectListeners(doc);
|
||||
|
||||
// convert the passed in overlay options into props
|
||||
// that get passed down into the new overlay
|
||||
Object.assign(element, opts);
|
||||
@ -10,39 +13,59 @@ export function createOverlay<T extends HTMLIonOverlayElement & Required<B>, B>(
|
||||
element.overlayId = lastId++;
|
||||
|
||||
// append the overlay element to the document body
|
||||
const doc = element.ownerDocument;
|
||||
const appRoot = doc.querySelector('ion-app') || doc.body;
|
||||
appRoot.appendChild(element);
|
||||
getAppRoot(doc).appendChild(element);
|
||||
|
||||
doc.body.addEventListener('keyup', ev => {
|
||||
if (ev.key === 'Escape') {
|
||||
const lastOverlay = getOverlay(doc);
|
||||
if (lastOverlay && lastOverlay.backdropDismiss) {
|
||||
lastOverlay.dismiss(null, BACKDROP);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return element.componentOnReady();
|
||||
}
|
||||
|
||||
export function dismissOverlay(data: any, role: string | undefined, overlays: OverlayMap, id: number): Promise<void> {
|
||||
id = id >= 0 ? id : getHighestId(overlays);
|
||||
const overlay = overlays.get(id);
|
||||
export function connectListeners(doc: Document) {
|
||||
if (lastId === 0) {
|
||||
lastId = 1;
|
||||
doc.body.addEventListener('keyup', ev => {
|
||||
if (ev.key === 'Escape') {
|
||||
const lastOverlay = getOverlay(doc);
|
||||
if (lastOverlay && lastOverlay.backdropDismiss === true) {
|
||||
lastOverlay.dismiss('backdrop');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function dismissOverlay(doc: Document, data: any, role: string | undefined, overlayTag: string, id: number): Promise<void> {
|
||||
const overlay = getOverlay(doc, overlayTag, id);
|
||||
if (!overlay) {
|
||||
return Promise.reject('overlay does not exist');
|
||||
}
|
||||
return overlay.dismiss(data, role);
|
||||
}
|
||||
|
||||
export function getTopOverlay<T extends HTMLIonOverlayElement>(overlays: OverlayMap): T {
|
||||
return overlays.get(getHighestId(overlays)) as T;
|
||||
export function getOverlays(doc: Document, overlayTag?: string): HTMLIonOverlayElement[] {
|
||||
const overlays = Array.from(getAppRoot(doc).children) as HTMLIonOverlayElement[];
|
||||
if (overlayTag == null) {
|
||||
return overlays;
|
||||
}
|
||||
overlayTag = overlayTag.toUpperCase();
|
||||
return overlays.filter(c => c.tagName === overlayTag);
|
||||
}
|
||||
|
||||
export function getHighestId(overlays: OverlayMap) {
|
||||
let minimum = -1;
|
||||
overlays.forEach((_, id) => {
|
||||
if (id > minimum) {
|
||||
minimum = id;
|
||||
}
|
||||
});
|
||||
return minimum;
|
||||
}
|
||||
|
||||
export function removeLastOverlay(overlays: OverlayMap) {
|
||||
const toRemove = getTopOverlay(overlays);
|
||||
return toRemove ? toRemove.dismiss() : Promise.resolve();
|
||||
export function getOverlay(doc: Document, overlayTag?: string, id?: number): HTMLIonOverlayElement | undefined {
|
||||
const overlays = getOverlays(doc, overlayTag);
|
||||
if (id != null) {
|
||||
return overlays.find(o => o.overlayId === id);
|
||||
}
|
||||
return (id == null)
|
||||
? overlays[overlays.length - 1]
|
||||
: overlays.find(o => o.overlayId === id);
|
||||
}
|
||||
|
||||
export async function present(
|
||||
@ -94,6 +117,10 @@ export async function dismiss(
|
||||
overlay.el.remove();
|
||||
}
|
||||
|
||||
function getAppRoot(doc: Document) {
|
||||
return doc.querySelector('ion-app') || doc.body;
|
||||
}
|
||||
|
||||
async function overlayAnimation(
|
||||
overlay: OverlayInterface,
|
||||
animationBuilder: AnimationBuilder,
|
||||
|
Reference in New Issue
Block a user