Merge pull request #6993 from manucorporat/more-uieventmanager

Toggle and Refresh using UIEventManager
This commit is contained in:
Adam Bradley
2016-06-21 10:52:25 -05:00
committed by GitHub
4 changed files with 80 additions and 127 deletions

View File

@ -170,6 +170,13 @@ export class Content extends Ion {
}
};
}
/**
* @private
*/
getScrollElement(): HTMLElement {
return this._scrollEle;
}
/**
* @private

View File

@ -4,6 +4,7 @@ import {Content} from '../content/content';
import {Icon} from '../icon/icon';
import {isTrueProperty} from '../../util/util';
import {CSS, pointerCoord, transitionEnd} from '../../util/dom';
import {PointerEvents, UIEventManager} from '../../util/ui-event-manager';
/**
@ -95,15 +96,10 @@ import {CSS, pointerCoord, transitionEnd} from '../../util/dom';
export class Refresher {
private _appliedStyles: boolean = false;
private _didStart: boolean;
private _lastStart: number = 0;
private _lastCheck: number = 0;
private _isEnabled: boolean = true;
private _mDown: Function;
private _mMove: Function;
private _mUp: Function;
private _tStart: Function;
private _tMove: Function;
private _tEnd: Function;
private _events: UIEventManager = new UIEventManager(false);
private _pointerEvents: PointerEvents;
/**
* The current state which the refresher is in. The refresher's states include:
@ -155,7 +151,7 @@ export class Refresher {
* will automatically go into the `refreshing` state. By default, the pull
* maximum will be the result of `pullMin + 60`.
*/
@Input() pullMax: number = null;
@Input() pullMax: number = this.pullMin + 60;
/**
* @input {number} How many milliseconds it takes to close the refresher. Default is `280`.
@ -202,8 +198,7 @@ export class Refresher {
constructor(
@Host() private _content: Content,
private _zone: NgZone,
elementRef: ElementRef
) {
elementRef: ElementRef) {
_content.addCssClass('has-refresher');
// deprecated warning
@ -222,31 +217,29 @@ export class Refresher {
private _onStart(ev: TouchEvent): any {
// if multitouch then get out immediately
if (ev.touches && ev.touches.length > 1) {
return 1;
return false;
}
if (this.state !== STATE_INACTIVE) {
return false;
}
let scrollHostScrollTop = this._content.getContentDimensions().scrollTop;
// if the scrollTop is greater than zero then it's
// not possible to pull the content down yet
if (scrollHostScrollTop > 0) {
return false;
}
let coord = pointerCoord(ev);
console.debug('Pull-to-refresh, onStart', ev.type, 'y:', coord.y);
let now = Date.now();
if (this._lastStart + 100 > now) {
return 2;
}
this._lastStart = now;
if ( ev.type === 'mousedown' && !this._mMove) {
this._mMove = this._content.addMouseMoveListener( this._onMove.bind(this) );
}
this.startY = this.currentY = coord.y;
this.progress = 0;
if (!this.pullMax) {
this.pullMax = (this.pullMin + 60);
}
this.state = STATE_PULLING;
return true;
}
private _onMove(ev: TouchEvent): any {
private _onMove(ev: TouchEvent) {
// this method can get called like a bazillion times per second,
// so it's built to be as efficient as possible, and does its
// best to do any DOM read/writes only when absolutely necessary
@ -396,12 +389,6 @@ export class Refresher {
// reset on any touchend/mouseup
this.startY = null;
if (this._mMove) {
// we don't want to always listen to mousemoves
// remove it if we're still listening
this._mMove();
this._mMove = null;
}
}
private _beginRefresh() {
@ -463,10 +450,8 @@ export class Refresher {
this.state = state;
this._setCss(0, '', true, delay);
if (this._mMove) {
// always remove the mousemove event
this._mMove();
this._mMove = null;
if (this._pointerEvents) {
this._pointerEvents.stop();
}
}
@ -481,43 +466,13 @@ export class Refresher {
}
private _setListeners(shouldListen: boolean) {
const self = this;
const content = self._content;
this._events.unlistenAll();
this._pointerEvents = null;
if (shouldListen) {
// add listener outside of zone
// touch handlers
self._zone.runOutsideAngular(function() {
if (!self._tStart) {
self._tStart = content.addTouchStartListener( self._onStart.bind(self) );
}
if (!self._tMove) {
self._tMove = content.addTouchMoveListener( self._onMove.bind(self) );
}
if (!self._tEnd) {
self._tEnd = content.addTouchEndListener( self._onEnd.bind(self) );
}
// mouse handlers
// mousemove does not get added until mousedown fires
if (!self._mDown) {
self._mDown = content.addMouseDownListener( self._onStart.bind(self) );
}
if (!self._mUp) {
self._mUp = content.addMouseUpListener( self._onEnd.bind(self) );
}
});
} else {
// unregister event listeners from content element
self._mDown && self._mDown();
self._mMove && self._mMove();
self._mUp && self._mUp();
self._tStart && self._tStart();
self._tMove && self._tMove();
self._tEnd && self._tEnd();
self._mDown = self._mMove = self._mUp = self._tStart = self._tMove = self._tEnd = null;
this._pointerEvents = this._events.pointerEvents(this._content.getScrollElement(),
this._onStart.bind(this),
this._onMove.bind(this),
this._onEnd.bind(this));
}
}

View File

@ -5,6 +5,7 @@ import {Form} from '../../util/form';
import {isTrueProperty} from '../../util/util';
import {Item} from '../item/item';
import {pointerCoord} from '../../util/dom';
import {UIEventManager} from '../../util/ui-event-manager';
const TOGGLE_VALUE_ACCESSOR = new Provider(
@ -87,6 +88,7 @@ export class Toggle implements ControlValueAccessor {
private _startX: number;
private _msPrv: number = 0;
private _fn: Function;
private _events: UIEventManager = new UIEventManager();
/**
* @private
@ -113,27 +115,14 @@ export class Toggle implements ControlValueAccessor {
}
}
/**
* @private
*/
private pointerDown(ev: UIEvent) {
if (this._isPrevented(ev)) {
return;
}
private pointerDown(ev: UIEvent): boolean {
this._startX = pointerCoord(ev).x;
this._activated = true;
return true;
}
/**
* @private
*/
private pointerMove(ev: UIEvent) {
if (this._startX) {
if (this._isPrevented(ev)) {
return;
}
let currentX = pointerCoord(ev).x;
console.debug('toggle, pointerMove', ev.type, currentX);
@ -152,16 +141,8 @@ export class Toggle implements ControlValueAccessor {
}
}
/**
* @private
*/
private pointerUp(ev: UIEvent) {
if (this._startX) {
if (this._isPrevented(ev)) {
return;
}
let endX = pointerCoord(ev).x;
if (this.checked) {
@ -188,9 +169,7 @@ export class Toggle implements ControlValueAccessor {
this.onChange(this._checked);
}
/**
* @private
*/
private _setChecked(isChecked: boolean) {
if (isChecked !== this._checked) {
this._checked = isChecked;
@ -256,6 +235,11 @@ export class Toggle implements ControlValueAccessor {
*/
ngAfterContentInit() {
this._init = true;
this._events.pointerEventsRef(this._elementRef,
(ev: any) => this.pointerDown(ev),
(ev: any) => this.pointerMove(ev),
(ev: any) => this.pointerUp(ev)
);
}
/**
@ -263,20 +247,7 @@ export class Toggle implements ControlValueAccessor {
*/
ngOnDestroy() {
this._form.deregister(this);
}
/**
* @private
*/
private _isPrevented(ev: UIEvent) {
if (ev.type.indexOf('touch') > -1) {
this._msPrv = Date.now() + 2000;
} else if (this._msPrv > Date.now() && ev.type.indexOf('mouse') > -1) {
ev.preventDefault();
ev.stopPropagation();
return true;
}
this._events.unlistenAll();
}
}

View File

@ -1,9 +1,12 @@
import {ElementRef} from '@angular/core';
const MOUSE_WAIT = 2 * 1000;
class PointerEvents {
/**
* @private
*/
export class PointerEvents {
private rmTouchStart: Function = null;
private rmTouchMove: Function = null;
private rmTouchEnd: Function = null;
@ -14,6 +17,8 @@ class PointerEvents {
private lastTouchEvent: number = 0;
mouseWait: number = 2 * 1000;
constructor(private ele: any,
private pointerDown: any,
private pointerMove: any,
@ -26,7 +31,7 @@ class PointerEvents {
}
private handleTouchStart(ev: any) {
this.lastTouchEvent = Date.now() + MOUSE_WAIT;
this.lastTouchEvent = Date.now() + this.mouseWait;
if (!this.pointerDown(ev)) {
return;
}
@ -72,22 +77,27 @@ class PointerEvents {
this.pointerUp(ev);
}
destroy() {
this.rmTouchStart && this.rmTouchStart();
stop() {
this.rmTouchMove && this.rmTouchMove();
this.rmTouchEnd && this.rmTouchEnd();
this.rmMouseStart && this.rmMouseStart();
this.rmMouseMove && this.rmMouseMove();
this.rmMouseUp && this.rmMouseUp();
this.rmTouchStart = null;
this.rmTouchMove = null;
this.rmTouchEnd = null;
this.rmMouseStart = null;
this.rmMouseMove && this.rmMouseMove();
this.rmMouseUp && this.rmMouseUp();
this.rmMouseMove = null;
this.rmMouseUp = null;
}
destroy() {
this.rmTouchStart && this.rmTouchStart();
this.rmTouchStart = null;
this.rmMouseStart && this.rmMouseStart();
this.rmMouseStart = null;
this.stop();
this.pointerDown = null;
this.pointerMove = null;
this.pointerUp = null;
@ -97,6 +107,10 @@ class PointerEvents {
}
/**
* @private
*/
export class UIEventManager {
private events: Function[] = [];
@ -109,8 +123,11 @@ export class UIEventManager {
pointerEventsRef(ref: ElementRef, pointerStart: any, pointerMove: any, pointerEnd: any, option?: any): Function {
return this.pointerEvents(ref.nativeElement, pointerStart, pointerMove, pointerEnd, option);
}
pointerEvents(element: any, pointerDown: any, pointerMove: any, pointerUp: any, option: any = false): Function {
pointerEvents(element: any, pointerDown: any, pointerMove: any, pointerUp: any, option: any = false): PointerEvents {
if (!element) {
return;
}
let submanager = new PointerEvents(
element,
pointerDown,
@ -121,10 +138,13 @@ export class UIEventManager {
let removeFunc = () => submanager.destroy();
this.events.push(removeFunc);
return removeFunc;
return submanager;
}
listen(element: any, eventName: string, callback: any, option: any = false): Function {
if (!element) {
return;
}
let removeFunc = listenEvent(element, eventName, this.zoneWrapped, option, callback);
this.events.push(removeFunc);
return removeFunc;