This commit is contained in:
Dan Bucholtz
2017-08-28 13:25:43 -05:00
parent e0a29db3bb
commit 11385ea7f1
9 changed files with 237 additions and 25 deletions

View File

@ -0,0 +1,4 @@
export const PORTAL_DEFAULT = 'general';
export const PORTAL_LOADING = 'loading';
export const PORTAL_MODAL = 'modal';
export const PORTAL_TOAST = 'toast';

View File

@ -0,0 +1,5 @@
import { Config } from '../..';
export interface App {
element?: HTMLElement;
config?: Config;
}

View File

@ -1,5 +1,18 @@
import { Component } from '@stencil/core';
import { Element, Component, Listen, Prop } from '@stencil/core';
import { Nav, NavContainer, OverlayPortal } from '../../navigation/nav-interfaces';
import { Config } from '../..';
import { App } from './app-interfaces';
import { isReady } from '../../utils/helpers';
import {
PORTAL_DEFAULT,
PORTAL_LOADING,
PORTAL_MODAL,
PORTAL_TOAST
} from './app-constants';
const rootNavs = new Map<number, Nav>();
const portals = new Map<string, OverlayPortal>();
@Component({
tag: 'ion-app',
@ -12,8 +25,119 @@ import { Component } from '@stencil/core';
theme: 'app'
}
})
export class App {
export class IonApp implements App {
@Element() element: HTMLElement;
@Prop({ context: 'config' }) config: Config;
@Listen('body:navInit')
registerRootNav(event: CustomEvent) {
rootNavs.set((event.detail as Nav).id, (event.detail as Nav));
}
@Listen('body:registerPortal')
registerPortal(event: CustomEvent) {
portals.set((event.detail as OverlayPortal).type, (event.detail as OverlayPortal));
}
componentWillLoad() {
componentDidLoadImpl(this);
}
getActiveNavs(rootNavId?: number): Nav[] {
const portal = portals.get(PORTAL_MODAL);
if (portal && portal.views && portal.views.length) {
return findTopNavs(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: Nav[] = [];
rootNavs.forEach(nav => {
activeNavs = activeNavs.concat(findTopNavs(nav));
});
return activeNavs;
}
getNavByIdOrName(nameOrId: number | string) {
const navs = Array.from(rootNavs.values());
for (const navContainer of navs) {
const match = getNavByIdOrNameImpl(navContainer, nameOrId);
if (match) {
return match;
}
}
return null;
}
render() {
return <slot></slot>;
return ([
<slot></slot>,
<ion-overlay-portal type={PORTAL_MODAL}></ion-overlay-portal>,
<ion-overlay-portal type={PORTAL_DEFAULT}></ion-overlay-portal>,
<ion-overlay-portal type={PORTAL_LOADING}></ion-overlay-portal>,
<ion-overlay-portal type={PORTAL_TOAST}></ion-overlay-portal>,
]);
}
}
export function findTopNavs(nav: NavContainer): NavContainer[] {
let containers: NavContainer[] = [];
const childNavs = nav.getActiveChildNavs();
if (!childNavs || !childNavs.length) {
containers.push(nav);
} else {
childNavs.forEach(childNav => {
const topNavs = findTopNavs(childNav);
containers = containers.concat(topNavs);
});
}
return containers;
}
export function getNavByIdOrNameImpl(nav: NavContainer, id: number | string): NavContainer {
if (nav.id === id || nav.name === id) {
return nav;
}
for (const child of nav.getAllChildNavs()) {
const tmp = getNavByIdOrNameImpl(child, id);
if (tmp) {
return tmp;
}
}
return null;
}
export function componentDidLoadImpl(app: App) {
app.element.classList.add(app.config.get('mode'));
// TODO add platform classes
if (app.config.getBoolean('hoverCSS', true)) {
app.element.classList.add('enable-hover');
}
// TODO fire platform ready
}
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
console.log('todo');
});
}

View File

@ -34,8 +34,8 @@ export class IonNav implements Nav {
init(this);
}
ionViewDidLoad() {
ionViewDidLoadImpl(this);
componentDidLoad() {
componentDidLoadImpl(this);
}
@ -129,7 +129,7 @@ export class IonNav implements Nav {
}
}
export function ionViewDidLoadImpl(nav: Nav) {
export function componentDidLoadImpl(nav: Nav) {
nav.navInit.emit(nav);
if (nav.root) {
nav.setRoot(nav.root);
@ -205,11 +205,14 @@ export function getNavController(nav: Nav): Promise<any> {
return isReady(nav.navController as any as HTMLElement);
}
export function navInitializedImpl(nav: Nav, event: CustomEvent) {
if (nav.element !== event.target) {
console.log('nav.id is parent of: ', (event as any).detail.id);
export function navInitializedImpl(potentialParent: Nav, event: CustomEvent) {
if (potentialParent.element !== event.target) {
// set the parent on the child nav that dispatched the event
(event.detail as Nav).parent = nav;
(event.detail as Nav).parent = potentialParent;
if (!potentialParent.childNavs) {
potentialParent.childNavs = [];
}
potentialParent.childNavs.push((event.detail as Nav));
// kill the event so it doesn't propagate further
event.stopPropagation();
}

View File

@ -0,0 +1,45 @@
import { Component, Element, Event, EventEmitter, Prop } from '@stencil/core';
import { Nav, NavContainer, OverlayPortal } from '../../navigation/nav-interfaces';
@Component({
tag: 'ion-overlay-portal'
})
export class IonOverlayPortal implements NavContainer, OverlayPortal {
id: number;
name: string;
parent: Nav;
@Element() element: HTMLElement;
@Prop() type: string;
@Event() registerPortal: EventEmitter;
getActiveChildNavs(): NavContainer[] {
throw new Error("Method not implemented.");
}
getAllChildNavs?(): NavContainer[] {
throw new Error("Method not implemented.");
}
getType(): string {
return 'portal';
}
getSecondaryIdentifier(): string {
return null;
}
componentWillLoad() {
componentWillLoadImpl(this);
}
render() {
return <slot></slot>;
}
}
export function componentWillLoadImpl(overlayPortal: OverlayPortal) {
overlayPortal.registerPortal.emit(overlayPortal);
}

View File

@ -0,0 +1,15 @@
import { Component } from '@stencil/core';
@Component({
tag: 'ion-utils'
})
export class IonUtils {
setTitle(newTitle: string): void {
if (document.title !== newTitle) {
document.title = newTitle;
}
}
}