Files
2015-06-04 11:51:15 -05:00

272 lines
7.2 KiB
JavaScript

import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {bind} from 'angular2/di';
import * as util from 'ionic/util';
import {NavController} from './nav-controller';
import {Nav} from './nav';
import {NavBase} from './nav-base';
import {TabPane, NavPane, NavPaneSection} from './nav';
export class NavItem {
constructor(navBase, Component, params = {}) {
this.navBase = navBase;
this.Component = Component;
this.params = params;
this.id = util.nextUid();
this._titleEle = undefined;
this._backBtn = undefined;
this.disposals = [];
// if it's possible to go back from this nav item
this.enableBack = false;
this.protos = {};
}
addProtoViewRef(name, protoViewRef) {
this.protos[name] = protoViewRef;
}
stage(callback) {
// update if it's possible to go back from this nav item
//this.enableBack = !!this.navBase.getPrevious(this);
if (this.instance) {
// already compiled this view
return callback();
}
// compile the Component
this.navBase.compiler.compileInHost(this.Component).then(componentProtoViewRef => {
// 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 = getProtoViewStructure(componentProtoViewRef);
// get the appropriate NavPane which this NavItem will fit into
this.navBase.getPane(itemStructure, pane => {
// create a new injector just for this NavItem
let injector = this.navBase.injector.resolveAndCreateChild([
bind(NavBase).toValue(this.navBase),
bind(NavController).toValue(this.navBase.navCtrl),
bind(NavParams).toValue(new NavParams(this.params)),
bind(NavItem).toValue(this)
]);
// add the content of the view to the content area
let viewContainer = pane.contentContainerRef;
let hostViewRef = viewContainer.create(componentProtoViewRef, -1, null, injector);
let newLocation = new ElementRef(hostViewRef, 0);
this.instance = this.navBase.loader._viewManager.getComponent(newLocation);
this.disposals.push(() => {
viewContainer.remove( viewContainer.indexOf(hostViewRef) );
});
this.viewEle = hostViewRef._view.render._view.rootNodes[0];
this.viewEle.classList.add('nav-item');
let context = {
boundElementIndex: 0,
parentView: {
_view: hostViewRef._view.componentChildViews[0]
}
};
// add only the sections it needs
let navbarViewContainer = pane.sections.navbar.viewContainerRef;
if (navbarViewContainer && itemStructure.navbar && this.protos.navbar) {
this.navbarView = navbarViewContainer.create(this.protos.navbar, -1, context, injector);
this.disposals.push(() => {
navbarViewContainer.remove( navbarViewContainer.indexOf(this.navbarView) );
});
}
this.loaded();
callback();
});
});
}
cache() {
this.didCache();
}
destroy() {
for (let i = 0; i < this.disposals.length; i++) {
this.disposals[i]();
}
this.didUnload();
// just to help prevent any possible memory leaks
for (let name in this) {
if (this.hasOwnProperty(name)) {
this[name] = null;
}
}
}
viewElement() {
return this.viewEle;
}
navbarElement() {
if (this.navbarView && this.navbarView._view) {
return this.navbarView._view.render._view.rootNodes[0];
}
}
contentElement() {
return this.viewEle.querySelector('ion-content');
}
titleElement() {
if (this._titleEle === undefined) {
let navbarElement = this.navbarElement();
if (navbarElement) {
let titleEle = navbarElement.querySelector('ion-title');
if (titleEle) {
this._titleEle = titleEle;
return this._titleEle;
}
}
this._titleEle = null;
}
return this._titleEle;
}
backButtonElement() {
if (this._backBtn === undefined) {
let navbarElement = this.navbarElement();
if (navbarElement) {
let backBtn = navbarElement.querySelector('back-button');
if (backBtn) {
this._backBtn = backBtn;
return this._backBtn;
}
}
this._backBtn = null;
}
return this._backBtn;
}
/*
The view has loaded. This event only happens once per view being
created. If a view leaves but is cached, then this will not
fire again on a subsequent viewing. This method is a good place
to put your setup code for the view; however, it is not the
recommended method to use when a view becomes active.
*/
loaded() {
this.instance && this.instance.viewLoaded && this.instance.viewLoaded();
}
/*
The view is about to enter and become the active view.
*/
willEnter() {
this.instance && this.instance.viewWillEnter && this.instance.viewWillEnter();
}
/*
The view has fully entered and is now the active view. This
will fire, whether it was the first load or loaded from the cache.
*/
didEnter() {
this.instance && this.instance.viewDidEnter && this.instance.viewDidEnter();
}
/*
The view has is about to leave and no longer be the active view.
*/
willLeave() {
this.instance && this.instance.viewWillLeave && this.instance.viewWillLeave();
}
/*
The view has finished leaving and is no longer the active view. This
will fire, whether it is cached or unloaded.
*/
didLeave() {
this.instance && this.instance.viewDidLeave && this.instance.viewDidLeave();
}
/*
The view is about to become cached.
*/
willCache() {
this.instance && this.instance.viewWillCache && this.instance.viewWillCache();
}
/*
The view is now cached.
*/
didCache() {
this.instance && this.instance.viewDidCache && this.instance.viewDidCache();
}
/*
The view is about to be destroyed and have its elements removed.
*/
willUnload() {
this.instance && this.instance.viewWillUnload && this.instance.viewWillUnload();
}
/*
The view has been destroyed and its elements have been removed.
*/
didUnload() {
this.instance && this.instance.viewDidUnload && this.instance.viewDidUnload();
}
}
export class NavParams {
constructor(params) {
util.extend(this, params);
}
}
function getProtoViewStructure(componentProtoViewRef) {
let navbar = true;
let tabs = false;
let toolbars = [];
let key = '_';
// componentProtoViewRef._protoView.elementBinders.forEach(rootElementBinder => {
// if (!rootElementBinder.componentDirective || !rootElementBinder.nestedProtoView) return;
// rootElementBinder.nestedProtoView.elementBinders.forEach(nestedElementBinder => {
// let componentDirective = nestedElementBinder.componentDirective;
// if (componentDirective && componentDirective.metadata.id == 'Tab') {
// navbar = tabs = true;
// }
// });
// });
if (navbar) {
key += 'n'
}
if (toolbars.length) {
key += 'b' + toolbars.length;
}
return {
navbar: navbar,
tabs: tabs,
toolbars: toolbars,
key: key
};
}