mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-22 13:32:54 +08:00
Merge pull request #6993 from manucorporat/more-uieventmanager
Toggle and Refresh using UIEventManager
This commit is contained in:
@ -170,6 +170,13 @@ export class Content extends Ion {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
getScrollElement(): HTMLElement {
|
||||
return this._scrollEle;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user