NavItem renamed to ViewItem

This commit is contained in:
Adam Bradley
2015-06-09 13:14:53 -05:00
parent b28bd21ad0
commit 359ab9d5c1
11 changed files with 155 additions and 131 deletions

View File

@@ -9,9 +9,10 @@ import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {Compiler} from 'angular2/angular2';
import {bind} from 'angular2/di';
import {ViewItem} from './view-item';
import {NavController} from '../nav/nav-controller';
import {NavItem, NavParams} from '../nav/nav-item';
import {Pane, NavBarContainer} from '../nav/pane';
import {PaneController} from '../nav/pane';
import {NavParams} from '../nav/nav-item';
import {Transition} from '../../transitions/transition';
import {ClickBlock} from '../../util/click-block';
import * as util from 'ionic/util';
@@ -30,85 +31,20 @@ export class ViewController {
this.parent = parent;
this.compiler = compiler;
this.elementRef = elementRef;
this.domElement = elementRef.domElement;
this.loader = loader;
this.injector = injector;
this.items = [];
this.navCtrl = new NavController(this);
this.panes = new PaneController(this);
this.sbTransition = null;
this.sbActive = false;
this.panes = {};
this.id = ++itemIds;
this.childIds = -1;
}
setPaneAnchor(elementRef) {
this.anchorElementRef = elementRef;
}
getPane(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
if (this.panes[itemStructure.key]) {
// nav pane which the entering component already exists
callback(this.panes[itemStructure.key]);
} else {
// create a new nav pane
this.panes[itemStructure.key] = null;
let injector = this.injector.resolveAndCreateChild([
bind(ViewController).toValue(this)
]);
// add a Pane element
// when the Pane is added, it'll also add its reference to the panes object
this.loader.loadNextToExistingLocation(Pane, this.anchorElementRef, injector).then(() => {
// get the pane reference by name
let pane = this.panes[itemStructure.key];
// get the element inside the Pane to add sections to
let sectionViewContainerRef = pane.sectionAnchorElementRef;
let promises = [];
let sectionsToAdd = []
// decide which sections should be added to this Pane, ie: nav bars, tab bars, 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( this.loader.loadNextToExistingLocation(SectionClass, sectionViewContainerRef, null) );
});
// wait for all of the sections to resolve
Promise.all(promises).then(() => {
callback(pane);
});
});
}
}
addPane(pane) {
for (let np in this.panes) {
if (this.panes[np] === null) {
this.panes[np] = pane;
return;
}
}
}
push(ComponentClass, params = {}, opts = {}) {
if (!ComponentClass || this.isTransitioning()) {
return Promise.reject();
@@ -126,13 +62,13 @@ export class ViewController {
opts.direction = opts.direction || 'forward';
// the active item is going to be the leaving one (if one exists)
let leavingItem = this.getActive() || new NavItem();
let leavingItem = this.getActive() || new ViewItem();
leavingItem.shouldDestroy = false;
leavingItem.shouldCache = true;
leavingItem.willCache();
// create a new NavStackItem
let enteringItem = new NavItem(this, ComponentClass, params);
let enteringItem = new ViewItem(this, ComponentClass, params);
// add the item to the stack
this.add(enteringItem);
@@ -158,7 +94,7 @@ export class ViewController {
// get the active item and set that it is staged to be leaving
// was probably the one popped from the stack
let leavingItem = this.getActive() || new NavItem();
let leavingItem = this.getActive() || new ViewItem();
leavingItem.shouldDestroy = true;
leavingItem.shouldCache = false;
leavingItem.willUnload();
@@ -259,7 +195,7 @@ export class ViewController {
// get the active item and set that it is staged to be leaving
// was probably the one popped from the stack
let leavingItem = this.getActive() || new NavItem();
let leavingItem = this.getActive() || new ViewItem();
leavingItem.shouldDestroy = true;
leavingItem.shouldCache = false;
leavingItem.willLeave();
@@ -377,7 +313,7 @@ export class ViewController {
if (opts.animate) {
// block possible clicks during transition
ClickBlock(true, 520);
this.getNavElement().classList.add('transitioning');
this.getContainerElement().classList.add('transitioning');
}
}
@@ -396,7 +332,7 @@ export class ViewController {
}
});
this.getNavElement().classList.remove('transitioning');
this.getContainerElement().classList.remove('transitioning');
// allow clicks again
ClickBlock(false);
@@ -468,8 +404,8 @@ export class ViewController {
return null;
}
getNavElement() {
return this.domElement;
getContainerElement() {
return this.elementRef.domElement;
}
navbarViewContainer(nbContainer) {
@@ -526,7 +462,7 @@ export class ViewController {
}
width() {
return this.domElement.offsetWidth;
return this.getContainerElement().offsetWidth;
}
}

View File

@@ -0,0 +1,304 @@
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 {ViewController} from '../view/view-controller';
import {NavController} from '../nav/nav-controller';
import {NavParams} from '../nav/nav-params';
export class ViewItem {
constructor(viewController, ComponentClass, params = {}) {
this.viewController = viewController;
this.ComponentClass = ComponentClass;
this.params = new NavParams(this.params);
this.instance = null;
this.state = 0;
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) {
let viewController = this.viewController;
// update if it's possible to go back from this nav item
this.enableBack = viewController && !!viewController.getPrevious(this);
if (this.instance || !viewController) {
// already compiled this view
return callback();
}
// compile the Component
viewController.compiler.compileInHost(this.ComponentClass).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 Pane which this ViewItem will fit into
viewController.panes.get(itemStructure, pane => {
// create a new injector just for this ViewItem
let injector = viewController.injector.resolveAndCreateChild([
bind(ViewController).toValue(viewController),
bind(NavController).toValue(viewController.navCtrl),
bind(NavParams).toValue(this.params),
bind(ViewItem).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.setInstance( viewController.loader._viewManager.getComponent(newLocation) );
this.setViewElement( hostViewRef._view.render._view.rootNodes[0] );
this.disposals.push(() => {
viewContainer.remove( viewContainer.indexOf(hostViewRef) );
});
// get the view's context so when creating the navbar
// it uses the same context as the content
let context = {
boundElementIndex: 0,
parentView: {
_view: hostViewRef._view.componentChildViews[0]
}
};
// get the item container's nav bar
let navbarViewContainer = viewController.navbarViewContainer();
// get the item's navbar protoview
let navbarProtoView = this.protos.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 && navbarProtoView) {
this.navbarView = navbarViewContainer.create(navbarProtoView, -1, context, injector);
this.disposals.push(() => {
navbarViewContainer.remove( navbarViewContainer.indexOf(this.navbarView) );
});
}
// this item has finished loading
this.loaded();
// all done, fire the callback
if (this._wait) {
this._waitCallback = callback;
} else {
callback();
}
});
});
}
waitForResolve() {
this._wait = true;
}
resolve() {
if (this._wait) {
this._waitCallback && this._waitCallback();
this._wait = this._waitCallback = null;
}
}
setInstance(instance) {
this.instance = instance;
}
setViewElement(viewEle) {
this.viewEle = viewEle;
viewEle && viewEle.classList.add('nav-item');
}
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() {
let navbarView = this.navbarView;
if (navbarView && navbarView._view) {
return 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();
}
}
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
};
}