From d13fa4e2cfc3b3039239a9e09ea701ad9bc624b4 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Thu, 16 Jun 2016 11:28:02 -0500 Subject: [PATCH] refactor(structure): allow content to scroll under headers/footers --- src/animations/animation.ts | 349 ++++++++++++++---- src/animations/builtins.ts | 4 +- src/components/action-sheet/action-sheet.ts | 12 +- src/components/alert/alert.ts | 38 +- src/components/app/structure.scss | 186 ++++++---- src/components/content/content.ts | 22 +- src/components/loading/loading.ts | 36 +- src/components/modal/modal.ts | 36 +- src/components/nav/nav-controller.ts | 35 +- src/components/nav/nav.ts | 2 +- src/components/nav/test/basic/index.ts | 66 ++-- src/components/nav/view-controller.ts | 145 ++++---- src/components/navbar/navbar.ts | 22 +- src/components/picker/picker.ts | 6 +- src/components/popover/popover.ts | 49 +-- src/components/slides/test/intro/index.ts | 1 - src/components/slides/test/intro/main.html | 18 +- src/components/tabs/tab.ts | 36 +- src/components/tabs/tabs.ios.scss | 10 +- src/components/tabs/tabs.md.scss | 4 +- src/components/tabs/tabs.scss | 56 --- src/components/tabs/tabs.ts | 80 ++-- src/components/tabs/tabs.wp.scss | 4 +- src/components/tabs/test/advanced/index.ts | 107 +----- .../tabs/test/advanced/modalChat.html | 9 + src/components/tabs/test/advanced/signIn.html | 21 ++ .../tabs/test/advanced/tab1page1.html | 15 + .../tabs/test/advanced/tab1page2.html | 12 + .../tabs/test/advanced/tab1page3.html | 11 + .../tabs/test/advanced/tab2page1.html | 11 + .../tabs/test/advanced/tab2page2.html | 12 + .../tabs/test/advanced/tab2page3.html | 11 + .../tabs/test/advanced/tab3page1.html | 9 + src/components/tabs/test/basic/index.ts | 57 +-- src/components/tabs/test/child-navs/index.ts | 58 +-- src/components/tabs/test/ghost/index.ts | 44 ++- src/components/toast/test/basic/index.ts | 8 +- src/components/toast/test/basic/main.html | 8 +- src/components/toast/toast.ts | 123 +++--- src/components/toolbar/toolbar-item.ts | 33 ++ src/components/toolbar/toolbar-title.ts | 65 ++++ src/components/toolbar/toolbar.scss | 9 - src/components/toolbar/toolbar.ts | 126 +++---- .../virtual-scroll/test/basic/main.html | 18 +- .../test/image-gallery/main.html | 18 +- .../test/sliding-item/main.html | 18 +- src/config/bootstrap.ts | 55 +-- src/config/directives.ts | 8 +- src/config/modes.ts | 2 +- src/transitions/page-transition.ts | 142 +++++++ src/transitions/transition-ios.ts | 31 +- src/transitions/transition-md.ts | 22 +- src/transitions/transition-wp.ts | 22 +- src/transitions/transition.ts | 21 +- src/util/util.scss | 5 + tooling/generators/page/page.tmpl.html | 12 +- tooling/generators/page/page.tmpl.ts | 6 +- 57 files changed, 1390 insertions(+), 956 deletions(-) create mode 100644 src/components/tabs/test/advanced/modalChat.html create mode 100644 src/components/tabs/test/advanced/signIn.html create mode 100644 src/components/tabs/test/advanced/tab1page1.html create mode 100644 src/components/tabs/test/advanced/tab1page2.html create mode 100644 src/components/tabs/test/advanced/tab1page3.html create mode 100644 src/components/tabs/test/advanced/tab2page1.html create mode 100644 src/components/tabs/test/advanced/tab2page2.html create mode 100644 src/components/tabs/test/advanced/tab2page3.html create mode 100644 src/components/tabs/test/advanced/tab3page1.html create mode 100644 src/components/toolbar/toolbar-item.ts create mode 100644 src/components/toolbar/toolbar-title.ts create mode 100644 src/transitions/page-transition.ts diff --git a/src/animations/animation.ts b/src/animations/animation.ts index 0ab680a6f3..03f59df759 100644 --- a/src/animations/animation.ts +++ b/src/animations/animation.ts @@ -4,25 +4,37 @@ import {assign, isDefined} from '../util/util'; /** * @private - **/ + * + * - play + * - Add before classes - DOM WRITE + * - Remove before classes - DOM WRITE + * - Add before inline styles - DOM WRITE + * - set inline FROM styles - DOM WRITE + * - RAF + * - run before functions that have dom reads - DOM READ + * - run before functions that have dom writes - DOM WRITE + * - set css transition duration/easing - DOM WRITE + * - RAF + * - set inline TO styles - DOM WRITE + */ export class Animation { private _parent: Animation; - private _c: Animation[]; - private _el: HTMLElement[]; + private _c: Animation[] = []; + private _el: HTMLElement[] = []; private _opts: AnimationOptions; - private _fx: {[key: string]: EffectProperty}; + private _fx: {[key: string]: EffectProperty} = {}; private _dur: number; private _easing: string; - private _bfSty: { [property: string]: any; }; - private _bfAdd: string[]; - private _bfRmv: string[]; - private _afSty: { [property: string]: any; }; - private _afAdd: string[]; - private _afRmv: string[]; - private _pFns: Function[]; - private _fFns: Function[]; - private _fOnceFns: Function[]; - private _wChg: boolean = false; + private _bfSty: { [property: string]: any; } = {}; + private _bfAdd: string[] = []; + private _bfRmv: string[] = []; + private _afSty: { [property: string]: any; } = {}; + private _afAdd: string[] = []; + private _afRmv: string[] = []; + private _bfReadFns: Function[] = []; + private _bfWriteFns: Function[] = []; + private _fFns: Function[] = []; + private _fOnceFns: Function[] = []; private _rv: boolean = false; private _unregTrans: Function; private _tmr: number; @@ -33,7 +45,6 @@ export class Animation { public hasCompleted: boolean = false; constructor(ele?: any, opts: AnimationOptions = {}) { - this._reset(); this.element(ele); this._opts = assign({ @@ -41,22 +52,15 @@ export class Animation { }, opts); } + /** + * NO DOM + */ _reset() { - this._el = []; - this._c = []; this._fx = {}; - this._bfSty = {}; - this._bfAdd = []; - this._bfRmv = []; this._afSty = {}; - this._afAdd = []; - this._afRmv = []; - - this._pFns = []; - this._fFns = []; - this._fOnceFns = []; + this._el.length = this._c.length = this._bfAdd.length = this._bfRmv.length = this._afAdd.length = this._afRmv.length = this._fFns.length = this._bfReadFns.length = this._bfWriteFns.length = this._fOnceFns.length = 0; this._easing = this._dur = null; } @@ -83,6 +87,9 @@ export class Animation { return this; } + /** + * NO DOM + */ private _addEle(ele: any) { if (ele.nativeElement) { ele = ele.nativeElement; @@ -90,46 +97,67 @@ export class Animation { if (ele.nodeType === 1) { this._el.push(ele); - - // does this element suport will-change property? - this._wChg = (typeof ele.style.willChange !== 'undefined'); } } + /** + * NO DOM + */ parent(parentAnimation: Animation): Animation { this._parent = parentAnimation; return this; } + /** + * NO DOM + */ add(childAnimation: Animation): Animation { childAnimation.parent(this); this._c.push(childAnimation); return this; } + /** + * NO DOM + */ getDuration(): number { return this._dur !== null ? this._dur : (this._parent && this._parent.getDuration()) || 0; } + /** + * NO DOM + */ duration(milliseconds: number): Animation { this._dur = milliseconds; return this; } + /** + * NO DOM + */ getEasing(): string { return this._easing !== null ? this._easing : (this._parent && this._parent.getEasing()) || null; } + /** + * NO DOM + */ easing(name: string): Animation { this._easing = name; return this; } + /** + * NO DOM + */ from(prop: string, val: any): Animation { this._addProp('from', prop, val); return this; } + /** + * NO DOM + */ to(prop: string, val: any, clearProperyAfterTransition?: boolean): Animation { var fx: EffectProperty = this._addProp('to', prop, val); @@ -142,10 +170,16 @@ export class Animation { return this; } + /** + * NO DOM + */ fromTo(prop: string, fromVal: any, toVal: any, clearProperyAfterTransition?: boolean): Animation { return this.from(prop, fromVal).to(prop, toVal, clearProperyAfterTransition); } + /** + * NO DOM + */ private _addProp(state: string, prop: string, val: any): EffectProperty { var fxProp: EffectProperty = this._fx[prop]; @@ -166,7 +200,7 @@ export class Animation { } // add from/to EffectState to the EffectProperty - var fxState = fxProp[state] = { + var fxState: EffectState = fxProp[state] = { val: val, num: null, unit: '', @@ -188,14 +222,9 @@ export class Animation { return fxProp; } - fadeIn(): Animation { - return this.fromTo('opacity', 0.001, 1, true); - } - - fadeOut(): Animation { - return this.fromTo('opacity', 0.999, 0); - } - + /** + * NO DOM + */ get before() { return { addClass: (className: string): Animation => { @@ -215,10 +244,21 @@ export class Animation { this._bfSty[propertyNames[i]] = ''; } return this; + }, + addDomReadFn: (domReadFn: Function): Animation => { + this._bfReadFns.push(domReadFn); + return this; + }, + addDomWriteFn: (domWriteFn: Function): Animation => { + this._bfWriteFns.push(domWriteFn); + return this; } }; } + /** + * NO DOM + */ get after() { return { addClass: (className: string): Animation => { @@ -242,12 +282,18 @@ export class Animation { }; } + /** + * DOM WRITE + */ play(opts: PlayOptions = {}) { var self = this; var i: number; - var duration: number = isDefined(opts.duration) ? opts.duration : self._dur; - console.debug('Animation, play, duration', duration, 'easing', self._easing); + if (isDefined(opts.duration)) { + self._dur = opts.duration; + } + + console.debug('Animation, play, duration', self._dur, 'easing', self._easing); // always default that an animation does not tween // a tween requires that an Animation class has an element @@ -255,11 +301,6 @@ export class Animation { // and that the FROM/TO effect can tween numeric values self.hasTween = false; self.hasCompleted = false; - - // fire off all the onPlays - for (i = 0; i < self._pFns.length; i++) { - self._pFns[i](); - } self.isPlaying = true; // this is the top level animation and is in full control @@ -269,34 +310,51 @@ export class Animation { // FROM property and transition duration, wait a few frames, then // kick off the animation by setting the TO property for each animation - // stage all of the before css classes and inline styles - // will recursively stage all child elements - self._before(); - // ensure all past transition end events have been cleared self._clearAsync(); - if (duration > 30) { + if (self._dur > 30) { // this animation has a duration, so it should animate // place all the elements with their FROM properties // set the FROM properties + // ******** DOM WRITE **************** self._progress(0); // add the will-change or translateZ properties when applicable + // ******** DOM WRITE **************** self._willChg(true); // set the async TRANSITION END event // and run onFinishes when the transition ends - self._asyncEnd(duration, true); + // ******** DOM WRITE **************** + self._asyncEnd(self._dur, true); // begin each animation when everything is rendered in their place // and the transition duration/easing is ready to go rafFrames(self._opts.renderDelay / 16, function() { // there's been a moment and the elements are in place + // fire off all the "before" function that have DOM READS in them + // elements will be in the DOM, however visibily hidden + // so we can read their dimensions if need be + // ******** DOM READ **************** + self._beforeReadFn(); + + // ******** DOM READS ABOVE / DOM WRITES BELOW **************** + + // fire off all the "before" function that have DOM WRITES in them + // ******** DOM WRITE **************** + self._beforeWriteFn(); + + // stage all of the before css classes and inline styles + // will recursively stage all child elements + // ******** DOM WRITE **************** + self._before(); + // now set the TRANSITION duration/easing - self._setTrans(duration, false); + // ******** DOM WRITE **************** + self._setTrans(self._dur, false); // wait a few moments again to wait for the transition // info to take hold in the DOM @@ -305,25 +363,55 @@ export class Animation { // and the transition duration/easing is set // now set the TO properties // which will trigger the transition to begin + // ******** DOM WRITE **************** self._progress(1); }); }); } else { - // this animation does not have a duration, so it should not animate - // just go straight to the TO properties and call it done - self._progress(1); + // this animation does not have a duration + // but we still need to apply the styles and wait + // a frame so we can accurately read the dimensions + rafFrames(self._opts.renderDelay / 16, function() { - // since there was no animation, immediately run the after - self._after(); + // fire off all the "before" function that have DOM READS in them + // elements will be in the DOM, however visibily hidden + // so we can read their dimensions if need be + // ******** DOM READ **************** + self._beforeReadFn(); - // since there was no animation, it's done - // fire off all the onFinishes - self._didFinish(true); + // ******** DOM READS ABOVE / DOM WRITES BELOW **************** + + // fire off all the "before" function that have DOM WRITES in them + // ******** DOM WRITE **************** + self._beforeWriteFn(); + + // ensure before css has ran + // ******** DOM WRITE **************** + self._before(); + + // this animation does not have a duration, so it should not animate + // just go straight to the TO properties and call it done + // ******** DOM WRITE **************** + self._progress(1); + + // since there was no animation, immediately run the after + // ******** DOM WRITE **************** + self._after(); + + // since there was no animation, it's done + // fire off all the onFinishes + // and now you know + self._didFinish(true); + + }); } } + /** + * DOM WRITE + */ stop(opts: PlayOptions = {}) { var self = this; var duration = isDefined(opts.duration) ? opts.duration : 0; @@ -333,6 +421,7 @@ export class Animation { this._clearAsync(); // set the TO properties + // ******** DOM WRITE **************** self._progress(stepValue); if (duration > 30) { @@ -340,15 +429,18 @@ export class Animation { // place all the elements with their TO properties // now set the TRANSITION duration + // ******** DOM WRITE **************** self._setTrans(duration, true); // set the async TRANSITION END event // and run onFinishes when the transition ends + // ******** DOM WRITE **************** self._asyncEnd(duration, false); } else { // this animation does not have a duration, so it should not animate // just go straight to the TO properties and call it done + // ******** DOM WRITE **************** self._after(); // since there was no animation, it's done @@ -357,6 +449,9 @@ export class Animation { } } + /** + * DOM WRITE + */ _asyncEnd(duration: number, shouldComplete: boolean) { var self = this; @@ -367,9 +462,11 @@ export class Animation { self._clearAsync(); // set the after styles + // ******** DOM WRITE **************** self._after(); // remove will change properties + // ******** DOM WRITE **************** self._willChg(false); // transition finished @@ -386,15 +483,19 @@ export class Animation { self._clearAsync(); // too late to have a smooth animation, just finish it + // ******** DOM WRITE **************** self._setTrans(0, true); // ensure the ending progress step gets rendered + // ******** DOM WRITE **************** self._progress(1); // set the after styles + // ******** DOM WRITE **************** self._after(); // remove will change properties + // ******** DOM WRITE **************** self._willChg(false); // transition finished @@ -409,6 +510,9 @@ export class Animation { self._tmr = nativeTimeout(onTransitionFallback, duration + 400); } + /** + * NO DOM + */ _clearAsync() { this._unregTrans && this._unregTrans(); if (this._tmr) { @@ -417,6 +521,9 @@ export class Animation { } } + /** + * DOM WRITE + */ _progress(stepValue: number) { // bread 'n butter var i: number; @@ -427,6 +534,7 @@ export class Animation { var tweenEffect: boolean; for (i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** this._c[i]._progress(stepValue); } @@ -469,6 +577,7 @@ export class Animation { } else { for (i = 0; i < this._el.length; i++) { + // ******** DOM WRITE **************** this._el[i].style[prop] = val; } } @@ -479,13 +588,14 @@ export class Animation { // place all transforms on the same property if (transforms.length) { - if (!this._wChg) { + if (!SUPPORTS_WILL_CHANGE) { // if the element doesn't support will-change // then auto add translateZ for transform properties transforms.push('translateZ(0px)'); } for (i = 0; i < this._el.length; i++) { + // ******** DOM WRITE **************** this._el[i].style[CSS.transform] = transforms.join(' '); } } @@ -494,39 +604,49 @@ export class Animation { } + /** + * DOM WRITE + */ _setTrans(duration: number, forcedLinearEasing: boolean) { var i: number; var easing: string; // set the TRANSITION properties inline on the element for (i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** this._c[i]._setTrans(duration, forcedLinearEasing); } if (Object.keys(this._fx).length) { for (i = 0; i < this._el.length; i++) { // all parent/child animations should have the same duration + // ******** DOM WRITE **************** this._el[i].style[CSS.transitionDuration] = duration + 'ms'; // each animation can have a different easing easing = (forcedLinearEasing ? 'linear' : this.getEasing()); if (easing) { + // ******** DOM WRITE **************** this._el[i].style[CSS.transitionTimingFn] = easing; } } } } + /** + * DOM WRITE + */ _willChg(addWillChange: boolean) { var i: number; var wc: string[]; var prop: string; for (i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** this._c[i]._willChg(addWillChange); } - if (this._wChg) { + if (SUPPORTS_WILL_CHANGE) { wc = []; if (addWillChange) { @@ -538,11 +658,15 @@ export class Animation { } for (i = 0; i < this._el.length; i++) { + // ******** DOM WRITE **************** this._el[i].style['willChange'] = wc.join(','); } } } + /** + * DOM WRITE + */ _before() { // before the RENDER_DELAY // before the animations have started @@ -553,6 +677,7 @@ export class Animation { // stage all of the child animations for (i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** this._c[i]._before(); } @@ -562,22 +687,62 @@ export class Animation { // css classes to add before the animation for (j = 0; j < this._bfAdd.length; j++) { + // ******** DOM WRITE **************** ele.classList.add(this._bfAdd[j]); } // css classes to remove before the animation for (j = 0; j < this._bfRmv.length; j++) { + // ******** DOM WRITE **************** ele.classList.remove(this._bfRmv[j]); } // inline styles to add before the animation for (prop in this._bfSty) { + // ******** DOM WRITE **************** ele.style[prop] = this._bfSty[prop]; } } } } + /** + * DOM READ + */ + _beforeReadFn() { + var i: number; + + for (i = 0; i < this._c.length; i++) { + // ******** DOM READ **************** + this._c[i]._beforeReadFn(); + } + + for (i = 0; i < this._bfReadFns.length; i++) { + // ******** DOM READ **************** + this._bfReadFns[i](); + } + } + + /** + * DOM WRITE + */ + _beforeWriteFn() { + var i: number; + + for (i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** + this._c[i]._beforeWriteFn(); + } + + for (i = 0; i < this._bfReadFns.length; i++) { + // ******** DOM WRITE **************** + this._bfWriteFns[i](); + } + } + + /** + * DOM WRITE + */ _after() { // after the animations have finished var i: number; @@ -586,6 +751,7 @@ export class Animation { var ele: HTMLElement; for (i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** this._c[i]._after(); } @@ -593,7 +759,9 @@ export class Animation { ele = this._el[i]; // remove the transition duration/easing + // ******** DOM WRITE **************** ele.style[CSS.transitionDuration] = ''; + // ******** DOM WRITE **************** ele.style[CSS.transitionTimingFn] = ''; if (this._rv) { @@ -601,16 +769,19 @@ export class Animation { // css classes that were added before the animation should be removed for (j = 0; j < this._bfAdd.length; j++) { + // ******** DOM WRITE **************** ele.classList.remove(this._bfAdd[j]); } // css classes that were removed before the animation should be added for (j = 0; j < this._bfRmv.length; j++) { + // ******** DOM WRITE **************** ele.classList.add(this._bfRmv[j]); } // inline styles that were added before the animation should be removed for (prop in this._bfSty) { + // ******** DOM WRITE **************** ele.style[prop] = ''; } @@ -619,16 +790,19 @@ export class Animation { // css classes to add after the animation for (j = 0; j < this._afAdd.length; j++) { + // ******** DOM WRITE **************** ele.classList.add(this._afAdd[j]); } // css classes to remove after the animation for (j = 0; j < this._afRmv.length; j++) { + // ******** DOM WRITE **************** ele.classList.remove(this._afRmv[j]); } // inline styles to add after the animation for (prop in this._afSty) { + // ******** DOM WRITE **************** ele.style[prop] = this._afSty[prop]; } } @@ -636,17 +810,26 @@ export class Animation { } + /** + * DOM WRITE + */ progressStart() { for (var i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** this._c[i].progressStart(); } + // ******** DOM WRITE **************** this._before(); // force no duration, linear easing + // ******** DOM WRITE **************** this._setTrans(0, true); } + /** + * DOM WRITE + */ progressStep(stepValue: number) { let now = Date.now(); @@ -657,6 +840,7 @@ export class Animation { stepValue = Math.min(1, Math.max(0, stepValue)); for (var i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** this._c[i].progressStep(stepValue); } @@ -666,18 +850,24 @@ export class Animation { stepValue = ((stepValue * -1) + 1); } + // ******** DOM WRITE **************** this._progress(stepValue); } } + /** + * DOM WRITE + */ progressEnd(shouldComplete: boolean, currentStepValue: number) { console.debug('Animation, progressEnd, shouldComplete', shouldComplete, 'currentStepValue', currentStepValue); for (var i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** this._c[i].progressEnd(shouldComplete, currentStepValue); } // set all the animations to their final position + // ******** DOM WRITE **************** this._progress(shouldComplete ? 1 : 0); // if it's already at the final position, or close, then it's done @@ -685,25 +875,29 @@ export class Animation { if (currentStepValue < 0.05 || currentStepValue > 0.95) { // the progress was already left off at the point that is finished // for example, the left menu was dragged all the way open already + // ******** DOM WRITE **************** this._after(); + + // ******** DOM WRITE **************** this._willChg(false); + this._didFinish(shouldComplete); } else { // the stepValue was left off at a point when it needs to finish transition still // for example, the left menu was opened 75% and needs to finish opening + // ******** DOM WRITE **************** this._asyncEnd(64, shouldComplete); // force quick duration, linear easing + // ******** DOM WRITE **************** this._setTrans(64, true); } } - onPlay(callback: Function): Animation { - this._pFns.push(callback); - return this; - } - + /** + * POSSIBLE DOM READ/WRITE + */ onFinish(callback: Function, onceTimeCallback: boolean = false, clearOnFinishCallacks: boolean = false): Animation { if (clearOnFinishCallacks) { this._fFns = []; @@ -718,6 +912,9 @@ export class Animation { return this; } + /** + * POSSIBLE DOM READ/WRITE + */ _didFinish(hasCompleted: boolean) { this.isPlaying = false; this.hasCompleted = hasCompleted; @@ -732,6 +929,9 @@ export class Animation { this._fOnceFns = []; } + /** + * NO DOM + */ reverse(shouldReverse: boolean = true): Animation { for (var i = 0; i < this._c.length; i++) { this._c[i].reverse(shouldReverse); @@ -740,17 +940,22 @@ export class Animation { return this; } + /** + * DOM WRITE + */ destroy(removeElement?: boolean) { var i: number; var ele: HTMLElement; for (i = 0; i < this._c.length; i++) { + // ******** DOM WRITE **************** this._c[i].destroy(removeElement); } if (removeElement) { for (i = 0; i < this._el.length; i++) { ele = this._el[i]; + // ******** DOM WRITE **************** ele.parentNode && ele.parentNode.removeChild(ele); } } @@ -759,6 +964,9 @@ export class Animation { this._reset(); } + /** + * NO DOM + */ _transEl(): HTMLElement { // get the lowest level element that has an Animation var i: number; @@ -774,9 +982,9 @@ export class Animation { return (this.hasTween && this._el.length ? this._el[0] : null); } - /* - STATIC CLASSES - */ + + // ***** STATIC CLASSES ********* + static create(name: string, opts: AnimationOptions = {}): Animation { let AnimationClass = AnimationRegistry[name]; @@ -825,5 +1033,6 @@ const TRANSFORMS: any = { }; const CSS_VALUE_REGEX = /(^-?\d*\.?\d*)(.*)/; +const SUPPORTS_WILL_CHANGE = (typeof document.documentElement.style['willChange'] !== 'undefined'); let AnimationRegistry: any = {}; diff --git a/src/animations/builtins.ts b/src/animations/builtins.ts index 25200d7750..367c6cfc9f 100644 --- a/src/animations/builtins.ts +++ b/src/animations/builtins.ts @@ -32,7 +32,7 @@ class FadeIn extends Animation { this .easing('ease-in') .duration(400) - .fadeIn(); + .fromTo('opacity', 0.001, 1, true); } } Animation.register('fade-in', FadeIn); @@ -44,7 +44,7 @@ class FadeOut extends Animation { this .easing('ease-out') .duration(250) - .fadeOut(); + .fromTo('opacity', 0.999, 0); } } Animation.register('fade-out', FadeOut); diff --git a/src/components/action-sheet/action-sheet.ts b/src/components/action-sheet/action-sheet.ts index aa6e5abe5f..ec52b560c0 100644 --- a/src/components/action-sheet/action-sheet.ts +++ b/src/components/action-sheet/action-sheet.ts @@ -377,7 +377,7 @@ export interface ActionSheetOptions { class ActionSheetSlideIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); @@ -394,7 +394,7 @@ Transition.register('action-sheet-slide-in', ActionSheetSlideIn); class ActionSheetSlideOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); @@ -411,7 +411,7 @@ Transition.register('action-sheet-slide-out', ActionSheetSlideOut); class ActionSheetMdSlideIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); @@ -428,7 +428,7 @@ Transition.register('action-sheet-md-slide-in', ActionSheetMdSlideIn); class ActionSheetMdSlideOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); @@ -444,7 +444,7 @@ Transition.register('action-sheet-md-slide-out', ActionSheetMdSlideOut); class ActionSheetWpSlideIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); @@ -461,7 +461,7 @@ Transition.register('action-sheet-wp-slide-in', ActionSheetWpSlideIn); class ActionSheetWpSlideOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); diff --git a/src/components/alert/alert.ts b/src/components/alert/alert.ts index 49c0a500d3..0716e27805 100644 --- a/src/components/alert/alert.ts +++ b/src/components/alert/alert.ts @@ -571,7 +571,7 @@ class AlertCmp { // this is an alert with text inputs // return an object of all the values with the input name as the key - let values = {}; + let values: {[k: string]: string} = {}; this.d.inputs.forEach(i => { values[i.name] = i.value; }); @@ -605,14 +605,14 @@ export interface AlertInputOptions { */ class AlertPopIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.alert-wrapper')); - wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.1', '1'); - backdrop.fromTo('opacity', '0.01', '0.3'); + wrapper.fromTo('opacity', 0.01, 1).fromTo('scale', 1.1, 1); + backdrop.fromTo('opacity', 0.01, 0.3); this .easing('ease-in-out') @@ -626,14 +626,14 @@ Transition.register('alert-pop-in', AlertPopIn); class AlertPopOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.alert-wrapper')); - wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '0.9'); - backdrop.fromTo('opacity', '0.3', '0'); + wrapper.fromTo('opacity', 0.99, 0).fromTo('scale', 1, 0.9); + backdrop.fromTo('opacity', 0.3, 0); this .easing('ease-in-out') @@ -647,14 +647,14 @@ Transition.register('alert-pop-out', AlertPopOut); class AlertMdPopIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.alert-wrapper')); - wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.1', '1'); - backdrop.fromTo('opacity', '0.01', '0.5'); + wrapper.fromTo('opacity', 0.01, 1).fromTo('scale', 1.1, 1); + backdrop.fromTo('opacity', 0.01, 0.5); this .easing('ease-in-out') @@ -668,14 +668,14 @@ Transition.register('alert-md-pop-in', AlertMdPopIn); class AlertMdPopOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.alert-wrapper')); - wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '0.9'); - backdrop.fromTo('opacity', '0.5', '0'); + wrapper.fromTo('opacity', 0.99, 0).fromTo('scale', 1, 0.9); + backdrop.fromTo('opacity', 0.5, 0); this .easing('ease-in-out') @@ -690,14 +690,14 @@ Transition.register('alert-md-pop-out', AlertMdPopOut); class AlertWpPopIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.alert-wrapper')); - wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.3', '1'); - backdrop.fromTo('opacity', '0.01', '0.5'); + wrapper.fromTo('opacity', 0.01, 1).fromTo('scale', 1.3, 1); + backdrop.fromTo('opacity', 0.01, 0.5); this .easing('cubic-bezier(0,0 0.05,1)') @@ -711,14 +711,14 @@ Transition.register('alert-wp-pop-in', AlertWpPopIn); class AlertWpPopOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.alert-wrapper')); - wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '1.3'); - backdrop.fromTo('opacity', '0.5', '0'); + wrapper.fromTo('opacity', 0.99, 0).fromTo('scale', 1, 1.3); + backdrop.fromTo('opacity', 0.5, 0); this .easing('ease-out') diff --git a/src/components/app/structure.scss b/src/components/app/structure.scss index 3b7a50600e..3805777523 100644 --- a/src/components/app/structure.scss +++ b/src/components/app/structure.scss @@ -15,6 +15,8 @@ $z-index-refresher: 0; $z-index-navbar-section: 10; +$z-index-page-container: 0; +$z-index-selected-tab: 1; $z-index-toolbar: 10; $z-index-toolbar-background: -1; @@ -85,64 +87,138 @@ body { text-size-adjust: none; } -ion-app.app-init, + +// Nav Container Structure +// -------------------------------------------------- + +ion-app, ion-nav, +ion-tab, ion-tabs { position: absolute; top: 0; left: 0; - display: flex; + z-index: $z-index-page-container; + display: block; overflow: hidden; - flex-direction: column; - width: 100%; height: 100%; } -ion-navbar-section { - display: block; - - width: 100%; - min-height: 50px; +ion-tab scroll-cotent { + display: none; } -ion-content-section { - position: relative; - display: block; - - flex: 1; - - width: 100%; - height: 100%; +ion-tab.show-tab { + z-index: $z-index-selected-tab; } +ion-tab.show-tab scroll-cotent { + display: block; +} + + +// Page Container Structure +// -------------------------------------------------- + ion-page { position: absolute; top: 0; left: 0; - display: none; - - flex-direction: column; + display: block; width: 100%; height: 100%; - &.show-page { - display: flex; - } + // do not show, but still render so we can get dimensions + visibility: hidden; } ion-content { position: relative; + top: 0; + left: 0; display: block; - flex: 1; - width: 100%; height: 100%; } +ion-page > ion-content { + position: absolute; +} + +ion-page scroll-content { + // do not render the scroll-content at all until ready + display: none; +} + +ion-page.show-page { + // show the page now that it's ready + visibility: visible; +} + +ion-page.show-page scroll-content { + // render the content when ready + display: block; +} + +ion-page.tab-subpage { + position: fixed; + z-index: 10; +} + + +// Toolbar Container Structure +// -------------------------------------------------- + +ion-header { + position: absolute; + top: 0; + left: 0; + z-index: $z-index-toolbar; + display: block; + + width: 100%; +} + +ion-footer { + position: absolute; + bottom: 0; + left: 0; + z-index: $z-index-toolbar; + display: block; + + width: 100%; +} + +ion-tabbar { + position: absolute; + bottom: 0; + left: 0; + z-index: $z-index-toolbar; + display: flex; + + width: 100%; + + // default to hidden until ready + visibility: hidden; +} + +ion-tabbar.show-tabbar { + visibility: visible; +} + +[tabbarPlacement=top] > ion-tabbar { + top: 0; + bottom: auto; +} + + +// Scrollable Content +// -------------------------------------------------- + scroll-content { position: absolute; top: 0; @@ -169,59 +245,9 @@ ion-content.js-scroll > scroll-content { will-change: initial; } -ion-tabbar { - position: absolute; - top: 0; - left: 0; - display: block; - width: 100%; - min-height: 50px; -} - -ion-tab-section { - position: relative; - top: 0; - left: 0; - display: block; - overflow: hidden; - - width: 100%; - height: 100%; -} - -ion-page.tab-subpage { - position: fixed; - z-index: 10; -} - -ion-navbar { - position: absolute; - top: 0; - left: 0; - z-index: $z-index-navbar-section; - display: block; - - width: 100%; - min-height: 50px; -} - -ion-navbar-section ion-navbar.toolbar { - position: absolute; -} - -ion-toolbar { - display: block; - - width: 100%; -} - -ion-toolbar[position=bottom] { - bottom: 0; - z-index: $z-index-toolbar; -} - -.sticky { - position: sticky; - top: 0; -} +[nav-viewport], +[nav-portal], +[tab-portal] { + display: none; +} \ No newline at end of file diff --git a/src/components/content/content.ts b/src/components/content/content.ts index 0ab440e4c9..9057578e9a 100644 --- a/src/components/content/content.ts +++ b/src/components/content/content.ts @@ -57,7 +57,9 @@ import {ScrollView} from '../../util/scroll-view'; } }) export class Content extends Ion { - private _padding: number = 0; + private _paddingTop: number = 0; + private _paddingBottom: number = 0; + private _scrollPadding: number = 0; private _inputPolling: boolean = false; private _scroll: ScrollView; private _scLsn: Function; @@ -370,14 +372,24 @@ export class Content extends Ion { * so content below the keyboard can be scrolled into view. */ addScrollPadding(newPadding: number) { - if (newPadding > this._padding) { + if (newPadding > this._scrollPadding) { console.debug('content addScrollPadding', newPadding); - this._padding = newPadding; + this._scrollPadding = newPadding; this._scrollEle.style.paddingBottom = newPadding + 'px'; } } + /** + * @private + */ + setContentPadding(paddingTop: number, paddingBottom: number) { + this._paddingTop = paddingTop; + this._paddingBottom = paddingBottom; + this._scrollEle.style.paddingTop = (paddingTop > 0 ? paddingTop + 'px' : ''); + this._scrollEle.style.paddingBottom = (paddingBottom > 0 ? paddingBottom + 'px' : ''); + } + /** * @private */ @@ -386,8 +398,8 @@ export class Content extends Ion { this._inputPolling = true; this._keyboard.onClose(() => { - this._padding = 0; - this._scrollEle.style.paddingBottom = ''; + this._scrollPadding = 0; + this._scrollEle.style.paddingBottom = (this._paddingBottom > 0 ? this._paddingBottom + 'px' : ''); this._inputPolling = false; this.addScrollPadding(0); }, 200, Infinity); diff --git a/src/components/loading/loading.ts b/src/components/loading/loading.ts index 1275d27678..17fd6f98c3 100644 --- a/src/components/loading/loading.ts +++ b/src/components/loading/loading.ts @@ -230,14 +230,14 @@ export interface LoadingOptions { */ class LoadingPopIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.loading-wrapper')); - wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.1', '1'); - backdrop.fromTo('opacity', '0.01', '0.3'); + wrapper.fromTo('opacity', 0.01, 1).fromTo('scale', 1.1, 1); + backdrop.fromTo('opacity', 0.01, 0.3); this .easing('ease-in-out') @@ -251,14 +251,14 @@ export interface LoadingOptions { class LoadingPopOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.loading-wrapper')); - wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '0.9'); - backdrop.fromTo('opacity', '0.3', '0'); + wrapper.fromTo('opacity', 0.99, 0).fromTo('scale', 1, 0.9); + backdrop.fromTo('opacity', 0.3, 0); this .easing('ease-in-out') @@ -272,14 +272,14 @@ export interface LoadingOptions { class LoadingMdPopIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.loading-wrapper')); - wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.1', '1'); - backdrop.fromTo('opacity', '0.01', '0.50'); + wrapper.fromTo('opacity', 0.01, 1).fromTo('scale', 1.1, 1); + backdrop.fromTo('opacity', 0.01, 0.5); this .easing('ease-in-out') @@ -293,14 +293,14 @@ export interface LoadingOptions { class LoadingMdPopOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.loading-wrapper')); - wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '0.9'); - backdrop.fromTo('opacity', '0.50', '0'); + wrapper.fromTo('opacity', 0.99, 0).fromTo('scale', 1, 0.9); + backdrop.fromTo('opacity', 0.5, 0); this .easing('ease-in-out') @@ -314,14 +314,14 @@ export interface LoadingOptions { class LoadingWpPopIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.loading-wrapper')); - wrapper.fromTo('opacity', '0.01', '1').fromTo('scale', '1.3', '1'); - backdrop.fromTo('opacity', '0.01', '0.16'); + wrapper.fromTo('opacity', 0.01, 1).fromTo('scale', 1.3, 1); + backdrop.fromTo('opacity', 0.01, 0.16); this .easing('cubic-bezier(0,0 0.05,1)') @@ -335,14 +335,14 @@ export interface LoadingOptions { class LoadingWpPopOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.loading-wrapper')); - wrapper.fromTo('opacity', '1', '0').fromTo('scale', '1', '1.3'); - backdrop.fromTo('opacity', '0.16', '0'); + wrapper.fromTo('opacity', 0.99, 0).fromTo('scale', 1, 1.3); + backdrop.fromTo('opacity', 0.16, 0); this .easing('ease-out') diff --git a/src/components/modal/modal.ts b/src/components/modal/modal.ts index fb8d913098..15fc460f4a 100644 --- a/src/components/modal/modal.ts +++ b/src/components/modal/modal.ts @@ -1,15 +1,15 @@ -import {Component, ComponentRef, ComponentResolver, ElementRef, HostListener, ViewChild, ViewContainerRef} from '@angular/core'; +import {Component, ComponentResolver, HostListener, ViewChild, ViewContainerRef} from '@angular/core'; import {addSelector} from '../../config/bootstrap'; import {Animation} from '../../animations/animation'; import {NavParams} from '../nav/nav-params'; import {isPresent, pascalCaseToDashCase} from '../../util/util'; import {Key} from '../../util/key'; -import {Transition, TransitionOptions} from '../../transitions/transition'; +import {PageTransition} from '../../transitions/page-transition'; +import {TransitionOptions} from '../../transitions/transition'; import {ViewController} from '../nav/view-controller'; import {windowDimensions} from '../../util/dom'; -import {nativeRaf, CSS} from '../../util/dom'; /** * @name Modal @@ -191,7 +191,7 @@ export class ModalCmp { } loadComponent(done: Function) { - addSelector(this._navParams.data.componentType, 'ion-modal-inner'); + addSelector(this._navParams.data.componentType, 'ion-page'); this._compiler.resolveComponent(this._navParams.data.componentType).then((componentFactory) => { let componentRef = this.viewport.createComponent(componentFactory, this.viewport.length, this.viewport.parentInjector); @@ -227,9 +227,9 @@ export class ModalCmp { /** * Animations for modals */ - class ModalSlideIn extends Transition { + class ModalSlideIn extends PageTransition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdropEle = ele.querySelector('ion-backdrop'); @@ -263,12 +263,12 @@ export class ModalCmp { } } } - Transition.register('modal-slide-in', ModalSlideIn); + PageTransition.register('modal-slide-in', ModalSlideIn); -class ModalSlideOut extends Transition { +class ModalSlideOut extends PageTransition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); @@ -290,12 +290,12 @@ class ModalSlideOut extends Transition { .add(wrapper); } } -Transition.register('modal-slide-out', ModalSlideOut); +PageTransition.register('modal-slide-out', ModalSlideOut); -class ModalMDSlideIn extends Transition { +class ModalMDSlideIn extends PageTransition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); @@ -311,7 +311,7 @@ class ModalMDSlideIn extends Transition { backdrop.fromTo('opacity', 0.01, 0.4); wrapper.fromTo('translateY', '40px', '0px'); - wrapper.fromTo('opacity', '0.01', '1.0'); + wrapper.fromTo('opacity', 0.01, 1); const DURATION = 280; const EASING = 'cubic-bezier(0.36,0.66,0.04,1)'; @@ -328,12 +328,12 @@ class ModalMDSlideIn extends Transition { } } } -Transition.register('modal-md-slide-in', ModalMDSlideIn); +PageTransition.register('modal-md-slide-in', ModalMDSlideIn); -class ModalMDSlideOut extends Transition { +class ModalMDSlideOut extends PageTransition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); @@ -341,7 +341,7 @@ class ModalMDSlideOut extends Transition { backdrop.fromTo('opacity', 0.4, 0.0); wrapper.fromTo('translateY', '0px', '40px'); - wrapper.fromTo('opacity', '1.0', '0.00'); + wrapper.fromTo('opacity', 0.99, 0); this .element(leavingView.pageRef()) @@ -351,4 +351,4 @@ class ModalMDSlideOut extends Transition { .add(backdrop); } } -Transition.register('modal-md-slide-out', ModalMDSlideOut); +PageTransition.register('modal-md-slide-out', ModalMDSlideOut); diff --git a/src/components/nav/nav-controller.ts b/src/components/nav/nav-controller.ts index 519bfd5d13..5c352eb155 100644 --- a/src/components/nav/nav-controller.ts +++ b/src/components/nav/nav-controller.ts @@ -1,4 +1,4 @@ -import {ViewContainerRef, ComponentResolver, ComponentRef, provide, ReflectiveInjector, ResolvedReflectiveProvider, ElementRef, NgZone, Renderer, EventEmitter} from '@angular/core'; +import {ViewContainerRef, ComponentResolver, ComponentFactory, ComponentRef, provide, ReflectiveInjector, ResolvedReflectiveProvider, ElementRef, NgZone, Renderer, EventEmitter} from '@angular/core'; import {addSelector} from '../../config/bootstrap'; import {App} from '../app/app'; @@ -1059,7 +1059,7 @@ export class NavController extends Ion { // DOM WRITE this.setTransitioning(true, 500); - this.loadPage(enteringView, null, opts, () => { + this.loadPage(enteringView, this._viewport, opts, () => { enteringView.fireLoaded(); this.viewDidLoad.emit(enteringView); this._postRender(transId, enteringView, leavingView, isAlreadyTransitioning, opts, done); @@ -1467,8 +1467,8 @@ export class NavController extends Ion { /** * @private */ - loadPage(view: ViewController, navbarContainerRef: ViewContainerRef, opts: NavOptions, done: Function) { - if (!this._viewport || !view.componentType) { + loadPage(view: ViewController, viewport: ViewContainerRef, opts: NavOptions, done: Function) { + if (!viewport || !view.componentType) { return; } @@ -1489,7 +1489,7 @@ export class NavController extends Ion { let componentRef = componentFactory.create(childInjector, null, null); - this._viewport.insert(componentRef.hostView, this._viewport.length); + viewport.insert(componentRef.hostView, viewport.length); // a new ComponentRef has been created // set the ComponentRef's instance to its ViewController @@ -1518,30 +1518,6 @@ export class NavController extends Ion { componentRef.destroy(); }); - if (!navbarContainerRef) { - // there was not a navbar container ref already provided - // so use the location of the actual navbar template - navbarContainerRef = view.getNavbarViewRef(); - } - - // find a navbar template if one is in the page - let navbarTemplateRef = view.getNavbarTemplateRef(); - - // check if we have both a navbar ViewContainerRef and a template - if (navbarContainerRef && navbarTemplateRef) { - // let's now create the navbar view - let navbarViewRef = navbarContainerRef.createEmbeddedView(navbarTemplateRef); - - view.onDestroy(() => { - // manually destroy the navbar when the page is destroyed - navbarViewRef.destroy(); - }); - } - - // options may have had a postLoad method - // used mainly by tabs - opts.postLoad && opts.postLoad(view); - // our job is done here done(view); }); @@ -1852,7 +1828,6 @@ export interface NavOptions { keyboardClose?: boolean; preload?: boolean; transitionDelay?: number; - postLoad?: Function; progressAnimation?: boolean; climbNav?: boolean; ev?: any; diff --git a/src/components/nav/nav.ts b/src/components/nav/nav.ts index 819c97eac5..54bc2a942c 100644 --- a/src/components/nav/nav.ts +++ b/src/components/nav/nav.ts @@ -109,7 +109,7 @@ import {ViewController} from './view-controller'; */ @Component({ selector: 'ion-nav', - template: '
', + template: '
', directives: [NavPortal], encapsulation: ViewEncapsulation.None, }) diff --git a/src/components/nav/test/basic/index.ts b/src/components/nav/test/basic/index.ts index 2c1bf10783..e9fe791646 100644 --- a/src/components/nav/test/basic/index.ts +++ b/src/components/nav/test/basic/index.ts @@ -13,15 +13,18 @@ class MyCmpTest{} @Component({ template: ` - - {{title}} - - - - - - - + + + {{title}} + + + + + + + + + @@ -57,7 +60,7 @@ class MyCmpTest{} directives: [MyCmpTest] }) class FirstPage { - pushPage; + pushPage = FullPage; title = 'First Page'; pages: Array = []; @ViewChild(Content) content: Content; @@ -66,8 +69,6 @@ class FirstPage { private nav: NavController, private view: ViewController ) { - this.pushPage = FullPage; - for (var i = 1; i <= 50; i++) { this.pages.push(i); } @@ -201,12 +202,15 @@ class FullPage { @Component({ template: ` - - Primary Color Page Header - - - - + + + Primary Color Page Header + + + + + +

@@ -221,9 +225,12 @@ class FullPage {
- - Footer - + + + + Footer + + ` }) class PrimaryHeaderPage { @@ -267,9 +274,12 @@ class PrimaryHeaderPage { @Component({ template: ` - - Another Page Header - + + + Another Page Header + + + @@ -289,9 +299,11 @@ class PrimaryHeaderPage { - - Another Page Footer - + + + Another Page Footer + + ` }) class AnotherPage { diff --git a/src/components/nav/view-controller.ts b/src/components/nav/view-controller.ts index d93697ea19..3ca658db92 100644 --- a/src/components/nav/view-controller.ts +++ b/src/components/nav/view-controller.ts @@ -1,9 +1,11 @@ import {Output, EventEmitter, Type, TemplateRef, ViewContainerRef, ElementRef, Renderer, ChangeDetectorRef} from '@angular/core'; +import {Header, Footer} from '../toolbar/toolbar'; +import {isPresent, merge} from '../../util/util'; import {Navbar} from '../navbar/navbar'; import {NavController, NavOptions} from './nav-controller'; import {NavParams} from './nav-params'; -import {isPresent, merge} from '../../util/util'; +import {Tabs} from '../tabs/tabs'; /** @@ -27,13 +29,13 @@ export class ViewController { private _cntDir: any; private _cntRef: ElementRef; private _tbRefs: ElementRef[] = []; - private _destroys: Function[] = []; + private _hdrDir: Header; + private _ftrDir: Footer; + private _destroyFn: Function; private _hdAttr: string = null; private _leavingOpts: NavOptions = null; private _loaded: boolean = false; private _nbDir: Navbar; - private _nbTmpRef: TemplateRef; - private _nbVwRef: ViewContainerRef; private _onDismiss: Function = null; private _pgRef: ElementRef; private _cd: ChangeDetectorRef; @@ -110,6 +112,9 @@ export class ViewController { this.didUnload = new EventEmitter(); } + /** + * @private + */ subscribe(generatorOrNext?: any): any { return this._emitter.subscribe(generatorOrNext); } @@ -121,10 +126,16 @@ export class ViewController { this._emitter.emit(data); } + /** + * @private + */ onDismiss(callback: Function) { this._onDismiss = callback; } + /** + * @private + */ dismiss(data?: any, role?: any, navOptions: NavOptions = {}) { let options = merge({}, this._leavingOpts, navOptions); return this._nav.remove(this._nav.indexOf(this), 1, options).then(() => { @@ -140,6 +151,13 @@ export class ViewController { this._nav = navCtrl; } + /** + * @private + */ + getNav() { + return this._nav; + } + /** * @private */ @@ -201,31 +219,21 @@ export class ViewController { /** * You can find out the index of the current view is in the current navigation stack. * - * ```typescript + * ```ts * export class Page1 { - * constructor(view: ViewController){ - * this.view = view; + * constructor(private view: ViewController){ * // Just log out the index * console.log(this.view.index); * } * } * ``` * - * @returns {number} Returns the index of this page within its NavController. + * @returns {number} Returns the index of this page within its `NavController`. */ get index(): number { return (this._nav ? this._nav.indexOf(this) : -1); } - /** - * @private - */ - private isRoot(): boolean { - // deprecated warning - console.warn('ViewController isRoot() has been renamed to isFirst()'); - return this.isFirst(); - } - /** * @returns {boolean} Returns if this Page is the first in the stack of pages within its NavController. */ @@ -255,11 +263,6 @@ export class ViewController { this._hdAttr = (shouldShow ? null : ''); renderer.setElementAttribute(this._pgRef.nativeElement, 'hidden', this._hdAttr); - - let navbarRef = this.navbarRef(); - if (navbarRef) { - renderer.setElementAttribute(navbarRef.nativeElement, 'hidden', this._hdAttr); - } } } @@ -273,34 +276,6 @@ export class ViewController { } } - /** - * @private - */ - setNavbarTemplateRef(templateRef: TemplateRef) { - this._nbTmpRef = templateRef; - } - - /** - * @private - */ - getNavbarTemplateRef(): TemplateRef { - return this._nbTmpRef; - } - - /** - * @private - */ - getNavbarViewRef() { - return this._nbVwRef; - } - - /** - * @private - */ - setNavbarViewRef(viewContainerRef: ViewContainerRef) { - this._nbVwRef = viewContainerRef; - } - /** * @private */ @@ -331,6 +306,13 @@ export class ViewController { return this._cntRef; } + /** + * @private + */ + setContent(directive: any) { + this._cntDir = directive; + } + /** * @private */ @@ -340,7 +322,6 @@ export class ViewController { /** * @private - * @returns {elementRef} Returns the Page's Content ElementRef */ toolbarRefs(): ElementRef[] { return this._tbRefs; @@ -349,8 +330,29 @@ export class ViewController { /** * @private */ - setContent(directive: any) { - this._cntDir = directive; + setHeader(directive: Header) { + this._hdrDir = directive; + } + + /** + * @private + */ + getHeader() { + return this._hdrDir; + } + + /** + * @private + */ + setFooter(directive: Footer) { + this._ftrDir = directive; + } + + /** + * @private + */ + getFooter() { + return this._ftrDir; } /** @@ -376,15 +378,16 @@ export class ViewController { } /** - * You can find out of the current view has a Navbar or not. Be sure to wrap this in an `ionViewWillEnter` method in order to make sure the view has rendered fully. + * You can find out of the current view has a Navbar or not. Be sure + * to wrap this in an `ionViewWillEnter` method in order to make sure + * the view has rendered fully. * - * ```typescript + * ```ts * export class Page1 { - * constructor(view: ViewController) { - * this.view = view - * } + * constructor(private viewCtrl: ViewController) {} + * * ionViewWillEnter(){ - * console.log('Do we have a Navbar?', this.view.hasNavbar()); + * console.log('Do we have a Navbar?', this.viewCtrl.hasNavbar()); * } *} * ``` @@ -448,9 +451,8 @@ export class ViewController { * * ```ts * export class MyClass{ - * constructor(viewCtrl: ViewController){ - * this.viewCtrl = viewCtrl - * } + * constructor(private viewCtrl: ViewController) {} + * * ionViewWillEnter() { * this.viewCtrl.setBackButtonText('Previous'); * } @@ -484,12 +486,14 @@ export class ViewController { isLoaded(): boolean { return this._loaded; } + /** * The loaded method is used to load any dynamic content/components - * into the dom before proceeding with the transition. If a component needs - * dynamic component loading, extending ViewController and overriding - * this method is a good option - * @param {function} done is a callback that must be called when async loading/actions are completed + * into the dom before proceeding with the transition. If a component + * needs dynamic component loading, extending ViewController and + * overriding this method is a good option + * @param {function} done is a callback that must be called when async + * loading/actions are completed */ loaded(done: (() => any)) { done(); @@ -572,7 +576,7 @@ export class ViewController { * @private */ onDestroy(destroyFn: Function) { - this._destroys.push(destroyFn); + this._destroyFn = destroyFn; } /** @@ -582,11 +586,8 @@ export class ViewController { this.didUnload.emit(null); ctrlFn(this, 'DidUnload'); - for (var i = 0; i < this._destroys.length; i++) { - this._destroys[i](); - } - this._destroys.length = 0; - this._tbRefs.length = 0; + this._destroyFn && this._destroyFn(); + this._destroyFn = null; } } diff --git a/src/components/navbar/navbar.ts b/src/components/navbar/navbar.ts index d5a2d281f3..d29710a716 100644 --- a/src/components/navbar/navbar.ts +++ b/src/components/navbar/navbar.ts @@ -1,4 +1,4 @@ -import {Component, Directive, Optional, ElementRef, Renderer, TemplateRef, forwardRef, Inject, ViewContainerRef, Input} from '@angular/core'; +import {Component, Directive, Optional, ElementRef, Renderer, forwardRef, Inject, Input} from '@angular/core'; import {Ion} from '../ion'; import {Icon} from '../icon/icon'; @@ -137,8 +137,7 @@ export class Navbar extends ToolbarBase { private _app: App, @Optional() viewCtrl: ViewController, elementRef: ElementRef, - config: Config, - private _renderer: Renderer + config: Config ) { super(elementRef); @@ -230,14 +229,13 @@ export class Navbar extends ToolbarBase { selector: 'template[navbar]' }) export class NavbarTemplate { - constructor( - viewContainerRef: ViewContainerRef, - templateRef: TemplateRef, - @Optional() viewCtrl: ViewController - ) { - if (viewCtrl) { - viewCtrl.setNavbarTemplateRef(templateRef); - viewCtrl.setNavbarViewRef(viewContainerRef); - } + constructor() { + // deprecated warning: added 2016-06-14, beta.10 + console.warn('ion-navbar no longer requires *navbar attribute. Please restructure header to:\n' + + '\n' + + ' \n' + + ' ...\n' + + ' \n' + + ''); } } diff --git a/src/components/picker/picker.ts b/src/components/picker/picker.ts index c0ca56235f..6cf5a13c70 100644 --- a/src/components/picker/picker.ts +++ b/src/components/picker/picker.ts @@ -613,7 +613,7 @@ class PickerDisplayCmp { } getSelected(): any { - let selected = {}; + let selected: {[k: string]: any} = {}; this.d.columns.forEach((col, index) => { let selectedColumn = col.options[col.selectedIndex]; selected[col.name] = { @@ -658,7 +658,7 @@ export interface PickerColumnOption { */ class PickerSlideIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); @@ -675,7 +675,7 @@ Transition.register('picker-slide-in', PickerSlideIn); class PickerSlideOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); diff --git a/src/components/popover/popover.ts b/src/components/popover/popover.ts index 291ca7cf8a..6791b0eb8b 100644 --- a/src/components/popover/popover.ts +++ b/src/components/popover/popover.ts @@ -2,7 +2,8 @@ import {Component, ComponentResolver, ElementRef, HostListener, Renderer, ViewCh import {addSelector} from '../../config/bootstrap'; import {Animation} from '../../animations/animation'; -import {Transition, TransitionOptions} from '../../transitions/transition'; +import {PageTransition} from '../../transitions/page-transition'; +import {TransitionOptions} from '../../transitions/transition'; import {Config} from '../../config/config'; import {NavParams} from '../nav/nav-params'; import {Platform} from '../../platform/platform'; @@ -244,9 +245,9 @@ export interface PopoverOptions { /** * Animations for popover */ -class PopoverTransition extends Transition { - constructor(opts: TransitionOptions) { - super(opts); +class PopoverTransition extends PageTransition { + constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { + super(enteringView, leavingView, opts); } mdPositionView(nativeEle: HTMLElement, ev: any) { @@ -392,16 +393,16 @@ class PopoverTransition extends Transition { } class PopoverPopIn extends PopoverTransition { - constructor(private enteringView: ViewController, private leavingView: ViewController, private opts: TransitionOptions) { - super(opts); + constructor(enteringView: ViewController, leavingView: ViewController, private opts: TransitionOptions) { + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.popover-wrapper')); - wrapper.fromTo('opacity', '0.01', '1'); - backdrop.fromTo('opacity', '0.01', '0.08'); + wrapper.fromTo('opacity', 0.01, 1); + backdrop.fromTo('opacity', 0.01, 0.08); this .easing('ease') @@ -417,19 +418,19 @@ class PopoverPopIn extends PopoverTransition { }); } } -Transition.register('popover-pop-in', PopoverPopIn); +PageTransition.register('popover-pop-in', PopoverPopIn); class PopoverPopOut extends PopoverTransition { - constructor(private enteringView: ViewController, private leavingView: ViewController, private opts: TransitionOptions) { - super(opts); + constructor(enteringView: ViewController, leavingView: ViewController, private opts: TransitionOptions) { + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let backdrop = new Animation(ele.querySelector('ion-backdrop')); let wrapper = new Animation(ele.querySelector('.popover-wrapper')); - wrapper.fromTo('opacity', '1', '0'); - backdrop.fromTo('opacity', '0.08', '0'); + wrapper.fromTo('opacity', 0.99, 0); + backdrop.fromTo('opacity', 0.08, 0); this .easing('ease') @@ -438,20 +439,20 @@ class PopoverPopOut extends PopoverTransition { .add(wrapper); } } -Transition.register('popover-pop-out', PopoverPopOut); +PageTransition.register('popover-pop-out', PopoverPopOut); class PopoverMdPopIn extends PopoverTransition { - constructor(private enteringView: ViewController, private leavingView: ViewController, private opts: TransitionOptions) { - super(opts); + constructor(enteringView: ViewController, leavingView: ViewController, private opts: TransitionOptions) { + super(enteringView, leavingView, opts); let ele = enteringView.pageRef().nativeElement; let content = new Animation(ele.querySelector('.popover-content')); let viewport = new Animation(ele.querySelector('.popover-viewport')); - content.fromTo('scale', '0.001', '1'); - viewport.fromTo('opacity', '0', '1'); + content.fromTo('scale', 0.001, 1); + viewport.fromTo('opacity', 0.01, 1); this .easing('cubic-bezier(0.36,0.66,0.04,1)') @@ -467,26 +468,26 @@ class PopoverMdPopIn extends PopoverTransition { }); } } -Transition.register('popover-md-pop-in', PopoverMdPopIn); +PageTransition.register('popover-md-pop-in', PopoverMdPopIn); class PopoverMdPopOut extends PopoverTransition { - constructor(private enteringView: ViewController, private leavingView: ViewController, private opts: TransitionOptions) { - super(opts); + constructor(enteringView: ViewController, leavingView: ViewController, private opts: TransitionOptions) { + super(enteringView, leavingView, opts); let ele = leavingView.pageRef().nativeElement; let wrapper = new Animation(ele.querySelector('.popover-wrapper')); - wrapper.fromTo('opacity', '1', '0'); + wrapper.fromTo('opacity', 0.99, 0); this .easing('ease') .duration(500) - .fadeIn() + .fromTo('opacity', 0.01, 1) .add(wrapper); } } -Transition.register('popover-md-pop-out', PopoverMdPopOut); +PageTransition.register('popover-md-pop-out', PopoverMdPopOut); let popoverIds = -1; diff --git a/src/components/slides/test/intro/index.ts b/src/components/slides/test/intro/index.ts index 860bd9752c..0c9df59672 100644 --- a/src/components/slides/test/intro/index.ts +++ b/src/components/slides/test/intro/index.ts @@ -51,7 +51,6 @@ class IntroPage {

Another Page

- ` }) class MainPage {} diff --git a/src/components/slides/test/intro/main.html b/src/components/slides/test/intro/main.html index 8f810f8714..364f82929d 100644 --- a/src/components/slides/test/intro/main.html +++ b/src/components/slides/test/intro/main.html @@ -1,11 +1,13 @@ - - - - - Slides - + + + + + + Slides + + diff --git a/src/components/tabs/tab.ts b/src/components/tabs/tab.ts index 0abbf34cb1..f62335497b 100644 --- a/src/components/tabs/tab.ts +++ b/src/components/tabs/tab.ts @@ -207,7 +207,7 @@ export class Tab extends NavController { @Output() ionSelect: EventEmitter = new EventEmitter(); constructor( - @Inject(forwardRef(() => Tabs)) parentTabs: Tabs, + @Inject(forwardRef(() => Tabs)) public parent: Tabs, app: App, config: Config, keyboard: Keyboard, @@ -218,9 +218,9 @@ export class Tab extends NavController { private _cd: ChangeDetectorRef ) { // A Tab is a NavController for its child pages - super(parentTabs, app, config, keyboard, elementRef, zone, renderer, compiler); + super(parent, app, config, keyboard, elementRef, zone, renderer, compiler); - parentTabs.add(this); + parent.add(this); this._panelId = 'tabpanel-' + this.id; this._btnId = 'tab-' + this.id; @@ -266,11 +266,7 @@ export class Tab extends NavController { console.debug('Tabs, preload', this.id); this.load({ animate: false, - preload: true, - postLoad: (viewCtrl: ViewController) => { - let navbar = viewCtrl.getNavbar(); - navbar && navbar.setHidden(true); - } + preload: true }, function(){}); } }, wait); @@ -279,18 +275,14 @@ export class Tab extends NavController { /** * @private */ - loadPage(viewCtrl: ViewController, navbarContainerRef: any, opts: NavOptions, done: Function) { - // by default a page's navbar goes into the shared tab's navbar section - navbarContainerRef = this.parent.navbarContainerRef; - + loadPage(viewCtrl: ViewController, viewport: ViewContainerRef, opts: NavOptions, done: Function) { let isTabSubPage = (this.parent.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; + viewport = this.parent.portal; } - super.loadPage(viewCtrl, navbarContainerRef, opts, () => { + super.loadPage(viewCtrl, viewport, opts, () => { if (isTabSubPage) { // add the .tab-subpage css class to tabs pages that should act like subpages let pageEleRef = viewCtrl.pageRef(); @@ -316,18 +308,6 @@ export class Tab extends NavController { // this tab is not selected, do not detect changes this._cd.detach(); } - - this.hideNavbars(!isSelected); - } - - /** - * @private - */ - hideNavbars(shouldHideNavbars: boolean) { - this._views.forEach(viewCtrl => { - let navbar = viewCtrl.getNavbar(); - navbar && navbar.setHidden(shouldHideNavbars); - }); } /** diff --git a/src/components/tabs/tabs.ios.scss b/src/components/tabs/tabs.ios.scss index 7ba14f7b35..5708065e74 100644 --- a/src/components/tabs/tabs.ios.scss +++ b/src/components/tabs/tabs.ios.scss @@ -15,12 +15,12 @@ $tab-button-ios-active-color: $toolbar-ios-active-color !default; $tab-button-ios-inactive-color: $toolbar-ios-inactive-color !default; -tabbar { +ion-tabbar { border-top: 1px solid $toolbar-ios-border-color; background: $tabbar-ios-background; } -ion-tabs[tabbarPlacement=top] tabbar { +ion-tabs[tabbarPlacement=top] ion-tabbar { border-top: 0; border-bottom: 1px solid $toolbar-ios-border-color; } @@ -98,11 +98,11 @@ ion-tabs[tabbarPlacement=top] tabbar { &.hairlines ion-tabs { - tabbar { + ion-tabbar { border-top-width: $hairlines-width; } - &[tabbarPlacement="top"] tabbar { + &[tabbarPlacement="top"] ion-tabbar { border-bottom-width: $hairlines-width; } @@ -114,7 +114,7 @@ ion-tabs[tabbarPlacement=top] tabbar { @mixin tabbar-ios($color-name, $color-base, $color-contrast) { - ion-tabs[#{$color-name}] tabbar { + ion-tabs[#{$color-name}] ion-tabbar { border-color: darken($color-base, 10%); background-color: $color-base; diff --git a/src/components/tabs/tabs.md.scss b/src/components/tabs/tabs.md.scss index 0df34e15f3..258bf65097 100644 --- a/src/components/tabs/tabs.md.scss +++ b/src/components/tabs/tabs.md.scss @@ -15,7 +15,7 @@ $tab-button-md-active-color: $toolbar-md-active-color !default; $tab-button-md-inactive-color: $toolbar-md-inactive-color !default; -tabbar { +ion-tabbar { background: $tabbar-md-background; } @@ -101,7 +101,7 @@ tab-highlight { @mixin tabbar-md($color-name, $color-base, $color-contrast) { - ion-tabs[#{$color-name}] tabbar { + ion-tabs[#{$color-name}] ion-tabbar { background-color: $color-base; .tab-button { diff --git a/src/components/tabs/tabs.scss b/src/components/tabs/tabs.scss index e43a0cd6cc..c1dfd0415a 100644 --- a/src/components/tabs/tabs.scss +++ b/src/components/tabs/tabs.scss @@ -4,62 +4,6 @@ // -------------------------------------------------- -ion-tabs { - display: flex; - overflow: hidden; - - flex-direction: column; - - margin: 0; - padding: 0; - - width: 100%; - max-width: 100%; - height: 100%; - max-height: 100%; -} - -ion-tab { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - display: none; - overflow: hidden; - - flex-direction: column; - - width: 100%; - height: 100%; - - &.show-tab { - display: flex; - } -} - -ion-tabs > ion-navbar-section { - order: $flex-order-tabbar-navbar; -} - -ion-tabbar-section { - position: relative; - - order: $flex-order-tabbar-bottom; -} - -[tabbarPlacement=top] ion-tabbar-section { - order: $flex-order-tabbar-top; -} - -tabbar { - position: relative; - display: flex; - overflow: hidden; - - justify-content: center; -} - .tab-button { @include user-select-none(); diff --git a/src/components/tabs/tabs.ts b/src/components/tabs/tabs.ts index 4cb361445a..ea9a839e87 100644 --- a/src/components/tabs/tabs.ts +++ b/src/components/tabs/tabs.ts @@ -1,4 +1,4 @@ -import {Component, Directive, ElementRef, Optional, Host, forwardRef, ViewContainerRef, ViewChild, ViewChildren, EventEmitter, Output, Input, Renderer, ViewEncapsulation} from '@angular/core'; +import {Component, ElementRef, Optional, ViewChild, ViewContainerRef, EventEmitter, Output, Input, Renderer, ViewEncapsulation} from '@angular/core'; import {App} from '../app/app'; import {Config} from '../../config/config'; @@ -133,34 +133,26 @@ import {ViewController} from '../nav/view-controller'; @Component({ selector: 'ion-tabs', template: - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '{{t.tabTitle}}' + - '{{t.tabBadge}}' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '', + '' + + '' + + '' + + '{{t.tabTitle}}' + + '{{t.tabBadge}}' + + '' + + '' + + '' + + '' + + '' + + '
', directives: [ TabButton, - TabHighlight, - forwardRef(() => TabNavBarAnchor) + TabHighlight ], encapsulation: ViewEncapsulation.None, }) export class Tabs extends Ion { private _ids: number = -1; - private _preloadTabs: boolean = null; - private _tabs: Array = []; + private _tabs: Tab[] = []; private _onReady: any = null; private _sbPadding: boolean; private _useHighlight: boolean; @@ -170,11 +162,6 @@ export class Tabs extends Ion { */ id: number; - /** - * @private - */ - navbarContainerRef: ViewContainerRef; - /** * @private */ @@ -215,6 +202,16 @@ export class Tabs extends Ion { */ @ViewChild(TabHighlight) private _highlight: TabHighlight; + /** + * @private + */ + @ViewChild('tabbar') private _tabbar: ElementRef; + + /** + * @private + */ + @ViewChild('portal', {read: ViewContainerRef}) portal: ViewContainerRef; + /** * @private */ @@ -230,11 +227,12 @@ export class Tabs extends Ion { private _renderer: Renderer ) { super(_elementRef); + this.parent = parent; this.id = ++tabIds; - this.subPages = _config.getBoolean('tabSubPages', false); - this._useHighlight = _config.getBoolean('tabbarHighlight', false); - this._sbPadding = _config.getBoolean('statusbarPadding', false); + this.subPages = _config.getBoolean('tabSubPages'); + this._useHighlight = _config.getBoolean('tabbarHighlight'); + this._sbPadding = _config.getBoolean('statusbarPadding'); if (parent) { // this Tabs has a parent Nav @@ -501,17 +499,17 @@ export class Tabs extends Ion { return nav; } + /** + * @private + */ + setTabbarPosition(top: number, bottom: number) { + let tabbarEle = this._tabbar.nativeElement; + + tabbarEle.style.top = (top > -1 ? top + 'px' : ''); + tabbarEle.style.bottom = (bottom > -1 ? bottom + 'px' : ''); + tabbarEle.classList.add('show-tabbar'); + } + } let tabIds = -1; - - -/** - * @private - */ -@Directive({selector: 'template[navbar-anchor]'}) -class TabNavBarAnchor { - constructor(@Host() tabs: Tabs, viewContainerRef: ViewContainerRef) { - tabs.navbarContainerRef = viewContainerRef; - } -} diff --git a/src/components/tabs/tabs.wp.scss b/src/components/tabs/tabs.wp.scss index 09dda92531..2695e47b86 100644 --- a/src/components/tabs/tabs.wp.scss +++ b/src/components/tabs/tabs.wp.scss @@ -16,7 +16,7 @@ $tab-button-wp-inactive-color: $toolbar-wp-inactive-color !default; $tab-button-wp-background-activated: rgba(0, 0, 0, .1) !default; -tabbar { +ion-tabbar { background: $tabbar-wp-background; } @@ -94,7 +94,7 @@ tabbar { @mixin tabbar-wp($color-name, $color-base, $color-contrast) { - ion-tabs[#{$color-name}] tabbar { + ion-tabs[#{$color-name}] ion-tabbar { background-color: $color-base; .tab-button { diff --git a/src/components/tabs/test/advanced/index.ts b/src/components/tabs/test/advanced/index.ts index ccc17eba3c..4757cff407 100644 --- a/src/components/tabs/test/advanced/index.ts +++ b/src/components/tabs/test/advanced/index.ts @@ -1,30 +1,10 @@ import {Component, ViewChild} from '@angular/core'; -import {Location} from '@angular/common'; import {ionicBootstrap, NavController, NavParams, Modal, ViewController, Tabs, Tab} from '../../../../../src'; @Component({ - template: ` - - Sign In - - - - - Username: - - - - Password: - - - - - - - - ` + templateUrl: './signIn.html' }) class SignIn { constructor(private nav: NavController) {} @@ -38,14 +18,7 @@ class SignIn { @Component({ - template: ` - - Chat Modal - - -

-
- ` + templateUrl: './modalChat.html' }) class ChatPage { constructor(private viewCtrl: ViewController) {} @@ -115,19 +88,7 @@ class TabsPage { // tab 1 // @Component({ - template: '' + - '' + - 'Tabs 1 Page 1' + - '' + - '' + - '

' + - '

' + - '

' + - '

' + - '

UserId: {{userId}}

' + - '' + - '' + - '
' + templateUrl: './tab1page1.html' }) class Tab1Page1 { userId: string; @@ -178,16 +139,7 @@ class Tab1Page1 { @Component({ - template: '' + - '' + - 'Tabs 1 Page 2' + - '' + - '' + - '

' + - '

' + - '' + - '' + - '
' + templateUrl: './tab1page2.html' }) class Tab1Page2 { constructor(private nav: NavController) {} @@ -219,15 +171,7 @@ class Tab1Page2 { @Component({ - template: '' + - '' + - 'Tabs 1 Page 3' + - '' + - '' + - '

' + - '' + - '' + - '
' + templateUrl: './tab1page3.html' }) class Tab1Page3 { constructor(private nav: NavController) {} @@ -254,20 +198,11 @@ class Tab1Page3 { } - // // tab 2 // @Component({ - template: '' + - '' + - 'Tabs 2 Page 1' + - '' + - '' + - '

' + - '' + - '' + - '
' + templateUrl: './tab2page1.html' }) class Tab2Page1 { constructor(private nav: NavController) {} @@ -299,16 +234,7 @@ class Tab2Page1 { @Component({ - template: '' + - '' + - 'Tabs 2 Page 2' + - '' + - '' + - '

' + - '

' + - '' + - '' + - '
' + templateUrl: './tab2page2.html' }) class Tab2Page2 { constructor(private nav: NavController) {} @@ -340,15 +266,7 @@ class Tab2Page2 { @Component({ - template: '' + - '' + - 'Tabs 2 Page 3' + - '' + - '' + - '

' + - '' + - '' + - '
' + templateUrl: './tab2page3.html' }) class Tab2Page3 { constructor(private nav: NavController) {} @@ -375,16 +293,11 @@ class Tab2Page3 { } - // // tab 3 // @Component({ - template: '' + - '' + - 'Tabs 3' + - '' + - '

Tabs 3

' + templateUrl: './tab3page1.html' }) class Tab3Page1 { @@ -411,7 +324,7 @@ class Tab3Page1 { @Component({ - template: '' + template: `` }) class E2EApp { root = SignIn; diff --git a/src/components/tabs/test/advanced/modalChat.html b/src/components/tabs/test/advanced/modalChat.html new file mode 100644 index 0000000000..8fe83bda4b --- /dev/null +++ b/src/components/tabs/test/advanced/modalChat.html @@ -0,0 +1,9 @@ + + + Chat Modal + + + + +

+
diff --git a/src/components/tabs/test/advanced/signIn.html b/src/components/tabs/test/advanced/signIn.html new file mode 100644 index 0000000000..e76c619891 --- /dev/null +++ b/src/components/tabs/test/advanced/signIn.html @@ -0,0 +1,21 @@ + + + Sign In + + + + + + + Username: + + + + Password: + + + + + + + diff --git a/src/components/tabs/test/advanced/tab1page1.html b/src/components/tabs/test/advanced/tab1page1.html new file mode 100644 index 0000000000..171afb998c --- /dev/null +++ b/src/components/tabs/test/advanced/tab1page1.html @@ -0,0 +1,15 @@ + + + Tabs 1, Page 1 + + + + +

+

+

+

+

UserId: {{userId}}

+ + +
diff --git a/src/components/tabs/test/advanced/tab1page2.html b/src/components/tabs/test/advanced/tab1page2.html new file mode 100644 index 0000000000..4468b4e3e5 --- /dev/null +++ b/src/components/tabs/test/advanced/tab1page2.html @@ -0,0 +1,12 @@ + + + Tabs 1, Page 2 + + + + +

+

+ + +
diff --git a/src/components/tabs/test/advanced/tab1page3.html b/src/components/tabs/test/advanced/tab1page3.html new file mode 100644 index 0000000000..cfe94ef21a --- /dev/null +++ b/src/components/tabs/test/advanced/tab1page3.html @@ -0,0 +1,11 @@ + + + Tabs 1, Page 3 + + + + +

+ + +
\ No newline at end of file diff --git a/src/components/tabs/test/advanced/tab2page1.html b/src/components/tabs/test/advanced/tab2page1.html new file mode 100644 index 0000000000..9b3a3f386e --- /dev/null +++ b/src/components/tabs/test/advanced/tab2page1.html @@ -0,0 +1,11 @@ + + + Tabs 2, Page 1 + + + + +

+ + +
\ No newline at end of file diff --git a/src/components/tabs/test/advanced/tab2page2.html b/src/components/tabs/test/advanced/tab2page2.html new file mode 100644 index 0000000000..c0d6218d62 --- /dev/null +++ b/src/components/tabs/test/advanced/tab2page2.html @@ -0,0 +1,12 @@ + + + Tabs 2, Page 2 + + + + +

+

+ + +
\ No newline at end of file diff --git a/src/components/tabs/test/advanced/tab2page3.html b/src/components/tabs/test/advanced/tab2page3.html new file mode 100644 index 0000000000..a79fc9fb7e --- /dev/null +++ b/src/components/tabs/test/advanced/tab2page3.html @@ -0,0 +1,11 @@ + + + Tabs 2, Page 3 + + + + +

+ + +
\ No newline at end of file diff --git a/src/components/tabs/test/advanced/tab3page1.html b/src/components/tabs/test/advanced/tab3page1.html new file mode 100644 index 0000000000..2151121853 --- /dev/null +++ b/src/components/tabs/test/advanced/tab3page1.html @@ -0,0 +1,9 @@ + + + Tabs 3, Page 1 + + + + +

Tabs 3, Page 1

+
\ No newline at end of file diff --git a/src/components/tabs/test/basic/index.ts b/src/components/tabs/test/basic/index.ts index d7d43fe26a..bd97deab37 100644 --- a/src/components/tabs/test/basic/index.ts +++ b/src/components/tabs/test/basic/index.ts @@ -6,19 +6,21 @@ import {ionicBootstrap, NavController, App, Alert, Modal, ViewController, Tab, T // @Component({ template: ` - - - - + + + + + - - Filter Sessions - + + Filter Sessions + - - - - + + + + + @@ -66,9 +68,12 @@ class MyModal { // @Component({ template: ` - - Heart - + + + Heart + + + @@ -108,9 +113,12 @@ export class Tab1 { // @Component({ template: ` - - Schedule - + + + Schedule + + + @@ -159,12 +167,15 @@ export class Tab2 { // @Component({ template: ` - - - Stopwatch - + + + + Stopwatch + + +

Tab 3

diff --git a/src/components/tabs/test/child-navs/index.ts b/src/components/tabs/test/child-navs/index.ts index 09c93a0f69..d24c27f87a 100644 --- a/src/components/tabs/test/child-navs/index.ts +++ b/src/components/tabs/test/child-navs/index.ts @@ -7,18 +7,20 @@ import {ionicBootstrap, NavController, App, Alert, Modal, ViewController, Tab, T // @Component({ template: ` - - - Tab 1 - - + + + + Tab 1 + + + ` }) -export class Tab1 { +class Tab1 { root = SecondPage; } @@ -27,18 +29,20 @@ export class Tab1 { // @Component({ template: ` - - - Tab 2 - - + + + + Tab 2 + + + ` }) -export class Tab2 { +class Tab2 { root = SecondPage; } @@ -47,18 +51,20 @@ export class Tab2 { // @Component({ template: ` - - - Tab 3 - - + + + + Tab 3 + + + ` }) -export class Tab3 { +class Tab3 { root = SecondPage; } @@ -88,11 +94,13 @@ class ThirdPage{ @Component({ template: ` - - - Fourth Page Comp - - + + + + Fourth Page Comp + + + @@ -124,7 +132,7 @@ class FourthPage{ ` }) -export class TabsPage { +class TabsPage { root1 = Tab1; root2 = Tab2; root3 = Tab3; @@ -133,7 +141,7 @@ export class TabsPage { @Component({ template: `` }) -export class E2EApp { +class E2EApp { root = TabsPage; } diff --git a/src/components/tabs/test/ghost/index.ts b/src/components/tabs/test/ghost/index.ts index 79a154c859..3fa2b23332 100644 --- a/src/components/tabs/test/ghost/index.ts +++ b/src/components/tabs/test/ghost/index.ts @@ -7,9 +7,11 @@ import {ionicBootstrap, NavController, Tab} from '../../../../../src'; // @Component({ template: ` - - Heart - + + + Heart + +

Tab 1

@@ -24,9 +26,11 @@ class Tab1 { // @Component({ template: ` - - Star - + + + Star + +

Tab 2

@@ -41,12 +45,14 @@ class Tab2 { // @Component({ template: ` - - - Stopwatch - + + + + Stopwatch + +

Tab 3

@@ -61,12 +67,14 @@ class Tab3 { // @Component({ template: ` - - - Quesarito - + + + + Quesarito + +

Quesarito

diff --git a/src/components/toast/test/basic/index.ts b/src/components/toast/test/basic/index.ts index ee863f9ec3..adef2dec77 100644 --- a/src/components/toast/test/basic/index.ts +++ b/src/components/toast/test/basic/index.ts @@ -4,9 +4,11 @@ import {ionicBootstrap, Toast, NavController} from '../../../../../src'; @Component({ template: ` - - Another Page - + + + Another Page + +

This is another page to show that the toast stays.

diff --git a/src/components/toast/test/basic/main.html b/src/components/toast/test/basic/main.html index 4713777d31..132785b40f 100644 --- a/src/components/toast/test/basic/main.html +++ b/src/components/toast/test/basic/main.html @@ -1,6 +1,8 @@ - - Toasts - + + + Toasts + + diff --git a/src/components/toast/toast.ts b/src/components/toast/toast.ts index cda38bf065..daaadd06cf 100644 --- a/src/components/toast/toast.ts +++ b/src/components/toast/toast.ts @@ -70,7 +70,7 @@ export class Toast extends ViewController { super(ToastCmp, opts); // set the position to the bottom if not provided - if ( ! opts.position || ! this.isValidPosition(opts.position)) { + if (! opts.position || ! this.isValidPosition(opts.position)) { opts.position = TOAST_POSITION_BOTTOM; } @@ -173,7 +173,7 @@ class ToastCmp implements AfterViewInit { private _elementRef: ElementRef, params: NavParams, renderer: Renderer - ) { + ) { this.d = params.data; @@ -237,25 +237,27 @@ export interface ToastOptions { class ToastSlideIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); // DOM READS let ele = enteringView.pageRef().nativeElement; const wrapperEle = ele.querySelector('.toast-wrapper'); let wrapper = new Animation(wrapperEle); - if ( enteringView.data && enteringView.data.position === TOAST_POSITION_TOP ) { + if (enteringView.data && enteringView.data.position === TOAST_POSITION_TOP) { // top // by default, it is -100% hidden (above the screen) // so move from that to 10px below top: 0px; wrapper.fromTo('translateY', '-100%', `${10}px`); - } else if ( enteringView.data && enteringView.data.position === TOAST_POSITION_MIDDLE ) { + + } else if (enteringView.data && enteringView.data.position === TOAST_POSITION_MIDDLE) { // Middle // just center it and fade it in let topPosition = Math.floor(ele.clientHeight / 2 - wrapperEle.clientHeight / 2); // DOM WRITE wrapperEle.style.top = `${topPosition}px`; - wrapper.fromTo('opacity', '0.01', '1.0'); + wrapper.fromTo('opacity', 0.01, 1); + } else { // bottom // by default, it is 100% hidden (below the screen), @@ -263,168 +265,159 @@ class ToastSlideIn extends Transition { wrapper.fromTo('translateY', '100%', `${0 - 10}px`); } - const EASE: string = 'cubic-bezier(.36,.66,.04,1)'; - const DURATION: number = 400; - // DOM WRITES - this.easing(EASE).duration(DURATION).add(wrapper); + this.easing('cubic-bezier(.36,.66,.04,1)').duration(400).add(wrapper); } } class ToastSlideOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); - // DOM reads let ele = leavingView.pageRef().nativeElement; const wrapperEle = ele.querySelector('.toast-wrapper'); let wrapper = new Animation(wrapperEle); - if ( leavingView.data && leavingView.data.position === TOAST_POSITION_TOP ) { + if (leavingView.data && leavingView.data.position === TOAST_POSITION_TOP) { // top // reverse arguments from enter transition wrapper.fromTo('translateY', `${10}px`, '-100%'); - } else if ( leavingView.data && leavingView.data.position === TOAST_POSITION_MIDDLE ) { + + } else if (leavingView.data && leavingView.data.position === TOAST_POSITION_MIDDLE) { // Middle // just fade it out - wrapper.fromTo('opacity', '1.0', '0.0'); + wrapper.fromTo('opacity', 0.99, 0); + } else { // bottom // reverse arguments from enter transition wrapper.fromTo('translateY', `${0 - 10}px`, '100%'); } - const EASE: string = 'cubic-bezier(.36,.66,.04,1)'; - const DURATION: number = 300; - // DOM writes - this.easing(EASE).duration(DURATION).add(wrapper); + this.easing('cubic-bezier(.36,.66,.04,1)').duration(300).add(wrapper); } } class ToastMdSlideIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); // DOM reads let ele = enteringView.pageRef().nativeElement; const wrapperEle = ele.querySelector('.toast-wrapper'); let wrapper = new Animation(wrapperEle); - if ( enteringView.data && enteringView.data.position === TOAST_POSITION_TOP ) { + if (enteringView.data && enteringView.data.position === TOAST_POSITION_TOP) { // top // by default, it is -100% hidden (above the screen) // so move from that to top: 0px; - wrapper.fromTo('translateY', '-100%', `0px`); - } else if ( enteringView.data && enteringView.data.position === TOAST_POSITION_MIDDLE ) { + wrapper.fromTo('translateY', '-100%', `0%`); + + } else if (enteringView.data && enteringView.data.position === TOAST_POSITION_MIDDLE) { // Middle // just center it and fade it in let topPosition = Math.floor(ele.clientHeight / 2 - wrapperEle.clientHeight / 2); // DOM WRITE wrapperEle.style.top = `${topPosition}px`; - wrapper.fromTo('opacity', '0.01', '1.0'); + wrapper.fromTo('opacity', 0.01, 1); + } else { // bottom // by default, it is 100% hidden (below the screen), // so move from that to bottom: 0px - wrapper.fromTo('translateY', '100%', `0px`); + wrapper.fromTo('translateY', '100%', `0%`); } - const EASE: string = 'cubic-bezier(.36,.66,.04,1)'; - const DURATION: number = 400; - - this.easing(EASE).duration(DURATION).add(wrapper); + this.easing('cubic-bezier(.36,.66,.04,1)').duration(400).add(wrapper); } } class ToastMdSlideOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); - // DOM reads let ele = leavingView.pageRef().nativeElement; const wrapperEle = ele.querySelector('.toast-wrapper'); let wrapper = new Animation(wrapperEle); - if ( leavingView.data && leavingView.data.position === TOAST_POSITION_TOP ) { + if (leavingView.data && leavingView.data.position === TOAST_POSITION_TOP) { // top // reverse arguments from enter transition - wrapper.fromTo('translateY', `${0}px`, '-100%'); - } else if ( leavingView.data && leavingView.data.position === TOAST_POSITION_MIDDLE ) { + wrapper.fromTo('translateY', `${0}%`, '-100%'); + + } else if (leavingView.data && leavingView.data.position === TOAST_POSITION_MIDDLE) { // Middle // just fade it out - wrapper.fromTo('opacity', '1.0', '0.0'); + wrapper.fromTo('opacity', 0.99, 0); + } else { // bottom // reverse arguments from enter transition - wrapper.fromTo('translateY', `${0}px`, '100%'); + wrapper.fromTo('translateY', `${0}%`, '100%'); } - // DOM writes - - const EASE: string = 'cubic-bezier(.36,.66,.04,1)'; - const DURATION: number = 450; - - this.easing(EASE).duration(DURATION).add(wrapper); + this.easing('cubic-bezier(.36,.66,.04,1)').duration(450).add(wrapper); } } class ToastWpPopIn extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); - // DOM reads let ele = enteringView.pageRef().nativeElement; const wrapperEle = ele.querySelector('.toast-wrapper'); let wrapper = new Animation(wrapperEle); - if ( enteringView.data && enteringView.data.position === TOAST_POSITION_TOP ) { + if (enteringView.data && enteringView.data.position === TOAST_POSITION_TOP) { // top - wrapper.fromTo('opacity', '0.01', '1'); - wrapper.fromTo('scale', '1.3', '1'); - } else if ( enteringView.data && enteringView.data.position === TOAST_POSITION_MIDDLE ) { + wrapper.fromTo('opacity', 0.01, 1); + wrapper.fromTo('scale', 1.3, 1); + + } else if (enteringView.data && enteringView.data.position === TOAST_POSITION_MIDDLE) { // Middle // just center it and fade it in let topPosition = Math.floor(ele.clientHeight / 2 - wrapperEle.clientHeight / 2); + // DOM WRITE wrapperEle.style.top = `${topPosition}px`; - wrapper.fromTo('opacity', '0.01', '1.0'); - wrapper.fromTo('scale', '1.3', '1'); + wrapper.fromTo('opacity', 0.01, 1); + wrapper.fromTo('scale', 1.3, 1); + } else { // bottom - wrapper.fromTo('opacity', '0.01', '1'); - wrapper.fromTo('scale', '1.3', '1'); + wrapper.fromTo('opacity', 0.01, 1); + wrapper.fromTo('scale', 1.3, 1); } - // DOM writes - const EASE: string = 'cubic-bezier(0,0 0.05,1)'; - const DURATION: number = 200; - this.easing(EASE).duration(DURATION).add(wrapper); + this.easing('cubic-bezier(0,0 0.05,1)').duration(200).add(wrapper); } } class ToastWpPopOut extends Transition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); // DOM reads let ele = leavingView.pageRef().nativeElement; const wrapperEle = ele.querySelector('.toast-wrapper'); let wrapper = new Animation(wrapperEle); - if ( leavingView.data && leavingView.data.position === TOAST_POSITION_TOP ) { + if (leavingView.data && leavingView.data.position === TOAST_POSITION_TOP) { // top // reverse arguments from enter transition - wrapper.fromTo('opacity', '1', '0.00'); - wrapper.fromTo('scale', '1', '1.3'); - } else if ( leavingView.data && leavingView.data.position === TOAST_POSITION_MIDDLE ) { + wrapper.fromTo('opacity', 0.99, 0); + wrapper.fromTo('scale', 1, 1.3); + + } else if (leavingView.data && leavingView.data.position === TOAST_POSITION_MIDDLE) { // Middle // just fade it out - wrapper.fromTo('opacity', '1.0', '0.00'); - wrapper.fromTo('scale', '1', '1.3'); + wrapper.fromTo('opacity', 0.99, 0); + wrapper.fromTo('scale', 1, 1.3); + } else { // bottom // reverse arguments from enter transition - wrapper.fromTo('opacity', '1', '0.00'); - wrapper.fromTo('scale', '1', '1.3'); + wrapper.fromTo('opacity', 0.99, 0); + wrapper.fromTo('scale', 1, 1.3); } // DOM writes diff --git a/src/components/toolbar/toolbar-item.ts b/src/components/toolbar/toolbar-item.ts new file mode 100644 index 0000000000..a0254eacd4 --- /dev/null +++ b/src/components/toolbar/toolbar-item.ts @@ -0,0 +1,33 @@ +import {Directive, ElementRef, Optional, forwardRef, Inject, ContentChildren} from '@angular/core'; + +import {Button} from '../button/button'; +import {Navbar} from '../navbar/navbar'; +import {Toolbar} from './toolbar'; + + +/** + * @private + */ +@Directive({ + selector: 'ion-buttons,[menuToggle]' +}) +export class ToolbarItem { + inToolbar: boolean; + + constructor( + elementRef: ElementRef, + @Optional() toolbar: Toolbar, + @Optional() @Inject(forwardRef(() => Navbar)) navbar: Navbar + ) { + toolbar && toolbar.addItemRef(elementRef); + navbar && navbar.addItemRef(elementRef); + this.inToolbar = !!(toolbar || navbar); + } + + @ContentChildren(Button) + set _buttons(buttons: any) { + if (this.inToolbar) { + Button.setRoles(buttons, 'bar-button'); + } + } +} diff --git a/src/components/toolbar/toolbar-title.ts b/src/components/toolbar/toolbar-title.ts new file mode 100644 index 0000000000..7512f4d770 --- /dev/null +++ b/src/components/toolbar/toolbar-title.ts @@ -0,0 +1,65 @@ +import {Component, ElementRef, Optional, forwardRef, Inject, ChangeDetectionStrategy, ViewEncapsulation} from '@angular/core'; + +import {Ion} from '../ion'; +import {Navbar} from '../navbar/navbar'; +import {Toolbar} from './toolbar'; + + +/** + * @name Title + * @description + * `ion-title` is a component that sets the title of the `Toolbar` or `Navbar` + * + * @usage + * + * ```html + * + * + * Tab 1 + * + * + * ``` + * + * Or to create a navbar with a toolbar as a subheader: + * + * ```html + * + * + * Tab 1 + * + * + * + * + * Subheader + * + * ``` + * + * @demo /docs/v2/demos/title/ + */ +@Component({ + selector: 'ion-title', + template: + '
' + + '' + + '
', + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, +}) +export class ToolbarTitle extends Ion { + constructor( + private _elementRef: ElementRef, + @Optional() toolbar: Toolbar, + @Optional() @Inject(forwardRef(() => Navbar)) navbar: Navbar + ) { + super(_elementRef); + toolbar && toolbar.setTitleCmp(this); + navbar && navbar.setTitleCmp(this); + } + + /** + * @private + */ + getTitleText() { + return this._elementRef.nativeElement.textContent; + } +} diff --git a/src/components/toolbar/toolbar.scss b/src/components/toolbar/toolbar.scss index 9042de583a..01e9c6fff7 100644 --- a/src/components/toolbar/toolbar.scss +++ b/src/components/toolbar/toolbar.scss @@ -5,17 +5,12 @@ .toolbar { - position: relative; - z-index: $z-index-toolbar; - display: flex; overflow: hidden; - flex: 0; flex-direction: row; align-items: center; justify-content: space-between; - order: $flex-order-toolbar-top; width: 100%; } @@ -35,10 +30,6 @@ pointer-events: none; } -.toolbar[position=bottom] { - order: $flex-order-toolbar-bottom; -} - ion-title { display: flex; diff --git a/src/components/toolbar/toolbar.ts b/src/components/toolbar/toolbar.ts index 024292bc1b..77e8385c22 100644 --- a/src/components/toolbar/toolbar.ts +++ b/src/components/toolbar/toolbar.ts @@ -8,6 +8,48 @@ import {Navbar} from '../navbar/navbar'; import {ViewController} from '../nav/view-controller'; +@Directive({ + selector: 'ion-header' +}) +export class Header { + private _h: number = 0; + + constructor(viewCtr: ViewController, private _elementRef: ElementRef) { + viewCtr.setHeader(this); + } + + setHeight(heightPixels: number) { + this._h = heightPixels; + this._elementRef.nativeElement.style.height = (heightPixels > 0 ? heightPixels + 'px' : ''); + } + + getHeight(): number { + return this._h; + } +} + + +@Directive({ + selector: 'ion-footer' +}) +export class Footer { + private _h: number = 0; + + constructor(viewCtr: ViewController, private _elementRef: ElementRef) { + viewCtr.setFooter(this); + } + + setHeight(heightPixels: number) { + this._h = heightPixels; + this._elementRef.nativeElement.style.height = (heightPixels > 0 ? heightPixels + 'px' : ''); + } + + getHeight(): number { + return this._h; + } +} + + /** * @private */ @@ -160,90 +202,8 @@ export class Toolbar extends ToolbarBase { config: Config ) { super(elementRef); - this._sbPadding = config.getBoolean('statusbarPadding', false); viewCtrl && viewCtrl.setToolbarRef(elementRef); + this._sbPadding = config.getBoolean('statusbarPadding'); } } - -/** - * @name Title - * @description - * `ion-title` is a component that sets the title of the `Toolbar` or `Navbar` - * - * @usage - * - * ```html - * - * Tab 1 - * - * ``` - * - * Or to create a navbar with a toolbar as a subheader: - * - * ```html - * - * Tab 1 - * - * - * - * Subheader - * - * ``` - * - * @demo /docs/v2/demos/title/ - */ -@Component({ - selector: 'ion-title', - template: - '
' + - '' + - '
', - changeDetection: ChangeDetectionStrategy.OnPush, - encapsulation: ViewEncapsulation.None, -}) -export class ToolbarTitle extends Ion { - constructor( - elementRef: ElementRef, - @Optional() toolbar: Toolbar, - @Optional() @Inject(forwardRef(() => Navbar)) navbar: Navbar - ) { - super(elementRef); - toolbar && toolbar.setTitleCmp(this); - navbar && navbar.setTitleCmp(this); - } - /** - * @private - */ - getTitleText() { - return this.getNativeElement().textContent; - } -} - - -/** - * @private - */ -@Directive({ - selector: 'ion-buttons,[menuToggle],ion-nav-items' -}) -export class ToolbarItem { - inToolbar: boolean; - - constructor( - elementRef: ElementRef, - @Optional() toolbar: Toolbar, - @Optional() @Inject(forwardRef(() => Navbar)) navbar: Navbar - ) { - toolbar && toolbar.addItemRef(elementRef); - navbar && navbar.addItemRef(elementRef); - this.inToolbar = !!(toolbar || navbar); - } - - @ContentChildren(Button) - set _buttons(buttons: any) { - if (this.inToolbar) { - Button.setRoles(buttons, 'bar-button'); - } - } -} diff --git a/src/components/virtual-scroll/test/basic/main.html b/src/components/virtual-scroll/test/basic/main.html index af0c7a7446..8a434f9057 100644 --- a/src/components/virtual-scroll/test/basic/main.html +++ b/src/components/virtual-scroll/test/basic/main.html @@ -1,11 +1,13 @@ - - Virtual Scroll{{webview}} - - - - + + + Virtual Scroll{{webview}} + + + + + diff --git a/src/components/virtual-scroll/test/image-gallery/main.html b/src/components/virtual-scroll/test/image-gallery/main.html index c32968cdb3..96f0f1ce29 100644 --- a/src/components/virtual-scroll/test/image-gallery/main.html +++ b/src/components/virtual-scroll/test/image-gallery/main.html @@ -31,14 +31,16 @@ } - - Virtual Scroll: Image Gallery - - - - + + + Virtual Scroll: Image Gallery + + + + + diff --git a/src/components/virtual-scroll/test/sliding-item/main.html b/src/components/virtual-scroll/test/sliding-item/main.html index 71899a9d41..f8b7f26641 100644 --- a/src/components/virtual-scroll/test/sliding-item/main.html +++ b/src/components/virtual-scroll/test/sliding-item/main.html @@ -1,11 +1,13 @@ - - Virtual Scroll{{webview}} - - - - + + + Virtual Scroll{{webview}} + + + + + diff --git a/src/config/bootstrap.ts b/src/config/bootstrap.ts index 4dc0fa8a1b..fa21cb0aa0 100644 --- a/src/config/bootstrap.ts +++ b/src/config/bootstrap.ts @@ -12,7 +12,7 @@ import {IONIC_DIRECTIVES} from './directives'; import {isPresent} from '../util/util'; import {Keyboard} from '../util/keyboard'; import {MenuController} from '../components/menu/menu-controller'; -import {nativeTimeout, closest} from '../util/dom'; +import {nativeTimeout, closest, nativeRaf} from '../util/dom'; import {NavRegistry} from '../components/nav/nav-registry'; import {Platform} from '../platform/platform'; import {ScrollView} from '../util/scroll-view'; @@ -42,25 +42,27 @@ const _reflect: any = Reflect; * ionicBootstrap(MyClass, null, {tabbarPlacement: 'bottom'}) * ``` */ -export function ionicBootstrap(appRootComponent: any, customProviders?: Array, config?: any): Promise> { +export function ionicBootstrap(appRootComponent: any, customProviders?: Array, config?: any) { // get all Ionic Providers let providers = ionicProviders(customProviders, config); // automatically set "ion-app" selector to users root component addSelector(appRootComponent, 'ion-app'); - // call angular bootstrap - return bootstrap(appRootComponent, providers).then(ngComponentRef => { - // ionic app has finished bootstrapping - return ionicPostBootstrap(ngComponentRef); + cssReady(() => { + // call angular bootstrap + bootstrap(appRootComponent, providers).then(ngComponentRef => { + // ionic app has finished bootstrapping + ionicPostBootstrap(ngComponentRef); + }); }); } - /** - * @private - */ -export function ionicPostBootstrap(ngComponentRef: ComponentRef): ComponentRef { +/** + * @private + */ +export function ionicPostBootstrap(ngComponentRef: ComponentRef) { let app: App = ngComponentRef.injector.get(App); app.setAppInjector(ngComponentRef.injector); @@ -72,15 +74,28 @@ export function ionicPostBootstrap(ngComponentRef: ComponentRef): Component // TODO: Use PLATFORM_INITIALIZER ngComponentRef.injector.get(TapClick); - // TODO: Use Renderer - ngComponentRef.location.nativeElement.classList.add('app-init'); - return ngComponentRef; } - /** - * @private - */ +let cssLoadAttempt = 0; +function cssReady(done: Function) { + let appEle = document.body.querySelector('ion-app'); + + if (!appEle || appEle.clientHeight > 0 || cssLoadAttempt > 300) { + done(); + + } else { + nativeRaf(() => { + cssLoadAttempt++; + cssReady(done); + }); + } +} + + +/** + * @private + */ export function ionicProviders(customProviders?: Array, config?: any): any[] { let directives = IONIC_DIRECTIVES; @@ -148,10 +163,6 @@ function setupDom(window: Window, document: Document, config: Config, platform: linkEle.href = href; } - let headStyle = document.createElement('style'); - headStyle.innerHTML = 'ion-app{display:none}'; - document.head.appendChild(headStyle); - // set the mode class name // ios/md/wp bodyEle.classList.add(mode); @@ -179,11 +190,11 @@ function setupDom(window: Window, document: Document, config: Config, platform: // touch devices should not use :hover CSS pseudo // enable :hover CSS when the "hoverCSS" setting is not false - if (config.get('hoverCSS') !== false) { + if (config.getBoolean('hoverCSS', true) !== false) { bodyEle.classList.add('enable-hover'); } - if ( config.getBoolean('clickBlock', true) !== false ) { + if (config.getBoolean('clickBlock', true) !== false) { clickBlock.enable(); } diff --git a/src/config/directives.ts b/src/config/directives.ts index b00a191f20..aea6cdf751 100644 --- a/src/config/directives.ts +++ b/src/config/directives.ts @@ -22,7 +22,9 @@ import {Item} from '../components/item/item'; import {ItemSliding, ItemOptions} from '../components/item/item-sliding'; import {VirtualScroll} from '../components/virtual-scroll/virtual-scroll'; import {VirtualItem, VirtualHeader, VirtualFooter} from '../components/virtual-scroll/virtual-item'; -import {Toolbar, ToolbarTitle, ToolbarItem} from '../components/toolbar/toolbar'; +import {Toolbar, Header, Footer} from '../components/toolbar/toolbar'; +import {ToolbarItem} from '../components/toolbar/toolbar-item'; +import {ToolbarTitle} from '../components/toolbar/toolbar-title'; import {Icon} from '../components/icon/icon'; import {Spinner} from '../components/spinner/spinner'; import {Checkbox} from '../components/checkbox/checkbox'; @@ -83,6 +85,8 @@ import {ShowWhen, HideWhen} from '../components/show-hide-when/show-hide-when'; * - SlideLazy * - Tabs * - Tab + * - Header + * - Footer * - Toolbar * - ToolbarTitle * - ToolbarItem @@ -153,6 +157,8 @@ export const IONIC_DIRECTIVES: any[] = [ Tab, // Toolbar + Header, + Footer, Toolbar, ToolbarTitle, ToolbarItem, diff --git a/src/config/modes.ts b/src/config/modes.ts index 18267fa97c..c33fef411d 100644 --- a/src/config/modes.ts +++ b/src/config/modes.ts @@ -71,7 +71,7 @@ Config.setModeConfig('md', { modalLeave: 'modal-md-slide-out', pageTransition: 'md-transition', - pageTransitionDelay: 16, + pageTransitionDelay: 64, pickerEnter: 'picker-slide-in', pickerLeave: 'picker-slide-out', diff --git a/src/transitions/page-transition.ts b/src/transitions/page-transition.ts new file mode 100644 index 0000000000..7136d3caee --- /dev/null +++ b/src/transitions/page-transition.ts @@ -0,0 +1,142 @@ +import {Animation} from '../animations/animation'; +import {closest} from '../util/dom'; +import {Content} from '../components/content/content'; +import {Tabs} from '../components/tabs/tabs'; +import {Transition} from './transition'; +import {ViewController} from '../components/nav/view-controller'; + + +/** + * @private + */ +export class PageTransition extends Transition { + enteringPage: Animation; + paddingTop = 0; + paddingBottom = 0; + headerHeight = 0; + footerHeight = 0; + tabbarOnTop: boolean = null; + + constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { + super(enteringView, leavingView, opts); + + this.enteringPage = new Animation(this.enteringView.pageRef()); + this.enteringPage.before.addClass('show-page'); + this.add(this.enteringPage); + + this.before.addDomReadFn(this.readDimensions.bind(this)); + this.before.addDomWriteFn(this.writeContentPadding.bind(this)); + } + + /** + * DOM READ + */ + readDimensions() { + let pageElementRef = this.enteringView.pageRef(); + if (!pageElementRef) return; + + let pageEle = pageElementRef.nativeElement; + if (pageEle.tagName !== 'ION-PAGE') { + pageEle = pageEle.querySelector('ion-page'); + if (!pageEle) { + return; + } + } + + let ele: HTMLElement; + let computedStyle: any; + + for (var i = 0; i < pageEle.children.length; i++) { + ele = pageEle.children[i]; + + if (ele.tagName === 'ION-CONTENT') { + computedStyle = getComputedStyle(ele); + this.paddingTop += parsePxUnit(computedStyle.paddingTop); + this.paddingBottom += parsePxUnit(computedStyle.paddingBottom); + + } else if (ele.tagName === 'ION-HEADER') { + this.headerHeight = ele.clientHeight; + this.paddingTop += this.headerHeight; + + } else if (ele.tagName === 'ION-FOOTER') { + this.footerHeight = ele.clientHeight; + this.paddingBottom += this.footerHeight; + } + } + + ele = pageEle; + let tabbarEle: HTMLElement; + let tabbarOnTop: boolean; + + while (ele && ele.tagName !== 'ION-MODAL' && !ele.classList.contains('tab-subpage')) { + + if (ele.tagName === 'ION-TABS') { + tabbarEle = ele.firstElementChild; + tabbarOnTop = ele.getAttribute('tabbarplacement') === 'top'; + + if (tabbarOnTop) { + this.paddingTop += tabbarEle.clientHeight; + + } else { + this.paddingBottom += tabbarEle.clientHeight; + } + + if (this.tabbarOnTop === null) { + // this is the first tabbar found, remember it's position + this.tabbarOnTop = tabbarOnTop; + } + } + + ele = ele.parentElement; + } + } + + /** + * DOM WRITE + */ + writeContentPadding() { + if (this.paddingTop || this.paddingBottom) { + let content = this.enteringView.getContent(); + + if (content && content instanceof Content) { + content.setContentPadding(this.paddingTop, this.paddingBottom); + } + } + + if (this.tabbarOnTop !== null) { + let tab = this.enteringView.getNav(); + if (tab && tab.parent) { + let tabs = tab.parent; + if (tabs instanceof Tabs) { + if (this.tabbarOnTop) { + tabs.setTabbarPosition(this.headerHeight, -1); + + } else { + tabs.setTabbarPosition(-1, 0); + } + } + } + } + } + + destroy() { + super.destroy(); + this.enteringView = this.enteringPage = null; + } + +} + +function parsePxUnit(val: string): number { + return (val.indexOf('px') > 0) ? parseInt(val, 10) : 0; +} + +export interface TransitionOptions { + animation: string; + duration: number; + easing: string; + direction: string; + renderDelay?: number; + isRTL?: boolean; + ev?: any; +} + diff --git a/src/transitions/transition-ios.ts b/src/transitions/transition-ios.ts index 0a49fecb3d..6f29750e9c 100644 --- a/src/transitions/transition-ios.ts +++ b/src/transitions/transition-ios.ts @@ -1,5 +1,6 @@ import {Animation} from '../animations/animation'; -import {Transition, TransitionOptions} from './transition'; +import {PageTransition} from './page-transition'; +import {TransitionOptions} from './transition'; import {ViewController} from '../components/nav/view-controller'; const DURATION = 500; @@ -13,10 +14,10 @@ const OFF_OPACITY = 0.8; const SHOW_BACK_BTN_CSS = 'show-back-button'; -class IOSTransition extends Transition { +class IOSTransition extends PageTransition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); this.duration(opts.duration || DURATION); this.easing(opts.easing || EASING); @@ -28,10 +29,6 @@ class IOSTransition extends Transition { let enteringHasNavbar = enteringView.hasNavbar(); let leavingHasNavbar = leavingView && leavingView.hasNavbar(); - let enteringPage = new Animation(enteringView.pageRef()); - enteringPage.before.addClass('show-page'); - this.add(enteringPage); - // entering content let enteringContent = new Animation(enteringView.contentRef()); enteringContent.element(enteringView.toolbarRefs()); @@ -66,8 +63,8 @@ class IOSTransition extends Transition { .add(enteringNavbarBg) .add(enteringBackButton); - enteringTitle.fadeIn(); - enteringNavbarItems.fadeIn(); + enteringTitle.fromTo(OPACITY, 0.01, 1, true); + enteringNavbarItems.fromTo(OPACITY, 0.01, 1, true); // set properties depending on direction if (backDirection) { @@ -78,7 +75,7 @@ class IOSTransition extends Transition { // back direction, entering page has a back button enteringBackButton .before.addClass(SHOW_BACK_BTN_CSS) - .fadeIn(); + .fromTo(OPACITY, 0.01, 1, true); } } else { @@ -90,7 +87,7 @@ class IOSTransition extends Transition { // should just fade in, no sliding enteringNavbarBg .before.clearStyles([TRANSLATEX]) - .fadeIn(); + .fromTo(OPACITY, 0.01, 1, true); } else { // entering navbar, forward direction, and there's no leaving navbar @@ -105,7 +102,7 @@ class IOSTransition extends Transition { // forward direction, entering page has a back button enteringBackButton .before.addClass(SHOW_BACK_BTN_CSS) - .fadeIn(); + .fromTo(OPACITY, 0.01, 1, true); let enteringBackBtnText = new Animation(enteringView.backBtnTextRef()); enteringBackBtnText.fromTo(TRANSLATEX, '100px', '0px'); @@ -153,9 +150,9 @@ class IOSTransition extends Transition { this.add(leavingNavBar); // fade out leaving navbar items - leavingBackButton.fadeOut(); - leavingTitle.fadeOut(); - leavingNavbarItems.fadeOut(); + leavingBackButton.fromTo(OPACITY, 0.99, 0); + leavingTitle.fromTo(OPACITY, 0.99, 0); + leavingNavbarItems.fromTo(OPACITY, 0.99, 0); if (backDirection) { // leaving navbar, back direction @@ -166,7 +163,7 @@ class IOSTransition extends Transition { // should just fade out, no sliding leavingNavbarBg .before.clearStyles([TRANSLATEX]) - .fadeOut(); + .fromTo('opacity', 0.99, 0); } else { // leaving navbar, back direction, and there's no entering navbar @@ -191,4 +188,4 @@ class IOSTransition extends Transition { } -Transition.register('ios-transition', IOSTransition); +PageTransition.register('ios-transition', IOSTransition); diff --git a/src/transitions/transition-md.ts b/src/transitions/transition-md.ts index 8aadb7c934..034a6c86f4 100644 --- a/src/transitions/transition-md.ts +++ b/src/transitions/transition-md.ts @@ -1,5 +1,6 @@ import {Animation} from '../animations/animation'; -import {Transition, TransitionOptions} from './transition'; +import {PageTransition} from './page-transition'; +import {TransitionOptions} from './transition'; import {ViewController} from '../components/nav/view-controller'; const TRANSLATEY = 'translateY'; @@ -8,10 +9,10 @@ const CENTER = '0px'; const SHOW_BACK_BTN_CSS = 'show-back-button'; -class MDTransition extends Transition { +class MDTransition extends PageTransition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); // what direction is the transition going let backDirection = (opts.direction === 'back'); @@ -20,20 +21,15 @@ class MDTransition extends Transition { let enteringHasNavbar = enteringView.hasNavbar(); let leavingHasNavbar = leavingView && leavingView.hasNavbar(); - // entering content item moves in bottom to center - let enteringPage = new Animation(enteringView.pageRef()); - enteringPage.before.addClass('show-page'); - this.add(enteringPage); - if (backDirection) { this.duration(opts.duration || 200).easing('cubic-bezier(0.47,0,0.745,0.715)'); - enteringPage.before.clearStyles([TRANSLATEY]); + this.enteringPage.before.clearStyles([TRANSLATEY]); } else { this.duration(opts.duration || 280).easing('cubic-bezier(0.36,0.66,0.04,1)'); - enteringPage + this.enteringPage .fromTo(TRANSLATEY, OFF_BOTTOM, CENTER, true) - .fadeIn(); + .fromTo('opacity', 0.01, 1, true); } if (enteringHasNavbar) { @@ -55,11 +51,11 @@ class MDTransition extends Transition { // leaving content this.duration(opts.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()); + this.add(leavingPage.fromTo(TRANSLATEY, CENTER, OFF_BOTTOM).fromTo('opacity', 0.99, 0)); } } } -Transition.register('md-transition', MDTransition); +PageTransition.register('md-transition', MDTransition); diff --git a/src/transitions/transition-wp.ts b/src/transitions/transition-wp.ts index 364d0bc759..7b98ac3cbc 100644 --- a/src/transitions/transition-wp.ts +++ b/src/transitions/transition-wp.ts @@ -1,15 +1,16 @@ import {Animation} from '../animations/animation'; -import {Transition, TransitionOptions} from './transition'; +import {PageTransition} from './page-transition'; +import {TransitionOptions} from './transition'; import {ViewController} from '../components/nav/view-controller'; const SHOW_BACK_BTN_CSS = 'show-back-button'; const SCALE_SMALL = .95; -class WPTransition extends Transition { +class WPTransition extends PageTransition { constructor(enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { - super(opts); + super(enteringView, leavingView, opts); // what direction is the transition going let backDirection = (opts.direction === 'back'); @@ -18,20 +19,15 @@ class WPTransition extends Transition { let enteringHasNavbar = enteringView.hasNavbar(); let leavingHasNavbar = leavingView && leavingView.hasNavbar(); - // entering content scale from smaller to larger - let enteringPage = new Animation(enteringView.pageRef()); - enteringPage.before.addClass('show-page'); - this.add(enteringPage); - if (backDirection) { this.duration(opts.duration || 120).easing('cubic-bezier(0.47,0,0.745,0.715)'); - enteringPage.before.clearStyles(['scale']); + this.enteringPage.before.clearStyles(['scale']); } else { this.duration(opts.duration || 280).easing('cubic-bezier(0,0 0.05,1)'); - enteringPage + this.enteringPage .fromTo('scale', SCALE_SMALL, 1, true) - .fadeIn(); + .fromTo('opacity', 0.01, 1, true); } if (enteringHasNavbar) { @@ -53,11 +49,11 @@ class WPTransition extends Transition { // leaving content this.duration(opts.duration || 200).easing('cubic-bezier(0.47,0,0.745,0.715)'); let leavingPage = new Animation(leavingView.pageRef()); - this.add(leavingPage.fromTo('scale', 1, SCALE_SMALL).fadeOut()); + this.add(leavingPage.fromTo('scale', 1, SCALE_SMALL).fromTo('opacity', 0.99, 0)); } } } -Transition.register('wp-transition', WPTransition); +PageTransition.register('wp-transition', WPTransition); diff --git a/src/transitions/transition.ts b/src/transitions/transition.ts index 4312f41bf5..d6cd2a2ada 100644 --- a/src/transitions/transition.ts +++ b/src/transitions/transition.ts @@ -1,13 +1,28 @@ import {Animation} from '../animations/animation'; +import {closest} from '../util/dom'; +import {Content} from '../components/content/content'; +import {Tabs} from '../components/tabs/tabs'; import {ViewController} from '../components/nav/view-controller'; /** * @private - **/ + * + * - play + * - Add before classes - DOM WRITE + * - Remove before classes - DOM WRITE + * - Add before inline styles - DOM WRITE + * - set inline FROM styles - DOM WRITE + * - RAF + * - read toolbar dimensions - DOM READ + * - write content top/bottom padding - DOM WRITE + * - set css transition duration/easing - DOM WRITE + * - RAF + * - set inline TO styles - DOM WRITE + */ export class Transition extends Animation { - constructor(opts: TransitionOptions) { + constructor(public enteringView: ViewController, leavingView: ViewController, opts: TransitionOptions) { super(null, { renderDelay: opts.renderDelay }); @@ -39,4 +54,4 @@ export interface TransitionOptions { ev?: any; } -let TransitionRegistry = {}; +let TransitionRegistry: any = {}; diff --git a/src/util/util.scss b/src/util/util.scss index 9d23af2513..e85db6575c 100755 --- a/src/util/util.scss +++ b/src/util/util.scss @@ -6,6 +6,11 @@ template { display: none !important; } +.sticky { + position: sticky; + top: 0; +} + // Focus Outline // -------------------------------------------------- diff --git a/tooling/generators/page/page.tmpl.html b/tooling/generators/page/page.tmpl.html index 38d51863a8..6d2097f41a 100644 --- a/tooling/generators/page/page.tmpl.html +++ b/tooling/generators/page/page.tmpl.html @@ -4,10 +4,12 @@ See http://ionicframework.com/docs/v2/components/#navigation for more info on Ionic pages and navigation. --> - - <%= name %> - + + + <%= name %> + + + + - - diff --git a/tooling/generators/page/page.tmpl.ts b/tooling/generators/page/page.tmpl.ts index 3dbb3e0a84..3e98370326 100644 --- a/tooling/generators/page/page.tmpl.ts +++ b/tooling/generators/page/page.tmpl.ts @@ -11,5 +11,9 @@ import { NavController } from 'ionic-angular'; templateUrl: 'build/<%= directory %>/<%= fileName %>/<%= fileName %>.html', }) export class <%= jsClassName %> { - constructor(private nav: NavController) {} + + constructor(private nav: NavController) { + + } + }