From 0032858e3844ab9ca79e87a2521b4a9a38cee50a Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Fri, 15 May 2015 12:25:24 -0500 Subject: [PATCH] betterz iOS toolbars --- ionic/collide/animation.js | 40 +++++++++++++++---- ionic/collide/collide.js | 9 ++++- ionic/collide/complete-call.js | 14 +++++++ ionic/collide/process-element.js | 20 +++++++--- ionic/collide/tick.js | 14 +++++++ ionic/components/app/structure.scss | 4 ++ .../nav/test/basic/pages/second-page.js | 4 +- .../nav/test/basic/pages/third-page.js | 4 +- ionic/components/toolbar/extensions/ios.scss | 3 ++ ionic/components/toolbar/toolbar.scss | 14 ++++--- ionic/transitions/ios-transition.js | 12 +++--- ionic/transitions/none-transition.js | 18 ++++----- 12 files changed, 118 insertions(+), 38 deletions(-) diff --git a/ionic/collide/animation.js b/ionic/collide/animation.js index 50e5889b1d..c7043bf0ed 100644 --- a/ionic/collide/animation.js +++ b/ionic/collide/animation.js @@ -18,6 +18,12 @@ export class Animation { this.children = []; + this._addStartClasses = []; + this._removeStartClasses = []; + + this._addEndClasses = []; + this._removeEndClasses = []; + this.elements(ele); } @@ -53,7 +59,7 @@ export class Animation { return this; } - _setupElements(clearCache, onNextFrame) { + _prepare(clearCache, onNextFrame) { // ensure another animation wasnt about to start if (this._nextAF) { @@ -105,7 +111,7 @@ export class Animation { this._options = util.extend(opts, this._options); // get the elements ready - for (var i = 0, ii = this._ele.length; i < ii; i++) { + for (let i = 0, ii = this._ele.length; i < ii; i++) { processElement('start', this, i, clearCache); } @@ -118,7 +124,7 @@ export class Animation { return Promise.resolve(); } - _queueAnimation() { + _queue() { if (this._ele.length) { if (this._call === null) { @@ -173,9 +179,9 @@ export class Animation { var clearCache = (this._aniType !== 'start'); - var promise = this._setupElements(clearCache, () => { + var promise = this._prepare(clearCache, () => { this._aniType = 'start'; - this._queueAnimation(); + this._queue(); }); promises.push(promise); @@ -193,7 +199,7 @@ export class Animation { var clearCache = (this._aniType !== 'progress'); - var promise = this._setupElements(clearCache, () => { + var promise = this._prepare(clearCache, () => { this._aniType = 'progress'; }); @@ -212,7 +218,7 @@ export class Animation { this.children[i].progress(value); } - this._queueAnimation(); + this._queue(); } } @@ -228,6 +234,26 @@ export class Animation { return this; } + addStartClass(className) { + this._addStartClasses.push(className); + return this; + } + + removeStartClass(className) { + this._removeStartClasses.push(className); + return this; + } + + addEndClass(className) { + this._addEndClasses.push(className); + return this; + } + + removeEndClass(className) { + this._removeEndClasses.push(className); + return this; + } + isAnimating() { var eleData; if (this._ele) { diff --git a/ionic/collide/collide.js b/ionic/collide/collide.js index 12b53e746d..023c5d6c95 100644 --- a/ionic/collide/collide.js +++ b/ionic/collide/collide.js @@ -79,8 +79,15 @@ export let Collide = { rootPropertyValueCache: {}, /* A cache for transform updates, which must be manually flushed via CSS.flushTransformCache(). */ - transformCache: {} + transformCache: {}, + + startAddCls: null, + startRmvCls: null, + endAddCls: null, + endRmvCls: null }; + + return element.$collide; }, /* get/set element data */ diff --git a/ionic/collide/complete-call.js b/ionic/collide/complete-call.js index 02dd0c9edf..c46b296ac5 100644 --- a/ionic/collide/complete-call.js +++ b/ionic/collide/complete-call.js @@ -46,6 +46,20 @@ export function completeCall(callIndex, isStopped) { } } + if (eleData.endAddCls) { + for (var k = 0; k < eleData.endAddCls.length; k++) { + element.classList.add(eleData.endAddCls[k]); + } + eleData.endAddCls = null; + } + + if (eleData.endRmvCls) { + for (var k = 0; k < eleData.endRmvCls.length; k++) { + element.classList.remove(eleData.endRmvCls[k]); + } + eleData.endRmvCls = null; + } + /* If the element's queue is empty (if only the 'inprogress' item is left at position 0) or if its queue is about to run a non-Collide-initiated entry, turn off the isAnimating flag. A non-Collide-initiatied queue entry's logic might alter an element's CSS values and thereby cause Collide's cached value data to go stale. To detect if a queue entry was initiated by Collide, diff --git a/ionic/collide/process-element.js b/ionic/collide/process-element.js index 2c2332bad6..15eb33a650 100644 --- a/ionic/collide/process-element.js +++ b/ionic/collide/process-element.js @@ -23,6 +23,7 @@ export function processElement(action, animation, elementIndex, clearCache) { var elements = animation._ele; var elementsLength = elements.length; var element = elements[elementIndex]; + var eleData; var opts = animation._options; var propertiesMap = animation._properties; @@ -50,9 +51,16 @@ export function processElement(action, animation, elementIndex, clearCache) { ******************/ if (data(element) === undefined) { - Collide.initData(element); + eleData = Collide.initData(element); + } else { + eleData = data(element); } + if (animation._addStartClasses.length) eleData.startAddCls = animation._addStartClasses.slice(); + if (animation._removeStartClasses.length) eleData.startRmvCls = animation._removeStartClasses.slice(); + if (animation._addEndClasses.length) eleData.endAddCls = animation._addEndClasses.slice(); + if (animation._removeEndClasses.length) eleData.endRmvCls = animation._removeEndClasses.slice(); + /****************** Option: Delay @@ -236,7 +244,7 @@ export function processElement(action, animation, elementIndex, clearCache) { /* The per-element isAnimating flag is used to indicate whether it's safe (i.e. the data isn't stale) to transfer over end values to use as start values. If it's set to true and there is a previous Collide call to pull values from, do so. */ - var eleData = data(element); + eleData = data(element); if (clearCache) { eleData.tweensContainer = undefined; } else if (eleData.tweensContainer && eleData.isAnimating === true) { @@ -345,7 +353,7 @@ export function processElement(action, animation, elementIndex, clearCache) { Property support is determined via prefixCheck(), which returns a false flag when no supported is detected. */ /* Note: Since SVG elements have some of their properties directly applied as HTML attributes, there is no way to check for their explicit browser support, and so we skip skip this check for them. */ - if (!data(element).isSVG && rootProperty !== 'tween' && CSS.Names.prefixCheck(rootProperty)[1] === false && CSS.Normalizations.registered[rootProperty] === undefined) { + if (!eleData.isSVG && rootProperty !== 'tween' && CSS.Names.prefixCheck(rootProperty)[1] === false && CSS.Normalizations.registered[rootProperty] === undefined) { if (Collide.debug) console.log('Skipping [' + rootProperty + '] due to a lack of browser support.'); continue; } @@ -370,7 +378,7 @@ export function processElement(action, animation, elementIndex, clearCache) { /* The previous call's rootPropertyValue is extracted from the element's data cache since that's the instance of rootPropertyValue that gets freshly updated by the tweening process, whereas the rootPropertyValue attached to the incoming lastTweensContainer is equal to the root property's value prior to any tweening. */ - rootPropertyValue = data(element).rootPropertyValueCache[rootProperty]; + rootPropertyValue = eleData.rootPropertyValueCache[rootProperty]; /* If values were not transferred from a previous Collide call, query the DOM as needed. */ } else { @@ -607,8 +615,8 @@ export function processElement(action, animation, elementIndex, clearCache) { /* Store the tweensContainer and options if we're working on the default effects queue, so that they can be used by the reverse command. */ if (opts.queue === '') { - data(element).tweensContainer = tweensContainer; - data(element).opts = opts; + eleData.tweensContainer = tweensContainer; + eleData.opts = opts; } } diff --git a/ionic/collide/tick.js b/ionic/collide/tick.js index b9f93fadec..e89a1e95c9 100644 --- a/ionic/collide/tick.js +++ b/ionic/collide/tick.js @@ -109,6 +109,20 @@ function tick(timestamp) { continue; } + if (eleData.startAddCls) { + for (var k = 0; k < eleData.startAddCls.length; k++) { + element.classList.add(eleData.startAddCls[k]); + } + eleData.startAddCls = null; + } + + if (eleData.startRmvCls) { + for (var k = 0; k < eleData.startRmvCls.length; k++) { + element.classList.remove(eleData.startRmvCls[k]); + } + eleData.startRmvCls = null; + } + var transformPropertyExists = false; diff --git a/ionic/components/app/structure.scss b/ionic/components/app/structure.scss index 167a105646..3f4e1e5779 100644 --- a/ionic/components/app/structure.scss +++ b/ionic/components/app/structure.scss @@ -76,6 +76,10 @@ ion-toolbar { // by default .nav-item is hidden // and the transition animation will display it display: none; + + &.show-nav-item { + display: block; + } } ion-content { diff --git a/ionic/components/nav/test/basic/pages/second-page.js b/ionic/components/nav/test/basic/pages/second-page.js index d7a80255a3..291361df58 100644 --- a/ionic/components/nav/test/basic/pages/second-page.js +++ b/ionic/components/nav/test/basic/pages/second-page.js @@ -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, Header, Toolbar} from 'ionic/ionic'; +import {NavController, NavParams, Header, Toolbar, ToolbarTitle} from 'ionic/ionic'; import {ThirdPage} from './third-page'; @Component() @View({ templateUrl: 'pages/second-page.html', - directives: [Header, Toolbar] + directives: [Header, Toolbar, ToolbarTitle] }) export class SecondPage { constructor( diff --git a/ionic/components/nav/test/basic/pages/third-page.js b/ionic/components/nav/test/basic/pages/third-page.js index 279dad6457..fe1bad72fa 100644 --- a/ionic/components/nav/test/basic/pages/third-page.js +++ b/ionic/components/nav/test/basic/pages/third-page.js @@ -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, Header, Toolbar} from 'ionic/ionic'; +import {NavController, Header, Toolbar, ToolbarTitle} from 'ionic/ionic'; @Component() @View({ templateUrl: 'pages/third-page.html', - directives: [Header, Toolbar] + directives: [Header, Toolbar, ToolbarTitle] }) export class ThirdPage { constructor( diff --git a/ionic/components/toolbar/extensions/ios.scss b/ionic/components/toolbar/extensions/ios.scss index 15469418f2..17caa01ba1 100644 --- a/ionic/components/toolbar/extensions/ios.scss +++ b/ionic/components/toolbar/extensions/ios.scss @@ -39,6 +39,7 @@ $toolbar-ios-button-background-color: transparent !default; .toolbar [side="primary"] { @include flex-order(map-get($toolbar-order-ios, 'primary')); } + .toolbar [side="secondary"] { @include flex-order(map-get($toolbar-order-ios, 'secondary')); } @@ -46,8 +47,10 @@ $toolbar-ios-button-background-color: transparent !default; ion-title { @include flex-order(map-get($toolbar-order-ios, 'title')); font-size: $toolbar-ios-title-font-size; + font-weight: 500; text-align: center; } + .toolbar-back-button { @include flex-order(map-get($toolbar-order-ios, 'back-button')); } diff --git a/ionic/components/toolbar/toolbar.scss b/ionic/components/toolbar/toolbar.scss index fa2c569da5..90bc88618a 100644 --- a/ionic/components/toolbar/toolbar.scss +++ b/ionic/components/toolbar/toolbar.scss @@ -20,16 +20,20 @@ $toolbar-secondary-flex-order: 10; } ion-toolbar { - /*@include flex-display(); @include flex-direction(row); @include flex-align-items(center); - @include flex-justify-content(space-between);*/ + @include flex-justify-content(space-between); - // by default ion-toolbar is hidden - // and the transition animation will display it + // by default ion-toolbar is display:none and + // the transition animation will add the show class display: none; + + &.show-toolbar { + @include flex-display(); + } } + // buttons are primary by default ion-toolbar .button, ion-toolbar [side="primary"] { @@ -40,7 +44,7 @@ ion-toolbar [side="secondary"] { @include flex-order(map-get($toolbar-order-core, 'secondary')); } -.toolbar-title.toolbar-title { +ion-title { // double selector to override the following @include flex-display(); @include flex(1); diff --git a/ionic/transitions/ios-transition.js b/ionic/transitions/ios-transition.js index 961dcd79b8..66a9ecccc3 100644 --- a/ionic/transitions/ios-transition.js +++ b/ionic/transitions/ios-transition.js @@ -44,26 +44,26 @@ class IOSTransition extends Animation { // entering item moves to center // before starting, set enteringItem to display: block enteringContent - .display('block') + .addStartClass('show-nav-item') .to(TRANSLATE_X, 0) .to(OPACITY, 1); enteringToolbars - .display('block') + .addStartClass('show-toolbar') .to(TRANSLATE_X, 0) .to(OPACITY, 1); // leaving view moves off screen // when completed, set leavingItem to display: none leavingContent + .removeEndClass('show-nav-item') .from(TRANSLATE_X, 0) - .from(OPACITY, 1) - .display('none'); + .from(OPACITY, 1); leavingToolbars + .removeEndClass('show-toolbar') .from(TRANSLATE_X, 0) - .from(OPACITY, 1) - .display('none'); + .from(OPACITY, 1); // set properties depending on direction if (opts.direction === 'back') { diff --git a/ionic/transitions/none-transition.js b/ionic/transitions/none-transition.js index 2bb86c483b..78ac4d9bdd 100644 --- a/ionic/transitions/none-transition.js +++ b/ionic/transitions/none-transition.js @@ -10,26 +10,26 @@ class NoneTransition { // show entering contet let enteringContent = enteringItem.getContent(); - enteringContent.style.display = 'block'; + enteringContent.classList.add('show-nav-item'); enteringContent.style.transform = 'translateX(0%)'; // show entering headers - let toolbarElements = enteringItem.getToolbars(); - for (let i = 0; i < toolbarElements.length; i++) { - toolbarElements[i].style.display = 'block'; - toolbarElements[i].style.transform = 'translateX(0%)'; + let enteringToolbars = enteringItem.getToolbars(); + for (let i = 0; i < enteringToolbars.length; i++) { + enteringToolbars[i].classList.add('show-toolbar'); + enteringToolbars[i].style.transform = 'translateX(0%)'; } // hide the leaving item if (leavingItem) { let leavingContent = leavingItem.getContent(); if (leavingContent) { - leavingContent.style.display = ''; + leavingContent.classList.remove('show-nav-item'); } - let leavingHeaderElements = leavingItem.getToolbars(); - for (let i = 0; i < leavingHeaderElements.length; i++) { - leavingHeaderElements[i].style.display = ''; + let leavingToolbars = leavingItem.getToolbars(); + for (let i = 0; i < leavingToolbars.length; i++) { + leavingToolbars[i].classList.remove('show-toolbar'); } } }