From 95501a1e8640dea746d521922ef9dfc8e09dc58c Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Mon, 4 Jan 2016 22:28:49 -0600 Subject: [PATCH] fix(tap): do not fire tap click while scrolling Fixes #681 --- ionic/components/app/app.ts | 28 ++++++++++--- ionic/components/content/content.ts | 53 ++++++++++++------------- ionic/components/tap-click/tap-click.ts | 24 +++++++---- 3 files changed, 64 insertions(+), 41 deletions(-) diff --git a/ionic/components/app/app.ts b/ionic/components/app/app.ts index 952de73a14..f9cf582db1 100644 --- a/ionic/components/app/app.ts +++ b/ionic/components/app/app.ts @@ -4,7 +4,6 @@ import {Title} from 'angular2/platform/browser'; import {Config} from '../../config/config'; import {ClickBlock} from '../../util/click-block'; import {rafFrames} from '../../util/dom'; -import {ScrollTo} from '../../animations/scroll-to'; /** @@ -15,20 +14,21 @@ import {ScrollTo} from '../../animations/scroll-to'; @Injectable() export class IonicApp { - constructor(config: Config, clickBlock: ClickBlock, zone: NgZone) { - this._config = config; - this._zone = zone; + constructor( + private _config: Config, + private _clickBlock: ClickBlock, + private _zone: NgZone + ) { this._titleSrv = new Title(); this._title = ''; this._disTime = 0; - this._clickBlock = clickBlock; + this._scrollTime = 0; // Our component registry map this.components = {}; } /** - * @private * Sets the document title. * @param {string} val Value to set the document title to. */ @@ -75,6 +75,22 @@ export class IonicApp { return (this._disTime < Date.now()); } + /** + * @private + */ + setScrolling() { + this._scrollTime = Date.now(); + } + + /** + * @private + * Boolean if the app is actively scrolling or not. + * @return {bool} + */ + isScrolling() { + return (this._scrollTime + 64 > Date.now()); + } + /** * @private * Register a known component with a key, for easy lookups later. diff --git a/ionic/components/content/content.ts b/ionic/components/content/content.ts index 3c866fac26..10866d1265 100644 --- a/ionic/components/content/content.ts +++ b/ionic/components/content/content.ts @@ -1,9 +1,9 @@ import {Component, ElementRef, Optional, NgZone} from 'angular2/core'; import {Ion} from '../ion'; +import {IonicApp} from '../app/app'; import {Config} from '../../config/config'; import {raf} from '../../util/dom'; -import {Keyboard} from '../../util/keyboard'; import {ViewController} from '../nav/view-controller'; import {Animation} from '../../animations/animation'; import {ScrollTo} from '../../animations/scroll-to'; @@ -37,10 +37,15 @@ export class Content extends Ion { * @param {ElementRef} elementRef A reference to the component's DOM element. * @param {Config} config The config object to change content's default settings. */ - constructor(elementRef: ElementRef, config: Config, keyboard: Keyboard, @Optional() viewCtrl: ViewController, private _zone: NgZone) { - super(elementRef, config); + constructor( + elementRef: ElementRef, + private _config: Config, + @Optional() viewCtrl: ViewController, + private _app: IonicApp, + private _zone: NgZone + ) { + super(elementRef, _config); this.scrollPadding = 0; - this.keyboard = keyboard; if (viewCtrl) { viewCtrl.setContent(this); @@ -53,7 +58,23 @@ export class Content extends Ion { */ ngOnInit() { super.ngOnInit(); - this.scrollElement = this.getNativeElement().children[0]; + + let self = this; + self.scrollElement = self.getNativeElement().children[0]; + + self._scroll = function(ev) { + self._app.setScrolling(); + }; + + if (self._config.get('tapPolyfill') === true) { + self._zone.runOutsideAngular(function() { + self.scrollElement.addEventListener('scroll', self._scroll); + }); + } + } + + ngOnDestroy() { + this.scrollElement.removeEventListener('scroll', this._scroll); } /** @@ -287,28 +308,6 @@ export class Content extends Ion { this.scrollPadding = newScrollPadding; this.scrollElement.style.paddingBottom = newScrollPadding + 'px'; - - // if (!this.keyboardPromise) { - // console.debug('add scroll keyboard close callback', newScrollPadding); - // - // this.keyboardPromise = this.keyboard.onClose(() => { - // console.debug('scroll keyboard closed', newScrollPadding); - // - // if (this) { - // if (this.scrollPadding && this.scrollElement) { - // let close = new Animation(this.scrollElement); - // close - // .duration(250) - // .fromTo('paddingBottom', this.scrollPadding + 'px', '0px') - // .play(); - // } - // - // this.scrollPadding = 0; - // this.keyboardPromise = null; - // } - // }); - // - // } } } diff --git a/ionic/components/tap-click/tap-click.ts b/ionic/components/tap-click/tap-click.ts index 03155645fd..f5183ce0d0 100644 --- a/ionic/components/tap-click/tap-click.ts +++ b/ionic/components/tap-click/tap-click.ts @@ -58,20 +58,28 @@ export class TapClick { this.lastTouch = Date.now(); if (this.usePolyfill && this.startCoord && this.app.isEnabled()) { + // only dispatch mouse click events from a touchend event + // when tapPolyfill config is true, and the startCoordand endCoord + // are not too far off from each other let endCoord = pointerCoord(ev); - if (!hasPointerMoved(POINTER_TOLERANCE, this.startCoord, endCoord)) { - console.debug('create click from touch ' + Date.now()); - // prevent native mouse click events for XX amount of time this.disableClick = this.lastTouch + DISABLE_NATIVE_CLICK_AMOUNT; - // manually dispatch the mouse click event - let clickEvent = document.createEvent('MouseEvents'); - clickEvent.initMouseEvent('click', true, true, window, 1, 0, 0, endCoord.x, endCoord.y, false, false, false, false, 0, null); - clickEvent.isIonicTap = true; - ev.target.dispatchEvent(clickEvent); + if (this.app.isScrolling()) { + // do not fire off a click event while the app was scrolling + console.debug('click from touch prevented by scrolling ' + Date.now()); + + } else { + // dispatch a mouse click event + console.debug('create click from touch ' + Date.now()); + + let clickEvent = document.createEvent('MouseEvents'); + clickEvent.initMouseEvent('click', true, true, window, 1, 0, 0, endCoord.x, endCoord.y, false, false, false, false, 0, null); + clickEvent.isIonicTap = true; + ev.target.dispatchEvent(clickEvent); + } } }