Files
2015-11-12 10:45:32 -05:00

217 lines
4.8 KiB
TypeScript

import {pointerCoord, hasPointerMoved, transitionEnd} from '../../util/dom';
import {Activator} from './activator';
import {RippleActivator} from './ripple';
let startCoord = null;
let pointerTolerance = 4;
let lastTouch = 0;
let lastActivated = 0;
let disableNativeClickUntil = 0;
let disableNativeClickAmount = 3000;
let activator = null;
let isTapPolyfill = false;
let app = null;
let win = null;
let doc = null;
export function initTapClick(windowInstance, documentInstance, appInstance, config, fastdom) {
win = windowInstance;
doc = documentInstance;
app = appInstance;
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);
addListener('touchstart', touchStart);
addListener('touchend', touchEnd);
addListener('touchcancel', touchCancel);
addListener('mousedown', mouseDown, true);
addListener('mouseup', mouseUp, true);
}
function touchStart(ev) {
touchAction();
pointerStart(ev);
}
function touchEnd(ev) {
touchAction();
if (isTapPolyfill && startCoord && app.isEnabled()) {
let endCoord = pointerCoord(ev);
if (!hasPointerMoved(pointerTolerance, startCoord, endCoord)) {
console.debug('create click from touch');
disableNativeClickUntil = Date.now() + disableNativeClickAmount;
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);
}
}
pointerEnd(ev);
}
function touchCancel(ev) {
touchAction();
pointerCancel(ev);
}
function mouseDown(ev) {
if (isDisabledNativeClick()) {
console.debug('mouseDown prevent');
ev.preventDefault();
ev.stopPropagation();
} else if (lastTouch + disableNativeClickAmount < Date.now()) {
pointerStart(ev);
}
}
function mouseUp(ev) {
if (isDisabledNativeClick()) {
console.debug('mouseUp prevent');
ev.preventDefault();
ev.stopPropagation();
}
if (lastTouch + disableNativeClickAmount < Date.now()) {
pointerEnd(ev);
}
}
function pointerStart(ev) {
let activatableEle = getActivatableTarget(ev.target);
if (activatableEle) {
startCoord = pointerCoord(ev);
let now = Date.now();
if (lastActivated + 150 < now) {
activator && activator.downAction(ev, activatableEle, startCoord.x, startCoord.y);
lastActivated = now;
}
moveListeners(true);
} else {
startCoord = null;
}
}
function pointerEnd(ev) {
moveListeners(false);
activator && activator.upAction();
}
function pointerMove(ev) {
let moveCoord = pointerCoord(ev);
if ( hasPointerMoved(10, startCoord, moveCoord) ) {
pointerCancel(ev);
}
}
function pointerCancel(ev) {
console.debug('pointerCancel from', ev.type);
activator && activator.clearState();
moveListeners(false);
}
function moveListeners(shouldAdd) {
if (shouldAdd) {
if (isTapPolyfill) {
addListener('touchmove', pointerMove);
}
addListener('mousemove', pointerMove);
} else {
if (isTapPolyfill) {
removeListener('touchmove', pointerMove);
}
removeListener('mousemove', pointerMove);
}
}
function setDisableNativeClick() {
if (isTapPolyfill) {
disableNativeClickTime = Date.now() + disableNativeClickLimit;
}
}
function isDisabledNativeClick() {
return disableNativeClickUntil > Date.now();
}
function click(ev) {
let preventReason = null;
if (!app.isEnabled()) {
preventReason = 'appDisabled';
} else if (!ev.isIonicTap && isDisabledNativeClick()) {
preventReason = 'nativeClick';
}
if (preventReason !== null) {
console.debug('click prevent', preventReason);
ev.preventDefault();
ev.stopPropagation();
}
}
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;
}
export function isActivatable(ele) {
if (ACTIVATABLE_ELEMENTS.test(ele.tagName)) {
return true;
}
let attributes = ele.attributes;
for (let i = 0, l = attributes.length; i < l; i++) {
if (ACTIVATABLE_ATTRIBUTES.test(attributes[i].name)) {
return true;
}
}
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);
}
const ACTIVATABLE_ELEMENTS = /^(A|BUTTON)$/;
const ACTIVATABLE_ATTRIBUTES = /tappable/;