From 36f82b2473e08a61bbe18061d70c413074e93965 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Thu, 29 Oct 2015 14:37:49 -0500 Subject: [PATCH] refactor(NavController): restructuring and perf improvements --- ionic/animations/animation.ts | 4 +- ionic/components/app/structure.scss | 144 ++++++---- ionic/components/button/button.scss | 1 - ionic/components/content/content.scss | 65 ----- ionic/components/content/content.ts | 1 + ionic/components/menu/menu.ts | 5 + ionic/components/modal/modal.scss | 19 -- ionic/components/modal/modal.ts | 7 +- ionic/components/nav-bar/modes/ios.scss | 4 + ionic/components/nav-bar/nav-bar.scss | 10 +- ionic/components/nav-bar/nav-bar.ts | 19 +- ionic/components/nav/nav-controller.ts | 81 +++--- ionic/components/nav/nav.ts | 269 +----------------- ionic/components/nav/test/basic/e2e.ts | 8 +- ionic/components/nav/test/basic/index.ts | 115 +++++--- ionic/components/nav/view-controller.ts | 112 ++++---- .../components/overlay/overlay-controller.ts | 10 +- .../search-bar/test/floating/e2e.ts | 6 +- .../search-bar/test/floating/main.html | 3 - ionic/components/segment/test/basic/e2e.ts | 14 +- ionic/components/tabs/tab.ts | 95 +++---- ionic/components/tabs/tabs.scss | 5 - ionic/components/tabs/tabs.ts | 89 +++--- .../tabs/test/tab-bar-scenarios/index.ts | 2 + .../tabs/test/tab-bar-scenarios/main.html | 8 - .../tabs/test/tab-bar-scenarios/styles.css | 12 + ionic/components/toolbar/modes/ios.scss | 2 + ionic/components/toolbar/toolbar.scss | 2 - ionic/config/config.ts | 5 + ionic/config/decorators.ts | 35 +-- ionic/config/modes.ts | 1 + ionic/config/test/config.spec.ts | 36 +++ ionic/gestures/hammer.ts | 6 +- ionic/ionic.core.scss | 1 - ionic/platform/test/platform.spec.ts | 14 + ionic/transitions/ios-transition.ts | 76 ++--- ionic/transitions/md-transition.ts | 93 +----- ionic/util/util.scss | 45 ++- ionic/util/util.ts | 10 +- package.json | 1 - scripts/e2e/e2e.template.html | 21 +- scripts/e2e/e2e.template.js | 2 +- scripts/snapshot/ionic.snapshot.js | 2 +- scripts/snapshot/snapshot.config.js | 4 +- scripts/snapshot/snapshot.task.js | 15 +- 45 files changed, 592 insertions(+), 887 deletions(-) delete mode 100644 ionic/components/content/content.scss create mode 100644 ionic/components/tabs/test/tab-bar-scenarios/styles.css diff --git a/ionic/animations/animation.ts b/ionic/animations/animation.ts index 2894fadcba..f464cfabf3 100644 --- a/ionic/animations/animation.ts +++ b/ionic/animations/animation.ts @@ -251,7 +251,7 @@ export class Animation { }); } - if (self._duration > 64) { + if (self._duration > 32) { // begin each animation when everything is rendered in their starting point // give the browser some time to render everything in place before starting setTimeout(kickoff, this._opts.renderDelay); @@ -550,7 +550,7 @@ class Animate { this.toEffect = parseEffect(toEffect); - this.shouldAnimate = (duration > 64); + this.shouldAnimate = (duration > 32); if (!this.shouldAnimate) { return inlineStyle(ele, this.toEffect); diff --git a/ionic/components/app/structure.scss b/ionic/components/app/structure.scss index 8c06d7903f..34b505f933 100644 --- a/ionic/components/app/structure.scss +++ b/ionic/components/app/structure.scss @@ -82,79 +82,123 @@ body { background-color: $background-color; } -ion-app { +ion-app, +ion-nav, +ion-tabs { display: flex; flex-direction: column; - - overflow: hidden; - height: 100%; - max-width: 100%; - max-height: 100%; - margin: 0; - padding: 0; - -} - -ion-nav { + position: absolute; + top: 0; + left: 0; + width: 100%; height: 100%; } -ion-pane, -ion-view.pane-view { +ion-navbar-section { + display: block; + width: 100%; + min-height: 50px; +} + +ion-content-section { + display: block; + flex: 1; + position: relative; + width: 100%; + height: 100%; +} + +ion-page { + display: flex; + flex-direction: column; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + transform: translateZ(0); +} + +ion-content { + position: relative; + display: block; + width: 100%; + height: 100%; + flex: 1; + background-color: $background-color; +} + +scroll-content { position: absolute; top: 0; right: 0; bottom: 0; left: 0; - width: 100%; - height: 100%; - overflow: hidden; - - display: flex; - flex-direction: column; + display: block; + overflow-y: scroll; + overflow-x: hidden; + -webkit-overflow-scrolling: touch; + will-change: scroll-position; } -ion-view.pane-view { - background: transparent; -} - -ion-view { - display: none; +ion-tab-bar { + display: block; position: absolute; top: 0; left: 0; width: 100%; + min-height: 50px; +} + +ion-tab-section { + display: block; + position: relative; + top: 0; + left: 0; + width: 100%; height: 100%; - flex-direction: column; - - background-color: $background-color; - - transform: translateZ(0px); - - &.show-view { - display: flex; - } + overflow: hidden; } -[no-navbar] > ion-navbar-section { - display: none; +ion-page.tab-subpage { + position: fixed; + z-index: 10; } -ion-navbar-section { - position: relative; - min-height: 4.4rem; - z-index: $z-index-navbar-section; +ion-navbar { + display: block; + position: absolute; + top: 0; + left: 0; + width: 100%; + min-height: 50px; + z-index: 10; } -ion-content-section { - position: relative; - z-index: $z-index-content-section; - flex: 1; - order: $flex-order-view-content; +ion-navbar-section ion-navbar.toolbar { + position: absolute; } -[hidden], -template, -root-anchor { - display: none !important; +ion-toolbar { + display: block; + width: 100%; + height: 50px; +} + +ion-toolbar[position=bottom] { + bottom: 0; + z-index: 10; +} + +ion-scrollbar { + position: fixed; + top: 0; + right: 0; + z-index: 10; + width: 10px; +} + +.hide-navtive-scrollbar ion-content { + padding-right: 20px; + width: calc(100% + 20px); } diff --git a/ionic/components/button/button.scss b/ionic/components/button/button.scss index eeb28cb16d..487944937f 100644 --- a/ionic/components/button/button.scss +++ b/ionic/components/button/button.scss @@ -29,7 +29,6 @@ button, align-items: center; justify-content: center; - will-change: background-color, opacity; transition: background-color, opacity 100ms linear; margin: $button-margin; diff --git a/ionic/components/content/content.scss b/ionic/components/content/content.scss deleted file mode 100644 index e6b71c8744..0000000000 --- a/ionic/components/content/content.scss +++ /dev/null @@ -1,65 +0,0 @@ - -// Content -// -------------------------------------------------- - -$content-background-color: $background-color !default; - - -ion-content { - position: relative; - display: block; - flex: 1; - background-color: $content-background-color; -} - -scroll-content { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - display: block; - overflow-y: scroll; // has to be scroll for momentum scrolling, not auto - overflow-x: hidden; - -webkit-overflow-scrolling: touch; - will-change: scroll-position; -} - - - -// Content Padding -// -------------------------------------------------- - -$content-padding: 16px !default; - - -[padding], -[padding] > scroll-content { - padding: $content-padding; -} - -[padding-top] { - padding-top: $content-padding; -} - -[padding-right] { - padding-right: $content-padding; -} - -[padding-bottom] { - padding-bottom: $content-padding; -} - -[padding-left] { - padding-left: $content-padding; -} - -[padding-vertical] { - padding-top: $content-padding; - padding-bottom: $content-padding; -} - -[padding-horizontal] { - padding-right: $content-padding; - padding-left: $content-padding; -} diff --git a/ionic/components/content/content.ts b/ionic/components/content/content.ts index 6f36aa234c..2fca0a00b5 100644 --- a/ionic/components/content/content.ts +++ b/ionic/components/content/content.ts @@ -42,6 +42,7 @@ export class Content extends Ion { if (viewCtrl) { viewCtrl.setContent(this); + viewCtrl.setContentRef(elementRef); } } diff --git a/ionic/components/menu/menu.ts b/ionic/components/menu/menu.ts index aac93507f4..7c59d37a8b 100644 --- a/ionic/components/menu/menu.ts +++ b/ionic/components/menu/menu.ts @@ -138,6 +138,11 @@ export class Menu extends Ion { this._type = new menuTypeCls(this); this.type = type; + + if (this.config.get('animate') === false) { + this._type.open.duration(33); + this._type.close.duration(33); + } } /** diff --git a/ionic/components/modal/modal.scss b/ionic/components/modal/modal.scss index 1c2881e1c1..63d2528bf3 100644 --- a/ionic/components/modal/modal.scss +++ b/ionic/components/modal/modal.scss @@ -10,22 +10,3 @@ $modal-inset-mode-right: 20% !default; $modal-inset-mode-bottom: 20% !default; $modal-inset-mode-left: 20% !default; $modal-inset-mode-min-height: 240px !default; - - -ion-modal { - position: absolute; - top: 0; - z-index: $z-index-overlay; - overflow: hidden; - min-height: 100%; - width: 100%; - background-color: $modal-background-color; - - display: flex; - flex-direction: column; - - transform: translate3d(0px, 100%, 0px); - &.show-overlay { - transform: translate3d(0px, 0px, 0px); - } -} diff --git a/ionic/components/modal/modal.ts b/ionic/components/modal/modal.ts index 2fdb6f4dfd..05fd95b13f 100644 --- a/ionic/components/modal/modal.ts +++ b/ionic/components/modal/modal.ts @@ -3,7 +3,6 @@ import {Injectable} from 'angular2/angular2'; import {OverlayController} from '../overlay/overlay-controller'; import {Config} from '../../config/config'; import {Animation} from '../../animations/animation'; -import {makeComponent} from '../../config/decorators'; import * as util from 'ionic/util'; /** @@ -46,11 +45,7 @@ export class Modal { * @returns {TODO} TODO */ open(componentType: Type, opts={}) { - let modalComponent = makeComponent(componentType, { - selector: 'ion-modal' - }); - - return this.ctrl.open(OVERLAY_TYPE, modalComponent, util.extend(this._defaults, opts)); + return this.ctrl.open(OVERLAY_TYPE, componentType, util.extend(this._defaults, opts)); } /** diff --git a/ionic/components/nav-bar/modes/ios.scss b/ionic/components/nav-bar/modes/ios.scss index d0d91f654b..1ccea60915 100644 --- a/ionic/components/nav-bar/modes/ios.scss +++ b/ionic/components/nav-bar/modes/ios.scss @@ -8,3 +8,7 @@ $navbar-ios-height: 4.4rem !default; ion-navbar-section { min-height: $navbar-ios-height; } + +.back-button { + transform: translateZ(0px); +} diff --git a/ionic/components/nav-bar/nav-bar.scss b/ionic/components/nav-bar/nav-bar.scss index 413cfbdfbd..e7b31f10f5 100644 --- a/ionic/components/nav-bar/nav-bar.scss +++ b/ionic/components/nav-bar/nav-bar.scss @@ -4,17 +4,11 @@ ion-navbar.toolbar { - position: absolute; - display: none; - - &.show-navbar { - display: flex; - } + display: flex; } .back-button { - order: map-get($toolbar-order, backButton); - transform: translateZ(0px); + order: map-get($toolbar-order, backButton); display: none; &.show-back-button { diff --git a/ionic/components/nav-bar/nav-bar.ts b/ionic/components/nav-bar/nav-bar.ts index 89c4869a58..533bfabc9c 100644 --- a/ionic/components/nav-bar/nav-bar.ts +++ b/ionic/components/nav-bar/nav-bar.ts @@ -1,4 +1,4 @@ -import {Component, Directive, Optional, ElementRef, Renderer, TemplateRef, forwardRef, Inject} from 'angular2/angular2'; +import {Component, Directive, Optional, ElementRef, Renderer, TemplateRef, forwardRef, Inject, ViewContainerRef} from 'angular2/angular2'; import {Ion} from '../ion'; import {Icon} from '../icon/icon'; @@ -65,6 +65,9 @@ class BackButtonText extends Ion { '' + '' + '
', + host: { + '[hidden]': '_hidden' + }, directives: [BackButton, BackButtonText, Icon] }) export class Navbar extends ToolbarBase { @@ -105,6 +108,10 @@ export class Navbar extends ToolbarBase { this.app.setTitle(this.getTitleText()); } + setHidden(isHidden) { + this._hidden = isHidden + } + } @@ -118,9 +125,13 @@ export class Navbar extends ToolbarBase { }) export class NavbarTemplate { constructor( - @Optional() viewCtrl: ViewController, - @Optional() templateRef: TemplateRef + viewContainerRef: ViewContainerRef, + templateRef: TemplateRef, + @Optional() viewCtrl: ViewController ) { - viewCtrl && viewCtrl.setNavbarTemplateRef(templateRef); + if (viewCtrl) { + viewCtrl.setNavbarTemplateRef(templateRef); + viewCtrl.setNavbarViewRef(viewContainerRef); + } } } diff --git a/ionic/components/nav/nav-controller.ts b/ionic/components/nav/nav-controller.ts index 9c599e1074..8ee53827db 100644 --- a/ionic/components/nav/nav-controller.ts +++ b/ionic/components/nav/nav-controller.ts @@ -1,7 +1,6 @@ import {Compiler, ElementRef, Injector, provide, NgZone, DynamicComponentLoader, AppViewManager, Renderer} from 'angular2/angular2'; import {Ion} from '../ion'; -import {makeComponent} from '../../config/decorators'; import {IonicApp} from '../app/app'; import {Config} from '../../config/config'; import {ViewController} from './view-controller'; @@ -445,6 +444,9 @@ export class NavController extends Ion { if (!opts.animation) { opts.animation = this.config.get('viewTransition'); } + if (this.config.get('animate') === false) { + opts.animate = false; + } // wait for the new view to complete setup enteringView.stage(() => { @@ -508,34 +510,51 @@ export class NavController extends Ion { } - /** - * @private - * TODO - */ - compileView(componentType) { - // create a new ion-view annotation - let viewComponentType = makeComponent(componentType, { - selector: 'ion-view', - host: { - '[class.pane-view]': '_paneView' - } - }); - - // compile the Component - return this._compiler.compileInHost(viewComponentType); - } - - /** - * @private - * TODO - */ - loadNextToAnchor(type, location, viewCtrl) { + loadPage(viewCtrl, navbarContainerRef, done) { let providers = this.providers.concat(Injector.resolve([ provide(ViewController, {useValue: viewCtrl}), provide(NavParams, {useValue: viewCtrl.params}) ])); - return this._loader.loadNextToLocation(type, location, providers); + this._loader.loadIntoLocation(viewCtrl.componentType, this.elementRef, 'contents', providers).then(componentRef => { + + viewCtrl.addDestroy(() => { + componentRef.dispose(); + }); + + // a new ComponentRef has been created + // set the ComponentRef's instance to this ViewController + viewCtrl.setInstance(componentRef.instance); + + // remember the ElementRef to the ion-page elementRef that was just created + viewCtrl.setPageRef(componentRef.location); + + if (!navbarContainerRef) { + navbarContainerRef = viewCtrl.getNavbarViewRef(); + } + + let navbarTemplateRef = viewCtrl.getNavbarTemplateRef(); + if (navbarContainerRef && navbarTemplateRef) { + let navbarView = navbarContainerRef.createEmbeddedView(navbarTemplateRef); + + viewCtrl.addDestroy(() => { + let index = navbarContainerRef.indexOf(navbarView); + if (index > -1) { + navbarContainerRef.remove(index); + } + }); + } + + if (this._views.length === 1) { + this._zone.runOutsideAngular(() => { + setTimeout(() => { + this.renderer.setElementClass(this.elementRef, 'has-views', true); + }, 200); + }); + } + + done(viewCtrl); + }); } /** @@ -543,6 +562,7 @@ export class NavController extends Ion { * TODO */ swipeBackStart() { + return; if (!this.app.isEnabled() || !this.canSwipeBack()) { return; } @@ -594,6 +614,7 @@ export class NavController extends Ion { * @param {TODO} progress TODO */ swipeBackProgress(value) { + return; if (this._sbTrans) { // continue to disable the app while actively dragging this.app.setEnabled(false, 4000); @@ -610,6 +631,7 @@ export class NavController extends Ion { * @param {number} rate How fast it closes */ swipeBackEnd(completeSwipeBack, rate) { + return; if (!this._sbTrans) return; // disables the app during the transition @@ -672,6 +694,7 @@ export class NavController extends Ion { * TODO */ _sbComplete() { + return; if (this.canSwipeBack()) { // it is possible to swipe back @@ -789,16 +812,6 @@ export class NavController extends Ion { }); } - addHasViews() { - if (this._views.length === 1) { - this._zone.runOutsideAngular(() => { - setTimeout(() => { - this.renderer.setElementClass(this.elementRef, 'has-views', true); - }, 200); - }); - } - } - /** * TODO * @param {TODO} nbContainer TODO diff --git a/ionic/components/nav/nav.ts b/ionic/components/nav/nav.ts index f2bf31712d..d1106fc800 100644 --- a/ionic/components/nav/nav.ts +++ b/ionic/components/nav/nav.ts @@ -130,18 +130,10 @@ import {NavController} from './nav-controller'; defaultInputs: { 'swipeBackEnabled': true }, - template: '', - directives: [forwardRef(() => NavPaneAnchor)] + template: '' }) export class Nav extends NavController { - /** - * TODO - * @param {NavController} hostNavCtrl TODO - * @param {Injector} injector TODO - * @param {ElementRef} elementRef TODO - * @param {NgZone} zone TODO - */ constructor( @Optional() hostNavCtrl: NavController, app: IonicApp, @@ -154,7 +146,6 @@ export class Nav extends NavController { renderer: Renderer ) { super(hostNavCtrl, app, config, elementRef, compiler, loader, viewManager, zone, renderer); - this.panes = []; } /** @@ -171,263 +162,7 @@ export class Nav extends NavController { } // default the swipe back to be enabled - let isSwipeBackEnabled = (this.swipeBackEnabled || '').toString() !== 'false'; - this.isSwipeBackEnabled( isSwipeBackEnabled ); - } - - /** - * @private - * TODO - * @param {TODO} componentType TODO - * @param {TODO} hostProtoViewRef TODO - * @param {TODO} viewCtrl TODO - * @param {Function} done TODO - * @return {TODO} TODO - */ - loadContainer(componentType, hostProtoViewRef, 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.getStructure(hostProtoViewRef); - - if (structure.tabs) { - // the component being loaded is an - // Tabs is essentially a pane, cuz it has its own navbar and content containers - this.loadNextToAnchor(componentType, this.anchorElementRef(), viewCtrl).then(componentRef => { - - componentRef.instance._paneView = true; - - viewCtrl.disposals.push(() => { - componentRef.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 - this.loadNextToAnchor(componentType, pane.contentAnchorRef, viewCtrl).then(componentRef => { - - viewCtrl.disposals.push(() => { - componentRef.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(componentRef.instance); - - // remember the ElementRef to the content that was just created - viewCtrl.setContentRef(componentRef.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 - 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); - } - }); - } - - this.addHasViews(); - - done(); - }); - - }); - } - } - - /** - * @private - * TODO - * @param {TODO} structure TODO - * @param {TODO} viewCtrl TODO - * @param {Function} done TODO - * @return {TODO} TODO - */ - 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.bindings).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); - }); - - } - } - /** - * @private - * TODO - * @param {TODO} pane TODO - * @return {TODO} TODO - */ - addPane(pane) { - this.newPane = pane; - } - - /** - * @private - * TODO - * @param {TODO} componentProtoViewRef TODO - * @return {TODO} TODO - */ - getStructure(componentProtoViewRef) { - let templateCmds = componentProtoViewRef._protoView.templateCmds; - let compiledTemplateData, directives; - let i, ii, j, jj, k, kk; - - for (i = 0, ii = templateCmds.length; i < ii; i++) { - if (templateCmds[i].template) { - compiledTemplateData = templateCmds[i].template.getData(templateCmds[i].templateId); - if (compiledTemplateData) { - for (j = 0, jj = compiledTemplateData.commands.length; j < jj; j++) { - directives = compiledTemplateData.commands[j].directives; - - if (directives && (kk = directives.length)) { - - for (k = 0; k < kk; k++) { - - if (directives[k].name == 'NavbarTemplate') { - return { navbar: true }; - } - - if (directives[k].name == 'Tabs') { - return { tabs: true }; - } - - } - - } - - } - } - } - } - - return {}; - } - -} - -/** - * @private - */ -@Directive({selector: 'template[pane-anchor]'}) -class NavPaneAnchor { - constructor(@Host() nav: Nav, elementRef: ElementRef) { - nav.anchorElementRef(elementRef); - } -} - -/** - * @private - */ -@Directive({selector: 'template[navbar-anchor]'}) -class NavBarAnchor { - constructor( - @Host() @Inject(forwardRef(() => Pane)) pane: Pane, - viewContainerRef: ViewContainerRef - ) { - pane.navbarContainerRef = viewContainerRef; - } -} - -/** - * @private - */ -@Directive({selector: 'template[content-anchor]'}) -class ContentAnchor { - constructor( - @Host() @Inject(forwardRef(() => Pane)) pane: Pane, - elementRef: ElementRef - ) { - pane.contentAnchorRef = elementRef; - } -} - -/** - * @private - */ -@Component({ - selector: 'ion-pane', - template: - '' + - '' + - '' + - '' + - '' + - '', - 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.navbar = hasNavbar; - this.renderer.setElementAttribute(this.elementRef, 'no-navbar', hasNavbar ? null : '' ); + this.isSwipeBackEnabled( (this.swipeBackEnabled || '').toString() !== 'false' ); } } diff --git a/ionic/components/nav/test/basic/e2e.ts b/ionic/components/nav/test/basic/e2e.ts index e33c933135..bf022c3ae7 100644 --- a/ionic/components/nav/test/basic/e2e.ts +++ b/ionic/components/nav/test/basic/e2e.ts @@ -1,16 +1,16 @@ it('should go from 1 to 2', function() { - element(by.css('#from1To2')).click(); + element(by.css('.e2eFrom1To2')).click(); }); it('should go from 2 to 3', function() { - element(by.css('#from2To3')).click(); + element(by.css('.e2eFrom2To3')).click(); }); it('should go from 3 to 2', function() { - element(by.css('#from3To2')).click(); + element(by.css('.e2eFrom3To2')).click(); }); it('should go from 2 to 1', function() { - element(by.css('#from2To1')).click(); + element(by.css('.e2eFrom2To1')).click(); }); diff --git a/ionic/components/nav/test/basic/index.ts b/ionic/components/nav/test/basic/index.ts index 6115f188a3..8b88fc2dba 100644 --- a/ionic/components/nav/test/basic/index.ts +++ b/ionic/components/nav/test/basic/index.ts @@ -6,7 +6,7 @@ import {NavParams, NavController} from 'ionic/ionic'; @Page({ template: ` - FriendsEnemies + {{title}} @@ -16,14 +16,15 @@ import {NavParams, NavController} from 'ionic/ionic';

{{title}}

-

-

-

-

-

-

- - +

+

+

+

+

+

+

+

+

` }) @@ -36,19 +37,27 @@ class FirstPage { this.nav = nav; this.title = 'First Page'; - this.pushPage = SecondPage; + this.pushPage = FullPage; } setViews() { let items = [ - ThirdPage + PrimaryHeaderPage ]; this.nav.setViews(items); } - push() { - this.nav.push(SecondPage, { id: 8675309, myData: [1,2,3,4] } ); + pushPrimaryHeaderPage() { + this.nav.push(PrimaryHeaderPage); + } + + pushFullPage() { + this.nav.push(FullPage, { id: 8675309, myData: [1,2,3,4] } ); + } + + pushAnother() { + this.nav.push(AnotherPage); } } @@ -56,42 +65,45 @@ class FirstPage { @Page({ template: ` -

Second page

+

Full page

This page does not have a nav bar!

-

-

-

-

-
+

+

+

+

+

+

` }) -class SecondPage { +class FullPage { constructor( nav: NavController, params: NavParams ) { this.nav = nav; this.params = params; - - console.log('Second page params:', params); } setViews() { let items = [ FirstPage, - ThirdPage + PrimaryHeaderPage ]; this.nav.setViews(items); } - pop() { - this.nav.pop(); + pushPrimaryHeaderPage() { + this.nav.push(PrimaryHeaderPage); } - push() { - this.nav.push(ThirdPage); + pushAnother() { + this.nav.push(AnotherPage); + } + + pushFirstPage() { + this.nav.push(FirstPage); } } @@ -99,29 +111,32 @@ class SecondPage { @Page({ template: ` - Third Page Header + + Primary Color Page Header + -

-

+

+

+

` }) -class ThirdPage { +class PrimaryHeaderPage { constructor( nav: NavController ) { this.nav = nav } - push() { - this.nav.push(FourthPage); + pushAnother() { + this.nav.push(AnotherPage); } - pop() { - this.nav.pop() + pushFullPage() { + this.nav.push(FullPage, { id: 8675309, myData: [1,2,3,4] } ); } insert() { @@ -137,28 +152,40 @@ class ThirdPage { @Page({ template: ` - Fourth Page Header + + Another Page Header + -

- -

+

+

+

+

` }) -class FourthPage { +class AnotherPage { constructor( nav: NavController ) { this.nav = nav } + + pushFullPage() { + this.nav.push(FullPage); + } + + pushPrimaryHeaderPage() { + this.nav.push(PrimaryHeaderPage); + } + + pushFirstPage() { + this.nav.push(FirstPage); + } } @App({ - template: ` - - `, - views: [FirstPage, SecondPage, ThirdPage] + template: `` }) class E2EApp { constructor() { diff --git a/ionic/components/nav/view-controller.ts b/ionic/components/nav/view-controller.ts index ef0eb72bfe..0f54bad89d 100644 --- a/ionic/components/nav/view-controller.ts +++ b/ionic/components/nav/view-controller.ts @@ -12,15 +12,7 @@ export class ViewController { this.params = new NavParams(params); this.instance = null; this.state = 0; - this.disposals = []; - } - - setContent(content) { - this._content = content; - } - - getContent() { - return this._content; + this._destroys = []; } /** @@ -34,25 +26,18 @@ export class ViewController { return done(); } - // compile the component and create a ProtoViewRef - navCtrl.compileView(this.componentType).then(hostProtoViewRef => { + // get the pane the NavController wants to use + // the pane is where all this content will be placed into + navCtrl.loadPage(this, null, () => { - if (this.shouldDestroy) return done(); - - // get the pane the NavController wants to use - // the pane is where all this content will be placed into - navCtrl.loadContainer(this.componentType, hostProtoViewRef, this, () => { - - // this ViewController instance has finished loading - try { - this.loaded(); - } catch (e) { - console.error(e); - } - - done(); - }); + // this ViewController instance has finished loading + try { + this.loaded(); + } catch (e) { + console.error(e); + } + done(); }); } @@ -87,55 +72,66 @@ export class ViewController { return this.index === 0; } + addDestroy(destroyFn) { + this._destroys.push(destroyFn); + } + /** * TODO */ destroy() { - for (let i = 0; i < this.disposals.length; i++) { - this.disposals[i](); + for (let i = 0; i < this._destroys.length; i++) { + this._destroys[i](); } + this._destroys = []; } - /** - * @private - */ setNavbarTemplateRef(templateRef) { this._nbTmpRef = templateRef; } - /** - * @private - */ getNavbarTemplateRef() { return this._nbTmpRef; } - /** - * TODO - * @returns {TODO} TODO - */ - setContentRef(contentElementRef) { - this._cntRef = contentElementRef; + getNavbarViewRef() { + return this._nbVwRef; + } + + setNavbarViewRef(viewContainerRef) { + this._nbVwRef = viewContainerRef; + } + + setPageRef(elementRef) { + this._pgRef = elementRef; + } + + pageRef() { + return this._pgRef; + } + + setContentRef(elementRef) { + this._cntRef = elementRef; } - /** - * TODO - * @returns {TODO} TODO - */ contentRef() { return this._cntRef; } - setNavbar(navbarView) { - this._nbVw = navbarView; + setContent(directive) { + this._cntDir = directive; + } + + getContent() { + return this._cntDir; + } + + setNavbar(directive) { + this._nbDir = directive; } - /** - * TODO - * @returns {TODO} TODO - */ getNavbar() { - return this._nbVw; + return this._nbDir; } /** @@ -263,18 +259,8 @@ export class ViewController { } domCache(isActiveView, isPreviousView) { - let renderInDom = (isActiveView || isPreviousView); - - let contentRef = this.contentRef(); - if (contentRef) { - // the active view, and the previous view should have the 'show-view' css class - // all others, like a cached page 2 back, should now have 'show-view' so it's not rendered - contentRef.nativeElement.classList[renderInDom ? 'add' : 'remove' ]('show-view'); - } - - let navbarRef = this.getNavbar(); - if (navbarRef) { - navbarRef.elementRef.nativeElement.classList[renderInDom ? 'add' : 'remove' ]('show-navbar'); + if (this.instance) { + this.instance._hidden = (!isActiveView && !isPreviousView); } } diff --git a/ionic/components/overlay/overlay-controller.ts b/ionic/components/overlay/overlay-controller.ts index afa679830f..e037caa5ca 100644 --- a/ionic/components/overlay/overlay-controller.ts +++ b/ionic/components/overlay/overlay-controller.ts @@ -1,6 +1,7 @@ import {Component, NgZone, Injectable, Renderer} from 'angular2/angular2'; import {IonicApp} from '../app/app'; +import {Config} from '../../config/config'; import {Animation} from '../../animations/animation'; import * as util from 'ionic/util'; @@ -8,8 +9,9 @@ import * as util from 'ionic/util'; @Injectable() export class OverlayController { - constructor(app: IonicApp, zone: NgZone, renderer: Renderer) { + constructor(app: IonicApp, config: Config, zone: NgZone, renderer: Renderer) { this.app = app; + this.config = config; this.zone = zone; this.renderer = renderer; this.refs = []; @@ -54,6 +56,9 @@ export class OverlayController { instance.onPageWillEnter && instance.onPageWillEnter(); let animation = Animation.create(ref.location.nativeElement, opts.enterAnimation); + if (this.config.get('animate') === false) { + animation.duration(0); + } animation.before.addClass('show-overlay'); this.app.setEnabled(false, animation.duration()); @@ -95,6 +100,9 @@ export class OverlayController { instance.onPageWillUnload && instance.onPageWillUnload(); let animation = Animation.create(ref.location.nativeElement, opts.leaveAnimation); + if (this.config.get('animate') === false) { + animation.duration(0); + } animation.after.removeClass('show-overlay'); this.app.setEnabled(false, animation.duration()); diff --git a/ionic/components/search-bar/test/floating/e2e.ts b/ionic/components/search-bar/test/floating/e2e.ts index 005c76d784..d94aca112f 100644 --- a/ionic/components/search-bar/test/floating/e2e.ts +++ b/ionic/components/search-bar/test/floating/e2e.ts @@ -15,15 +15,11 @@ it('custom cancel button should focus', function() { element(by.css('.e2eCustomCancelButtonFloatingSearchBar input')).sendKeys("DD"); }); -it('custom cancel button long text should focus', function() { - element(by.css('.e2eCustomCancelButtonLongTextFloatingSearchBar input')).sendKeys("EE"); -}); - it('custom cancel action should focus', function() { element(by.css('.e2eCustomCancelActionFloatingSearchBar input')).sendKeys("FF"); }); -// TODO - this test will work on iOS but fail on Android +// TODO - this test will work on iOS but fail on Android // it('custom cancel action should alert', function() { // element(by.css('.e2eCustomCancelActionFloatingSearchBar .search-bar-cancel')).click(); // }); diff --git a/ionic/components/search-bar/test/floating/main.html b/ionic/components/search-bar/test/floating/main.html index 550270944a..a9390091ed 100644 --- a/ionic/components/search-bar/test/floating/main.html +++ b/ionic/components/search-bar/test/floating/main.html @@ -11,9 +11,6 @@
Search - Custom Cancel Button
-
Search - Custom Cancel Button Long
- -
Search - Custom Cancel Action
diff --git a/ionic/components/segment/test/basic/e2e.ts b/ionic/components/segment/test/basic/e2e.ts index c941f0bef6..06d1d6bb26 100644 --- a/ionic/components/segment/test/basic/e2e.ts +++ b/ionic/components/segment/test/basic/e2e.ts @@ -1,16 +1,10 @@ -it('friends should be selected', function() { +it('friends and standard should be selected', function() { element(by.css('.e2eSegmentFriends')).click(); + element(by.css('.e2eSegmentStandard')).click(); }); -it('standard should be selected', function() { - element(by.css('.e2eSegmentStandard')).click(); -}); - -it('model c should be selected', function() { +it('model c and top grossing should be selected', function() { element(by.css('.e2eSegmentModelC')).click(); -}); - -it('top grossing should be selected', function() { - element(by.css('.e2eSegmentTopGrossing')).click(); + element(by.css('.e2eSegmentTopGrossing')).click(); }); diff --git a/ionic/components/tabs/tab.ts b/ionic/components/tabs/tab.ts index 9c9e334fd2..135e488cef 100644 --- a/ionic/components/tabs/tab.ts +++ b/ionic/components/tabs/tab.ts @@ -1,4 +1,4 @@ -import {Component, Directive, Host, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, forwardRef, NgZone, Renderer} from 'angular2/angular2'; +import {Component, Directive, Host, ElementRef, Compiler, DynamicComponentLoader, AppViewManager, NgZone, Renderer} from 'angular2/angular2'; import {IonicApp} from '../app/app'; import {Config} from '../../config/config'; @@ -64,8 +64,7 @@ import {Tabs} from './tabs'; '[class.show-tab]': 'isSelected', 'role': 'tabpanel' }, - template: '', - directives: [forwardRef(() => TabContentAnchor)] + template: '' }) export class Tab extends NavController { @@ -83,91 +82,71 @@ export class Tab extends NavController { // A Tab is a NavController for its child pages super(tabs, app, config, elementRef, compiler, loader, viewManager, zone, renderer); this.tabs = tabs; - this._isInitial = tabs.add(this); } onInit() { - console.debug('Tab onInit', this.getIndex()); + console.debug('Tab onInit', this.index); if (this._isInitial) { this.tabs.select(this); } else if (this.tabs.preloadTabs) { - // setTimeout(() => { - // this.load(() => { - // console.debug('preloaded tab', this.getIndex()); - // }); - // }, 500 * this.getIndex()); + setTimeout(() => { + this.load(() => { + console.debug('preloaded tab', this.index); + this.hideNavbars(true); + }); + }, 500 * this.index); } } - load(callback) { + load(done) { if (!this._loaded && this.root) { let opts = { animate: false }; - this.push(this.root, null, opts).then(callback); + this.push(this.root, null, opts).then(done); this._loaded = true; } else { - callback(); + done(); } } - loadContainer(componentType, hostProtoViewRef, viewCtrl, done) { + loadPage(viewCtrl, navbarContainerRef, done) { + // by default a page's navbar goes into the shared tab's navbar section + navbarContainerRef = this.tabs.navbarContainerRef; - this.loadNextToAnchor(componentType, this.contentAnchorRef, viewCtrl).then(componentRef => { + let isTabSubPage = (this.tabs.subPages && viewCtrl.index > 0); + if (isTabSubPage) { + // a subpage, that's not the first index + // should not use the shared tabs navbar section, but use it's own + navbarContainerRef = null; + } - viewCtrl.disposals.push(() => { - componentRef.dispose(); - }); - - // a new ComponentRef has been created - // set the ComponentRef's instance to this ViewController - viewCtrl.setInstance(componentRef.instance); - - // remember the ElementRef to the content that was just created - viewCtrl.setContentRef(componentRef.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 - 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); - } - }); + super.loadPage(viewCtrl, navbarContainerRef, () => { + if (viewCtrl.instance) { + viewCtrl.instance._tabSubPage = isTabSubPage; } - - this.addHasViews(); - done(); }); - } - getIndex() { + setSelected(isSelected) { + this.isSelected = isSelected; + this.hideNavbars(!isSelected); + } + + hideNavbars(shouldHideNavbars) { + this._views.forEach(viewCtrl => { + let navbar = viewCtrl.getNavbar(); + navbar && navbar.setHidden(shouldHideNavbars); + }); + } + + get index() { return this.tabs.getIndex(this); } } - - -@Directive({selector: 'template[content-anchor]'}) -class TabContentAnchor { - constructor(@Host() tab: Tab, elementRef: ElementRef) { - tab.contentAnchorRef = elementRef; - } -} diff --git a/ionic/components/tabs/tabs.scss b/ionic/components/tabs/tabs.scss index 003493df98..a85f7093e6 100644 --- a/ionic/components/tabs/tabs.scss +++ b/ionic/components/tabs/tabs.scss @@ -46,10 +46,6 @@ ion-tabs > ion-navbar-section { order: $flex-order-tab-bar-navbar; } -ion-tabs ion-navbar.toolbar.deselected-tab { - display: none; -} - ion-tab-bar-section { position: relative; order: $flex-order-tab-bar-bottom; @@ -161,4 +157,3 @@ tab-highlight { [tab-bar-icons=hide] .tab-button-icon { display: none; } - diff --git a/ionic/components/tabs/tabs.ts b/ionic/components/tabs/tabs.ts index 2cdeaeae13..389d3f8b33 100644 --- a/ionic/components/tabs/tabs.ts +++ b/ionic/components/tabs/tabs.ts @@ -1,4 +1,4 @@ -import {Directive, ElementRef, Optional, Host, NgFor, forwardRef, ViewContainerRef} from 'angular2/angular2'; +import {Directive, ElementRef, Optional, Host, NgFor, NgIf, forwardRef, ViewContainerRef} from 'angular2/angular2'; import {Ion} from '../ion'; import {IonicApp} from '../app/app'; @@ -71,7 +71,7 @@ import {Icon} from '../icon/icon'; '' + '' + '' + - '' + + '' + '' + '{{t.tabTitle}}' + '' + @@ -84,6 +84,7 @@ import {Icon} from '../icon/icon'; directives: [ Icon, NgFor, + NgIf, forwardRef(() => TabButton), forwardRef(() => TabHighlight), forwardRef(() => TabNavBarAnchor) @@ -108,18 +109,22 @@ export class Tabs extends Ion { super(elementRef, config); this.app = app; this.preload = config.get('preloadTabs'); + this.subPages = config.get('tabSubPages'); // collection of children "Tab" instances, which extends NavController - this._tabs = []; + this.tabs = []; // 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 if (viewCtrl) { - this._ready = new Promise(res => { this._isReady = res; }); + viewCtrl.setContent(this); + viewCtrl.setContentRef(elementRef); + // TODO: improve how this works, probably not use promises here + this.readyPromise = new Promise(res => { this.isReady = res; }); viewCtrl.onReady = () => { - return this._ready; + return this.readyPromise; }; } } @@ -131,9 +136,9 @@ export class Tabs extends Ion { tab.id = ++_tabIds; tab.btnId = 'tab-' + tab.id; tab.panelId = 'tabpanel-' + tab.id; - this._tabs.push(tab); + this.tabs.push(tab); - return (this._tabs.length === 1); + return (this.tabs.length === 1); } /** @@ -142,40 +147,25 @@ export class Tabs extends Ion { * @returns {TODO} TODO */ select(tabOrIndex) { - let selectedTab = null; - - if (typeof tabOrIndex === 'number') { - selectedTab = this.getByIndex(tabOrIndex); - - } else { - selectedTab = tabOrIndex; - } - - if (!selectedTab || !this.app.isEnabled()) { + let selectedTab = (typeof tabOrIndex === 'number' ? this.getByIndex(tabOrIndex) : tabOrIndex); + if (!selectedTab) { return Promise.reject(); } + console.debug('select tab', selectedTab.id); + let deselectedTab = this.getSelected(); if (selectedTab === deselectedTab) { // no change - return this._touchActive(selectedTab); + return this.touchActive(selectedTab); } - console.debug('select tab', selectedTab.id); - selectedTab.load(() => { - this._isReady && this._isReady(); + this.isReady && this.isReady(); - this._tabs.forEach(tab => { - tab.isSelected = (tab === selectedTab); - - tab._views.forEach(viewCtrl => { - let navbarRef = viewCtrl.navbarRef(); - if (navbarRef) { - navbarRef.nativeElement.classList[tab.isSelected ? 'remove': 'add']('deselected-tab'); - } - }); + this.tabs.forEach(tab => { + tab.setSelected(tab === selectedTab); }); this.highlight && this.highlight.select(selectedTab); @@ -188,23 +178,23 @@ export class Tabs extends Ion { * @returns {TODO} TODO */ getByIndex(index) { - if (index < this._tabs.length && index > -1) { - return this._tabs[index]; + if (index < this.tabs.length && index > -1) { + return this.tabs[index]; } return null; } getSelected() { - for (let i = 0; i < this._tabs.length; i++) { - if (this._tabs[i].isSelected) { - return this._tabs[i]; + for (let i = 0; i < this.tabs.length; i++) { + if (this.tabs[i].isSelected) { + return this.tabs[i]; } } return null; } getIndex(tab) { - return this._tabs.indexOf(tab); + return this.tabs.indexOf(tab); } /** @@ -212,10 +202,8 @@ export class Tabs extends Ion { * "Touch" the active tab, either going back to the root view of the tab * or scrolling the tab to the top */ - _touchActive(tab) { - let stateLen = tab.length(); - - if(stateLen > 1) { + touchActive(tab) { + if (tab.length() > 1) { // Pop to the root view return tab.popToRoot(); } @@ -230,7 +218,6 @@ let _tabIds = -1; /** * @private - * TODO */ @Directive({ selector: '.tab-button', @@ -243,17 +230,15 @@ let _tabIds = -1; '[class.has-icon]': 'hasIcon', '[class.has-title-only]': 'hasTitleOnly', '[class.icon-only]': 'hasIconOnly', - '(click)': 'onClick($event)', + '[class.disable-hover]': 'disHover', + '(click)': 'onClick()', } }) class TabButton extends Ion { constructor(@Host() tabs: Tabs, config: Config, elementRef: ElementRef) { super(elementRef, config); this.tabs = tabs; - - if (config.get('hoverCSS') === false) { - elementRef.nativeElement.classList.add('disable-hover'); - } + this.disHover = (config.get('hoverCSS') === false); } onInit() { @@ -264,16 +249,14 @@ class TabButton extends Ion { this.hasIconOnly = (this.hasIcon && !this.hasTitle); } - onClick(ev) { - ev.stopPropagation(); - ev.preventDefault(); + onClick() { this.tabs.select(this.tab); } } + /** * @private - * TODO */ @Directive({ selector: 'tab-highlight' @@ -306,14 +289,10 @@ class TabHighlight { /** * @private - * TODO */ @Directive({selector: 'template[navbar-anchor]'}) class TabNavBarAnchor { - constructor( - @Host() tabs: Tabs, - viewContainerRef: ViewContainerRef - ) { + constructor(@Host() tabs: Tabs, viewContainerRef: ViewContainerRef) { tabs.navbarContainerRef = viewContainerRef; } } diff --git a/ionic/components/tabs/test/tab-bar-scenarios/index.ts b/ionic/components/tabs/test/tab-bar-scenarios/index.ts index 43aed36502..834efa41bb 100644 --- a/ionic/components/tabs/test/tab-bar-scenarios/index.ts +++ b/ionic/components/tabs/test/tab-bar-scenarios/index.ts @@ -5,3 +5,5 @@ import {App} from 'ionic/ionic'; templateUrl: 'main.html' }) class E2EApp {} + +document.body.innerHTML += '' diff --git a/ionic/components/tabs/test/tab-bar-scenarios/main.html b/ionic/components/tabs/test/tab-bar-scenarios/main.html index 3db2d1f21c..6c2e11d34a 100644 --- a/ionic/components/tabs/test/tab-bar-scenarios/main.html +++ b/ionic/components/tabs/test/tab-bar-scenarios/main.html @@ -59,11 +59,3 @@
- - - diff --git a/ionic/components/tabs/test/tab-bar-scenarios/styles.css b/ionic/components/tabs/test/tab-bar-scenarios/styles.css new file mode 100644 index 0000000000..b5b6cbf640 --- /dev/null +++ b/ionic/components/tabs/test/tab-bar-scenarios/styles.css @@ -0,0 +1,12 @@ + +ion-tabs { + position: relative; + top: auto; + height: auto; + margin-bottom: 20px; +} + +ion-navbar-section, +ion-content-section { + display: none !important; +} diff --git a/ionic/components/toolbar/modes/ios.scss b/ionic/components/toolbar/modes/ios.scss index e6699d1bd5..f1b10aa69e 100644 --- a/ionic/components/toolbar/modes/ios.scss +++ b/ionic/components/toolbar/modes/ios.scss @@ -84,6 +84,7 @@ ion-title { height: 100%; padding: 0px 90px 1px 90px; pointer-events: none; + transform: translateZ(0px); } .toolbar-title { @@ -96,6 +97,7 @@ ion-title { ion-nav-items { flex: 1; order: map-get($toolbar-order-ios, primary); + transform: translateZ(0px); } ion-nav-items[secondary] { diff --git a/ionic/components/toolbar/toolbar.scss b/ionic/components/toolbar/toolbar.scss index 9127b8d73f..1e5ca5bd15 100644 --- a/ionic/components/toolbar/toolbar.scss +++ b/ionic/components/toolbar/toolbar.scss @@ -75,7 +75,6 @@ ion-title { order: map-get($toolbar-order, title); display: flex; align-items: center; - transform: translateZ(0px); } .toolbar-title { @@ -109,7 +108,6 @@ ion-title { ion-nav-items { display: block; margin: 0 0.2rem; - transform: translateZ(0px); pointer-events: none; order: map-get($toolbar-order, primary); } diff --git a/ionic/config/config.ts b/ionic/config/config.ts index 7685a8d6d3..c26b0be1b7 100644 --- a/ionic/config/config.ts +++ b/ionic/config/config.ts @@ -127,6 +127,11 @@ export class Config { let configObj = null; if (this._platform) { + let queryStringValue = this._platform.query('ionic' + key.toLowerCase()); + if (isDefined(queryStringValue)) { + return this._c[key] = (queryStringValue === 'true' ? true : queryStringValue === 'false' ? false : queryStringValue); + } + // check the platform settings object for this value // loop though each of the active platforms diff --git a/ionic/config/decorators.ts b/ionic/config/decorators.ts index 4095bbb0ba..e6b1f300af 100644 --- a/ionic/config/decorators.ts +++ b/ionic/config/decorators.ts @@ -1,18 +1,9 @@ -import {Component, Directive, View, bootstrap} from 'angular2/angular2' +import {Component, bootstrap} from 'angular2/angular2' import * as util from 'ionic/util'; import {ionicProviders} from './bootstrap'; import {IONIC_DIRECTIVES} from './directives'; -/** - * @private - */ -class PageImpl extends View { - constructor(args = {}) { - args.directives = (args.directives || []).concat(IONIC_DIRECTIVES); - super(args); - } -} /** * _For more information on how pages are created, see the [NavController API @@ -72,30 +63,30 @@ class PageImpl extends View { * you may see these tags if you inspect your markup, you don't need to include * them in your templates. */ -export function Page(args) { +export function Page(config={}) { return function(cls) { + config.selector = 'ion-page'; + config.directives = config.directives ? config.directives.concat(IONIC_DIRECTIVES) : IONIC_DIRECTIVES; + config.host = config.host || {}; + config.host['[hidden]'] = '_hidden'; + config.host['[class.tab-subpage]'] = '_tabSubPage'; var annotations = Reflect.getMetadata('annotations', cls) || []; - annotations.push(new PageImpl(args)); + annotations.push(new Component(config)); Reflect.defineMetadata('annotations', annotations, cls); return cls; } } -/** - * TODO - */ + export function ConfigComponent(config) { return function(cls) { - return makeComponent(cls, appendConfig(cls, config)); + var annotations = Reflect.getMetadata('annotations', cls) || []; + annotations.push(new Component(config)); + Reflect.defineMetadata('annotations', annotations, cls); + return cls; } } -export function makeComponent(cls, config) { - var annotations = Reflect.getMetadata('annotations', cls) || []; - annotations.push(new Component(config)); - Reflect.defineMetadata('annotations', annotations, cls); - return cls; -} function appendConfig(cls, config) { config.host = config.host || {}; diff --git a/ionic/config/modes.ts b/ionic/config/modes.ts index 7f62e076ba..aa40a4597d 100644 --- a/ionic/config/modes.ts +++ b/ionic/config/modes.ts @@ -48,6 +48,7 @@ Config.setModeConfig('md', { popupPopIn: 'popup-md-pop-in', popupPopOut: 'popup-md-pop-out', + tabSubPages: true, type: 'overlay', mdRipple: true, }); diff --git a/ionic/config/test/config.spec.ts b/ionic/config/test/config.spec.ts index 246b1c5d45..5f8a5bb3ff 100644 --- a/ionic/config/test/config.spec.ts +++ b/ionic/config/test/config.spec.ts @@ -57,6 +57,42 @@ export function run() { expect(config.get('tabBarPlacement')).toEqual('top'); }); + it('should get boolean value from querystring', () => { + let config = new Config(); + let platform = new Platform(); + platform.url('http://biff.com/?ionicanimate=true') + config.setPlatform(platform); + expect(config.get('animate')).toEqual(true); + + config = new Config(); + platform = new Platform(); + platform.url('http://biff.com/?ionicanimate=false') + config.setPlatform(platform); + expect(config.get('animate')).toEqual(false); + }); + + it('should get value from case insensitive querystring key', () => { + let config = new Config({ + mode: 'a' + }); + let platform = new Platform(); + platform.url('http://biff.com/?ionicConfigKey=b') + config.setPlatform(platform); + + expect(config.get('configKey')).toEqual('b'); + }); + + it('should get value from querystring', () => { + let config = new Config({ + mode: 'modeA' + }); + let platform = new Platform(); + platform.url('http://biff.com/?ionicmode=modeB') + config.setPlatform(platform); + + expect(config.get('mode')).toEqual('modeB'); + }); + it('should override mode platform', () => { let config = new Config({ mode: 'modeA', diff --git a/ionic/gestures/hammer.ts b/ionic/gestures/hammer.ts index c9e769ff73..5c781532a1 100644 --- a/ionic/gestures/hammer.ts +++ b/ionic/gestures/hammer.ts @@ -165,7 +165,7 @@ function ifUndefined(val1, val2) { */ function addEventListeners(target, types, handler) { each(splitStr(types), function(type) { - console.debug('hammer addEventListener', type, target.tagName); + //console.debug('hammer addEventListener', type, target.tagName); target.addEventListener(type, handler, false); }); } @@ -178,7 +178,7 @@ function addEventListeners(target, types, handler) { */ function removeEventListeners(target, types, handler) { each(splitStr(types), function(type) { - console.debug('hammer removeEventListener', type, target.tagName); + //console.debug('hammer removeEventListener', type, target.tagName); target.removeEventListener(type, handler, false); }); } @@ -394,7 +394,7 @@ Input.prototype = { * bind the events */ init: function() { - console.debug('hammer Input init') + //console.debug('hammer Input init') this.evEl && addEventListeners(this.element, this.evEl, this.domHandler); this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler); this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler); diff --git a/ionic/ionic.core.scss b/ionic/ionic.core.scss index ca6ad490ff..045b7abd6a 100644 --- a/ionic/ionic.core.scss +++ b/ionic/ionic.core.scss @@ -24,7 +24,6 @@ "components/button/button-icon", "components/button/button-fab", "components/checkbox/checkbox", - "components/content/content", "components/icon/icon", "components/item/item", "components/item/item-media", diff --git a/ionic/platform/test/platform.spec.ts b/ionic/platform/test/platform.spec.ts index 93b051b54b..4d77d04ae8 100644 --- a/ionic/platform/test/platform.spec.ts +++ b/ionic/platform/test/platform.spec.ts @@ -21,6 +21,20 @@ export function run() { expect(platform.is('ios')).toEqual(false); }); + it('should get case insensitive querystring value', () => { + let platform = new Platform(); + platform.url('/?KEY=value'); + + expect(platform.query('key')).toEqual('value'); + }); + + it('should get querystring value', () => { + let platform = new Platform(); + platform.url('/?key=value'); + + expect(platform.query('key')).toEqual('value'); + }); + it('should set ios via platformOverride, despite android querystring', () => { let platform = new Platform(); platform.url('/?ionicplatform=android'); diff --git a/ionic/transitions/ios-transition.ts b/ionic/transitions/ios-transition.ts index 9d43058b5b..b55cb5be2e 100644 --- a/ionic/transitions/ios-transition.ts +++ b/ionic/transitions/ios-transition.ts @@ -9,8 +9,6 @@ const OFF_RIGHT = '99.5%'; const OFF_LEFT = '-33%'; const CENTER = '0%' const OFF_OPACITY = 0.8; -const SHOW_NAVBAR_CSS = 'show-navbar'; -const SHOW_VIEW_CSS = 'show-view'; const SHOW_BACK_BTN_CSS = 'show-back-button'; @@ -36,29 +34,24 @@ class IOSTransition extends Animation { // entering content let enteringContent = new Animation(enteringView.contentRef()); - enteringContent - .before.addClass(SHOW_VIEW_CSS) - .before.setStyles({ zIndex: enteringView.index }); this.add(enteringContent); if (backDirection) { - // back direction + // entering content, back direction enteringContent .fromTo(TRANSLATEX, OFF_LEFT, CENTER) .fromTo(OPACITY, OFF_OPACITY, 1); } else { - // forward direction + // entering content, forward direction enteringContent .fromTo(TRANSLATEX, OFF_RIGHT, CENTER) .fromTo(OPACITY, 1, 1); } - - // entering navbar if (enteringHasNavbar) { + // entering page has a navbar let enteringNavBar = new Animation(enteringView.navbarRef()); - enteringNavBar.before.addClass(SHOW_NAVBAR_CSS); this.add(enteringNavBar); let enteringTitle = new Animation(enteringView.titleRef()); @@ -76,62 +69,68 @@ class IOSTransition extends Animation { // set properties depending on direction if (backDirection) { - // back direction + // entering navbar, back direction enteringTitle.fromTo(TRANSLATEX, OFF_LEFT, CENTER); if (enteringView.enableBack()) { - enteringBackButton.before.addClass(SHOW_BACK_BTN_CSS); + // back direction, entering page has a back button enteringBackButton.fadeIn(); } } else { - // forward direction + // entering navbar, forward direction enteringTitle.fromTo(TRANSLATEX, OFF_RIGHT, CENTER); - if (enteringView.enableBack()) { - enteringBackButton.before.addClass(SHOW_BACK_BTN_CSS); - enteringBackButton.fadeIn(); - - let enteringBackBtnText = new Animation(enteringView.backBtnTextRef()); - enteringBackBtnText.fromTo(TRANSLATEX, '150px', '0px'); - enteringNavBar.add(enteringBackBtnText); - } - if (leavingHasNavbar) { - // if there is a leaving navbar, then just fade this one in + // entering navbar, forward direction, and there's a leaving navbar + // should just fade in, no sliding enteringNavbarBg .fromTo(TRANSLATEX, CENTER, CENTER) .fadeIn(); } else { - enteringNavbarBg.fromTo(TRANSLATEX, OFF_RIGHT, CENTER); + // entering navbar, forward direction, and there's no leaving navbar + // should just slide in, no fading in + enteringNavbarBg + .fromTo(TRANSLATEX, OFF_RIGHT, CENTER) + .fromTo(OPACITY, 1, 1); } + + if (enteringView.enableBack()) { + // forward direction, entering page has a back button + enteringBackButton + .before.addClass(SHOW_BACK_BTN_CSS) + .fadeIn(); + + let enteringBackBtnText = new Animation(enteringView.backBtnTextRef()); + enteringBackBtnText.fromTo(TRANSLATEX, '100px', '0px'); + enteringNavBar.add(enteringBackBtnText); + } } } - // setup leaving view if (leavingView) { // leaving content let leavingContent = new Animation(leavingView.contentRef()); this.add(leavingContent); - leavingContent - .before.addClass(SHOW_VIEW_CSS) - .before.setStyles({ zIndex: leavingView.index }); if (backDirection) { + // leaving content, back direction leavingContent .fromTo(TRANSLATEX, CENTER, '100%') .fromTo(OPACITY, 1, 1); } else { + // leaving content, forward direction leavingContent .fromTo(TRANSLATEX, CENTER, OFF_LEFT) .fromTo(OPACITY, 1, OFF_OPACITY); } if (leavingHasNavbar) { + // leaving page has a navbar let leavingNavBar = new Animation(leavingView.navbarRef()); let leavingBackButton = new Animation(leavingView.backBtnRef()); let leavingTitle = new Animation(leavingView.titleRef()); @@ -145,25 +144,28 @@ class IOSTransition extends Animation { .add(leavingNavbarBg); this.add(leavingNavBar); - leavingBackButton - .after.removeClass(SHOW_BACK_BTN_CSS) - .fadeOut(); - + // fade out leaving navbar items + leavingBackButton.fadeOut(); leavingTitle.fadeOut(); leavingNavbarItems.fadeOut(); - // set properties depending on direction if (backDirection) { - // back direction + // leaving navbar, back direction leavingTitle.fromTo(TRANSLATEX, CENTER, '100%'); + if (enteringHasNavbar) { - // this is an entering navbar, just fade this out + // leaving navbar, back direction, and there's an entering navbar + // should just fade out, no sliding leavingNavbarBg .fromTo(TRANSLATEX, CENTER, CENTER) .fadeOut(); } else { - leavingNavbarBg.fromTo(TRANSLATEX, CENTER, '100%'); + // leaving navbar, back direction, and there's no entering navbar + // should just slide out, no fading out + leavingNavbarBg + .fromTo(TRANSLATEX, CENTER, '100%') + .fromTo(OPACITY, 1, 1); } let leavingBackBtnText = new Animation(leavingView.backBtnTextRef()); @@ -171,7 +173,7 @@ class IOSTransition extends Animation { leavingNavBar.add(leavingBackBtnText); } else { - // forward direction + // leaving navbar, forward direction leavingTitle.fromTo(TRANSLATEX, CENTER, OFF_LEFT); } } diff --git a/ionic/transitions/md-transition.ts b/ionic/transitions/md-transition.ts index 1bacee754e..2ead0ff4e3 100644 --- a/ionic/transitions/md-transition.ts +++ b/ionic/transitions/md-transition.ts @@ -4,16 +4,13 @@ import {Animation} from '../animations/animation'; const TRANSLATEY = 'translateY'; const OFF_BOTTOM = '40px'; const CENTER = '0px' -const SHOW_NAVBAR_CSS = 'show-navbar'; -const SHOW_VIEW_CSS = 'show-view'; const SHOW_BACK_BTN_CSS = 'show-back-button'; -const TABBAR_HEIGHT = '69px'; class MDTransition extends Animation { constructor(navCtrl, opts) { - opts.renderDelay = 160; + //opts.renderDelay = 80; super(null, opts); // what direction is the transition going @@ -27,98 +24,34 @@ class MDTransition extends Animation { let enteringHasNavbar = enteringView.hasNavbar(); let leavingHasNavbar = leavingView && leavingView.hasNavbar(); - // entering content item moves in bottom to center - let enteringContent = new Animation(enteringView.contentRef()); - enteringContent - .before.addClass(SHOW_VIEW_CSS) - .before.setStyles({ zIndex: enteringView.index }); - this.add(enteringContent); + let enteringPage = new Animation(enteringView.pageRef()); + this.add(enteringPage); if (backDirection) { this.duration(200).easing('cubic-bezier(0.47,0,0.745,0.715)'); - enteringContent.fromTo(TRANSLATEY, CENTER, CENTER); + enteringPage.fromTo(TRANSLATEY, CENTER, CENTER); } else { this.duration(280).easing('cubic-bezier(0.36,0.66,0.04,1)'); - enteringContent + enteringPage .fromTo(TRANSLATEY, OFF_BOTTOM, CENTER) .fadeIn(); } - // entering navbar - if (enteringHasNavbar) { - let enteringNavBar = new Animation(enteringView.navbarRef()); - enteringNavBar - .before.addClass(SHOW_NAVBAR_CSS) - .before.setStyles({ zIndex: enteringView.index + 10 }); - this.add(enteringNavBar); - - if (backDirection) { - enteringNavBar.fromTo(TRANSLATEY, CENTER, CENTER); - - } else { - enteringNavBar - .fromTo(TRANSLATEY, OFF_BOTTOM, CENTER) - .fadeIn(); - } - - if (enteringView.enableBack()) { - let enteringBackButton = new Animation(enteringView.backBtnRef()); - enteringBackButton.before.addClass(SHOW_BACK_BTN_CSS); - enteringNavBar.add(enteringBackButton); - } + if (enteringHasNavbar && enteringView.enableBack()) { + let enteringBackButton = new Animation(enteringView.backBtnRef()); + enteringBackButton.before.addClass(SHOW_BACK_BTN_CSS); + this.add(enteringBackButton); } // setup leaving view - if (leavingView) { + if (leavingView && backDirection) { // leaving content - let leavingContent = new Animation(leavingView.contentRef()); - this.add(leavingContent); - leavingContent - .before.addClass(SHOW_VIEW_CSS) - .before.setStyles({ zIndex: leavingView.index }); - - - if (backDirection) { - this.duration(200).easing('cubic-bezier(0.47,0,0.745,0.715)'); - leavingContent - .fromTo(TRANSLATEY, CENTER, OFF_BOTTOM) - .fadeOut(); - } - - - if (leavingHasNavbar) { - if (backDirection) { - let leavingNavBar = new Animation(leavingView.navbarRef()); - this.add(leavingNavBar); - - leavingNavBar - .before.setStyles({ zIndex: leavingView.index + 10 }) - .fadeOut(); - } - - } - } - - let viewLength = navCtrl.length(); - if ((viewLength === 1 || viewLength === 2) && navCtrl.tabs) { - let tabBarEle = navCtrl.tabs.elementRef.nativeElement.querySelector('ion-tab-bar-section'); - let tabBar = new Animation(tabBarEle); - - if (viewLength === 1 && backDirection) { - tabBar - .fromTo('height', '0px', TABBAR_HEIGHT) - .fadeIn(); - - } else if (viewLength === 2 && !backDirection) { - tabBar - .fromTo('height', TABBAR_HEIGHT, '0px') - .fadeOut(); - } - - this.add(tabBar); + this.duration(200).easing('cubic-bezier(0.47,0,0.745,0.715)'); + let leavingPage = new Animation(leavingView.pageRef()); + this.add(leavingPage.fromTo(TRANSLATEY, CENTER, OFF_BOTTOM).fadeOut()); } } diff --git a/ionic/util/util.scss b/ionic/util/util.scss index f9cebfa284..15a6b3d186 100755 --- a/ionic/util/util.scss +++ b/ionic/util/util.scss @@ -20,8 +20,49 @@ background: none !important; } -.hide.hide.hide { - display: none; +.hide, +[hidden], +template, +root-anchor { + display: none !important; +} + + +// Content Padding +// -------------------------------------------------- + +$content-padding: 16px !default; + + +[padding], +[padding] > scroll-content { + padding: $content-padding; +} + +[padding-top] { + padding-top: $content-padding; +} + +[padding-right] { + padding-right: $content-padding; +} + +[padding-bottom] { + padding-bottom: $content-padding; +} + +[padding-left] { + padding-left: $content-padding; +} + +[padding-vertical] { + padding-top: $content-padding; + padding-bottom: $content-padding; +} + +[padding-horizontal] { + padding-right: $content-padding; + padding-left: $content-padding; } diff --git a/ionic/util/util.ts b/ionic/util/util.ts index d0ee00d697..466bcbf532 100644 --- a/ionic/util/util.ts +++ b/ionic/util/util.ts @@ -167,12 +167,10 @@ export function getQuerystring(url, key) { const startIndex = url.indexOf('?'); if (startIndex !== -1) { const queries = url.slice(startIndex + 1).split('&'); - if (queries.length) { - queries.forEach((param) => { - var split = param.split('='); - queryParams[split[0]] = split[1].split('#')[0]; - }); - } + queries.forEach((param) => { + var split = param.split('='); + queryParams[split[0].toLowerCase()] = split[1].split('#')[0]; + }); } if (key) { return queryParams[key] || ''; diff --git a/package.json b/package.json index b5342fbd21..4ca03dd74f 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "mkdirp": "^0.5.1", "node-html-encoder": "0.0.2", "node-libs-browser": "^0.5.2", - "node-uuid": "^1.4.1", "q": "^1.4.1", "request": "2.53.0", "run-sequence": "^1.1.0", diff --git a/scripts/e2e/e2e.template.html b/scripts/e2e/e2e.template.html index 27eba2a0c0..df8985f237 100644 --- a/scripts/e2e/e2e.template.html +++ b/scripts/e2e/e2e.template.html @@ -2,22 +2,10 @@ - +