house of pane

This commit is contained in:
Adam Bradley
2015-06-05 15:03:05 -05:00
parent 4fa2e42a9f
commit 5c06eaff7e
14 changed files with 118 additions and 98 deletions

View File

@ -28,7 +28,7 @@ ion-nav {
height: 100%; height: 100%;
} }
ion-nav-pane { ion-pane {
position: absolute; position: absolute;
top: 0; top: 0;
right: 0; right: 0;
@ -98,18 +98,6 @@ ion-content {
will-change: scroll-position; will-change: scroll-position;
} }
$swipe-handle-width: 20px !default;
swipe-handle {
position: absolute;
top: 0;
left: 0;
display: block;
width: $swipe-handle-width;
height: 100%;
z-index: $z-index-swipe-handle;
}
// Hardware Acceleration // Hardware Acceleration
.transitioning { .transitioning {

View File

@ -3,7 +3,7 @@ import {Ancestor} from 'angular2/src/core/annotations_impl/visibility';
import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations'; import {Component, Directive} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view'; import {View} from 'angular2/src/core/annotations_impl/view';
import {NavController, NavParams, NavbarTemplate, Navbar, Content, Nav, NavPane, List, Item} from 'ionic/ionic'; import {NavController, NavParams, NavbarTemplate, Navbar, Content, Nav, List, Item} from 'ionic/ionic';
import {HackerNews} from '../hn' import {HackerNews} from '../hn'

View File

@ -93,6 +93,31 @@ $content-padding: 10px !default;
} }
// Swipe Handle
// --------------------------------------------------
$swipe-handle-width: 20px !default;
$swipe-handle-top: 80px !default;
$swipe-handle-bottom: 80px !default;
.swipe-handle {
position: absolute;
top: $swipe-handle-top;
left: 0;
bottom: $swipe-handle-bottom;
width: $swipe-handle-width;
z-index: $z-index-swipe-handle;
background: red;
opacity: 0.2;
transform: translate3d(-999px, 0px, 0px);
&.show-handle {
transform: translate3d(0px, 0px, 0px);
}
}
// Node Inserted Animation // Node Inserted Animation
// -------------------------------------------------- // --------------------------------------------------
// Used by the toolbar to know when the title has been rendered // Used by the toolbar to know when the title has been rendered

View File

@ -11,22 +11,22 @@ import {bind} from 'angular2/di';
import {NavController} from './nav-controller'; import {NavController} from './nav-controller';
import {NavItem, NavParams} from './nav-item'; import {NavItem, NavParams} from './nav-item';
import {NavPane, NavBarSection} from './nav-pane'; import {Pane, NavBarSection} from './pane';
import {Transition, ClickBlock} from 'ionic/ionic'; import {Transition, ClickBlock} from 'ionic/ionic';
import * as util from 'ionic/util'; import * as util from 'ionic/util';
let itemsIds = -1;
export class NavBase { export class NavBase {
constructor( constructor(
parentNavBase: NavBase, parent: NavBase,
compiler: Compiler, compiler: Compiler,
elementRef: ElementRef, elementRef: ElementRef,
loader: DynamicComponentLoader, loader: DynamicComponentLoader,
injector: Injector injector: Injector
) { ) {
this.parent = parent;
this.compiler = compiler; this.compiler = compiler;
this.elementRef = elementRef; this.elementRef = elementRef;
this.domElement = elementRef.domElement; this.domElement = elementRef.domElement;
@ -39,7 +39,7 @@ export class NavBase {
this.sbActive = false; this.sbActive = false;
this.panes = {}; this.panes = {};
this.id = ++itemsIds; this.id = ++itemIds;
this.childIds = -1; this.childIds = -1;
} }
@ -52,9 +52,9 @@ export class NavBase {
} }
getPane(itemStructure, callback) { getPane(itemStructure, callback) {
// this gets or creates the NavPane which similar nav items live in // this gets or creates the Pane which similar nav items live in
// Nav items with just a navbar/content would all use the same NavPane // Nav items with just a navbar/content would all use the same Pane
// Tabs and view's without a navbar would get a different NavPanes // Tabs and view's without a navbar would get a different Panes
if (this.panes[itemStructure.key]) { if (this.panes[itemStructure.key]) {
// nav pane which the entering component already exists // nav pane which the entering component already exists
@ -64,34 +64,38 @@ export class NavBase {
// create a new nav pane // create a new nav pane
this.panes[itemStructure.key] = null; this.panes[itemStructure.key] = null;
// add a NavPane element let injector = this.injector.resolveAndCreateChild([
// when the NavPane is added, it'll also add its reference to the panes object bind(NavBase).toValue(this)
this.loader.loadNextToExistingLocation(NavPane, this.anchorElementRef, null).then(() => { ]);
// get the navPane reference by name // add a Pane element
let navPane = this.panes[itemStructure.key]; // 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 element inside the NavPane to add sections to // get the pane reference by name
let sectionViewContainerRef = navPane.sectionAnchorElementRef; let pane = this.panes[itemStructure.key];
// get the element inside the Pane to add sections to
let sectionViewContainerRef = pane.sectionAnchorElementRef;
let promises = []; let promises = [];
let sectionsToAdd = [] let sectionsToAdd = []
// decide which sections should be added to this NavPane, ie: nav bars, tab bars, etc. // decide which sections should be added to this Pane, ie: nav bars, tab bars, etc.
// add only the sections it needs // add only the sections it needs
if (itemStructure.navbar) { if (itemStructure.navbar) {
sectionsToAdd.push(NavBarSection); sectionsToAdd.push(NavBarSection);
} }
// add the sections which this type of NavPane requires // add the sections which this type of Pane requires
sectionsToAdd.forEach(SectionClass => { sectionsToAdd.forEach(SectionClass => {
// as each section is compiled and added to the NavPane // as each section is compiled and added to the Pane
// the section will add a reference to itself in the NavPane's sections object // the section will add a reference to itself in the Pane's sections object
promises.push( this.loader.loadNextToExistingLocation(SectionClass, sectionViewContainerRef, null) ); promises.push( this.loader.loadNextToExistingLocation(SectionClass, sectionViewContainerRef, null) );
}); });
// wait for all of the sections to resolve // wait for all of the sections to resolve
Promise.all(promises).then(() => { Promise.all(promises).then(() => {
callback(navPane); callback(pane);
}); });
}); });
@ -99,10 +103,10 @@ export class NavBase {
} }
} }
addPane(navPane) { addPane(pane) {
for (let np in this.panes) { for (let np in this.panes) {
if (this.panes[np] === null) { if (this.panes[np] === null) {
this.panes[np] = navPane; this.panes[np] = pane;
return; return;
} }
} }
@ -384,6 +388,16 @@ export class NavBase {
} }
} }
swipeBackEnabled() {
if (this.items.length > 1) {
let activeItem = this.getActive();
if (activeItem) {
return activeItem.enableBack;
}
}
return false;
}
transitionStart(opts) { transitionStart(opts) {
if (opts.isAnimated) { if (opts.isAnimated) {
// block possible clicks during transition // block possible clicks during transition
@ -513,7 +527,7 @@ export class NavBase {
instances.push(item.instance); instances.push(item.instance);
} }
} }
return instances return instances;
} }
isActive(item) { isActive(item) {
@ -528,14 +542,6 @@ export class NavBase {
return this.domElement.offsetWidth; return this.domElement.offsetWidth;
} }
get swipeBackEnabled() {
// let activeItem = this.nav.getActive();
// if (activeItem) {
// return activeItem.enableBack;
// }
return false;
}
} }
const ACTIVE_STATE = 1; const ACTIVE_STATE = 1;
@ -545,3 +551,4 @@ const STAGED_LEAVING_STATE = 4;
const ACTIVELY_ENTERING_STATE = 5; const ACTIVELY_ENTERING_STATE = 5;
const ACTIVELY_LEAVING_STATE = 6; const ACTIVELY_LEAVING_STATE = 6;
let itemIds = -1;

