overhaul ion-views

This commit is contained in:
Adam Bradley
2015-05-27 11:54:57 -05:00
parent 99aa1c1321
commit 6a349baee7
15 changed files with 105 additions and 237 deletions

View File

@@ -302,7 +302,7 @@ class Animate {
this._duration = duration;
var easingName = easingConfig.name;
var easingName = easingConfig && easingConfig.name || 'linear';
var effects = [ convertProperties(fromEffect) ];
@@ -316,7 +316,7 @@ class Animate {
effects.push( convertProperties(toEffect) );
this.player = ele.animate(effects, {
duration: duration,
duration: duration || 0,
easing: easingName,
playbackRate: playbackRate || 1
});

View File

@@ -25,7 +25,6 @@ ion-app {
}
ion-nav {
// container of header.toolbar-container, footer.toolbar-container and .nav-item-container
position: absolute;
top: 0;
right: 0;
@@ -33,75 +32,49 @@ ion-nav {
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
}
.toolbar-container {
// container of many toolbars for each view in the ion-nav
position: relative;
ion-view {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
// by default this is display: none;
// and the transition animation will display it
display: none;
flex-direction: column;
&.show-view {
display: flex;
}
}
ion-toolbar {
display: flex;
min-height: 4.4rem;
order: $flex-order-toolbar-top;
}
footer.toolbar-container {
.stage-off {
transform: translateX(9999px);
}
ion-toolbar[footer] {
order: $flex-order-toolbar-bottom;
}
ion-toolbar {
// one view's toolbar, sibling to many view toolbars inside of .toolbar-container
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.nav-item-container {
// container of many .nav-item's, each one containing one view
position: relative;
flex: 1;
order: $flex-order-view-content;
}
.tab-item-container {
// container of each content for each tab component within a tabs component
position: relative;
flex: 1;
order: $flex-order-view-content;
}
.nav-item {
// user created view, sibling to many .nav-item's, contained by .nav-item-container
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
// by default .nav-item is hidden
// and the transition animation will display it
display: none;
&.show-nav-item {
display: block;
}
}
ion-content {
// content within the user created view, contained by .nav-item
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
position: relative;
display: block;
flex: 1;
order: $flex-order-view-content;
}
.scroll-content {
// extra div to allow overflow scrolling
// extra div added by ion-content directive to allow for overflow scrolling
position: absolute;
top: 0;
right: 0;

View File

@@ -265,15 +265,15 @@ export class NavBase {
cleanup() {
this.items.forEach((item) => {
if (item && item.shouldDestroy) {
this.remove(item);
util.dom.raf(() => {
if (item) {
if (item.shouldDestroy) {
this.remove(item);
item.destroy();
});
}
} else if(item.state !== ACTIVE_STATE) {
item.cache();
}
}
});
}

View File

@@ -3,6 +3,9 @@ import {bind} from 'angular2/di';
import * as util from 'ionic/util';
import {NavController} from './nav-controller';
import {NavView} from './nav-view';
const SHOW_VIEW_CSS = 'show-view';
export class NavItem {
@@ -15,7 +18,6 @@ export class NavItem {
this.headerProtos = [];
this.toolbarViews = [];
this._titleEle = undefined;
this.disposals = [];
// if it's possible to go back from this nav item
this.enableBack = false;
@@ -25,13 +27,19 @@ export class NavItem {
// update if it's possible to go back from this nav item
this.enableBack = !!this.nav.getPrevious(this);
if (!this.created) {
return this.create();
}
return Promise.resolve();
return this.create().then(() => {
return new Promise(resolve => {
this.viewEle && this.viewEle.classList.add(SHOW_VIEW_CSS);
resolve();
});
});
}
create() {
if (this.created) {
return Promise.resolve();
}
this.created = true;
let resolve;
@@ -43,30 +51,16 @@ export class NavItem {
bind(NavItem).toValue(this)
]);
this.nav.loader.loadNextToExistingLocation(this.Component, this.nav.contentElementRef, injector).then((componentRef) => {
this.nav.loader.loadNextToExistingLocation(this.Component, this.nav.viewElementRef, injector).then((componentRef) => {
// content
this.component = componentRef;
this.contentEle = componentRef.location.domElement;
this.contentEle.classList.add('nav-item');
this.contentEle.setAttribute('id', 'nav-item-' + this.id);
this.viewEle = componentRef.location.domElement;
this.viewEle.setAttribute('id', 'view-' + this.id);
if (componentRef && componentRef._dispose) {
this.disposals.push(componentRef._dispose);
}
// TODO: talk to misko about correct way to set context
let context = {
boundElementIndex: 0,
parentView: {
_view: componentRef.location.parentView._view.componentChildViews[0]
}
};
for (let i = 0; i < this.headerProtos.length; i++) {
this.createHeader(this.headerProtos[i], context, injector);
if (componentRef && componentRef.dispose) {
this._dispose = componentRef.dispose;
}
resolve();
@@ -75,44 +69,21 @@ export class NavItem {
return promise;
}
createHeader(toolbarProtoView, context, injector) {
let headerContainer = this.nav.headerContainerRef;
if (!headerContainer) return;
let atIndex = -1;
let headerView = headerContainer.create(toolbarProtoView, atIndex, context, injector);
if (headerView) {
this.toolbarViews.push(headerView);
this.disposals.push(() => {
headerContainer.remove( headerContainer.indexOf(headerView) );
});
}
viewElement() {
return this.viewEle;
}
addHeader(toolbarProtoView) {
this.headerProtos.push(toolbarProtoView);
contentElement() {
return this.viewEle.querySelector('ion-content');
}
getContent() {
return this.contentEle;
toolbarElements() {
return this.viewEle.querySelectorAll('ion-toolbar');
}
getToolbars() {
let elements = [];
for (let i = 0; i < this.toolbarViews.length; i++) {
var toolbarView = this.toolbarViews[i];
elements.push(toolbarView._view.render._view.rootNodes[0]);
}
return elements;
}
getTitle() {
titleElement() {
if (this._titleEle === undefined) {
let toolbarElements = this.getToolbars();
let toolbarElements = this.toolbarElements();
for (let i = 0; i < toolbarElements.length; i++) {
var titleEle = toolbarElements[i].querySelector('ion-title');
if (titleEle) {
@@ -125,9 +96,9 @@ export class NavItem {
return this._titleEle;
}
getBackButton() {
backButtonElement() {
if (this._backBtn === undefined) {
let toolbarElements = this.getToolbars();
let toolbarElements = this.toolbarElements();
for (let i = 0; i < toolbarElements.length; i++) {
var backBtn = toolbarElements[i].querySelector('back-button');
if (backBtn) {
@@ -140,10 +111,12 @@ export class NavItem {
return this._backBtn;
}
cache() {
this.viewEle.classList.remove(SHOW_VIEW_CSS);
}
destroy() {
for (let i = 0; i < this.disposals.length; i++) {
this.disposals[i]();
}
this._dispose && this._dispose();
// just to help prevent any possible memory leaks
for (let name in this) {

View File

@@ -17,15 +17,8 @@ import {ToolbarContainer} from '../toolbar/toolbar-container';
}
})
@View({
template: `
<header class="toolbar-container">
<template header-anchor></template>
</header>
<section class="nav-item-container">
<template content-anchor></template>
</section>
`,
directives: [HeaderAnchor, ContentAnchor, ToolbarContainer]
template: `<template view-anchor></template>`,
directives: [ViewAnchor]
})
export class Nav extends NavBase {
constructor(elementRef: ElementRef, loader: DynamicComponentLoader, injector: Injector) {
@@ -40,20 +33,10 @@ export class Nav extends NavBase {
@Directive({
selector: '[header-anchor]'
selector: '[view-anchor]'
})
class HeaderAnchor {
constructor(@Ancestor() nav: Nav, viewContainerRef: ViewContainerRef) {
nav.headerContainerRef = viewContainerRef;
}
}
@Directive({
selector: '[content-anchor]'
})
class ContentAnchor {
class ViewAnchor {
constructor(@Ancestor() nav: Nav, elementRef: ElementRef) {
nav.contentElementRef = elementRef;
nav.viewElementRef = elementRef;
}
}

View File

@@ -1,6 +1,5 @@
<ion-toolbar *header><ion-title>First Page: {{ val }}</ion-title></ion-toolbar>
<ion-toolbar><ion-title>First Page: {{ val }}</ion-title></ion-toolbar>
<ion-content class="padding">

View File

@@ -1,14 +1,14 @@
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {NavController, HeaderTemplate, Toolbar, Content} from 'ionic/ionic';
import {NavController, Toolbar, Content} from 'ionic/ionic';
import {SecondPage} from './second-page';
@Component({selector: 'ion-view'})
@View({
templateUrl: 'pages/first-page.html',
directives: [HeaderTemplate, Toolbar, Content]
directives: [Toolbar, Content]
})
export class FirstPage {
constructor(

View File

@@ -1,5 +1,5 @@
<ion-toolbar *header><ion-title>Second Page</ion-title></ion-toolbar>
<ion-toolbar><ion-title>Second Page</ion-title></ion-toolbar>
<ion-content class="padding">

View File

@@ -1,14 +1,14 @@
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {NavController, NavParams, HeaderTemplate, Toolbar, Content} from 'ionic/ionic';
import {NavController, NavParams, Toolbar, Content} from 'ionic/ionic';
import {ThirdPage} from './third-page';
@Component()
@Component({selector: 'ion-view'})
@View({
templateUrl: 'pages/second-page.html',
directives: [HeaderTemplate, Toolbar, Content]
directives: [Toolbar, Content]
})
export class SecondPage {
constructor(

View File

@@ -1,5 +1,5 @@
<ion-toolbar *header><ion-title>Third Page</ion-title></ion-toolbar>
<ion-toolbar><ion-title>Third Page</ion-title></ion-toolbar>
<ion-content class="padding">

View File

@@ -1,13 +1,13 @@
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {NavController, HeaderTemplate, Toolbar, Content} from 'ionic/ionic';
import {NavController, Toolbar, Content} from 'ionic/ionic';
@Component()
@Component({selector: 'ion-view'})
@View({
templateUrl: 'pages/third-page.html',
directives: [HeaderTemplate, Toolbar, Content]
directives: [Toolbar, Content]
})
export class ThirdPage {
constructor(

View File

@@ -34,7 +34,6 @@ import {BackButton} from './back-button';
})
export class Toolbar {
constructor(navItem: NavItem, elementRef: ElementRef) {
this.navItem = navItem;
this.domElement = elementRef.domElement;
this.config = Toolbar.config.invoke(this);
@@ -95,18 +94,3 @@ export class Toolbar {
}
new IonicComponent(Toolbar, {});
/*
Used to find and register headers in a view, and this directive's
content will be moved up to the common toolbar location, and created
using the same context as the view's content area.
*/
@Directive({
selector: 'template[header]'
})
export class HeaderTemplate {
constructor(navItem: NavItem, protoViewRef: ProtoViewRef) {
navItem.addHeader(protoViewRef);
}
}

View File

@@ -2,7 +2,8 @@
// Toolbar
// --------------------------------------------------
$toolbar-background: #f7f7f8 !default;
$toolbar-background-color: #fff !default;
$toolbar-order: (
back-button: 10,
title: 20,
@@ -11,22 +12,11 @@ $toolbar-order: (
);
.toolbar-container {
background: $toolbar-background;
}
ion-toolbar {
background: $toolbar-background-color;
flex-direction: row;
align-items: center;
justify-content: space-between;
// by default ion-toolbar is display:none and
// the transition animation will add the show class
display: none;
&.show-toolbar {
display: flex;
}
}
.toolbar-inner {

View File

@@ -1,6 +1,6 @@
import {Animation} from '../animations/animation';
import {rafPromise} from '../util/dom'
import {Transition} from './transition'
import {rafPromise} from '../util/dom';
import {Transition} from './transition';
const DURATION = 500;
@@ -32,24 +32,24 @@ class IOSTransition extends Animation {
let leavingItem = navCtrl.getStagedLeavingItem();
// create animation for the entering content
let enteringContent = new Animation(enteringItem.getContent());
let enteringContent = new Animation(enteringItem.contentElement());
// create animation for the entering toolbars
let enteringToolbars = new Animation(enteringItem.getToolbars());
let enteringToolbars = new Animation(enteringItem.toolbarElements());
// create animation for the entering title element
let enteringTitle = new Animation(enteringItem.getTitle());
let enteringTitle = new Animation(enteringItem.titleElement());
// create animation for the leaving content
// leavingItem could be null, but the animation instance knows to do nothing
let leavingContent = new Animation(leavingItem && leavingItem.getContent());
let leavingContent = new Animation(leavingItem && leavingItem.contentElement());
// create animation for the leaving content
// leavingItem could be null, but the animation instance knows to do nothing
let leavingToolbars = new Animation(leavingItem && leavingItem.getToolbars());
let leavingToolbars = new Animation(leavingItem && leavingItem.toolbarElements());
// create animation for the entering title element
let leavingTitle = new Animation(leavingItem && leavingItem.getTitle());
let leavingTitle = new Animation(leavingItem && leavingItem.titleElement());
// entering item moves to center
// before starting, set enteringItem to display: block
@@ -68,7 +68,7 @@ class IOSTransition extends Animation {
// if the back button should show, then fade it in
if (enteringItem.enableBack) {
let enteringBackButton = new Animation(enteringItem.getBackButton())
let enteringBackButton = new Animation(enteringItem.backButtonElement())
enteringBackButton.from(OPACITY, 0).to(OPACITY, 1);
this.addChild(enteringBackButton);
}
@@ -88,7 +88,7 @@ class IOSTransition extends Animation {
.from(OPACITY, 1);
if (leavingItem) {
let leavingBackButton = new Animation(leavingItem.getBackButton());
let leavingBackButton = new Animation(leavingItem.backButtonElement());
leavingBackButton.from(OPACITY, 1).to(OPACITY, 0);
this.addChild(leavingBackButton);
}

View File

@@ -1,53 +1,19 @@
import {Transition} from './transition'
import {Animation} from '../animations/animation';
import {Transition} from './transition';
import {rafPromise} from '../util/dom';
const SHOW_TOOLBAR_CSS = 'show-toolbar';
const SHOW_NAV_ITEM_CSS = 'show-nav-item';
class NoneTransition {
class NoneTransition extends Animation {
constructor(navCtrl) {
// get the entering and leaving items
let enteringItem = navCtrl.getStagedEnteringItem();
let leavingItem = navCtrl.getStagedLeavingItem();
// show entering contet
let enteringContent = enteringItem.getContent();
enteringContent.classList.add(SHOW_NAV_ITEM_CSS);
// show entering headers
let enteringToolbars = enteringItem.getToolbars();
for (let i = 0; i < enteringToolbars.length; i++) {
enteringToolbars[i].classList.add(SHOW_TOOLBAR_CSS);
}
// hide the leaving item
if (leavingItem) {
let leavingContent = leavingItem.getContent();
if (leavingContent) {
leavingContent.classList.remove(SHOW_NAV_ITEM_CSS);
}
let leavingToolbars = leavingItem.getToolbars();
for (let i = 0; i < leavingToolbars.length; i++) {
leavingToolbars[i].classList.remove(SHOW_TOOLBAR_CSS);
}
}
super();
}
stage() {
// immediately resolve
return Promise.resolve();
return rafPromise();
}
play() {
// immediately resolve
return Promise.resolve();
}
dispose(){}
}
Transition.register('none', NoneTransition);