diff --git a/ionic/components/button/test/basic/main.html b/ionic/components/button/test/basic/main.html index 417d012e9e..28341090bb 100644 --- a/ionic/components/button/test/basic/main.html +++ b/ionic/components/button/test/basic/main.html @@ -6,7 +6,7 @@

- +

diff --git a/ionic/components/tap-click/activator.ts b/ionic/components/tap-click/activator.ts index 928199f796..6fa768de38 100644 --- a/ionic/components/tap-click/activator.ts +++ b/ionic/components/tap-click/activator.ts @@ -7,7 +7,7 @@ export class Activator { this.app = app; this.queue = []; this.active = []; - this.clearStateTimeout = 180; + this.clearStateTimeout = 80; this.clearAttempt = 0; this.activatedClass = config.get('activatedClass') || 'activated'; this.x = 0; diff --git a/ionic/components/tap-click/ripple.scss b/ionic/components/tap-click/ripple.scss index 06f9d84b35..2b6f7f33a4 100644 --- a/ionic/components/tap-click/ripple.scss +++ b/ionic/components/tap-click/ripple.scss @@ -7,7 +7,7 @@ $ripple-background-color: rgba(0, 0, 0, 0.1) !default; md-ripple { position: absolute; - z-index: -1; + z-index: 0; display: block; border-radius: 50%; @@ -18,7 +18,3 @@ md-ripple { transform: scale(0.001) translateZ(0); } - -.item > md-ripple { - z-index: 0; -} diff --git a/ionic/components/tap-click/tap-click.ts b/ionic/components/tap-click/tap-click.ts index 6aee1605f6..861f5a2c27 100644 --- a/ionic/components/tap-click/tap-click.ts +++ b/ionic/components/tap-click/tap-click.ts @@ -1,244 +1,202 @@ -import {Injectable} from 'angular2/angular2'; - -import {IonicApp} from '../app/app'; -import {Config} from '../../config/config'; import {pointerCoord, hasPointerMoved, transitionEnd} from '../../util/dom'; import {Activator} from './activator'; import {RippleActivator} from './ripple'; -@Injectable() -export class TapClick { - - constructor(app: IonicApp, config: Config) { - const self = this; - self.app = app; - - self.pointerTolerance = 4; - self.lastTouch = 0; - self.lastActivated = 0; - self.disableClick = 0; - self.disableClickLimit = 1000; - - if (config.get('mdRipple')) { - self.activator = new RippleActivator(app, config); - } else { - self.activator = new Activator(app, config); - } - - self.enable( config.get('tapPolyfill') !== false ); - - function bindDom(type, listener, useCapture) { - document.addEventListener(type, listener, useCapture); - } - - bindDom('click', function(ev) { - self.click(ev); - }, true); - - bindDom('touchstart', function(ev) { - self.lastTouch = Date.now(); - self.pointerStart(ev); - }); - - bindDom('touchend', function(ev) { - self.lastTouch = Date.now(); - self.touchEnd(ev); - }); - - bindDom('touchcancel', function(ev) { - self.lastTouch = Date.now(); - self.pointerCancel(ev); - }); - - bindDom('mousedown', function(ev) { - self.mouseDown(ev); - }, true); - - bindDom('mouseup', function(ev) { - self.mouseUp(ev); - }, true); +let startCoord = null; +let pointerTolerance = 4; +let lastTouch = 0; +let lastActivated = 0; +let disableNativeClickTime = 0; +let disableNativeClickLimit = 1000; +let activator = null; +let isEnabled = false; +let app = null; +let config = null; +let win = null; +let doc = null; - self.pointerMove = function(ev) { - let moveCoord = pointerCoord(ev); +export function initTapClick(windowInstance, documentInstance, appInstance, configInstance) { + win = windowInstance; + doc = documentInstance; + app = appInstance; + config = configInstance; - if ( hasPointerMoved(10, self.start, moveCoord) ) { - self.pointerCancel(ev); - } - }; + activator = (config.get('mdRipple') ? new RippleActivator(app, config) : new Activator(app, config)); + isEnabled = (config.get('tapPolyfill') !== false); + + addListener('click', click, true); + + addListener('touchstart', touchStart); + addListener('touchend', touchEnd); + addListener('touchcancel', touchCancel); + + addListener('mousedown', mouseDown, true); + addListener('mouseup', mouseUp, true); +} - self.moveListeners = function(shouldAdd) { - document.removeEventListener('touchmove', self.pointerMove); - document.removeEventListener('mousemove', self.pointerMove); +function touchStart(ev) { + touchAction(); + pointerStart(ev); +} - if (shouldAdd) { - bindDom('touchmove', self.pointerMove); - bindDom('mousemove', self.pointerMove); - } - }; +function touchEnd(ev) { + touchAction(); - } + if (isEnabled && startCoord && app.isEnabled()) { + let endCoord = pointerCoord(ev); - enable(shouldEnable) { - this._enabled = shouldEnable; - } + if (!hasPointerMoved(pointerTolerance, startCoord, endCoord)) { + console.debug('create click from touch'); + setDisableNativeClick();; - /** - * TODO - * @param {TODO} ev TODO - */ - touchEnd(ev) { - let self = this; - - if (self._enabled && self.start && self.app.isEnabled()) { - let endCoord = pointerCoord(ev); - - if (!hasPointerMoved(self.pointerTolerance, self.start, endCoord)) { - console.debug('create click'); - - self.disableClick = 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); - } - } - - self.pointerEnd(ev); - } - - /** - * TODO - * @param {TODO} ev TODO - */ - mouseDown(ev) { - if (this.isDisabledClick()) { - console.debug('mouseDown prevent'); - ev.preventDefault(); - ev.stopPropagation(); - - } else if (this.lastTouch + 999 < Date.now()) { - this.pointerStart(ev); + let clickEvent = doc.createEvent('MouseEvents'); + clickEvent.initMouseEvent('click', true, true, win, 1, 0, 0, endCoord.x, endCoord.y, false, false, false, false, 0, null); + clickEvent.isIonicTap = true; + ev.target.dispatchEvent(clickEvent); } } - /** - * TODO - * @param {TODO} ev TODO - */ - mouseUp(ev) { - if (this.isDisabledClick()) { - console.debug('mouseUp prevent'); - ev.preventDefault(); - ev.stopPropagation(); - } + pointerEnd(ev); +} - if (this.lastTouch + 999 < Date.now()) { - this.pointerEnd(ev); - } +function touchCancel(ev) { + touchAction(); + pointerCancel(ev); +} + +function mouseDown(ev) { + if (isDisabledNativeClick()) { + console.debug('mouseDown prevent'); + ev.preventDefault(); + ev.stopPropagation(); + + } else if (lastTouch + disableNativeClickLimit < Date.now()) { + pointerStart(ev); + } +} + +function mouseUp(ev) { + if (isDisabledNativeClick()) { + console.debug('mouseUp prevent'); + ev.preventDefault(); + ev.stopPropagation(); } - /** - * TODO - * @param {TODO} ev TODO - */ - pointerStart(ev) { - let activatableEle = this.getActivatableTarget(ev.target); + if (lastTouch + disableNativeClickLimit < Date.now()) { + pointerEnd(ev); + } +} - if (activatableEle) { - this.start = pointerCoord(ev); +function pointerStart(ev) { + let activatableEle = getActivatableTarget(ev.target); - let now = Date.now(); - if (this.lastActivated + 100 < now) { - this.activator.downAction(ev, activatableEle, this.start.x, this.start.y); - this.lastActivated = now; - } + if (activatableEle) { + startCoord = pointerCoord(ev); - this.moveListeners(true); - - } else { - this.start = null; + let now = Date.now(); + if (lastActivated + 100 < now) { + activator.downAction(ev, activatableEle, startCoord.x, startCoord.y); + lastActivated = now; } + + moveListeners(true); + + } else { + startCoord = null; + } +} + +function pointerEnd(ev) { + activator.upAction(); + moveListeners(false); +} + +function pointerMove(ev) { + let moveCoord = pointerCoord(ev); + + if ( hasPointerMoved(10, startCoord, moveCoord) ) { + pointerCancel(ev); + } +} + +function pointerCancel(ev) { + console.debug('pointerCancel from', ev.type); + activator.clearState(); + moveListeners(false); + setDisableNativeClick(); +} + +function moveListeners(shouldAdd) { + removeListener('touchmove', pointerMove); + removeListener('mousemove', pointerMove); + if (shouldAdd) { + addListener('touchmove', pointerMove); + addListener('mousemove', pointerMove); + } +} + +function setDisableNativeClick() { + disableNativeClickTime = Date.now() + disableNativeClickLimit; +} + +function isDisabledNativeClick() { + return disableNativeClickTime > Date.now(); +} + +function click(ev) { + let preventReason = null; + + if (!app.isEnabled()) { + preventReason = 'appDisabled'; + + } else if (!ev.isIonicTap && isDisabledNativeClick()) { + preventReason = 'nativeClick'; } - /** - * TODO - */ - pointerEnd(ev) { - this.activator.upAction(); - this.moveListeners(false); + if (preventReason !== null) { + console.debug('click prevent', preventReason); + ev.preventDefault(); + ev.stopPropagation(); } +} - /** - * TODO - */ - pointerCancel(ev) { - console.debug('pointerCancel') - this.activator.clearState(); - this.moveListeners(false); - this.disableClick = Date.now(); +function getActivatableTarget(ele) { + let targetEle = ele; + for (let x = 0; x < 4; x++) { + if (!targetEle) break; + if (isActivatable(targetEle)) return targetEle; + targetEle = targetEle.parentElement; } + return null; +} - isDisabledClick() { - return this.disableClick + this.disableClickLimit > Date.now(); - } - - /** - * Whether the supplied click event should be allowed or not. - * @param {MouseEvent} ev The click event. - * @return {boolean} True if click event should be allowed, otherwise false. - */ - allowClick(ev) { - if (!this.app.isEnabled()) { - return false; - } - if (!ev.isIonicTap) { - if (this.isDisabledClick()) { - return false; - } - } +function isActivatable(ele) { + if (/^(A|BUTTON)$/.test(ele.tagName)) { return true; } - /** - * TODO - * @param {MouseEvent} ev TODO - */ - click(ev) { - if (!this.allowClick(ev)) { - console.debug('click prevent'); - ev.preventDefault(); - ev.stopPropagation(); - } - } - - getActivatableTarget(ele) { - let targetEle = ele; - for (let x = 0; x < 4; x++) { - if (!targetEle) break; - if (this.isActivatable(targetEle)) return targetEle; - targetEle = targetEle.parentElement; - } - return null; - } - - isActivatable(ele) { - if (/^(A|BUTTON)$/.test(ele.tagName)) { + let attributes = ele.attributes; + for (let i = 0, l = attributes.length; i < l; i++) { + if (/click|tappable/.test(attributes[i].name)) { return true; } - - let attributes = ele.attributes; - for (let i = 0, l = attributes.length; i < l; i++) { - if (/click|tappable/.test(attributes[i].name)) { - return true; - } - } - - return false; } + return false; +} + +function touchAction() { + lastTouch = Date.now(); +} + +function addListener(type, listener, useCapture) { + doc.addEventListener(type, listener, useCapture); +} + +function removeListener(type, listener) { + doc.removeEventListener(type, listener); } diff --git a/ionic/config/bootstrap.ts b/ionic/config/bootstrap.ts index 9619151f7a..601dd07dc5 100644 --- a/ionic/config/bootstrap.ts +++ b/ionic/config/bootstrap.ts @@ -16,7 +16,7 @@ import {NavRegistry} from '../components/nav/nav-registry'; import {Translate} from '../translation/translate'; import {ClickBlock} from '../util/click-block'; import {FeatureDetect} from '../util/feature-detect'; -import {TapClick} from '../components/tap-click/tap-click'; +import {initTapClick} from '../components/tap-click/tap-click'; import * as dom from '../util/dom'; @@ -35,7 +35,7 @@ export function ionicProviders(config) { config.setPlatform(platform); let events = new Events(); - let tapClick = new TapClick(app, config, window, document); + initTapClick(window, document, app, config); let featureDetect = new FeatureDetect(); setupDom(window, document, config, platform, featureDetect); @@ -48,7 +48,6 @@ export function ionicProviders(config) { provide(IonicApp, {useValue: app}), provide(Config, {useValue: config}), provide(Platform, {useValue: platform}), - provide(TapClick, {useValue: tapClick}), provide(FeatureDetect, {useValue: featureDetect}), provide(Events, {useValue: events}), Form,