View File

@ -4,9 +4,7 @@ import {bind} from 'angular2/di';
import * as util from 'ionic/util'; import * as util from 'ionic/util';
import {NavController} from './nav-controller'; import {NavController} from './nav-controller';
import {Nav} from './nav';
import {NavBase} from './nav-base'; import {NavBase} from './nav-base';
import {TabPane, NavPane, NavPaneSection} from './nav';
export class NavItem { export class NavItem {
@ -34,7 +32,7 @@ export class NavItem {
stage(callback) { stage(callback) {
// update if it's possible to go back from this nav item // update if it's possible to go back from this nav item
//this.enableBack = !!this.navBase.getPrevious(this); this.enableBack = !!this.navBase.getPrevious(this);
if (this.instance) { if (this.instance) {
// already compiled this view // already compiled this view
@ -48,7 +46,7 @@ export class NavItem {
// does it have a navbar? Is it tabs? Should it not have a navbar or any toolbars? // does it have a navbar? Is it tabs? Should it not have a navbar or any toolbars?
let itemStructure = getProtoViewStructure(componentProtoViewRef); let itemStructure = getProtoViewStructure(componentProtoViewRef);
// get the appropriate NavPane which this NavItem will fit into // get the appropriate Pane which this NavItem will fit into
this.navBase.getPane(itemStructure, pane => { this.navBase.getPane(itemStructure, pane => {
// create a new injector just for this NavItem // create a new injector just for this NavItem

View File

@ -1,6 +1,6 @@
import {Parent} from 'angular2/src/core/annotations_impl/visibility'; import {Parent} from 'angular2/src/core/annotations_impl/visibility';
import {Component, Directive, onInit} from 'angular2/src/core/annotations_impl/annotations'; import {Component, Directive, onInit} from 'angular2/src/core/annotations_impl/annotations';
import {Optional} from 'angular2/src/di/annotations_impl' import {Optional} from 'angular2/src/di/annotations_impl';
import {View} from 'angular2/src/core/annotations_impl/view'; import {View} from 'angular2/src/core/annotations_impl/view';
import {ElementRef} from 'angular2/src/core/compiler/element_ref'; import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader';
@ -9,7 +9,6 @@ import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {Compiler} from 'angular2/angular2'; import {Compiler} from 'angular2/angular2';
import {NavBase} from './nav-base'; import {NavBase} from './nav-base';
import {SwipeHandle} from './swipe-handle';
import {IonicComponent} from '../../config/component'; import {IonicComponent} from '../../config/component';

View File

@ -5,19 +5,21 @@ import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {ElementRef} from 'angular2/src/core/compiler/element_ref'; import {ElementRef} from 'angular2/src/core/compiler/element_ref';
import {Nav} from './nav'; import {Nav} from './nav';
import {SwipeHandle} from './swipe-handle';
@Component({selector:'ion-nav-pane'}) @Component({selector:'ion-pane'})
@View({ @View({
template: ` template: `
<template nav-section-anchor></template> <template pane-anchor></template>
<section class="content-container"> <section class="content-container">
<template content-anchor></template> <template content-anchor></template>
<div class="swipe-handle"></div>
</section> </section>
`, `,
directives: [NavPaneSectionAnchor, NavContentAnchor] directives: [PaneAnchor, PaneContentAnchor, SwipeHandle]
}) })
export class NavPane { export class Pane {
constructor(@Parent() nav: Nav, viewContainerRef: ViewContainerRef) { constructor(@Parent() nav: Nav, viewContainerRef: ViewContainerRef) {
this.viewContainerRef = viewContainerRef; this.viewContainerRef = viewContainerRef;
this.sections = {}; this.sections = {};
@ -30,11 +32,11 @@ export class NavPane {
@Directive({ @Directive({
selector: 'template[nav-section-anchor]' selector: 'template[pane-anchor]'
}) })
class NavPaneSectionAnchor { class PaneAnchor {
constructor(@Parent() navPane: NavPane, elementRef: ElementRef) { constructor(@Parent() pane: Pane, elementRef: ElementRef) {
navPane.sectionAnchorElementRef = elementRef; pane.sectionAnchorElementRef = elementRef;
} }
} }
@ -42,9 +44,9 @@ class NavPaneSectionAnchor {
@Directive({ @Directive({
selector: 'template[content-anchor]' selector: 'template[content-anchor]'
}) })
class NavContentAnchor { class PaneContentAnchor {
constructor(@Parent() navPane: NavPane, viewContainerRef: ViewContainerRef) { constructor(@Parent() pane: Pane, viewContainerRef: ViewContainerRef) {
navPane.contentContainerRef = viewContainerRef; pane.contentContainerRef = viewContainerRef;
} }
} }
@ -58,12 +60,12 @@ class NavContentAnchor {
template: ` template: `
<template section-anchor></template> <template section-anchor></template>
`, `,
directives: [NavBarSectionAnchor] directives: [PaneSectionAnchor]
}) })
export class NavBarSection { export class NavBarSection {
constructor(@Parent() navPane: NavPane, viewContainerRef: ViewContainerRef, elementRef: ElementRef) { constructor(@Parent() pane: Pane, viewContainerRef: ViewContainerRef, elementRef: ElementRef) {
this.navPane = navPane; this.pane = pane;
navPane.addSection('navbar', this); pane.addSection('navbar', this);
} }
} }
@ -72,7 +74,7 @@ export class NavBarSection {
@Directive({ @Directive({
selector: 'template[section-anchor]' selector: 'template[section-anchor]'
}) })
class NavBarSectionAnchor { class PaneSectionAnchor {
constructor(@Parent() navBarSection: NavBarSection, viewContainerRef: ViewContainerRef) { constructor(@Parent() navBarSection: NavBarSection, viewContainerRef: ViewContainerRef) {
navBarSection.viewContainerRef = viewContainerRef; navBarSection.viewContainerRef = viewContainerRef;
} }

View File

@ -1,23 +1,27 @@
import {ElementRef} from 'angular2/angular2' import {ElementRef} from 'angular2/angular2'
import {Parent} from 'angular2/src/core/annotations_impl/visibility';
import {Directive} from 'angular2/src/core/annotations_impl/annotations'; import {Directive} from 'angular2/src/core/annotations_impl/annotations';
import {Optional} from 'angular2/src/di/annotations_impl';
import {Gesture} from 'ionic/gestures/gesture'; import {Gesture} from 'ionic/gestures/gesture';
import {Nav} from './nav'; import {NavBase} from './nav-base';
@Directive({ @Directive({
selector: 'swipe-handle', selector: '.swipe-handle',
hostProperties: { hostProperties: {
'!nav.swipeBackEnabled': 'hidden' 'showHandle()': 'class.show-handle'
} }
}) })
export class SwipeHandle { export class SwipeHandle {
constructor(@Parent() nav: Nav, elementRef: ElementRef) { constructor(
@Optional() navBase: NavBase,
elementRef: ElementRef
) {
if (!navBase) return;
this.navBase = navBase;
let gesture = new Gesture(elementRef.domElement); let gesture = new Gesture(elementRef.domElement);
this.nav = nav;
gesture.listen(); gesture.listen();
gesture.on('panend', onDragEnd); gesture.on('panend', onDragEnd);
@ -58,7 +62,7 @@ export class SwipeHandle {
} }
} }
nav.swipeBackEnd(completeSwipeBack, progress, playbackRate); navBase.swipeBackEnd(completeSwipeBack, progress, playbackRate);
startX = null; startX = null;
} }
@ -69,14 +73,18 @@ export class SwipeHandle {
ev.stopPropagation(); ev.stopPropagation();
startX = ev.gesture.center.x; startX = ev.gesture.center.x;
swipeableAreaWidth = nav.width() - startX; swipeableAreaWidth = navBase.width() - startX;
nav.swipeBackStart(); navBase.swipeBackStart();
} }
nav.swipeBackProgress( (ev.gesture.center.x - startX) / swipeableAreaWidth ); navBase.swipeBackProgress( (ev.gesture.center.x - startX) / swipeableAreaWidth );
} }
} }
showHandle() {
return (this.navBase ? this.navBase.swipeBackEnabled() : false);
}
} }

View File

@ -1,6 +1,5 @@
import {Component, Parent, Decorator, View, NgElement} from 'angular2/angular2' import {Component, Parent, Decorator, View, NgElement} from 'angular2/angular2'
import {Nav} from 'ionic/components/nav/nav' import {Nav} from 'ionic/components/nav/nav'
//import {NavPane} from 'ionic/components/nav-pane/nav-pane'
import * as util from 'ionic/util' import * as util from 'ionic/util'
// TODO consider more explicit API, a la tabs // TODO consider more explicit API, a la tabs

View File

@ -43,7 +43,6 @@ import {IonicComponent} from 'ionic/config/component';
export class Tab { export class Tab {
constructor( constructor(
@Parent() tabs: Tabs, @Parent() tabs: Tabs,
@Optional() parentNavBase: NavBase,
compiler: Compiler, compiler: Compiler,
elementRef: ElementRef, elementRef: ElementRef,
loader: DynamicComponentLoader, loader: DynamicComponentLoader,
@ -51,13 +50,12 @@ export class Tab {
viewContainerRef: ViewContainerRef viewContainerRef: ViewContainerRef
) { ) {
this.navBase = new NavBase(parentNavBase, compiler, elementRef, loader, injector); this.navBase = new NavBase(tabs.navBase, compiler, elementRef, loader, injector);
this.parentNavBase = parentNavBase; if (tabs.navBase.parent) {
if (parentNavBase) { this.sections = tabs.navBase.parent.panes['_n'].sections;
this.sections = parentNavBase.panes['_n'].sections;
} }
this.item = new NavItem(parentNavBase); this.item = new NavItem(this.navBase);
this.item.setInstance(this); this.item.setInstance(this);
this.item.setViewElement(elementRef.domElement); this.item.setViewElement(elementRef.domElement);
tabs.add(this.item); tabs.add(this.item);

View File

@ -13,7 +13,6 @@ import {IonicComponent} from '../../config/component';
import {Tab} from './tab'; import {Tab} from './tab';
import {TabButton} from './tab-button'; import {TabButton} from './tab-button';
import {Icon} from '../icon/icon'; import {Icon} from '../icon/icon';
import {Nav, NavPane} from '../nav/nav';
import {NavItem} from '../nav/nav-item'; import {NavItem} from '../nav/nav-item';
import {NavBase} from '../nav/nav-base'; import {NavBase} from '../nav/nav-base';

View File

@ -1,3 +1,2 @@
<ion-nav [initial]="initial"> <ion-nav [initial]="initial"></ion-nav>
</ion-nav>

View File

@ -1,16 +1,8 @@
<ion-tabs> <ion-tabs>
<ion-tab [initial]="tab1Initial" tab-title="Tab 1" tab-icon="ion-home"> <ion-tab [initial]="tab1Initial" tab-title="Tab 1" tab-icon="ion-home"></ion-tab>
</ion-tab>
<ion-tab [initial]="tab2Initial" tab-title="Tab 2" tab-icon="ion-star" class="tab2"> <ion-tab [initial]="tab2Initial" tab-title="Tab 2" tab-icon="ion-star" class="tab2"></ion-tab>
</ion-tab>
</ion-tabs> </ion-tabs>
<style>
.tab2 f {
background: green
}
</style>

View File

@ -19,6 +19,12 @@
f:last-of-type { f:last-of-type {
background: red; background: red;
} }
ion-tab:nth-of-type(2) f {
background: green;
}
ion-tab:nth-of-type(3) f {
background: yellow;
}
</style> </style>
</head> </head>
<body> <body>