mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
refactor(app): add cordova-platform to ion-app, add back-button support, get api working
This commit is contained in:
30
packages/core/src/components.d.ts
vendored
30
packages/core/src/components.d.ts
vendored
@ -725,6 +725,36 @@ declare global {
|
||||
}
|
||||
|
||||
|
||||
import {
|
||||
CordovaPlatform as IonCordovaPlatform
|
||||
} from './components/cordova-platform/cordova-platform';
|
||||
|
||||
declare global {
|
||||
interface HTMLIonCordovaPlatformElement extends IonCordovaPlatform, HTMLElement {
|
||||
}
|
||||
var HTMLIonCordovaPlatformElement: {
|
||||
prototype: HTMLIonCordovaPlatformElement;
|
||||
new (): HTMLIonCordovaPlatformElement;
|
||||
};
|
||||
interface HTMLElementTagNameMap {
|
||||
"ion-cordova-platform": HTMLIonCordovaPlatformElement;
|
||||
}
|
||||
interface ElementTagNameMap {
|
||||
"ion-cordova-platform": HTMLIonCordovaPlatformElement;
|
||||
}
|
||||
namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
"ion-cordova-platform": JSXElements.IonCordovaPlatformAttributes;
|
||||
}
|
||||
}
|
||||
namespace JSXElements {
|
||||
export interface IonCordovaPlatformAttributes extends HTMLAttributes {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
import {
|
||||
Datetime as IonDatetime
|
||||
} from './components/datetime/datetime';
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, Listen, Method } from '@stencil/core';
|
||||
import { ActionSheetEvent, ActionSheetOptions } from '../../index';
|
||||
import { ActionSheetEvent, ActionSheetOptions, OverlayController } from '../../index';
|
||||
|
||||
let ids = 0;
|
||||
const actionSheets = new Map<number, HTMLIonActionSheetElement>();
|
||||
@ -7,7 +7,7 @@ const actionSheets = new Map<number, HTMLIonActionSheetElement>();
|
||||
@Component({
|
||||
tag: 'ion-action-sheet-controller'
|
||||
})
|
||||
export class ActionSheetController {
|
||||
export class ActionSheetController implements OverlayController {
|
||||
|
||||
@Method()
|
||||
create(opts?: ActionSheetOptions): Promise<HTMLIonActionSheetElement> {
|
||||
@ -38,6 +38,10 @@ export class ActionSheetController {
|
||||
return actionSheet.dismiss(data, role);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getTop() {
|
||||
return actionSheets.get(getHighestId());
|
||||
}
|
||||
|
||||
@Listen('body:ionActionSheetWillPresent')
|
||||
protected actionSheetWillPresent(ev: ActionSheetEvent) {
|
||||
|
@ -36,6 +36,9 @@
|
||||
#### dismiss()
|
||||
|
||||
|
||||
#### getTop()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, Listen, Method } from '@stencil/core';
|
||||
import { AlertEvent, AlertOptions } from '../../index';
|
||||
import { AlertEvent, AlertOptions, OverlayController } from '../../index';
|
||||
|
||||
let ids = 0;
|
||||
const alerts = new Map<number, HTMLIonAlertElement>();
|
||||
@ -7,7 +7,7 @@ const alerts = new Map<number, HTMLIonAlertElement>();
|
||||
@Component({
|
||||
tag: 'ion-alert-controller'
|
||||
})
|
||||
export class AlertController {
|
||||
export class AlertController implements OverlayController {
|
||||
|
||||
@Method()
|
||||
create(opts?: AlertOptions): Promise<HTMLIonAlertElement> {
|
||||
@ -38,6 +38,10 @@ export class AlertController {
|
||||
return alert.dismiss(data, role);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getTop() {
|
||||
return alerts.get(getHighestId());
|
||||
}
|
||||
|
||||
@Listen('body:ionAlertWillPresent')
|
||||
protected alertWillPresent(ev: AlertEvent) {
|
||||
|
@ -50,6 +50,9 @@ building the form within a modal instead.
|
||||
#### dismiss()
|
||||
|
||||
|
||||
#### getTop()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Component, Element, Listen, Method, Prop, State } from '@stencil/core';
|
||||
import { Config, NavContainer, NavEvent } from '../../index';
|
||||
import { isReady } from '../../utils/helpers';
|
||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core';
|
||||
import { Config, NavEvent, OverlayController, PublicNav, PublicViewController } from '../../index';
|
||||
|
||||
import { getOrAppendElement } from '../../utils/helpers';
|
||||
import { isCordova } from '../../global/platform-utils';
|
||||
|
||||
const rootNavs = new Map<number, HTMLIonNavElement>();
|
||||
const ACTIVE_SCROLLING_TIME = 100;
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'ion-app',
|
||||
styleUrls: {
|
||||
@ -18,10 +19,10 @@ const ACTIVE_SCROLLING_TIME = 100;
|
||||
})
|
||||
export class App {
|
||||
|
||||
private didScroll = false;
|
||||
private scrollTime = 0;
|
||||
|
||||
@Element() element: HTMLElement;
|
||||
@Event() exitApp: EventEmitter<ExitAppEventDetail>;
|
||||
|
||||
@State() modeCode: string;
|
||||
@State() hoverCSS = false;
|
||||
@ -44,16 +45,17 @@ export class App {
|
||||
* Returns an array of top level Navs
|
||||
*/
|
||||
@Method()
|
||||
getRootNavs(): NavContainer[] {
|
||||
/*const navs: NavContainer[] = [];
|
||||
rootNavs.forEach((rootNav: NavContainer) => {
|
||||
getRootNavs(): PublicNav[] {
|
||||
const navs: PublicNav[] = [];
|
||||
rootNavs.forEach((rootNav: PublicNav) => {
|
||||
navs.push(rootNav);
|
||||
});
|
||||
return navs;
|
||||
*/
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the application is enabled or not
|
||||
*/
|
||||
@Method()
|
||||
isEnabled(): boolean {
|
||||
return true;
|
||||
@ -79,45 +81,66 @@ export class App {
|
||||
@Method()
|
||||
setScrolling() {
|
||||
this.scrollTime = Date.now() + ACTIVE_SCROLLING_TIME;
|
||||
this.didScroll = true;
|
||||
}
|
||||
|
||||
@Method()
|
||||
getActiveNavs(_rootNavId?: number): NavContainer[] {
|
||||
/*const portal = portals.get(PORTAL_MODAL);
|
||||
if (portal && portal.views && portal.views.length) {
|
||||
return findTopNavs(portal);
|
||||
}
|
||||
*/
|
||||
// TODO - figure out if a modal is open, don't use portal
|
||||
/*if (!rootNavs.size) {
|
||||
return [];
|
||||
}
|
||||
if (rootNavId) {
|
||||
return findTopNavs(rootNavs.get(rootNavId));
|
||||
}
|
||||
if (rootNavs.size === 1) {
|
||||
return findTopNavs(rootNavs.values().next().value);
|
||||
}
|
||||
// fallback to just using all root navs
|
||||
let activeNavs: NavContainer[] = [];
|
||||
rootNavs.forEach(nav => {
|
||||
activeNavs = activeNavs.concat(findTopNavs(nav));
|
||||
});
|
||||
return activeNavs;
|
||||
*/
|
||||
return [];
|
||||
getTopNavs(rootNavId = -1): PublicNav[] {
|
||||
return getTopNavsImpl(rootNavId);
|
||||
}
|
||||
|
||||
@Method() getNavByIdOrName(_nameOrId: number | string): any {
|
||||
/*const navs = Array.from(rootNavs.values());
|
||||
@Method()
|
||||
getNavByIdOrName(nameOrId: number | string): PublicNav {
|
||||
const navs = Array.from(rootNavs.values());
|
||||
for (const navContainer of navs) {
|
||||
const match = getNavByIdOrNameImpl(navContainer, nameOrId);
|
||||
if (match) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
*/
|
||||
return null;
|
||||
}
|
||||
|
||||
@Method()
|
||||
hardwareBackButtonPressed() {
|
||||
// check if menu exists and is open
|
||||
return checkIfMenuIsOpen().then((done: boolean) => {
|
||||
if (!done) {
|
||||
// we need to check if there is an action-sheet, alert, loading, picker, popover or toast open
|
||||
// if so, just return and don't do anything
|
||||
// Why? I have no idea, but that is the existing behavior in Ionic 3
|
||||
return checkIfNotModalOverlayIsOpen();
|
||||
}
|
||||
return done;
|
||||
}).then((done: boolean) => {
|
||||
if (!done) {
|
||||
// if there's a modal open, close that instead
|
||||
return closeModalIfOpen();
|
||||
}
|
||||
return done;
|
||||
}).then((done: boolean) => {
|
||||
// okay cool, it's time to pop a nav if possible
|
||||
if (!done) {
|
||||
return popEligibleView();
|
||||
}
|
||||
return done;
|
||||
}).then((done: boolean) => {
|
||||
if (!done) {
|
||||
// okay, we didn't find a nav that we can pop, so we should just exit the app
|
||||
// since each platform exits differently, just delegate it to the platform to
|
||||
// figure out how to exit
|
||||
return this.exitApp.emit();
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
}
|
||||
|
||||
@Method()
|
||||
appResume(): void {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Method()
|
||||
appPaused(): void {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -133,17 +156,37 @@ export class App {
|
||||
render() {
|
||||
const isDevice = true;
|
||||
return [
|
||||
isCordova() && <ion-cordova-platform/>,
|
||||
isDevice && <ion-tap-click />,
|
||||
isDevice && <ion-status-tap />,
|
||||
// <ion-router-controller></ion-router-controller>
|
||||
<slot></slot>
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export function getTopNavsImpl(rootNavId = -1) {
|
||||
if (!rootNavs.size) {
|
||||
return [];
|
||||
}
|
||||
|
||||
export function findTopNavs(nav: NavContainer): NavContainer[] {
|
||||
let containers: NavContainer[] = [];
|
||||
if (rootNavId !== -1) {
|
||||
return findTopNavs(rootNavs.get(rootNavId));
|
||||
}
|
||||
|
||||
if (rootNavs.size === 1) {
|
||||
return findTopNavs(rootNavs.values().next().value);
|
||||
}
|
||||
|
||||
// fallback to just using all root navs
|
||||
let activeNavs: PublicNav[] = [];
|
||||
rootNavs.forEach(nav => {
|
||||
activeNavs = activeNavs.concat(findTopNavs(nav));
|
||||
});
|
||||
return activeNavs;
|
||||
}
|
||||
|
||||
export function findTopNavs(nav: PublicNav): PublicNav[] {
|
||||
let containers: PublicNav[] = [];
|
||||
const childNavs = nav.getChildNavs();
|
||||
if (!childNavs || !childNavs.length) {
|
||||
containers.push(nav);
|
||||
@ -156,11 +199,11 @@ export function findTopNavs(nav: NavContainer): NavContainer[] {
|
||||
return containers;
|
||||
}
|
||||
|
||||
export function getNavByIdOrNameImpl(nav: NavContainer, id: number | string): NavContainer {
|
||||
if (nav.id === id || nav.name === id) {
|
||||
export function getNavByIdOrNameImpl(nav: PublicNav, id: number | string): PublicNav {
|
||||
if (nav.navId === id || nav.name === id) {
|
||||
return nav;
|
||||
}
|
||||
for (const child of nav.getAllChildNavs()) {
|
||||
for (const child of nav.getChildNavs()) {
|
||||
const tmp = getNavByIdOrNameImpl(child, id);
|
||||
if (tmp) {
|
||||
return tmp;
|
||||
@ -169,12 +212,95 @@ export function getNavByIdOrNameImpl(nav: NavContainer, id: number | string): Na
|
||||
return null;
|
||||
}
|
||||
|
||||
export function handleBackButtonClick(): Promise<any> {
|
||||
// if there is a menu controller dom element, hydrate it, otherwise move on
|
||||
// TODO ensure ion-menu-controller is the name
|
||||
const menuControllerElement = document.querySelector('ion-menu-controller'); // TODO - use menu controller types
|
||||
const promise = menuControllerElement ? isReady(menuControllerElement) : Promise.resolve();
|
||||
return promise.then(() => {
|
||||
// TODO check if the menu is open, close it if so
|
||||
export function getHydratedController(tagName: string): Promise<HTMLElement> {
|
||||
const controller = getOrAppendElement(tagName);
|
||||
return (controller as any).componentOnReady();
|
||||
}
|
||||
|
||||
export function checkIfMenuIsOpen(): Promise<boolean> {
|
||||
return getHydratedController('ion-menu-controller').then((menuController: HTMLIonMenuControllerElement) => {
|
||||
if (menuController.isOpen()) {
|
||||
return menuController.close().then(() => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
export function checkIfNotModalOverlayIsOpen(): Promise<boolean> {
|
||||
const promises: Promise<any>[] = [];
|
||||
promises.push(checkIfOverlayExists('ion-action-sheet-controller'));
|
||||
promises.push(checkIfOverlayExists('ion-alert-controller'));
|
||||
promises.push(checkIfOverlayExists('ion-loading-controller'));
|
||||
promises.push(checkIfOverlayExists('ion-picker-controller'));
|
||||
promises.push(checkIfOverlayExists('ion-popover-controller'));
|
||||
promises.push(checkIfOverlayExists('ion-toast-controller'));
|
||||
return Promise.all(promises).then((results: boolean[]) => {
|
||||
return results.every((value: boolean) => !!value);
|
||||
});
|
||||
}
|
||||
|
||||
export function checkIfOverlayExists(tagName: string): Promise<boolean> {
|
||||
const overlayControllerElement = document.querySelector(tagName) as any as OverlayController;
|
||||
if (!overlayControllerElement) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
return (overlayControllerElement as any).componentOnReady().then(() => {
|
||||
return !!(overlayControllerElement.getTop());
|
||||
});
|
||||
}
|
||||
|
||||
export function closeModalIfOpen(): Promise<boolean> {
|
||||
return getHydratedController('ion-modal-controller').then((modalController: HTMLIonModalControllerElement) => {
|
||||
if (modalController.getTop()) {
|
||||
return modalController.dismiss().then(() => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
export function popEligibleView(): Promise<boolean> {
|
||||
let navToPop: PublicNav = null;
|
||||
let mostRecentVC: PublicViewController = null;
|
||||
rootNavs.forEach(nav => {
|
||||
const topNavs = getTopNavsImpl(nav.navId);
|
||||
const poppableNavs = topNavs.map(topNav => getPoppableNav(topNav)).filter(nav => !!nav).filter(nav => !!nav.last());
|
||||
poppableNavs.forEach(poppable => {
|
||||
const topViewController = poppable.last();
|
||||
if (!mostRecentVC || topViewController.timestamp >= mostRecentVC.timestamp) {
|
||||
mostRecentVC = topViewController;
|
||||
navToPop = poppable;
|
||||
}
|
||||
});
|
||||
});
|
||||
if (navToPop) {
|
||||
return navToPop.pop().then(() => {
|
||||
return true;
|
||||
});
|
||||
}
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
export function getPoppableNav(nav: PublicNav): PublicNav {
|
||||
if (!nav) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// to be a poppable nav, a nav must a top view, plus a view that we can pop back to
|
||||
if (nav.getViews.length > 1) {
|
||||
return nav;
|
||||
}
|
||||
|
||||
return getPoppableNav(nav.parent);
|
||||
}
|
||||
|
||||
export interface ExitAppEvent extends CustomEvent {
|
||||
target: HTMLIonAppElement;
|
||||
detail: ExitAppEventDetail;
|
||||
}
|
||||
|
||||
export interface ExitAppEventDetail {
|
||||
}
|
||||
|
@ -5,9 +5,17 @@
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
#### exitApp
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
#### getActiveNavs()
|
||||
#### appPaused()
|
||||
|
||||
|
||||
#### appResume()
|
||||
|
||||
|
||||
#### getNavByIdOrName()
|
||||
@ -18,8 +26,16 @@
|
||||
Returns an array of top level Navs
|
||||
|
||||
|
||||
#### getTopNavs()
|
||||
|
||||
|
||||
#### hardwareBackButtonPressed()
|
||||
|
||||
|
||||
#### isEnabled()
|
||||
|
||||
Returns whether the application is enabled or not
|
||||
|
||||
|
||||
#### isScrolling()
|
||||
|
||||
|
@ -0,0 +1,84 @@
|
||||
import { Component, Listen, Method} from '@stencil/core';
|
||||
|
||||
let isReady = false;
|
||||
let readyQueue: Function[] = [];
|
||||
|
||||
@Component({
|
||||
tag: 'ion-cordova-platform',
|
||||
styleUrls: {
|
||||
ios: 'cordova-platform.ios.scss',
|
||||
md: 'cordova-platform.md.scss'
|
||||
},
|
||||
host: {
|
||||
theme: 'cordova-platform'
|
||||
}
|
||||
})
|
||||
export class CordovaPlatform {
|
||||
|
||||
@Method()
|
||||
ready() {
|
||||
return readyImpl();
|
||||
}
|
||||
|
||||
@Listen('document:deviceready')
|
||||
deviceReadyHandler() {
|
||||
isReady = true;
|
||||
processReadyQueue();
|
||||
}
|
||||
|
||||
@Listen('body:exitApp')
|
||||
exitCordovaApp() {
|
||||
// this is lifted directly from Ionic 3
|
||||
((window.navigator as any).app as any).exitApp();
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
readyImpl().then(() => {
|
||||
// okay cool, we've received the ready event, we need to listen for the other events now
|
||||
document.addEventListener('backbutton', handleBackButton);
|
||||
|
||||
document.addEventListener('resume', handleResume);
|
||||
|
||||
document.addEventListener('pause', handlePause);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function handleBackButton() {
|
||||
return getHydratedApp().then((app: HTMLIonAppElement) => {
|
||||
return app.hardwareBackButtonPressed();
|
||||
});
|
||||
}
|
||||
|
||||
export function handleResume() {
|
||||
return getHydratedApp().then((app: HTMLIonAppElement) => {
|
||||
return app.appResume();
|
||||
});
|
||||
}
|
||||
|
||||
export function handlePause() {
|
||||
return getHydratedApp().then((app: HTMLIonAppElement) => {
|
||||
return app.appPaused();
|
||||
});
|
||||
}
|
||||
|
||||
export function getHydratedApp() {
|
||||
const app = document.querySelector('ion-app');
|
||||
return (app as any).componentOnReady();
|
||||
}
|
||||
|
||||
export function readyImpl(): Promise<any> {
|
||||
if (isReady) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
readyQueue.push(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
export function processReadyQueue() {
|
||||
for (const resolve of readyQueue) {
|
||||
resolve();
|
||||
}
|
||||
readyQueue = [];
|
||||
}
|
16
packages/core/src/components/cordova-platform/readme.md
Normal file
16
packages/core/src/components/cordova-platform/readme.md
Normal file
@ -0,0 +1,16 @@
|
||||
# ion-cordova-platform
|
||||
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
#### ready()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
*Built by [StencilJS](https://stenciljs.com/)*
|
@ -1,5 +1,5 @@
|
||||
import { Component, Listen, Method } from '@stencil/core';
|
||||
import { LoadingEvent, LoadingOptions } from '../../index';
|
||||
import { LoadingEvent, LoadingOptions, OverlayController } from '../../index';
|
||||
|
||||
let ids = 0;
|
||||
const loadings = new Map<number, HTMLIonLoadingElement>();
|
||||
@ -7,7 +7,7 @@ const loadings = new Map<number, HTMLIonLoadingElement>();
|
||||
@Component({
|
||||
tag: 'ion-loading-controller'
|
||||
})
|
||||
export class LoadingController {
|
||||
export class LoadingController implements OverlayController {
|
||||
|
||||
@Method()
|
||||
create(opts?: LoadingOptions): Promise<HTMLIonLoadingElement> {
|
||||
@ -35,6 +35,10 @@ export class LoadingController {
|
||||
return loading.dismiss(data, role);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getTop() {
|
||||
return loadings.get(getHighestId());
|
||||
}
|
||||
|
||||
@Listen('body:ionLoadingWillPresent')
|
||||
protected loadingWillPresent(ev: LoadingEvent) {
|
||||
|
@ -44,6 +44,9 @@ in the `usage` section below.
|
||||
#### dismiss()
|
||||
|
||||
|
||||
#### getTop()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, Listen, Method } from '@stencil/core';
|
||||
import { ModalEvent, ModalOptions } from '../../index';
|
||||
import { ModalEvent, ModalOptions, OverlayController } from '../../index';
|
||||
|
||||
let ids = 0;
|
||||
const modals = new Map<number, HTMLIonModalElement>();
|
||||
@ -7,7 +7,7 @@ const modals = new Map<number, HTMLIonModalElement>();
|
||||
@Component({
|
||||
tag: 'ion-modal-controller'
|
||||
})
|
||||
export class ModalController {
|
||||
export class ModalController implements OverlayController {
|
||||
|
||||
@Method()
|
||||
create(opts?: ModalOptions): Promise<HTMLIonModalElement> {
|
||||
@ -38,6 +38,10 @@ export class ModalController {
|
||||
return modal.dismiss(data, role);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getTop() {
|
||||
return modals.get(getHighestId());
|
||||
}
|
||||
|
||||
@Listen('body:ionModalWillPresent')
|
||||
protected modalWillPresent(ev: ModalEvent) {
|
||||
@ -50,7 +54,6 @@ export class ModalController {
|
||||
modals.delete(ev.target.modalId);
|
||||
}
|
||||
|
||||
|
||||
@Listen('body:keyup.escape')
|
||||
protected escapeKeyUp() {
|
||||
removeLastModal();
|
||||
|
@ -13,6 +13,9 @@
|
||||
#### dismiss()
|
||||
|
||||
|
||||
#### getTop()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -4,11 +4,11 @@ import {
|
||||
Animation,
|
||||
AnimationOptions,
|
||||
FrameworkDelegate,
|
||||
FrameworkMountingData,
|
||||
Nav,
|
||||
NavOptions,
|
||||
PublicViewController,
|
||||
ViewController,
|
||||
FrameworkMountingData
|
||||
} from '../../index';
|
||||
|
||||
export interface PublicNav {
|
||||
@ -27,20 +27,15 @@ export interface PublicNav {
|
||||
getPrevious(view?: PublicViewController): PublicViewController;
|
||||
canGoBack(): boolean;
|
||||
canSwipeBack(): boolean;
|
||||
getFirstView(): PublicViewController;
|
||||
first(): PublicViewController;
|
||||
last(): PublicViewController;
|
||||
getChildNavs(): PublicNav[];
|
||||
getViews(): PublicViewController[];
|
||||
|
||||
element?: HTMLElement;
|
||||
}
|
||||
|
||||
export interface NavContainer {
|
||||
id?: number;
|
||||
navId?: number;
|
||||
name?: string;
|
||||
parent?: Nav;
|
||||
getChildNavs?(): NavContainer[];
|
||||
getAllChildNavs?(): NavContainer[];
|
||||
getType?(): string;
|
||||
getSecondaryIdentifier?(): string;
|
||||
element?: HTMLElement;
|
||||
parent?: PublicNav;
|
||||
}
|
||||
|
||||
export interface NavOptions {
|
||||
@ -110,4 +105,5 @@ export interface PublicViewController {
|
||||
component?: any;
|
||||
instance?: any;
|
||||
element?: HTMLElement;
|
||||
timestamp?: number;
|
||||
}
|
||||
|
@ -159,7 +159,11 @@ export function canSwipeBack(_nav: Nav) {
|
||||
}
|
||||
|
||||
export function getFirstView(nav: Nav): ViewController {
|
||||
return nav.views && nav.views.length > 0 ? nav.views[0] : null;
|
||||
return nav.views && nav.views.length ? nav.views[0] : null;
|
||||
}
|
||||
|
||||
export function getLastView(nav: Nav): ViewController {
|
||||
return nav.views && nav.views.length ? nav.views[nav.views.length - 1] : null;
|
||||
}
|
||||
|
||||
export function getActiveChildNavs(nav: Nav): Nav[] {
|
||||
|
@ -6,7 +6,6 @@ import {
|
||||
ComponentDataPair,
|
||||
Config,
|
||||
FrameworkDelegate,
|
||||
NavContainer,
|
||||
NavOptions,
|
||||
NavResult,
|
||||
NavState,
|
||||
@ -29,6 +28,7 @@ import {
|
||||
getActiveImpl,
|
||||
getFirstView,
|
||||
getHydratedTransition,
|
||||
getLastView,
|
||||
getNextNavId,
|
||||
getNextTransitionId,
|
||||
getParentTransitionId,
|
||||
@ -62,7 +62,7 @@ const urlMap = new Map<string, TransitionInstruction>();
|
||||
tag: 'ion-nav',
|
||||
styleUrl: 'nav.scss'
|
||||
})
|
||||
export class Nav implements PublicNav, NavContainer {
|
||||
export class Nav implements PublicNav {
|
||||
|
||||
@Element() element: HTMLElement;
|
||||
@Event() navInit: EventEmitter<NavEventDetail>;
|
||||
@ -97,7 +97,6 @@ export class Nav implements PublicNav, NavContainer {
|
||||
componentWillLoad() {
|
||||
this.routes = Array.from(this.element.querySelectorAll('ion-route'))
|
||||
.map(child => child.getRoute());
|
||||
//this.useRouter = false; // this.config.getBoolean('useRouter', false);
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
@ -193,10 +192,15 @@ export class Nav implements PublicNav, NavContainer {
|
||||
}
|
||||
|
||||
@Method()
|
||||
getFirstView(): PublicViewController {
|
||||
first(): PublicViewController {
|
||||
return getFirstView(this);
|
||||
}
|
||||
|
||||
@Method()
|
||||
last(): PublicViewController {
|
||||
return getLastView(this);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getState(): NavState {
|
||||
assert(this.useRouter, 'routing is disabled');
|
||||
@ -340,7 +344,7 @@ export function canGoBackImpl(nav: Nav) {
|
||||
}
|
||||
|
||||
export function navInitializedImpl(potentialParent: Nav, event: NavEvent) {
|
||||
if (potentialParent.element !== event.target) {
|
||||
if ((potentialParent.element as any as HTMLIonNavElement) !== event.target) {
|
||||
// set the parent on the child nav that dispatched the event
|
||||
event.target.setParent(potentialParent);
|
||||
if (!potentialParent.childNavs) {
|
||||
|
@ -78,15 +78,15 @@ boolean
|
||||
#### clearTransitionInfoForUrl()
|
||||
|
||||
|
||||
#### first()
|
||||
|
||||
|
||||
#### getActive()
|
||||
|
||||
|
||||
#### getChildNavs()
|
||||
|
||||
|
||||
#### getFirstView()
|
||||
|
||||
|
||||
#### getId()
|
||||
|
||||
|
||||
@ -114,6 +114,9 @@ boolean
|
||||
#### isTransitioning()
|
||||
|
||||
|
||||
#### last()
|
||||
|
||||
|
||||
#### pop()
|
||||
|
||||
|
||||
|
@ -14,6 +14,7 @@ export class ViewController implements PublicViewController {
|
||||
overlay: boolean;
|
||||
zIndex: number;
|
||||
dismissProxy: any;
|
||||
timestamp: number;
|
||||
|
||||
|
||||
onDidDismiss: (data: any, role: string) => void;
|
||||
@ -159,6 +160,7 @@ export function didLoadImpl(viewController: ViewController) {
|
||||
}
|
||||
|
||||
export function initializeNewViewController(viewController: ViewController, data: any) {
|
||||
viewController.timestamp = Date.now();
|
||||
viewController.state = STATE_NEW;
|
||||
viewController.data = data || {};
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, Listen, Method } from '@stencil/core';
|
||||
import { PickerEvent, PickerOptions } from '../../index';
|
||||
import { PickerEvent, PickerOptions, OverlayController } from '../../index';
|
||||
|
||||
let ids = 0;
|
||||
const pickers = new Map<number, HTMLIonPickerElement>();
|
||||
@ -7,7 +7,7 @@ const pickers = new Map<number, HTMLIonPickerElement>();
|
||||
@Component({
|
||||
tag: 'ion-picker-controller'
|
||||
})
|
||||
export class PickerController {
|
||||
export class PickerController implements OverlayController {
|
||||
|
||||
@Method()
|
||||
create(opts?: PickerOptions): Promise<HTMLIonPickerElement> {
|
||||
@ -38,6 +38,10 @@ export class PickerController {
|
||||
return picker.dismiss(data, role);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getTop() {
|
||||
return pickers.get(getHighestId());
|
||||
}
|
||||
|
||||
@Listen('body:ionPickerWillPresent')
|
||||
protected pickerWillPresent(ev: PickerEvent) {
|
||||
|
@ -13,6 +13,9 @@
|
||||
#### dismiss()
|
||||
|
||||
|
||||
#### getTop()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, Listen, Method } from '@stencil/core';
|
||||
import { PopoverEvent, PopoverOptions } from '../../index';
|
||||
import { OverlayController, PopoverEvent, PopoverOptions } from '../../index';
|
||||
|
||||
let ids = 0;
|
||||
const popovers = new Map<number, HTMLIonPopoverElement>();
|
||||
@ -7,7 +7,7 @@ const popovers = new Map<number, HTMLIonPopoverElement>();
|
||||
@Component({
|
||||
tag: 'ion-popover-controller'
|
||||
})
|
||||
export class PopoverController {
|
||||
export class PopoverController implements OverlayController {
|
||||
|
||||
@Method()
|
||||
create(opts?: PopoverOptions): Promise<HTMLIonPopoverElement> {
|
||||
@ -38,6 +38,10 @@ export class PopoverController {
|
||||
return popover.dismiss(data, role);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getTop() {
|
||||
return popovers.get(getHighestId());
|
||||
}
|
||||
|
||||
@Listen('body:ionPopoverWillPresent')
|
||||
protected popoverWillPresent(ev: PopoverEvent) {
|
||||
|
@ -32,6 +32,9 @@ view. See the [usage](#usage) section for an example of passing this event.
|
||||
#### dismiss()
|
||||
|
||||
|
||||
#### getTop()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -13,6 +13,9 @@
|
||||
#### dismiss()
|
||||
|
||||
|
||||
#### getTop()
|
||||
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Component, Listen, Method } from '@stencil/core';
|
||||
import { ToastEvent, ToastOptions } from '../../index';
|
||||
import { OverlayController, ToastEvent, ToastOptions } from '../../index';
|
||||
|
||||
let ids = 0;
|
||||
const toasts = new Map<number, HTMLIonToastElement>();
|
||||
@ -7,7 +7,7 @@ const toasts = new Map<number, HTMLIonToastElement>();
|
||||
@Component({
|
||||
tag: 'ion-toast-controller'
|
||||
})
|
||||
export class ToastController {
|
||||
export class ToastController implements OverlayController {
|
||||
|
||||
@Method()
|
||||
create(opts?: ToastOptions): Promise<HTMLIonToastElement> {
|
||||
@ -38,6 +38,10 @@ export class ToastController {
|
||||
return toast.dismiss(data, role);
|
||||
}
|
||||
|
||||
@Method()
|
||||
getTop() {
|
||||
return toasts.get(getHighestId());
|
||||
}
|
||||
|
||||
@Listen('body:ionToastWillPresent')
|
||||
protected toastWillPresent(ev: ToastEvent) {
|
||||
|
9
packages/core/src/index.d.ts
vendored
9
packages/core/src/index.d.ts
vendored
@ -145,10 +145,6 @@ export interface OverlayDismissEventDetail {
|
||||
role?: string;
|
||||
}
|
||||
|
||||
export interface OverlayController {
|
||||
create(): HTMLElement;
|
||||
}
|
||||
|
||||
export interface FrameworkDelegate {
|
||||
attachViewToDom(elementOrContainerToMountTo: any, elementOrComponentToMount: any, propsOrDataObj?: any, classesToAdd?: string[], escapeHatch?: any): Promise<FrameworkMountingData>;
|
||||
removeViewFromDom(elementOrContainerToUnmountFrom: any, elementOrComponentToUnmount: any, escapeHatch?: any): Promise<void>;
|
||||
@ -160,7 +156,6 @@ export interface FrameworkMountingData {
|
||||
data: any;
|
||||
}
|
||||
|
||||
|
||||
declare global {
|
||||
|
||||
namespace JSXElements {
|
||||
@ -186,3 +181,7 @@ declare global {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface OverlayController {
|
||||
getTop(): HTMLElement;
|
||||
}
|
||||
|
@ -302,7 +302,7 @@ export function debounce(func: Function, wait = 0) {
|
||||
export function getNavAsChildIfExists(element: HTMLElement): HTMLIonNavElement|null {
|
||||
for (let i = 0; i < element.children.length; i++) {
|
||||
if (element.children[i].tagName.toLowerCase() === 'ion-nav') {
|
||||
return element.children[i] as HTMLIonNavElement;
|
||||
return element.children[i] as any as HTMLIonNavElement;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -42,6 +42,7 @@ exports.config = {
|
||||
{ components: ['ion-toggle'] },
|
||||
{ components: ['ion-toast', 'ion-toast-controller'] },
|
||||
{ components: ['ion-tap-click', 'ion-status-tap'] },
|
||||
{ components: ['ion-cordova-platform'] },
|
||||
],
|
||||
collections: [
|
||||
'ionicons'
|
||||
|
Reference in New Issue
Block a user