mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-26 16:21:55 +08:00
@ -31,8 +31,9 @@ $flex-order-view-content: 0;
|
||||
$flex-order-toolbar-top: -10;
|
||||
$flex-order-toolbar-bottom: 10;
|
||||
|
||||
$flex-order-tab-bar-top: -30;
|
||||
$flex-order-tab-bar-bottom: 30;
|
||||
$flex-order-tab-bar-navbar: -30;
|
||||
$flex-order-tab-bar-top: -20;
|
||||
$flex-order-tab-bar-bottom: 20;
|
||||
|
||||
|
||||
|
||||
@ -96,7 +97,8 @@ ion-nav {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
ion-pane {
|
||||
ion-pane,
|
||||
ion-view.pane-view {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
@ -110,14 +112,28 @@ ion-pane {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
ion-view {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
|
||||
background-color: $background-color;
|
||||
|
||||
transform: translateZ(0px);
|
||||
|
||||
&.show-view {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.no-navbar > .navbar-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.navbar-container {
|
||||
position: relative;
|
||||
min-height: 4.4rem;
|
||||
@ -131,20 +147,6 @@ ion-pane {
|
||||
order: $flex-order-view-content;
|
||||
}
|
||||
|
||||
ion-view {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
|
||||
background-color: $background-color;
|
||||
|
||||
transform: translateZ(0px);
|
||||
}
|
||||
|
||||
[hidden],
|
||||
template,
|
||||
root-anchor {
|
||||
|
@ -123,6 +123,6 @@ export class NavbarTemplate {
|
||||
@Optional() viewCtrl: ViewController,
|
||||
@Optional() templateRef: TemplateRef
|
||||
) {
|
||||
viewCtrl && viewCtrl.addTemplateRef('navbar', templateRef);
|
||||
viewCtrl && viewCtrl.setNavbarTemplateRef(templateRef);
|
||||
}
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
import {Component, View, Directive, Host, ElementRef, forwardRef, Inject} from 'angular2/angular2';
|
||||
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
|
||||
|
||||
import {Pane} from './pane';
|
||||
import {NavController} from './nav-controller';
|
||||
|
||||
|
||||
@Directive({selector: 'template[pane-anchor]'})
|
||||
export class PaneAnchor {
|
||||
constructor(
|
||||
@Host() @Inject(forwardRef(() => Pane)) pane: Pane,
|
||||
elementRef: ElementRef
|
||||
) {
|
||||
pane.sectionAnchorElementRef = elementRef;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Directive({selector: 'template[content-anchor]'})
|
||||
export class PaneContentAnchor {
|
||||
constructor(
|
||||
@Host() @Inject(forwardRef(() => Pane)) pane: Pane,
|
||||
viewContainerRef: ViewContainerRef
|
||||
) {
|
||||
pane.contentContainerRef = viewContainerRef;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Directive({
|
||||
selector: 'template[navbar-anchor]'
|
||||
})
|
||||
class NavBarAnchor {
|
||||
constructor(
|
||||
@Inject(forwardRef(() => NavController)) navCtrl: NavController,
|
||||
viewContainerRef: ViewContainerRef
|
||||
) {
|
||||
navCtrl.navbarViewContainer(viewContainerRef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'section',
|
||||
host: {
|
||||
'class': 'navbar-container'
|
||||
}
|
||||
})
|
||||
@View({
|
||||
template: '<template navbar-anchor></template>',
|
||||
directives: [NavBarAnchor]
|
||||
})
|
||||
export class NavBarContainer {}
|
@ -1,12 +1,12 @@
|
||||
import {Compiler, ElementRef, Injector, bind, NgZone} from 'angular2/angular2';
|
||||
import {Component, ComponentRef, Compiler, ElementRef, Injector, bind, NgZone} from 'angular2/angular2';
|
||||
import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader';
|
||||
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
import {AppViewManager} from 'angular2/src/core/compiler/view_manager';
|
||||
|
||||
import {Ion} from '../ion';
|
||||
import {IonicConfig} from '../../config/config';
|
||||
import {IonicApp} from '../app/app';
|
||||
import {ViewController} from './view-controller';
|
||||
import {PaneController} from './pane';
|
||||
import {Transition} from '../../transitions/transition';
|
||||
import {SwipeBackGesture} from './swipe-back';
|
||||
import * as util from 'ionic/util';
|
||||
@ -35,7 +35,6 @@ export class NavController extends Ion {
|
||||
this.zone = zone;
|
||||
|
||||
this.views = [];
|
||||
this.panes = new PaneController(this);
|
||||
|
||||
this._sbTrans = null;
|
||||
this._sbEnabled = config.setting('swipeBackEnabled') || false;
|
||||
@ -43,7 +42,6 @@ export class NavController extends Ion {
|
||||
|
||||
this.id = ++ctrlIds;
|
||||
this._ids = -1;
|
||||
this.zIndexes = -1;
|
||||
|
||||
// build a new injector for child ViewControllers to use
|
||||
this.bindings = Injector.resolve([
|
||||
@ -336,6 +334,51 @@ export class NavController extends Ion {
|
||||
|
||||
}
|
||||
|
||||
compileView(componentType) {
|
||||
// create a new ion-view annotation
|
||||
let annotation = new Component({
|
||||
selector: 'ion-view',
|
||||
host: {
|
||||
'[class.pane-view]': '_paneView'
|
||||
}
|
||||
});
|
||||
|
||||
let ionViewComponentType = DirectiveBinding.createFromType(componentType, annotation);
|
||||
|
||||
// create a unique token that works as a cache key
|
||||
ionViewComponentType.token = 'ionView' + componentType.name;
|
||||
|
||||
// compile the Component
|
||||
return this.compiler.compileInHost(ionViewComponentType);
|
||||
}
|
||||
|
||||
createViewComponetRef(hostProtoViewRef, contentContainerRef, viewCtrlBindings) {
|
||||
let bindings = this.bindings.concat(Injector.resolve(viewCtrlBindings));
|
||||
|
||||
// the same guts as DynamicComponentLoader.loadNextToLocation
|
||||
var hostViewRef =
|
||||
contentContainerRef.createHostView(hostProtoViewRef, -1, bindings);
|
||||
var newLocation = this.viewMngr.getHostElement(hostViewRef);
|
||||
var newComponent = this.viewMngr.getComponent(newLocation);
|
||||
|
||||
var dispose = () => {
|
||||
var index = contentContainerRef.indexOf(hostViewRef);
|
||||
if (index !== -1) {
|
||||
contentContainerRef.remove(index);
|
||||
}
|
||||
};
|
||||
|
||||
return new ComponentRef(newLocation, newComponent, dispose);
|
||||
}
|
||||
|
||||
getBindings(viewCtrl) {
|
||||
// create bindings to this ViewController and its NavParams
|
||||
return this.bindings.concat(Injector.resolve([
|
||||
bind(ViewController).toValue(viewCtrl),
|
||||
bind(NavParams).toValue(viewCtrl.params),
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@ -667,28 +710,6 @@ export class NavController extends Ion {
|
||||
return this._anchorER;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @returns {TODO} TODO
|
||||
*/
|
||||
anchorViewContainerRef() {
|
||||
if (arguments.length) {
|
||||
this._anchorVC = arguments[0];
|
||||
}
|
||||
return this._anchorVC;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @returns {TODO} TODO
|
||||
*/
|
||||
childNavbar() {
|
||||
if (arguments.length) {
|
||||
this._childNavbar = arguments[0];
|
||||
}
|
||||
return this._childNavbar;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} view TODO
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {Directive, View, ElementRef, Host, Optional, forwardRef, Injector, NgZone} from 'angular2/angular2';
|
||||
import {Component, Directive, View, ElementRef, Host, Optional, forwardRef, Inject, Injector, NgZone, Renderer} from 'angular2/angular2';
|
||||
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
|
||||
|
||||
import {IonicComponent} from '../../config/decorators';
|
||||
import {NavController} from './nav-controller';
|
||||
@ -23,18 +24,19 @@ export class Nav extends NavController {
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {NavController} hostnavCtrl TODO
|
||||
* @param {NavController} hostNavCtrl TODO
|
||||
* @param {Injector} injector TODO
|
||||
* @param {ElementRef} elementRef TODO
|
||||
* @param {NgZone} zone TODO
|
||||
*/
|
||||
constructor(
|
||||
@Optional() hostnavCtrl: NavController,
|
||||
@Optional() hostNavCtrl: NavController,
|
||||
injector: Injector,
|
||||
elementRef: ElementRef,
|
||||
zone: NgZone
|
||||
) {
|
||||
super(hostnavCtrl, injector, elementRef, zone);
|
||||
super(hostNavCtrl, injector, elementRef, zone);
|
||||
this.panes = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,8 +57,151 @@ export class Nav extends NavController {
|
||||
this.isSwipeBackEnabled( isSwipeBackEnabled );
|
||||
}
|
||||
|
||||
loadContainer(hostProtoViewRef, componentType, viewCtrl, done) {
|
||||
// this gets or creates the Pane which similar nav items live in
|
||||
// Nav items with just a navbar/content would all use the same Pane
|
||||
// Tabs and view's without a navbar would get a different Panes
|
||||
let structure = this.inspectStructure(hostProtoViewRef);
|
||||
|
||||
if (structure.tabs) {
|
||||
// the component being loaded is an <ion-tabs>
|
||||
// Tabs is essentially a pane, cuz it has its own navbar and content containers
|
||||
let contentContainerRef = this.viewMngr.getViewContainer(this.anchorElementRef());
|
||||
let viewComponetRef = this.createViewComponetRef(hostProtoViewRef, contentContainerRef, this.getBindings(viewCtrl));
|
||||
viewComponetRef.instance._paneView = true;
|
||||
|
||||
viewCtrl.disposals.push(() => {
|
||||
viewComponetRef.dispose();
|
||||
});
|
||||
|
||||
viewCtrl.onReady().then(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
} else {
|
||||
// normal ion-view going into pane
|
||||
this.getPane(structure, viewCtrl, (pane) => {
|
||||
// add the content of the view into the pane's content area
|
||||
let viewComponetRef = this.createViewComponetRef(hostProtoViewRef, pane.contentContainerRef, this.getBindings(viewCtrl));
|
||||
viewCtrl.disposals.push(() => {
|
||||
viewComponetRef.dispose();
|
||||
|
||||
// remove the pane if there are no view items left
|
||||
pane.totalViews--;
|
||||
if (pane.totalViews === 0) {
|
||||
pane.dispose && pane.dispose();
|
||||
}
|
||||
});
|
||||
|
||||
// count how many ViewControllers are in this pane
|
||||
pane.totalViews++;
|
||||
|
||||
// a new ComponentRef has been created
|
||||
// set the ComponentRef's instance to this ViewController
|
||||
viewCtrl.setInstance(viewComponetRef.instance);
|
||||
|
||||
// remember the ElementRef to the content that was just created
|
||||
viewCtrl.viewElementRef(viewComponetRef.location);
|
||||
|
||||
// get the NavController's container for navbars, which is
|
||||
// the place this NavController will add each ViewController's navbar
|
||||
let navbarContainerRef = pane.navbarContainerRef;
|
||||
|
||||
// get this ViewController's navbar TemplateRef, which may not
|
||||
// exist if the ViewController's template didn't have an <ion-navbar *navbar>
|
||||
let navbarTemplateRef = viewCtrl.getNavbarTemplateRef();
|
||||
|
||||
// create the navbar view if the pane has a navbar container, and the
|
||||
// ViewController's instance has a navbar TemplateRef to go to inside of it
|
||||
if (navbarContainerRef && navbarTemplateRef) {
|
||||
let navbarView = navbarContainerRef.createEmbeddedView(navbarTemplateRef, -1);
|
||||
|
||||
viewCtrl.disposals.push(() => {
|
||||
let index = navbarContainerRef.indexOf(navbarView);
|
||||
if (index > -1) {
|
||||
navbarContainerRef.remove(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getPane(structure, viewCtrl, done) {
|
||||
let pane = this.panes[this.panes.length - 1];
|
||||
|
||||
if (pane && pane.navbar === structure.navbar) {
|
||||
// the last pane's structure is the same as the one
|
||||
// this ViewController will need, so reuse it
|
||||
done(pane);
|
||||
|
||||
} else {
|
||||
// create a new nav pane
|
||||
this.loader.loadNextToLocation(Pane, this.anchorElementRef(), this.getBindings(viewCtrl)).then(componentRef => {
|
||||
|
||||
// get the pane reference
|
||||
pane = this.newPane;
|
||||
this.newPane = null;
|
||||
|
||||
pane.showNavbar(structure.navbar);
|
||||
pane.dispose = () => {
|
||||
componentRef.dispose();
|
||||
this.panes.splice(this.panes.indexOf(pane), 1);
|
||||
};
|
||||
|
||||
this.panes.push(pane);
|
||||
|
||||
done(pane);
|
||||
|
||||
}, loaderErr => {
|
||||
console.error(loaderErr);
|
||||
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
addPane(pane) {
|
||||
this.newPane = pane;
|
||||
}
|
||||
|
||||
inspectStructure(componentProtoViewRef) {
|
||||
let navbar = false;
|
||||
let tabs = false;
|
||||
//let key = '_';
|
||||
|
||||
componentProtoViewRef._protoView.elementBinders.forEach(rootElementBinder => {
|
||||
if (!rootElementBinder.componentDirective || !rootElementBinder.nestedProtoView) return;
|
||||
|
||||
rootElementBinder.nestedProtoView.elementBinders.forEach(nestedElementBinder => {
|
||||
if ( isComponent(nestedElementBinder, 'Tabs') ) {
|
||||
tabs = true;
|
||||
}
|
||||
if (!nestedElementBinder.componentDirective && nestedElementBinder.nestedProtoView) {
|
||||
nestedElementBinder.nestedProtoView.elementBinders.forEach(templatedElementBinder => {
|
||||
if ( isComponent(templatedElementBinder, 'Navbar') ) {
|
||||
navbar = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
navbar,
|
||||
tabs
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isComponent(elementBinder, id) {
|
||||
return (elementBinder && elementBinder.componentDirective && elementBinder.componentDirective.metadata.id == id);
|
||||
}
|
||||
|
||||
@Directive({selector: 'template[pane-anchor]'})
|
||||
class NavPaneAnchor {
|
||||
@ -64,3 +209,66 @@ class NavPaneAnchor {
|
||||
nav.anchorElementRef(elementRef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Directive({selector: 'template[navbar-anchor]'})
|
||||
class NavBarAnchor {
|
||||
constructor(
|
||||
@Host() @Inject(forwardRef(() => Pane)) pane: Pane,
|
||||
viewContainerRef: ViewContainerRef
|
||||
) {
|
||||
pane.navbarContainerRef = viewContainerRef;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Directive({selector: 'template[content-anchor]'})
|
||||
class ContentAnchor {
|
||||
constructor(
|
||||
@Host() @Inject(forwardRef(() => Pane)) pane: Pane,
|
||||
viewContainerRef: ViewContainerRef
|
||||
) {
|
||||
pane.contentContainerRef = viewContainerRef;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'ion-pane',
|
||||
host: {
|
||||
'class': 'nav'
|
||||
}
|
||||
})
|
||||
@View({
|
||||
template: '' +
|
||||
'<section class="navbar-container">' +
|
||||
'<template navbar-anchor></template>' +
|
||||
'</section>' +
|
||||
'<section class="content-container">' +
|
||||
'<template content-anchor></template>' +
|
||||
'</section>',
|
||||
directives: [NavBarAnchor, ContentAnchor]
|
||||
})
|
||||
class Pane {
|
||||
constructor(
|
||||
nav: Nav,
|
||||
elementRef: ElementRef,
|
||||
renderer: Renderer
|
||||
) {
|
||||
this.zIndex = (nav.panes.length ? nav.panes[nav.panes.length - 1].zIndex + 1 : 0);
|
||||
renderer.setElementStyle(elementRef, 'zIndex', this.zIndex);
|
||||
|
||||
nav.addPane(this);
|
||||
this.totalViews = 0;
|
||||
this.elementRef = elementRef;
|
||||
this.renderer = renderer;
|
||||
}
|
||||
|
||||
showNavbar(hasNavbar) {
|
||||
this.hasNavbar = hasNavbar;
|
||||
if (!hasNavbar) {
|
||||
this.renderer.setElementClass(this.elementRef, 'no-navbar', true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,134 +0,0 @@
|
||||
import {Component, Directive, View, ElementRef, Inject, forwardRef, Injector, bind} from 'angular2/angular2';
|
||||
|
||||
import {Ion} from '../ion';
|
||||
import {IonicConfig} from '../../config/config';
|
||||
import {NavController} from './nav-controller';
|
||||
import {IonicComponent} from '../../config/decorators';
|
||||
import {PaneAnchor, PaneContentAnchor, NavBarContainer} from './anchors';
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
export class PaneController {
|
||||
/**
|
||||
* TODO
|
||||
* @param {NavController} navCtrl TODO
|
||||
*/
|
||||
constructor(navCtrl: NavController) {
|
||||
this.panes = [];
|
||||
this.navCtrl = navCtrl;
|
||||
|
||||
this.bindings = Injector.resolve([
|
||||
bind(NavController).toValue(navCtrl)
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} nav TODO
|
||||
* @param {Function} nav TODO
|
||||
*/
|
||||
get(itemStructure, callback) {
|
||||
// this gets or creates the Pane which similar nav items live in
|
||||
// Nav items with just a navbar/content would all use the same Pane
|
||||
// Tabs and view's without a navbar would get a different Panes
|
||||
|
||||
let key = itemStructure.key;
|
||||
let navCtrl = this.navCtrl;
|
||||
let pane = this.panes[this.panes.length - 1];
|
||||
|
||||
if (pane && pane.key === key) {
|
||||
// the last pane's structure is the same as the one the item needs to go in
|
||||
callback(pane);
|
||||
|
||||
} else {
|
||||
// create a new nav pane
|
||||
navCtrl.loader.loadNextToLocation(Pane, navCtrl.anchorElementRef(), this.bindings).then((componentRef) => {
|
||||
|
||||
// get the pane reference
|
||||
pane = this.newPane;
|
||||
this.newPane = null;
|
||||
|
||||
let sectionAnchorElementRef = pane && pane.sectionAnchorElementRef;
|
||||
if (!sectionAnchorElementRef) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
pane.key = key;
|
||||
pane.dispose = () => {
|
||||
componentRef.dispose();
|
||||
this.panes.splice(this.panes.indexOf(pane), 1);
|
||||
};
|
||||
|
||||
this.panes.push(pane);
|
||||
|
||||
let promises = [];
|
||||
let sectionsToAdd = [];
|
||||
|
||||
// decide which sections should be added to this Pane, ie: nav bars, footers, etc.
|
||||
// add only the sections it needs
|
||||
if (itemStructure.navbar) {
|
||||
sectionsToAdd.push(NavBarContainer);
|
||||
}
|
||||
|
||||
// add the sections which this type of Pane requires
|
||||
sectionsToAdd.forEach(SectionClass => {
|
||||
// as each section is compiled and added to the Pane
|
||||
// the section will add a reference to itself in the Pane's sections object
|
||||
promises.push(
|
||||
navCtrl.loader.loadNextToLocation(SectionClass, sectionAnchorElementRef)
|
||||
);
|
||||
});
|
||||
|
||||
// wait for all of the sections to resolve
|
||||
Promise.all(promises).then(() => {
|
||||
callback(pane);
|
||||
}, err => {
|
||||
console.error(err)
|
||||
});
|
||||
|
||||
}, loaderErr => {
|
||||
console.error(loaderErr);
|
||||
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
add(pane) {
|
||||
this.newPane = pane;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@IonicComponent({
|
||||
selector: 'ion-pane',
|
||||
classId: 'nav',
|
||||
host: {
|
||||
'[style.z-index]': 'zIndex',
|
||||
}
|
||||
})
|
||||
@View({
|
||||
template: `
|
||||
<template pane-anchor></template>
|
||||
<section class="content-container">
|
||||
<template content-anchor></template>
|
||||
</section>
|
||||
`,
|
||||
directives: [PaneAnchor, PaneContentAnchor]
|
||||
})
|
||||
export class Pane extends Ion {
|
||||
constructor(
|
||||
@Inject(forwardRef(() => NavController)) navCtrl: NavController,
|
||||
elementRef: ElementRef,
|
||||
ionicConfig: IonicConfig
|
||||
) {
|
||||
super(elementRef, ionicConfig);
|
||||
navCtrl.panes.add(this);
|
||||
this.totalItems = 0;
|
||||
this.zIndex = ++navCtrl.zIndexes;
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
import {Component, EventEmitter, ElementRef, bind, Injector, ComponentRef} from 'angular2/angular2';
|
||||
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
|
||||
import {NavParams} from './nav-controller';
|
||||
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@ -16,188 +14,42 @@ export class ViewController {
|
||||
this.state = 0;
|
||||
this.disposals = [];
|
||||
|
||||
this.protos = {};
|
||||
this._nbItms = [];
|
||||
this._promises = [];
|
||||
|
||||
this.templateRefs = {};
|
||||
this.navbarTemplateRef = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} name TODO
|
||||
* @param {TODO} protoViewRef TODO
|
||||
* @private
|
||||
*/
|
||||
addProtoViewRef(name, protoViewRef) {
|
||||
this.protos[name] = protoViewRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} name TODO
|
||||
* @param {TODO} templateRef TODO
|
||||
*/
|
||||
addTemplateRef(name, templateRef) {
|
||||
this.templateRefs[name] = templateRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {Function} callback TODO
|
||||
* @returns {TODO} TODO
|
||||
*/
|
||||
stage(callback) {
|
||||
stage(done) {
|
||||
let navCtrl = this.navCtrl;
|
||||
|
||||
if (this.instance || !navCtrl) {
|
||||
// already compiled this view
|
||||
return callback();
|
||||
return done();
|
||||
}
|
||||
|
||||
let annotation = new Component({
|
||||
selector: 'ion-view',
|
||||
host: {
|
||||
'class': 'nav-item'
|
||||
}
|
||||
});
|
||||
// compile the componenet and create a ProtoViewRef
|
||||
navCtrl.compileView(this.componentType).then(hostProtoViewRef => {
|
||||
|
||||
let ionViewComponentType = DirectiveBinding.createFromType(this.componentType, annotation);
|
||||
// get the pane the NavController wants to use
|
||||
// the pane is where all this content will be placed into
|
||||
navCtrl.loadContainer(hostProtoViewRef, this.componentType, this, () => {
|
||||
|
||||
// create a unique token that works as a cache key
|
||||
ionViewComponentType.token = 'ionView' + this.componentType.name;
|
||||
|
||||
// compile the Component
|
||||
navCtrl.compiler.compileInHost(ionViewComponentType).then(hostProtoViewRef => {
|
||||
|
||||
// figure out the sturcture of this Component
|
||||
// does it have a navbar? Is it tabs? Should it not have a navbar or any toolbars?
|
||||
let itemStructure = this.sturcture = this.inspectStructure(hostProtoViewRef);
|
||||
|
||||
// get the appropriate Pane which this ViewController will fit into
|
||||
navCtrl.panes.get(itemStructure, pane => {
|
||||
this.pane = pane;
|
||||
|
||||
let bindings = navCtrl.bindings.concat(Injector.resolve([
|
||||
bind(NavParams).toValue(this.params),
|
||||
bind(ViewController).toValue(this)
|
||||
]));
|
||||
|
||||
// add the content of the view to the content area
|
||||
// it will already have the correct context
|
||||
let contentContainer = pane.contentContainerRef;
|
||||
|
||||
// the same guts as DynamicComponentLoader.loadNextToLocation
|
||||
var hostViewRef =
|
||||
contentContainer.createHostView(hostProtoViewRef, -1, bindings);
|
||||
var newLocation = navCtrl.viewMngr.getHostElement(hostViewRef);
|
||||
var newComponent = navCtrl.viewMngr.getComponent(newLocation);
|
||||
pane.totalItems++;
|
||||
|
||||
var dispose = () => {
|
||||
var index = contentContainer.indexOf(hostViewRef);
|
||||
if (index !== -1) {
|
||||
contentContainer.remove(index);
|
||||
|
||||
// remove the pane if there are no view items left
|
||||
pane.totalItems--;
|
||||
if (pane.totalItems === 0) {
|
||||
pane.dispose();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.disposals.push(dispose);
|
||||
var viewComponetRef = new ComponentRef(newLocation, newComponent, dispose);
|
||||
|
||||
// get the component's instance, and set it to the this ViewController
|
||||
this.setInstance(viewComponetRef.instance);
|
||||
this.viewElementRef(viewComponetRef.location);
|
||||
|
||||
// // get the item container's nav bar
|
||||
let navbarViewContainer = navCtrl.navbarViewContainer();
|
||||
|
||||
// // get the item's navbar protoview
|
||||
let navbarTemplateRef = this.templateRefs.navbar;
|
||||
|
||||
// add a navbar view if the pane has a navbar container, and the
|
||||
// item's instance has a navbar protoview to go to inside of it
|
||||
if (navbarViewContainer && navbarTemplateRef) {
|
||||
let navbarView = navbarViewContainer.createEmbeddedView(navbarTemplateRef, -1);
|
||||
|
||||
this.disposals.push(() => {
|
||||
let index = navbarViewContainer.indexOf(navbarView);
|
||||
if (index > -1) {
|
||||
navbarViewContainer.remove(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// this item has finished loading
|
||||
// this ViewController instance has finished loading
|
||||
try {
|
||||
this.loaded();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
// fire callback when all child promises have been resolved
|
||||
Promise.all(this._promises).then(() => {
|
||||
callback();
|
||||
this._promises = [];
|
||||
});
|
||||
|
||||
}, panesErr => {
|
||||
console.error(panesErr);
|
||||
done();
|
||||
});
|
||||
|
||||
}, compileInHostErr => {
|
||||
console.error(compileInHostErr);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} childPromise TODO
|
||||
*/
|
||||
addPromise(childPromise) {
|
||||
this._promises.push(childPromise);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} componentProtoViewRef TODO
|
||||
*/
|
||||
inspectStructure(componentProtoViewRef) {
|
||||
let navbar = false;
|
||||
let key = '_';
|
||||
|
||||
componentProtoViewRef._protoView.elementBinders.forEach(rootElementBinder => {
|
||||
if (!rootElementBinder.componentDirective || !rootElementBinder.nestedProtoView) return;
|
||||
|
||||
rootElementBinder.nestedProtoView.elementBinders.forEach(nestedElementBinder => {
|
||||
if ( isComponent(nestedElementBinder, 'Tabs') ) {
|
||||
navbar = true;
|
||||
}
|
||||
if (!nestedElementBinder.componentDirective && nestedElementBinder.nestedProtoView) {
|
||||
nestedElementBinder.nestedProtoView.elementBinders.forEach(templatedElementBinder => {
|
||||
if ( isComponent(templatedElementBinder, 'Navbar') ) {
|
||||
navbar = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (this.navCtrl.childNavbar()) {
|
||||
navbar = false;
|
||||
}
|
||||
|
||||
if (navbar) key += 'n'
|
||||
|
||||
return {
|
||||
navbar,
|
||||
key
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @returns {boolean} TODO
|
||||
@ -247,6 +99,20 @@ export class ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
setNavbarTemplateRef(templateRef) {
|
||||
this.navbarTemplateRef = templateRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
getNavbarTemplateRef() {
|
||||
return this.navbarTemplateRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {TODO} val TODO
|
||||
@ -329,7 +195,7 @@ export class ViewController {
|
||||
* TODO
|
||||
* @returns {TODO} TODO
|
||||
*/
|
||||
navbarBackgroundRef() {
|
||||
navbarBgRef() {
|
||||
let navbarView = this.navbarView();
|
||||
if (navbarView) {
|
||||
return navbarView.getNativeElement().querySelector('.toolbar-background');
|
||||
@ -406,7 +272,3 @@ export class ViewController {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isComponent(elementBinder, id) {
|
||||
return (elementBinder && elementBinder.componentDirective && elementBinder.componentDirective.metadata.id == id);
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {Directive, Component, View, Host, ElementRef, forwardRef, Injector, NgZone} from 'angular2/angular2';
|
||||
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
|
||||
|
||||
import {NavController} from '../nav/nav-controller';
|
||||
import {ViewController} from '../nav/view-controller';
|
||||
@ -31,8 +32,8 @@ import {Tabs} from './tabs';
|
||||
}
|
||||
})
|
||||
@View({
|
||||
template: '<template pane-anchor></template><ng-content></ng-content>',
|
||||
directives: [forwardRef(() => TabPaneAnchor)]
|
||||
template: '<template content-anchor></template><ng-content></ng-content>',
|
||||
directives: [forwardRef(() => TabContentAnchor)]
|
||||
})
|
||||
export class Tab extends NavController {
|
||||
|
||||
@ -55,12 +56,10 @@ export class Tab extends NavController {
|
||||
super(tabs, injector, elementRef, zone);
|
||||
this.tabs = tabs;
|
||||
|
||||
this.childNavbar(true);
|
||||
|
||||
let viewCtrl = this.viewCtrl = new ViewController(tabs.Host);
|
||||
viewCtrl.setInstance(this);
|
||||
viewCtrl.viewElementRef(elementRef);
|
||||
tabs.addTab(this);
|
||||
this._initTab = tabs.addTab(this);
|
||||
|
||||
this.navbarView = viewCtrl.navbarView = () => {
|
||||
let activeView = this.getActive();
|
||||
@ -79,18 +78,19 @@ export class Tab extends NavController {
|
||||
}
|
||||
|
||||
onInit() {
|
||||
if (this._initialResolve) {
|
||||
this.tabs.select(this).then(() => {
|
||||
this._initialResolve();
|
||||
this._initialResolve = null;
|
||||
});
|
||||
console.log('Tab onInit');
|
||||
|
||||
if (this._initTab) {
|
||||
this.tabs.select(this);
|
||||
|
||||
} else {
|
||||
// TODO: OPTIONAL PRELOAD OTHER TABS!
|
||||
// setTimeout(() => {
|
||||
// this.load();
|
||||
// }, 300);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {Function} callback TODO
|
||||
*/
|
||||
load(callback) {
|
||||
if (!this._loaded && this.root) {
|
||||
let opts = {
|
||||
@ -107,15 +107,6 @@ export class Tab extends NavController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @returns {TODO} TODO
|
||||
*/
|
||||
queueInitial() {
|
||||
// this Tab will be used as the initial one for the first load of Tabs
|
||||
return new Promise(res => { this._initialResolve = res; });
|
||||
}
|
||||
|
||||
get isSelected() {
|
||||
return this.tabs.isActive(this.viewCtrl);
|
||||
}
|
||||
@ -124,23 +115,53 @@ export class Tab extends NavController {
|
||||
return !this.tabs.isActive(this.viewCtrl);
|
||||
}
|
||||
|
||||
loadContainer(hostProtoViewRef, componentType, viewCtrl, done) {
|
||||
|
||||
let viewComponetRef = this.createViewComponetRef(hostProtoViewRef, this.contentContainerRef, this.getBindings(viewCtrl));
|
||||
viewCtrl.disposals.push(() => {
|
||||
viewComponetRef.dispose();
|
||||
});
|
||||
|
||||
// a new ComponentRef has been created
|
||||
// set the ComponentRef's instance to this ViewController
|
||||
viewCtrl.setInstance(viewComponetRef.instance);
|
||||
|
||||
// remember the ElementRef to the content that was just created
|
||||
viewCtrl.viewElementRef(viewComponetRef.location);
|
||||
|
||||
// get the NavController's container for navbars, which is
|
||||
// the place this NavController will add each ViewController's navbar
|
||||
let navbarContainerRef = this.tabs.navbarContainerRef;
|
||||
|
||||
// get this ViewController's navbar TemplateRef, which may not
|
||||
// exist if the ViewController's template didn't have an <ion-navbar *navbar>
|
||||
let navbarTemplateRef = viewCtrl.getNavbarTemplateRef();
|
||||
|
||||
// create the navbar view if the pane has a navbar container, and the
|
||||
// ViewController's instance has a navbar TemplateRef to go to inside of it
|
||||
if (navbarContainerRef && navbarTemplateRef) {
|
||||
let navbarView = navbarContainerRef.createEmbeddedView(navbarTemplateRef, -1);
|
||||
|
||||
viewCtrl.disposals.push(() => {
|
||||
let index = navbarContainerRef.indexOf(navbarView);
|
||||
if (index > -1) {
|
||||
navbarContainerRef.remove(index);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
@Directive({
|
||||
selector: 'template[pane-anchor]'
|
||||
})
|
||||
class TabPaneAnchor {
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {Tab} tab TODO
|
||||
* @param {ElementRef} elementRef TODO
|
||||
*/
|
||||
constructor(@Host() tab: Tab, elementRef: ElementRef) {
|
||||
tab.anchorElementRef(elementRef);
|
||||
@Directive({selector: 'template[content-anchor]'})
|
||||
class TabContentAnchor {
|
||||
constructor(
|
||||
@Host() tab: Tab,
|
||||
viewContainerRef: ViewContainerRef
|
||||
) {
|
||||
tab.contentContainerRef = viewContainerRef;
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,10 @@ ion-tab {
|
||||
}
|
||||
}
|
||||
|
||||
ion-tabs > .navbar-container {
|
||||
order: $flex-order-tab-bar-navbar;
|
||||
}
|
||||
|
||||
.tab-bar-container {
|
||||
position: relative;
|
||||
order: $flex-order-tab-bar-bottom;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import {Component, Directive, View, Injector, NgFor, ElementRef, Optional, Host, forwardRef, NgZone} from 'angular2/angular2';
|
||||
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
|
||||
|
||||
import {Ion} from '../ion';
|
||||
import {IonicApp} from '../app/app';
|
||||
@ -42,6 +43,9 @@ import * as dom from 'ionic/util/dom';
|
||||
})
|
||||
@IonicView({
|
||||
template: '' +
|
||||
'<section class="navbar-container">' +
|
||||
'<template navbar-anchor></template>' +
|
||||
'</section>' +
|
||||
'<nav class="tab-bar-container">' +
|
||||
'<tab-bar role="tablist">' +
|
||||
'<a *ng-for="#t of tabs" [tab]="t" class="tab-button" role="tab">' +
|
||||
@ -54,7 +58,11 @@ import * as dom from 'ionic/util/dom';
|
||||
'<section class="content-container">' +
|
||||
'<ng-content></ng-content>' +
|
||||
'</section>',
|
||||
directives: [forwardRef(() => TabButton), forwardRef(() => TabHighlight)]
|
||||
directives: [
|
||||
forwardRef(() => TabButton),
|
||||
forwardRef(() => TabHighlight),
|
||||
forwardRef(() => TabNavBarAnchor)
|
||||
]
|
||||
})
|
||||
export class Tabs extends NavController {
|
||||
/**
|
||||
@ -71,6 +79,8 @@ export class Tabs extends NavController {
|
||||
super(hostNavCtrl, injector, elementRef, zone);
|
||||
this.app = app;
|
||||
|
||||
this._ready = new Promise(res => { this._isReady = res; });
|
||||
|
||||
// Tabs may also be an actual ViewController which was navigated to
|
||||
// if Tabs is static and not navigated to within a NavController
|
||||
// then skip this and don't treat it as it's own ViewController
|
||||
@ -93,24 +103,19 @@ export class Tabs extends NavController {
|
||||
viewCtrl.enableBack = () => {
|
||||
return false;
|
||||
};
|
||||
|
||||
viewCtrl.onReady = () => {
|
||||
return this._ready;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO
|
||||
* @param {Tab} tab TODO
|
||||
*/
|
||||
addTab(tab) {
|
||||
// tab.viewCtrl refers to the ViewController of the individual Tab being added to Tabs (NavController)
|
||||
// this.viewCtrl refers to the ViewController instsance on Tabs
|
||||
this.add(tab.viewCtrl);
|
||||
|
||||
if (this.length() === 1) {
|
||||
// this was the first tab added, queue this one to be loaded and selected
|
||||
let promise = tab.queueInitial();
|
||||
this.viewCtrl && this.viewCtrl.addPromise(promise);
|
||||
}
|
||||
// return true/false if it's the initial tab
|
||||
return (this.length() === 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,6 +147,7 @@ export class Tabs extends NavController {
|
||||
|
||||
this.transition(enteringView, leavingView, opts, () => {
|
||||
this.highlight && this.highlight.select(tab);
|
||||
this._isReady();
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
@ -229,3 +235,14 @@ class TabHighlight {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Directive({selector: 'template[navbar-anchor]'})
|
||||
class TabNavBarAnchor {
|
||||
constructor(
|
||||
@Host() tabs: Tabs,
|
||||
viewContainerRef: ViewContainerRef
|
||||
) {
|
||||
tabs.navbarContainerRef = viewContainerRef;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
<ion-navbar *navbar>
|
||||
<ion-title>Heart</ion-title>
|
||||
</ion-navbar>
|
||||
<ion-content class="padding">
|
||||
<ion-content padding>
|
||||
<h2>Tab 1</h2>
|
||||
</ion-content>
|
||||
`
|
||||
@ -27,7 +27,7 @@ class Tab1 {
|
||||
<ion-navbar *navbar>
|
||||
<ion-title>Star</ion-title>
|
||||
</ion-navbar>
|
||||
<ion-content class="padding">
|
||||
<ion-content padding>
|
||||
<h2>Tab 2</h2>
|
||||
</ion-content>
|
||||
`
|
||||
@ -46,7 +46,7 @@ class Tab2 {
|
||||
<ion-navbar *navbar>
|
||||
<ion-title>Stopwatch</ion-title>
|
||||
</ion-navbar>
|
||||
<ion-content class="padding">
|
||||
<ion-content padding>
|
||||
<h2>Tab 3</h2>
|
||||
</ion-content>
|
||||
`
|
||||
@ -58,12 +58,13 @@ class Tab3 {
|
||||
}
|
||||
|
||||
@App({
|
||||
template: `
|
||||
template: `
|
||||
<ion-tabs>
|
||||
<ion-tab tab-title="Heart" tab-icon="heart" [root]="root1"></ion-tab>
|
||||
<ion-tab tab-title="Star" tab-icon="star" [root]="root2"></ion-tab>
|
||||
<ion-tab tab-title="Stopwatch" tab-icon="stopwatch" [root]="root3"></ion-tab>
|
||||
</ion-tabs>`
|
||||
<ion-tab tab-title="Heart" tab-icon="heart" [root]="root1"></ion-tab>
|
||||
<ion-tab tab-title="Star" tab-icon="star" [root]="root2"></ion-tab>
|
||||
<ion-tab tab-title="Stopwatch" tab-icon="stopwatch" [root]="root3"></ion-tab>
|
||||
</ion-tabs>
|
||||
`
|
||||
})
|
||||
export class TabsPage {
|
||||
constructor() {
|
||||
|
@ -32,7 +32,7 @@ class IOSTransition extends Transition {
|
||||
.fadeIn()
|
||||
.to(TRANSLATEX, CENTER);
|
||||
|
||||
this.enteringNavbarBackground
|
||||
this.enteringNavbarBg
|
||||
.to(TRANSLATEX, CENTER);
|
||||
|
||||
// leaving view moves off screen
|
||||
@ -45,7 +45,7 @@ class IOSTransition extends Transition {
|
||||
.from(TRANSLATEX, CENTER)
|
||||
.from(OPACITY, 1);
|
||||
|
||||
this.leavingNavbarBackground
|
||||
this.leavingNavbarBg
|
||||
.from(TRANSLATEX, CENTER);
|
||||
|
||||
// set properties depending on direction
|
||||
@ -59,7 +59,7 @@ class IOSTransition extends Transition {
|
||||
this.enteringTitle
|
||||
.from(TRANSLATEX, OFF_LEFT);
|
||||
|
||||
this.enteringNavbarBackground
|
||||
this.enteringNavbarBg
|
||||
.from(TRANSLATEX, OFF_LEFT);
|
||||
|
||||
this.leavingView
|
||||
@ -70,7 +70,7 @@ class IOSTransition extends Transition {
|
||||
.to(TRANSLATEX, '100%')
|
||||
.to(OPACITY, 0);
|
||||
|
||||
this.leavingNavbarBackground
|
||||
this.leavingNavbarBg
|
||||
.to(TRANSLATEX, '100%');
|
||||
|
||||
if (this.leaving.enableBack() && this.viewWidth() > 200) {
|
||||
@ -88,7 +88,7 @@ class IOSTransition extends Transition {
|
||||
this.enteringTitle
|
||||
.from(TRANSLATEX, '99.5%');
|
||||
|
||||
this.enteringNavbarBackground
|
||||
this.enteringNavbarBg
|
||||
.from(TRANSLATEX, '99.5%');
|
||||
|
||||
this.leavingView
|
||||
@ -99,7 +99,7 @@ class IOSTransition extends Transition {
|
||||
.to(TRANSLATEX, OFF_LEFT)
|
||||
.to(OPACITY, 0);
|
||||
|
||||
this.leavingNavbarBackground
|
||||
this.leavingNavbarBg
|
||||
.to(TRANSLATEX, OFF_LEFT);
|
||||
|
||||
if (this.entering.enableBack() && this.viewWidth() > 200) {
|
||||
|
@ -48,8 +48,8 @@ export class Transition extends Animation {
|
||||
this.enteringNavbarItems = new Animation(enteringView.navbarItemRefs());
|
||||
enteringNavbar.add(this.enteringNavbarItems.fadeIn());
|
||||
|
||||
this.enteringNavbarBackground = new Animation(enteringView.navbarBackgroundRef());
|
||||
enteringNavbar.add(this.enteringNavbarBackground);
|
||||
this.enteringNavbarBg = new Animation(enteringView.navbarBgRef());
|
||||
enteringNavbar.add(this.enteringNavbarBg);
|
||||
}
|
||||
|
||||
|
||||
@ -73,8 +73,8 @@ export class Transition extends Animation {
|
||||
this.leavingNavbarItems = new Animation(leavingView.navbarItemRefs());
|
||||
leavingNavbar.add(this.leavingNavbarItems.fadeOut());
|
||||
|
||||
this.leavingNavbarBackground = new Animation(leavingView.navbarBackgroundRef());
|
||||
leavingNavbar.add(this.leavingNavbarBackground);
|
||||
this.leavingNavbarBg = new Animation(leavingView.navbarBgRef());
|
||||
leavingNavbar.add(this.leavingNavbarBg);
|
||||
|
||||
this.add(this.leavingView, leavingNavbar);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@
|
||||
"rx": "rx"
|
||||
}
|
||||
})
|
||||
System.import("index");
|
||||
System.import("index").then(function(m) {}, console.error.bind(console));;
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
Reference in New Issue
Block a user