Merge branch 'master' into list-border-refactor

This commit is contained in:
Brandy Carney
2015-11-10 20:27:27 -05:00
12 changed files with 560 additions and 136 deletions

View File

@@ -2,7 +2,6 @@ import {Title} from 'angular2/angular2';
import {ClickBlock} from '../../util/click-block';
import {ScrollTo} from '../../animations/scroll-to';
import * as dom from '../../util/dom';
/**
@@ -11,11 +10,10 @@ import * as dom from '../../util/dom';
*/
export class IonicApp {
/**
* TODO
*/
constructor() {
this._title = new Title();
constructor(fastdom) {
this._fastdom = fastdom;
this._titleSrv = new Title();
this._title = '';
this._disTime = 0;
this._trnsTime = 0;
@@ -28,11 +26,12 @@ export class IonicApp {
* @param {string} val Value to set the document title to.
*/
setTitle(val) {
this._title.setTitle(val);
}
getTitle() {
return this._title.getTitle(val);
if (val !== this._title) {
this._title = val;
this._fastdom.defer(4, () => {
this._titleSrv.setTitle(this._title);
});
}
}
/**

View File

@@ -436,7 +436,7 @@ export class NavController extends Ion {
}
if (!opts.animation) {
opts.animation = this.config.get('viewTransition');
opts.animation = this.config.get('pageTransition');
}
if (this.config.get('animate') === false) {
opts.animate = false;
@@ -468,6 +468,7 @@ export class NavController extends Ion {
leavingView.state = STAGED_LEAVING_STATE;
// init the transition animation
opts.renderDelay = this.config.get('pageTransitionDelay');
let transAnimation = Transition.create(this, opts);
if (opts.animate === false) {
// force it to not animate the elements, just apply the "to" styles

View File

@@ -4,6 +4,7 @@ import {Ion} from '../ion';
import {IonicApp} from '../app/app';
import {Attr} from '../app/id';
import {Config} from '../../config/config';
import {Platform} from '../../platform/platform';
import {ViewController} from '../nav/view-controller';
import {ConfigComponent} from '../../config/decorators';
import {Icon} from '../icon/icon';
@@ -107,7 +108,8 @@ export class Tabs extends Ion {
app: IonicApp,
config: Config,
elementRef: ElementRef,
@Optional() viewCtrl: ViewController
@Optional() viewCtrl: ViewController,
private platform: Platform
) {
super(elementRef, config);
this.app = app;
@@ -132,6 +134,15 @@ export class Tabs extends Ion {
}
}
onInit() {
super.onInit();
if (this.highlight) {
this.platform.onResize(() => {
this.highlight.select(this.getSelected());
});
}
}
/**
* @private
*/
@@ -305,7 +316,7 @@ class TabButton extends Ion {
})
class TabHighlight {
constructor(@Host() tabs: Tabs, config: Config, elementRef: ElementRef) {
if (config.get('mode') === 'md') {
if (config.get('tabbarHighlight')) {
tabs.highlight = this;
this.elementRef = elementRef;
}
@@ -320,7 +331,7 @@ class TabHighlight {
this.init = true;
setTimeout(() => {
ele.classList.add('animate');
}, 64)
}, 64);
}
}

View File

@@ -3,11 +3,12 @@ import {raf} from '../../util/dom';
export class Activator {
constructor(app, config) {
constructor(app, config, fastdom) {
this.app = app;
this.fastdom = fastdom;
this.queue = [];
this.active = [];
this.clearStateTimeout = 80;
this.clearStateDefers = 5;
this.clearAttempt = 0;
this.activatedClass = config.get('activatedClass') || 'activated';
this.x = 0;
@@ -17,7 +18,7 @@ export class Activator {
downAction(ev, activatableEle, pointerX, pointerY, callback) {
// the user just pressed down
if (this.disableActivated(ev)) return;
if (this.disableActivated(ev)) return false;
// remember where they pressed
this.x = pointerX;
@@ -26,7 +27,7 @@ export class Activator {
// queue to have this element activated
this.queue.push(activatableEle);
raf(() => {
this.fastdom.write(() => {
let activatableEle;
for (let i = 0; i < this.queue.length; i++) {
activatableEle = this.queue[i];
@@ -37,13 +38,15 @@ export class Activator {
}
this.queue = [];
});
return true;
}
upAction() {
// the user was pressing down, then just let up
setTimeout(() => {
this.fastdom.defer(this.clearStateDefers, () => {
this.clearState();
}, this.clearStateTimeout);
});
}
clearState() {
@@ -65,11 +68,14 @@ export class Activator {
deactivate() {
// remove the active class from all active elements
for (let i = 0; i < this.active.length; i++) {
this.active[i].classList.remove(this.activatedClass);
}
this.queue = [];
this.active = [];
this.fastdom.write(() => {
for (let i = 0; i < this.active.length; i++) {
this.active[i].classList.remove(this.activatedClass);
}
this.active = [];
});
}
disableActivated(ev) {

View File

@@ -1,23 +1,38 @@
import {Activator} from './activator';
import {removeElement, raf} from '../../util/dom';
import {Animation} from '../../animations/animation';
import {raf} from '../../util/dom';
export class RippleActivator extends Activator {
constructor(app, config) {
super(app, config);
this.ripples = {};
constructor(app, config, fastdom) {
super(app, config, fastdom);
this.expands = {};
this.fades = {};
this.expandSpeed = null;
}
downAction(ev, activatableEle, pointerX, pointerY) {
if (super.downAction(ev, activatableEle, pointerX, pointerY) ) {
// create a new ripple element
this.expandSpeed = EXPAND_DOWN_PLAYBACK_RATE;
if (this.disableActivated(ev)) return;
this.fastdom.defer(2, () => {
super.downAction(ev, activatableEle, pointerX, pointerY);
this.fastdom.read(() => {
let clientRect = activatableEle.getBoundingClientRect();
// create a new ripple element
let clientRect = activatableEle.getBoundingClientRect();
this.fastdom.write(() => {
this.createRipple(activatableEle, pointerX, pointerY, clientRect);
});
});
});
}
}
createRipple(activatableEle, pointerX, pointerY, clientRect) {
let clientPointerX = (pointerX - clientRect.left);
let clientPointerY = (pointerY - clientRect.top);
@@ -29,6 +44,7 @@ export class RippleActivator extends Activator {
let duration = (1000 * Math.sqrt(radius / TOUCH_DOWN_ACCEL) + 0.5);
let rippleEle = document.createElement('md-ripple');
let rippleId = Date.now();
let eleStyle = rippleEle.style;
eleStyle.width = eleStyle.height = diameter + 'px';
eleStyle.marginTop = eleStyle.marginLeft = -(diameter / 2) + 'px';
@@ -37,96 +53,74 @@ export class RippleActivator extends Activator {
activatableEle.appendChild(rippleEle);
let ripple = this.ripples[Date.now()] = {
ele: rippleEle,
radius: radius,
duration: duration
};
// create the animation for the fade out, but don't start it yet
this.fades[rippleId] = new Animation(rippleEle, {renderDelay: 0});
this.fades[rippleId]
.fadeOut()
.duration(FADE_OUT_DURATION)
.playbackRate(1)
.onFinish(() => {
this.fastdom.write(() => {
this.fades[rippleId].dispose(true);
delete this.fades[rippleId];
});
});
// expand the circle from the users starting point
// start slow, and when they let up, then speed up the animation
ripple.expand = new Animation(rippleEle, {renderDelay: 0});
ripple.expand
this.expands[rippleId] = new Animation(rippleEle, {renderDelay: 0});
this.expands[rippleId]
.fromTo('scale', '0.001', '1')
.duration(duration)
.playbackRate(EXPAND_DOWN_PLAYBACK_RATE)
.playbackRate(this.expandSpeed)
.onFinish(()=> {
// finished expanding
ripple.expand && ripple.expand.dispose();
ripple.expand = null;
ripple.expanded = true;
this.expands[rippleId].dispose();
delete this.expands[rippleId];
this.next();
})
.play();
this.next();
}
upAction(forceFadeOut) {
upAction() {
this.deactivate();
let rippleId, ripple;
for (rippleId in this.ripples) {
ripple = this.ripples[rippleId];
this.expandSpeed = 1;
if (!ripple.fade || forceFadeOut) {
// ripple has not been let up yet
clearTimeout(ripple.fadeStart);
ripple.fadeStart = setTimeout(() => {
// speed up the rate if the animation is still going
ripple.expand && ripple.expand.playbackRate(EXPAND_OUT_PLAYBACK_RATE);
ripple.fade = new Animation(ripple.ele);
ripple.fade
.fadeOut()
.duration(OPACITY_OUT_DURATION)
.playbackRate(1)
.onFinish(() => {
ripple.fade && ripple.fade.dispose();
ripple.fade = null;
ripple.faded = true;
this.next();
})
.play();
this.fastdom.defer(4, () => {
this.next();
});
}
});
next() {
const now = Date.now();
let rippleId;
for (rippleId in this.expands) {
if (parseInt(rippleId, 10) + 4000 < now) {
this.expands[rippleId].dispose(true);
delete this.expands[rippleId];
} else if (this.expands[rippleId].playbackRate() === EXPAND_DOWN_PLAYBACK_RATE) {
this.expands[rippleId].playbackRate(EXPAND_OUT_PLAYBACK_RATE);
}
}
this.next();
}
for (rippleId in this.fades) {
if (parseInt(rippleId, 10) + 4000 < now) {
this.fades[rippleId].dispose(true);
delete this.fades[rippleId];
next(forceComplete) {
let rippleId, ripple;
for (rippleId in this.ripples) {
ripple = this.ripples[rippleId];
if ((ripple.expanded && ripple.faded && ripple.ele) || forceComplete) {
// finished expanding and the user has lifted the pointer
ripple.remove = true;
raf(() => {
this.remove();
});
} else if (!this.fades[rippleId].isPlaying) {
this.fades[rippleId].isPlaying = true;
this.fades[rippleId].play();
}
}
}
clearState() {
this.deactivate();
this.next(true);
}
remove() {
let rippleId, ripple;
for (rippleId in this.ripples) {
ripple = this.ripples[rippleId];
if (ripple.remove || parseInt(rippleId, 10) + 4000 < Date.now()) {
ripple.expand && ripple.expand.dispose();
ripple.fade && ripple.fade.dispose();
removeElement(ripple.ele);
ripple.ele = ripple.expand = ripple.fade = null;
delete this.ripples[rippleId];
}
}
this.next();
}
}
@@ -134,4 +128,4 @@ export class RippleActivator extends Activator {
const TOUCH_DOWN_ACCEL = 512;
const EXPAND_DOWN_PLAYBACK_RATE = 0.35;
const EXPAND_OUT_PLAYBACK_RATE = 3;
const OPACITY_OUT_DURATION = 750;
const FADE_OUT_DURATION = 700;

View File

@@ -12,27 +12,29 @@ let disableNativeClickAmount = 3000;
let activator = null;
let isTapPolyfill = false;
let app = null;
let config = null;
let win = null;
let doc = null;
export function initTapClick(windowInstance, documentInstance, appInstance, configInstance) {
export function initTapClick(windowInstance, documentInstance, appInstance, config, fastdom) {
win = windowInstance;
doc = documentInstance;
app = appInstance;
config = configInstance;
activator = (config.get('mdRipple') ? new RippleActivator(app, config) : new Activator(app, config));
if (config.get('activator') == 'ripple') {
activator = new RippleActivator(app, config, fastdom);
} else if (config.get('activator') == 'highlight') {
activator = new Activator(app, config, fastdom));
}
isTapPolyfill = (config.get('tapPolyfill') === true);
addListener('click', click, true);
if (isTapPolyfill) {
addListener('touchstart', touchStart);
addListener('touchend', touchEnd);
addListener('touchcancel', touchCancel);
}
addListener('touchstart', touchStart);
addListener('touchend', touchEnd);
addListener('touchcancel', touchCancel);
addListener('mousedown', mouseDown, true);
addListener('mouseup', mouseUp, true);
@@ -47,7 +49,7 @@ function touchStart(ev) {
function touchEnd(ev) {
touchAction();
if (startCoord && app.isEnabled()) {
if (isTapPolyfill && startCoord && app.isEnabled()) {
let endCoord = pointerCoord(ev);
if (!hasPointerMoved(pointerTolerance, startCoord, endCoord)) {
@@ -100,8 +102,8 @@ function pointerStart(ev) {
startCoord = pointerCoord(ev);
let now = Date.now();
if (lastActivated + 100 < now) {
activator.downAction(ev, activatableEle, startCoord.x, startCoord.y);
if (lastActivated + 150 < now) {
activator && activator.downAction(ev, activatableEle, startCoord.x, startCoord.y);
lastActivated = now;
}
@@ -114,7 +116,7 @@ function pointerStart(ev) {
function pointerEnd(ev) {
moveListeners(false);
activator.upAction();
activator && activator.upAction();
}
function pointerMove(ev) {
@@ -127,20 +129,22 @@ function pointerMove(ev) {
function pointerCancel(ev) {
console.debug('pointerCancel from', ev.type);
activator.clearState();
activator && activator.clearState();
moveListeners(false);
}
function moveListeners(shouldAdd) {
if (isTapPolyfill) {
removeListener('touchmove', pointerMove);
}
removeListener('mousemove', pointerMove);
if (shouldAdd) {
if (isTapPolyfill) {
addListener('touchmove', pointerMove);
}
addListener('mousemove', pointerMove);
} else {
if (isTapPolyfill) {
removeListener('touchmove', pointerMove);
}
removeListener('mousemove', pointerMove);
}
}
@@ -168,8 +172,6 @@ function click(ev) {
console.debug('click prevent', preventReason);
ev.preventDefault();
ev.stopPropagation();
} else {
activator.upAction();
}
}