mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
refactor(external-router): remove the external router controller, move the reconciliation methods to the nav itself, and move the external activation status information to ion-app
This commit is contained in:
@ -28,7 +28,7 @@ import { OutletInjector } from './outlet-injector';
|
|||||||
import { RouteEventHandler } from './route-event-handler';
|
import { RouteEventHandler } from './route-event-handler';
|
||||||
|
|
||||||
import { AngularComponentMounter, AngularEscapeHatch } from '..';
|
import { AngularComponentMounter, AngularEscapeHatch } from '..';
|
||||||
import { ensureExternalRounterController } from '../util/util';
|
import { getIonApp } from '../util/util';
|
||||||
|
|
||||||
let id = 0;
|
let id = 0;
|
||||||
|
|
||||||
@ -139,9 +139,14 @@ export class RouterOutlet implements OnDestroy, OnInit, RouterDelegate {
|
|||||||
export function activateRoute(navElement: HTMLIonNavElement,
|
export function activateRoute(navElement: HTMLIonNavElement,
|
||||||
component: Type<any>, data: any = {}, cfr: ComponentFactoryResolver, injector: Injector, isTopLevel: boolean): Promise<void> {
|
component: Type<any>, data: any = {}, cfr: ComponentFactoryResolver, injector: Injector, isTopLevel: boolean): Promise<void> {
|
||||||
|
|
||||||
return ensureExternalRounterController().then((externalRouterController) => {
|
return getIonApp().then((ionApp) => {
|
||||||
|
if (!ionApp) {
|
||||||
|
return Promise.reject(new Error(`<ion-app> element is required for angular router integration`));
|
||||||
|
}
|
||||||
const escapeHatch = getEscapeHatch(cfr, injector);
|
const escapeHatch = getEscapeHatch(cfr, injector);
|
||||||
return externalRouterController.reconcileNav(navElement, component, data, escapeHatch, isTopLevel);
|
return navElement.componentOnReady().then(() => {
|
||||||
|
return navElement.reconcileFromExternalRouter(component, data, escapeHatch, isTopLevel);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
Router
|
Router
|
||||||
} from '@angular/router';
|
} from '@angular/router';
|
||||||
|
|
||||||
import { ensureExternalRounterController } from '../util/util';
|
import { getIonApp } from '../util/util';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class RouteEventHandler {
|
export class RouteEventHandler {
|
||||||
@ -14,16 +14,16 @@ export class RouteEventHandler {
|
|||||||
|
|
||||||
router.events.subscribe((event: Event) => {
|
router.events.subscribe((event: Event) => {
|
||||||
if (event instanceof NavigationEnd) {
|
if (event instanceof NavigationEnd) {
|
||||||
ensureExternalRounterController().then((element) => {
|
getIonApp().then((appElement) => {
|
||||||
element.updateExternalNavOccuring(false);
|
appElement.updateExternalNavOccuring(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
externalNavStart() {
|
externalNavStart() {
|
||||||
return ensureExternalRounterController().then((element) => {
|
return getIonApp().then((appElement) => {
|
||||||
element.updateExternalNavOccuring(true);
|
appElement.updateExternalNavOccuring(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,7 @@ export function isString(something: any) {
|
|||||||
return typeof something === 'string' ? true : false;
|
return typeof something === 'string' ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureExternalRounterController(): Promise<HTMLIonExternalRouterControllerElement> {
|
export function getIonApp(): Promise<HTMLIonAppElement> {
|
||||||
const element = document.querySelector('ion-external-router-controller');
|
const element = ensureElementInBody('ion-app') as HTMLIonAppElement;
|
||||||
if (element) {
|
return element.componentOnReady();
|
||||||
return (element as any).componentOnReady();
|
|
||||||
}
|
|
||||||
const toCreate = document.createElement('ion-external-router-controller');
|
|
||||||
document.body.appendChild(toCreate);
|
|
||||||
return (toCreate as any).componentOnReady();
|
|
||||||
}
|
}
|
30
packages/core/src/components.d.ts
vendored
30
packages/core/src/components.d.ts
vendored
@ -875,36 +875,6 @@ declare global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
import {
|
|
||||||
ExternalRouterController as IonExternalRouterController
|
|
||||||
} from './components/external-router-controller/external-router-controller';
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface HTMLIonExternalRouterControllerElement extends IonExternalRouterController, HTMLStencilElement {
|
|
||||||
}
|
|
||||||
var HTMLIonExternalRouterControllerElement: {
|
|
||||||
prototype: HTMLIonExternalRouterControllerElement;
|
|
||||||
new (): HTMLIonExternalRouterControllerElement;
|
|
||||||
};
|
|
||||||
interface HTMLElementTagNameMap {
|
|
||||||
"ion-external-router-controller": HTMLIonExternalRouterControllerElement;
|
|
||||||
}
|
|
||||||
interface ElementTagNameMap {
|
|
||||||
"ion-external-router-controller": HTMLIonExternalRouterControllerElement;
|
|
||||||
}
|
|
||||||
namespace JSX {
|
|
||||||
interface IntrinsicElements {
|
|
||||||
"ion-external-router-controller": JSXElements.IonExternalRouterControllerAttributes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
namespace JSXElements {
|
|
||||||
export interface IonExternalRouterControllerAttributes extends HTMLAttributes {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FabButton as IonFabButton
|
FabButton as IonFabButton
|
||||||
} from './components/fab-button/fab-button';
|
} from './components/fab-button/fab-button';
|
||||||
|
@ -30,6 +30,49 @@ export class App {
|
|||||||
|
|
||||||
@Prop({ context: 'config' }) config: Config;
|
@Prop({ context: 'config' }) config: Config;
|
||||||
|
|
||||||
|
externalNavPromise: void | Promise<any> = null;
|
||||||
|
externalNavOccuring = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the promise set by an external navigation system
|
||||||
|
* This API is not meant for public usage and could
|
||||||
|
* change at any time
|
||||||
|
*/
|
||||||
|
@Method()
|
||||||
|
getExternalNavPromise(): void | Promise<any> {
|
||||||
|
return this.externalNavPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the Promise set by an external navigation system
|
||||||
|
* This API is not meant for public usage and could
|
||||||
|
* change at any time
|
||||||
|
*/
|
||||||
|
@Method()
|
||||||
|
setExternalNavPromise(value: null | Promise<any>): void {
|
||||||
|
this.externalNavPromise = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether an external navigation event is occuring
|
||||||
|
* This API is not meant for public usage and could
|
||||||
|
* change at any time
|
||||||
|
*/
|
||||||
|
@Method()
|
||||||
|
getExternalNavOccuring(): boolean {
|
||||||
|
return this.externalNavOccuring;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates whether an external navigation event is occuring
|
||||||
|
* This API is not meant for public usage and could
|
||||||
|
* change at any time
|
||||||
|
*/
|
||||||
|
@Method()
|
||||||
|
updateExternalNavOccuring(status: boolean) {
|
||||||
|
this.externalNavOccuring = status;
|
||||||
|
}
|
||||||
|
|
||||||
componentWillLoad() {
|
componentWillLoad() {
|
||||||
this.modeCode = this.config.get('mode');
|
this.modeCode = this.config.get('mode');
|
||||||
this.useRouter = this.config.getBoolean('useRouter', false);
|
this.useRouter = this.config.getBoolean('useRouter', false);
|
||||||
|
@ -12,6 +12,20 @@
|
|||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
#### getExternalNavOccuring()
|
||||||
|
|
||||||
|
Returns whether an external navigation event is occuring
|
||||||
|
This API is not meant for public usage and could
|
||||||
|
change at any time
|
||||||
|
|
||||||
|
|
||||||
|
#### getExternalNavPromise()
|
||||||
|
|
||||||
|
Returns the promise set by an external navigation system
|
||||||
|
This API is not meant for public usage and could
|
||||||
|
change at any time
|
||||||
|
|
||||||
|
|
||||||
#### getNavByIdOrName()
|
#### getNavByIdOrName()
|
||||||
|
|
||||||
|
|
||||||
@ -33,9 +47,23 @@ Returns whether the application is enabled or not
|
|||||||
Boolean if the app is actively scrolling or not.
|
Boolean if the app is actively scrolling or not.
|
||||||
|
|
||||||
|
|
||||||
|
#### setExternalNavPromise()
|
||||||
|
|
||||||
|
Updates the Promise set by an external navigation system
|
||||||
|
This API is not meant for public usage and could
|
||||||
|
change at any time
|
||||||
|
|
||||||
|
|
||||||
#### setScrolling()
|
#### setScrolling()
|
||||||
|
|
||||||
|
|
||||||
|
#### updateExternalNavOccuring()
|
||||||
|
|
||||||
|
Updates whether an external navigation event is occuring
|
||||||
|
This API is not meant for public usage and could
|
||||||
|
change at any time
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
|
@ -1,119 +0,0 @@
|
|||||||
import { Component, Method } from '@stencil/core';
|
|
||||||
import { EscapeHatch, NavResult } from '../../index';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
tag: 'ion-external-router-controller'
|
|
||||||
})
|
|
||||||
export class ExternalRouterController {
|
|
||||||
|
|
||||||
externalNavPromise: void | Promise<any> = null;
|
|
||||||
externalNavOccuring = false;
|
|
||||||
|
|
||||||
@Method()
|
|
||||||
getExternalNavPromise(): void | Promise<any> {
|
|
||||||
return this.externalNavPromise;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Method()
|
|
||||||
clearExternalNavPromise(): void {
|
|
||||||
this.externalNavPromise = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Method()
|
|
||||||
getExternalNavOccuring(): boolean {
|
|
||||||
return this.externalNavOccuring;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Method()
|
|
||||||
updateExternalNavOccuring(status: boolean) {
|
|
||||||
this.externalNavOccuring = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Method()
|
|
||||||
reconcileNav(nav: HTMLIonNavElement, component: any, data: any = {}, escapeHatch: EscapeHatch, isTopLevel: boolean) {
|
|
||||||
return nav.componentOnReady().then(() => {
|
|
||||||
// check if the nav has an `<ion-tab>` as a parent
|
|
||||||
if (isParentTab(nav)) {
|
|
||||||
// check if the tab is selected
|
|
||||||
return updateTab(this, nav, component, data, escapeHatch, isTopLevel);
|
|
||||||
} else {
|
|
||||||
return updateNav(nav, component, data, escapeHatch, isTopLevel);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isParentTab(navElement: HTMLIonNavElement) {
|
|
||||||
return navElement.parentElement.tagName.toLowerCase() === 'ion-tab';
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateTab(externalRouterController: ExternalRouterController, navElement: HTMLIonNavElement, component: any, data: any, escapeHatch: EscapeHatch, isTopLevel: boolean) {
|
|
||||||
|
|
||||||
const tab = navElement.parentElement as HTMLIonTabElement;
|
|
||||||
|
|
||||||
// yeah yeah, I know this is kind of ugly but oh well, I know the internal structure of <ion-tabs>
|
|
||||||
const tabs = tab.parentElement.parentElement as HTMLIonTabsElement;
|
|
||||||
|
|
||||||
return isTabSelected(tabs, tab).then((isSelected: boolean) => {
|
|
||||||
if (!isSelected) {
|
|
||||||
const promise = updateNav(navElement, component, data, escapeHatch, isTopLevel);
|
|
||||||
externalRouterController.externalNavPromise = promise;
|
|
||||||
// okay, the tab is not selected, so we need to do a "switch" transition
|
|
||||||
// basically, we should update the nav, and then swap the tabs
|
|
||||||
return promise.then(() => {
|
|
||||||
return tabs.select(tab);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// okay cool, the tab is already selected, so we want to see a transition
|
|
||||||
return updateNav(navElement, component, data, escapeHatch, isTopLevel);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function isTabSelected(tabsElement: HTMLIonTabsElement, tabElement: HTMLIonTabElement ): Promise<boolean> {
|
|
||||||
const promises: Promise<any>[] = [];
|
|
||||||
promises.push(tabsElement.componentOnReady());
|
|
||||||
promises.push(tabElement.componentOnReady());
|
|
||||||
return Promise.all(promises).then(() => {
|
|
||||||
return tabsElement.getSelected() === tabElement;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateNav(navElement: HTMLIonNavElement,
|
|
||||||
component: any, data: any, escapeHatch: EscapeHatch, isTopLevel: boolean): Promise<NavResult> {
|
|
||||||
|
|
||||||
|
|
||||||
// check if the component is the top view
|
|
||||||
const activeViews = navElement.getViews();
|
|
||||||
if (activeViews.length === 0) {
|
|
||||||
// there isn't a view in the stack, so push one
|
|
||||||
return navElement.setRoot(component, data, {}, escapeHatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentView = activeViews[activeViews.length - 1];
|
|
||||||
if (currentView.component === component) {
|
|
||||||
// the top view is already the component being activated, so there is no change needed
|
|
||||||
return Promise.resolve(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the component is the previous view, if so, pop back to it
|
|
||||||
if (activeViews.length > 1) {
|
|
||||||
// there's at least two views in the stack
|
|
||||||
const previousView = activeViews[activeViews.length - 2];
|
|
||||||
if (previousView.component === component) {
|
|
||||||
// cool, we match the previous view, so pop it
|
|
||||||
return navElement.pop(null, escapeHatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the component is already in the stack of views, in which case we pop back to it
|
|
||||||
for (const view of activeViews) {
|
|
||||||
if (view.component === component) {
|
|
||||||
// cool, we found the match, pop back to that bad boy
|
|
||||||
return navElement.popTo(view, null, escapeHatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// it's the top level nav, and it's not one of those other behaviors, so do a push so the user gets a chill animation
|
|
||||||
return navElement.push(component, data, { animate: isTopLevel }, escapeHatch);
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
# ion-external-router-controller
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Auto Generated Below -->
|
|
||||||
|
|
||||||
|
|
||||||
## Methods
|
|
||||||
|
|
||||||
#### clearExternalNavPromise()
|
|
||||||
|
|
||||||
|
|
||||||
#### getExternalNavOccuring()
|
|
||||||
|
|
||||||
|
|
||||||
#### getExternalNavPromise()
|
|
||||||
|
|
||||||
|
|
||||||
#### reconcileNav()
|
|
||||||
|
|
||||||
|
|
||||||
#### updateExternalNavOccuring()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------
|
|
||||||
|
|
||||||
*Built with [StencilJS](https://stenciljs.com/)*
|
|
@ -51,6 +51,7 @@ import {
|
|||||||
focusOutActiveElement,
|
focusOutActiveElement,
|
||||||
isDef,
|
isDef,
|
||||||
isNumber,
|
isNumber,
|
||||||
|
isParentTab,
|
||||||
normalizeUrl,
|
normalizeUrl,
|
||||||
} from '../../utils/helpers';
|
} from '../../utils/helpers';
|
||||||
|
|
||||||
@ -258,6 +259,11 @@ export class Nav implements PublicNav, NavOutlet {
|
|||||||
return allTransitionsCompleteImpl(this);
|
return allTransitionsCompleteImpl(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Method()
|
||||||
|
reconcileFromExternalRouter(component: any, data: any = {}, escapeHatch: EscapeHatch, isTopLevel: boolean) {
|
||||||
|
return reconcileFromExternalRouterImpl(this, component, data, escapeHatch, isTopLevel);
|
||||||
|
}
|
||||||
|
|
||||||
canSwipeBack(): boolean {
|
canSwipeBack(): boolean {
|
||||||
return (this.swipeBackEnabled &&
|
return (this.swipeBackEnabled &&
|
||||||
// this.childNavs.length === 0 &&
|
// this.childNavs.length === 0 &&
|
||||||
@ -1300,6 +1306,92 @@ export function getDefaultEscapeHatch(): EscapeHatch {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function reconcileFromExternalRouterImpl(nav: Nav, component: any, data: any = {}, escapeHatch: EscapeHatch, isTopLevel: boolean) {
|
||||||
|
// check if the nav has an `<ion-tab>` as a parent
|
||||||
|
if (isParentTab(nav.element as any)) {
|
||||||
|
// check if the tab is selected
|
||||||
|
return updateTab(nav, component, data, escapeHatch, isTopLevel);
|
||||||
|
} else {
|
||||||
|
return updateNav(nav, component, data, escapeHatch, isTopLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateTab(nav: Nav, component: any, data: any, escapeHatch: EscapeHatch, isTopLevel: boolean) {
|
||||||
|
|
||||||
|
const tab = nav.element.parentElement as HTMLIonTabElement;
|
||||||
|
|
||||||
|
// yeah yeah, I know this is kind of ugly but oh well, I know the internal structure of <ion-tabs>
|
||||||
|
const tabs = tab.parentElement.parentElement as HTMLIonTabsElement;
|
||||||
|
|
||||||
|
return isTabSelected(tabs, tab).then((isSelected: boolean) => {
|
||||||
|
if (!isSelected) {
|
||||||
|
const promise = updateNav(nav, component, data, escapeHatch, isTopLevel);
|
||||||
|
const app = document.querySelector('ion-app');
|
||||||
|
return app.componentOnReady().then(() => {
|
||||||
|
app.setExternalNavPromise(promise);
|
||||||
|
}).then(() => {
|
||||||
|
// okay, the tab is not selected, so we need to do a "switch" transition
|
||||||
|
// basically, we should update the nav, and then swap the tabs
|
||||||
|
return promise.then(() => {
|
||||||
|
return tabs.select(tab);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// okay cool, the tab is already selected, so we want to see a transition
|
||||||
|
return updateNav(nav, component, data, escapeHatch, isTopLevel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isTabSelected(tabsElement: HTMLIonTabsElement, tabElement: HTMLIonTabElement ): Promise<boolean> {
|
||||||
|
const promises: Promise<any>[] = [];
|
||||||
|
promises.push(tabsElement.componentOnReady());
|
||||||
|
promises.push(tabElement.componentOnReady());
|
||||||
|
return Promise.all(promises).then(() => {
|
||||||
|
return tabsElement.getSelected() === tabElement;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateNav(nav: Nav,
|
||||||
|
component: any, data: any, escapeHatch: EscapeHatch, isTopLevel: boolean): Promise<NavResult> {
|
||||||
|
|
||||||
|
|
||||||
|
// check if the component is the top view
|
||||||
|
const activeViews = nav.getViews();
|
||||||
|
if (activeViews.length === 0) {
|
||||||
|
// there isn't a view in the stack, so push one
|
||||||
|
return nav.setRoot(component, data, {}, escapeHatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentView = activeViews[activeViews.length - 1];
|
||||||
|
if (currentView.component === component) {
|
||||||
|
// the top view is already the component being activated, so there is no change needed
|
||||||
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the component is the previous view, if so, pop back to it
|
||||||
|
if (activeViews.length > 1) {
|
||||||
|
// there's at least two views in the stack
|
||||||
|
const previousView = activeViews[activeViews.length - 2];
|
||||||
|
if (previousView.component === component) {
|
||||||
|
// cool, we match the previous view, so pop it
|
||||||
|
return nav.pop(null, escapeHatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the component is already in the stack of views, in which case we pop back to it
|
||||||
|
for (const view of activeViews) {
|
||||||
|
if (view.component === component) {
|
||||||
|
// cool, we found the match, pop back to that bad boy
|
||||||
|
return nav.popTo(view, null, escapeHatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// it's the top level nav, and it's not one of those other behaviors, so do a push so the user gets a chill animation
|
||||||
|
return nav.push(component, data, { animate: isTopLevel }, escapeHatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface IsRedirectRequired {
|
export interface IsRedirectRequired {
|
||||||
required: boolean;
|
required: boolean;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
@ -143,6 +143,9 @@ boolean
|
|||||||
#### push()
|
#### push()
|
||||||
|
|
||||||
|
|
||||||
|
#### reconcileFromExternalRouter()
|
||||||
|
|
||||||
|
|
||||||
#### removeIndex()
|
#### removeIndex()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { Component, Element, Event, EventEmitter, Method, Prop, State, Watch } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, Method, Prop, State, Watch } from '@stencil/core';
|
||||||
import { ensureExternalRounterController, getNavAsChildIfExists } from '../../utils/helpers';
|
|
||||||
import { FrameworkDelegate } from '../..';
|
import { FrameworkDelegate } from '../..';
|
||||||
|
import { getIonApp, getNavAsChildIfExists } from '../../utils/helpers';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-tab',
|
tag: 'ion-tab',
|
||||||
@ -81,7 +83,7 @@ export class Tab {
|
|||||||
@Method()
|
@Method()
|
||||||
prepareActive(): Promise<any> {
|
prepareActive(): Promise<any> {
|
||||||
if (this.loaded) {
|
if (this.loaded) {
|
||||||
return this.configChildgNav();
|
return this.configChildNav();
|
||||||
}
|
}
|
||||||
this.loaded = true;
|
this.loaded = true;
|
||||||
|
|
||||||
@ -94,7 +96,7 @@ export class Tab {
|
|||||||
} else {
|
} else {
|
||||||
promise = Promise.resolve();
|
promise = Promise.resolve();
|
||||||
}
|
}
|
||||||
return promise.then(() => this.configChildgNav());
|
return promise.then(() => this.configChildNav());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Method()
|
@Method()
|
||||||
@ -108,15 +110,15 @@ export class Tab {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private configChildgNav(): Promise<any|void> {
|
private configChildNav(): Promise<any|void> {
|
||||||
const nav = getNavAsChildIfExists(this.el);
|
const nav = getNavAsChildIfExists(this.el);
|
||||||
if (nav) {
|
if (nav) {
|
||||||
// the tab's nav has been initialized externally
|
// the tab's nav has been initialized externally
|
||||||
return ensureExternalRounterController().then<void|any>((externalRouterController) => {
|
return getIonApp().then((ionApp) => {
|
||||||
const externalNavPromise = externalRouterController.getExternalNavPromise();
|
const externalNavPromise = ionApp ? ionApp.getExternalNavPromise() : null;
|
||||||
if (externalNavPromise) {
|
if (externalNavPromise) {
|
||||||
return externalNavPromise.then(() => {
|
return (externalNavPromise as any).then(() => {
|
||||||
externalRouterController.clearExternalNavPromise();
|
ionApp.setExternalNavPromise(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core';
|
import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core';
|
||||||
import { Config, NavEventDetail, NavOutlet } from '../../index';
|
import { Config, NavEventDetail, NavOutlet } from '../../index';
|
||||||
|
|
||||||
import { asyncRaf, ensureExternalRounterController } from '../../utils/helpers';
|
import { asyncRaf, getIonApp } from '../../utils/helpers';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -75,10 +75,13 @@ export class Tabs implements NavOutlet {
|
|||||||
|
|
||||||
const promises: Promise<any>[] = [];
|
const promises: Promise<any>[] = [];
|
||||||
promises.push(this.initTabs());
|
promises.push(this.initTabs());
|
||||||
promises.push(ensureExternalRounterController());
|
promises.push(getIonApp());
|
||||||
return Promise.all(promises).then(([_, externalRouterController]) => {
|
return Promise.all(promises).then(([_, ionApp]) => {
|
||||||
return (externalRouterController as HTMLIonExternalRouterControllerElement).getExternalNavOccuring();
|
if (ionApp) {
|
||||||
}).then((externalNavOccuring) => {
|
return (ionApp as HTMLIonAppElement).getExternalNavOccuring();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}).then((externalNavOccuring: boolean) => {
|
||||||
if (!externalNavOccuring) {
|
if (!externalNavOccuring) {
|
||||||
return this.initSelect();
|
return this.initSelect();
|
||||||
}
|
}
|
||||||
@ -116,11 +119,8 @@ export class Tabs implements NavOutlet {
|
|||||||
tab.selected = false;
|
tab.selected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
selectedTab.selected = true;
|
|
||||||
|
|
||||||
const leavingTab = this.selectedTab;
|
const leavingTab = this.selectedTab;
|
||||||
this.selectedTab = selectedTab;
|
|
||||||
|
|
||||||
|
|
||||||
return selectedTab.prepareActive()
|
return selectedTab.prepareActive()
|
||||||
.then(() => selectedTab.active = true)
|
.then(() => selectedTab.active = true)
|
||||||
@ -129,6 +129,8 @@ export class Tabs implements NavOutlet {
|
|||||||
if (leavingTab) {
|
if (leavingTab) {
|
||||||
leavingTab.active = false;
|
leavingTab.active = false;
|
||||||
}
|
}
|
||||||
|
selectedTab.selected = true;
|
||||||
|
this.selectedTab = selectedTab;
|
||||||
this.ionChange.emit(selectedTab);
|
this.ionChange.emit(selectedTab);
|
||||||
this.ionNavChanged.emit({isPop: false});
|
this.ionNavChanged.emit({isPop: false});
|
||||||
});
|
});
|
||||||
@ -216,6 +218,7 @@ export class Tabs implements NavOutlet {
|
|||||||
this.selectedTab = selectedTab;
|
this.selectedTab = selectedTab;
|
||||||
if (selectedTab) {
|
if (selectedTab) {
|
||||||
selectedTab.selected = true;
|
selectedTab.selected = true;
|
||||||
|
selectedTab.active = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -321,12 +321,14 @@ export function normalizeUrl(url: string) {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ensureExternalRounterController(): Promise<HTMLIonExternalRouterControllerElement> {
|
export function isParentTab(element: HTMLElement) {
|
||||||
const element = document.querySelector('ion-external-router-controller');
|
return element.parentElement.tagName.toLowerCase() === 'ion-tab';
|
||||||
if (element) {
|
}
|
||||||
return (element as any).componentOnReady();
|
|
||||||
}
|
export function getIonApp(): Promise<HTMLIonAppElement> {
|
||||||
const toCreate = document.createElement('ion-external-router-controller');
|
const appElement = document.querySelector('ion-app');
|
||||||
document.body.appendChild(toCreate);
|
if (!appElement) {
|
||||||
return (toCreate as any).componentOnReady();
|
return Promise.resolve(null);
|
||||||
|
}
|
||||||
|
return appElement.componentOnReady();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user