mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
Merge branch 'master' into list-border-refactor
This commit is contained in:
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user