/*global require, exports*/
/**
* @module montage/composer/press-composer
* @requires montage/core/core
* @requires montage/composer/composer
* @requires montage/core/event/mutable-event
*/
var Montage = require("../core/core").Montage,
Composer = require("./composer").Composer,
MutableEvent = require("../core/event/mutable-event").MutableEvent;
/*
* @class PressEvent
* @inherits MutableEvent
* @classdesc The event dispatched by the `PressComposer`, providing access to
* the raw DOM event and proxying its properties.
*/
var PressEvent = (function (){
function eventPropDescriptor(prop) {
return {
get: function () {
return this._event[prop];
}
};
}
function typePropDescriptor(prop) {
return {
get: function () {
return (this._touch) ? this._touch[prop] : this._event[prop];
}
};
}
var PressEvent = MutableEvent.specialize({
type: {
value: "press"
},
_event: {
enumerable: false,
value: null
},
event: {
get: function () {
return this._event;
},
set: function (value) {
this._event = value;
}
},
_touch: {
enumerable: false,
value: null
},
touch: {
get: function () {
return this._touch;
},
set: function (value) {
this._touch = value;
}
}
});
// These properties are available directly on the event
[
"altKey", "ctrlKey", "metaKey", "shiftKey",
"cancelBubble", "currentTarget", "defaultPrevented",
"eventPhase", "timeStamp", "preventDefault",
"stopImmediatePropagation", "stopPropagation"
].forEach(function (eventProp) {
Montage.defineProperty(PressEvent, eventProp, eventPropDescriptor(eventProp));
});
// These properties are available on the event in the case of mouse, and
// on the _touch in the case of touch
["clientX", "clientY", "pageX", "pageY", "screenX", "screenY", "target"].forEach(function (typeProp) {
Montage.defineProperty(PressEvent, typeProp, typePropDescriptor(typeProp));
});
return PressEvent;
}());
/**
* @class PressComposer
* @classdesc The `PressComposer` abstracts away handling mouse and touch
* events that represent presses, allowing generic detection of presses, long
* presses, and cancelled presses.
*
* @extends Composer
* @fires pressStart
* @fires press
* @fires longPress
* @fires pressCancel
*/
var PressComposer = exports.PressComposer = Composer.specialize(/** @lends PressComposer.prototype # */ {
/**
* Dispatched when a press begins. It is ended by either a {@link press} or
* {@link pressCancel} event.
*
* @event pressStart
* @memberof PressComposer
* @param {PressEvent} event
*/
/**
* Dispatched when a press is complete.
*
* @event press
* @memberof PressComposer
* @param {PressEvent} event
*/
/**
* Dispatched when a press lasts for longer than (@link longPressThreshold}
* On a long press, the sequence of events will be:
* - pressStart: as soon as the composer recognizes it is a press.
* - longPress: `longPressThreshold` after the pressStart, if the press has
* not yet ended.
* - press: when the press ends, if it isn't cancelled.
*
* Handlers of the `longPress` event can call `cancelPress` to prevent
* `press` being triggered.
*
* @event longPress
* @memberof PressComposer
* @param {PressEvent} event
*/
/**
* Dispatched when a press is canceled. This could be because the pointer
* left the element, was claimed by another component or maybe a phone call
* came in.
*
* @event pressCancel
* @memberof PressComposer
* @param {PressEvent} event
*/
// Load/unload
load: {
value: function () {
if (window.PointerEvent) {
this._element.addEventListener("pointerdown", this, true);
} else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
this._element.addEventListener("MSPointerDown", this, true);
} else {
this._element.addEventListener("touchstart", this, true);
this._element.addEventListener("mousedown", this, true);
}
}
},
unload: {
value: function () {
if (window.PointerEvent) {
this._element.removeEventListener("pointerdown", this, true);
} else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
this._element.removeEventListener("MSPointerDown", this, true);
} else {
this._element.removeEventListener("touchstart", this, true);
this._element.removeEventListener("mousedown", this, true);
}
}
},
/**
* Delegate that implements `surrenderPointer`. See Component for
* explanation of what this method should do.
*
* @type {Object}
* @default null
*/
delegate: {
value: null
},
/**
* Cancel the current press.
*
* Can be used in a "longPress" event handler to prevent the "press" event
* being fired.
* @returns boolean true if a press was canceled, false if the composer was
* already in a unpressed or canceled state.
*/
cancelPress: {
value: function () {
if (this._state === PressComposer.PRESSED) {
this._cancelPress();
return true;
}
return false;
}
},
_cancelPress: {
value: function (event) {
this._dispatchPressCancel(event);
this._endInteraction();
}
},
// Optimisation so that we don't set a timeout if we do not need to
addEventListener: {
value: function (type, listener, useCapture) {
Composer.prototype.addEventListener.call(this, type, listener, useCapture);
if (type === "longPress") {
this._shouldDispatchLongPress = true;
}
}
},
_state: {
value: 0
},
state: {
get: function () {
return this._state;
}
},
_shouldDispatchLongPress: {
value: false
},
_longPressThreshold: {
value: 1000
},
/**
* How long a press has to last (in milliseconds) for a longPress event to
* be dispatched
* @type number
*/
longPressThreshold: {
get: function () {
return this._longPressThreshold;
},
set: function (value) {
if (this._longPressThreshold !== value) {
this._longPressThreshold = value;
}
}
},
_needDispatchSafePress: {
value: false
},
_longPressTimeout: {
value: null
},
// Magic
_observedPointer: {
value: null
},
_initialCenterPositionX: {
value : 0
},
_initialCenterPositionY: {
value: 0
},
_shouldSaveInitialCenterPosition: {
value: false
},
_targetElementOnLastTouchMove: {
value: null
},
/**
* Remove event listeners after an interaction has finished.
* @private
*/
_endInteraction: {
value: function () {
if (this._element) {
this._removeEventListeners();
if (this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) {
this.component.eventManager.forfeitPointer(this._observedPointer, this);
}
this._observedPointer = null;
this._targetElementOnLastTouchMove = null;
this._state = PressComposer.UNPRESSED;
this._initialCenterPositionX = 0;
this._initialCenterPositionY = 0;
this._shouldSaveInitialCenterPosition = false;
}
}
},
/**
* Checks if we are observing one of the changed touches. Returns the index
* of the changed touch if one matches, otherwise returns false. Make sure
* to check against `!== false` or `=== false` as the
* matching index might be 0.
*
* @function
* @returns {number|boolean} The index of the matching touch, or false
* @private
*/
_changedTouchisObserved: {
value: function (changedTouches) {
if (this._observedPointer === null) {
return false;
}
var i = 0, changedTouchCount = changedTouches.length;
for (; i < changedTouchCount; i++) {
if (changedTouches[i].identifier === this._observedPointer) {
return i;
}
}
return false;
}
},
// Surrender pointer
surrenderPointer: {
value: function (pointer, component) {
var shouldSurrender = this.callDelegateMethod(
"shouldComposerSurrenderPointerToComponent",
this,
pointer,
component
);
if (typeof shouldSurrender !== "undefined" && shouldSurrender === false) {
return false;
}
this.cancelPress();
return true;
}
},
_shouldPerformPress: {
value: function () {
return !(this.component.disabled || this._observedPointer !== null);
}
},
// Handlers
capturePointerdown: {
value: function (event) {
if (event.pointerType === "touch" || (window.MSPointerEvent && event.pointerType === window.MSPointerEvent.MSPOINTER_TYPE_TOUCH)) {
this.captureTouchstart(event);
} else if (event.pointerType === "mouse" || (window.MSPointerEvent && event.pointerType === window.MSPointerEvent.MSPOINTER_TYPE_MOUSE)) {
this.captureMousedown(event);
}
}
},
handlePointerup: {
value: function (event) {
if (event.pointerType === "touch" || (window.MSPointerEvent && event.pointerType === window.MSPointerEvent.MSPOINTER_TYPE_TOUCH)) {
this.handleTouchend(event);
} else if (event.pointerType === "mouse" || (window.MSPointerEvent && event.pointerType === window.MSPointerEvent.MSPOINTER_TYPE_MOUSE)) {
this.handleMouseup(event);
}
}
},
handlePointercancel: {
value: function (event) {
if (event.pointerType === "touch" || (window.MSPointerEvent && event.pointerType === window.MSPointerEvent.MSPOINTER_TYPE_TOUCH)) {
this.handleTouchcancel(event);
}
}
},
captureTouchstart: {
value: function (event) {
if (this._shouldPerformPress()) {
if (event.pointerId !== void 0) { // -> pointer events support.
this._observedPointer = event.pointerId;
} else if (event.changedTouches && event.changedTouches.length === 1) {
this._observedPointer = event.changedTouches[0].identifier;
}
if (this._observedPointer !== null && this.component.eventManager.claimPointer(this._observedPointer, this)) {
this._addPointerDownListener();
} else {
this._observedPointer = null;
}
}
}
},
handleTouchend: {
value: function (event) {
if (this._observedPointer === null) {
this._endInteraction(event);
return;
}
var target;
if (event.pointerId === this._observedPointer) {
target = event.target;
} else if (this._changedTouchisObserved(event.changedTouches) !== false) {
// We need to keep the last element reached by a touchmove because we can't just rely on the position
// given by the touchEnd because in some cases, hiding the android keyboard for example, could result
// to change the press composer's element position between a touchStart and a touchEnd event. Therefore,
// getting the "wrong" target.
target = this._targetElementOnLastTouchMove || event.target;
}
if (target && this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) {
if (this.element === target || this.element.contains(target)) {
this._dispatchPress(event, typeof event.pointerId === "undefined" ? target : null);
} else {
this._dispatchPressCancel(event);
}
this._endInteraction(event);
}
}
},
// The PressComposer saves the initial center position after the first move or the first wheel event,
// in order to wait for a possible css transform (translate, scale...) appeared on its element
// after that the PressStart event has been raised.
_saveInitialCenterPositionIfNeeded: {
value: function () {
if (this._shouldSaveInitialCenterPosition) {
this._saveInitialCenterPosition();
this._shouldSaveInitialCenterPosition = false;
}
}
},
_cancelPressIfCenterPositionChange: {
value: function (event) {
this._saveInitialCenterPositionIfNeeded();
if (this._isPositionChanged(event)) {
this._cancelPress(event);
return true;
}
return false;
}
},
_handleMove: {
value: function (event) {
if (this._observedPointer === null) {
this._endInteraction(event);
return;
}
this._needDispatchSafePress = false;
if ((this._observedPointer === "mouse" || event.pointerId === this._observedPointer ||
(event.changedTouches && this._changedTouchisObserved(event.changedTouches) !== false)) &&
this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) {
if (!this._cancelPressIfCenterPositionChange(event) && event.type === "touchmove") {
var touch = event.changedTouches[0];
this._targetElementOnLastTouchMove = document.elementFromPoint(touch.clientX, touch.clientY);
}
}
}
},
captureWheel: {
value: function (event) {
if (this._observedPointer === null) {
this._endInteraction(event);
return;
}
if ((event.target === this.element || event.target === window ||
(typeof event.target.contains === "function" && event.target.contains(this.element)) || this.element.contains(event.target))) {
this._cancelPressIfCenterPositionChange(event);
}
}
},
handleTouchcancel: {
value: function (event) {
if (this._observedPointer === null || event.pointerId === this._observedPointer || this._changedTouchisObserved(event.changedTouches) !== false) {
if (this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) {
this._dispatchPressCancel(event);
}
this._endInteraction(event);
}
}
},
captureMousedown: {
value: function (event) {
if (event.button === 0 && this._shouldPerformPress()) {
this._observedPointer = "mouse";
this.component.eventManager.claimPointer(this._observedPointer, this);
if (this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) {
this._addPointerDownListener();
} else{
this._observedPointer = null;
}
}
}
},
/**
* Handle every kind of interactions (touch, mouse or pointer),
* in order to check if a press composer still claims the observed pointer in the bubbling phase.
* @private
*/
_handlePointerDown: {
value: function (event) {
this._removePointerDownListener();
if (this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) {
this._needDispatchSafePress = false;
if (event.type === "touchstart") {
var self = this;
window.nativeAddEventListener("touchstart", function _touchStartDefaultPrevented (touchStartEvent) {
window.nativeRemoveEventListener("touchstart", _touchStartDefaultPrevented, false);
self._needDispatchSafePress = !touchStartEvent.defaultPrevented;
}, false);
}
this._shouldSaveInitialCenterPosition = true;
this._addEventListeners();
this._dispatchPressStart(event);
} else {
this._observedPointer = null;
}
}
},
captureScroll: {
value: function (event) {
if (event.target === this.element || event.target === window ||
(typeof event.target.contains === "function" && event.target.contains(this.element)) ||
this.element.contains(event.target)) {
this._cancelPressIfCenterPositionChange(event);
}
}
},
handleMouseup: {
value: function (event) {
if (this._observedPointer === null) {
this._endInteraction(event);
return;
}
if (this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) {
var target = event.target;
while (target !== this._element && target && target.parentNode) {
target = target.parentNode;
}
if (target === this._element) {
this._dispatchPress(event);
this._endInteraction(event);
return;
}
}
this._cancelPress(event);
}
},
handleDragstart: {
value: function (event) {
this._cancelPress(event);
}
},
_saveInitialCenterPosition: {
value: function () {
// Makes sure we compute the position of a PressComposer’s element only on HTMLElement.
// Indeed a press composer can be used on other objects such as document, window…
if (this.element instanceof HTMLElement) {
var boundingClientRect = this.element.getBoundingClientRect();
this._initialCenterPositionX = boundingClientRect.left + (boundingClientRect.width / 2);
this._initialCenterPositionY = boundingClientRect.top + (boundingClientRect.height / 2);
}
}
},
_isPositionChanged: {
value: function (event) {
if (this.element instanceof HTMLElement) {
var boundingClientRect = this.element.getBoundingClientRect(),
newCenterPositionX = boundingClientRect.left + (boundingClientRect.width / 2),
newCenterPositionY = boundingClientRect.top + (boundingClientRect.height / 2);
if (this._initialCenterPositionX !== newCenterPositionX || this._initialCenterPositionY !== newCenterPositionY) {
var type = event.type,
deltaX = Math.abs(this._initialCenterPositionX - newCenterPositionX),
deltaY = Math.abs(this._initialCenterPositionY - newCenterPositionY),
radius = this._observedPointer === "mouse" || type === "wheel" || type === "mousewheel" || type === "scroll" ?
this._mouseRadiusThreshold : this._touchRadiusThreshold;
return Composer.isCoordinateOutsideRadius(deltaX, deltaY, radius);
}
}
return false;
}
},
_mouseRadiusThreshold: {
value: 2 //px
},
_touchRadiusThreshold: {
value: 4 //px
},
_addPointerDownListener: {
value: function () {
if (window.PointerEvent) {
this._element.addEventListener("pointerdown", this, false);
} else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
this._element.addEventListener("MSPointerDown", this, false);
} else {
if (this._observedPointer === "mouse") {
this._element.addEventListener("mousedown", this, false);
} else {
this._element.addEventListener("touchstart", this, false);
}
}
}
},
_removePointerDownListener: {
value: function () {
if (window.PointerEvent) {
this._element.removeEventListener("pointerdown", this, false);
} else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
this._element.removeEventListener("MSPointerDown", this, false);
} else {
if (this._observedPointer === "mouse") {
this._element.removeEventListener("mousedown", this, false);
} else {
this._element.removeEventListener("touchstart", this, false);
}
}
}
},
_addEventListeners: {
value: function () {
if (window.PointerEvent) {
if (this.shawdowRoot) {
this.shawdowRoot.addEventListener("pointerup", this, false);
this.shawdowRoot.addEventListener("pointermove", this, false);
this.shawdowRoot.addEventListener("pointercancel", this, false);
}
document.addEventListener("pointerup", this, false);
document.addEventListener("pointermove", this, false);
document.addEventListener("pointercancel", this, false);
} else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
if (this.shawdowRoot) {
this.shawdowRoot.addEventListener("MSPointerUp", this, false);
this.shawdowRoot.addEventListener("MSPointerMove", this, false);
this.shawdowRoot.addEventListener("MSPointerCancel", this, false);
}
document.addEventListener("MSPointerUp", this, false);
document.addEventListener("MSPointerMove", this, false);
document.addEventListener("MSPointerCancel", this, false);
} else {
if (this._observedPointer === "mouse") {
if (this.shawdowRoot) {
this.shawdowRoot.addEventListener("mouseup", this, false);
this.shawdowRoot.addEventListener("mousemove", this, false);
this.shawdowRoot.addEventListener("dragstart", this, false);
}
document.addEventListener("mouseup", this, false);
document.addEventListener("mousemove", this, false);
// Needed to cancel the press because once a drag is started
// no mouse events are fired
// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#initiate-the-drag-and-drop-operation
this._element.addEventListener("dragstart", this, false);
} else {
if (this.shawdowRoot) {
this.shawdowRoot.addEventListener("touchend", this, false);
this.shawdowRoot.addEventListener("touchcancel", this, false);
this.shawdowRoot.addEventListener("touchmove", this, false);
}
document.addEventListener("touchend", this, false);
document.addEventListener("touchcancel", this, false);
document.addEventListener("touchmove", this, false);
}
}
var wheelEventName = typeof window.onwheel !== "undefined" || typeof window.WheelEvent !== "undefined" ?
"wheel" : "mousewheel";
if (this.shawdowRoot) {
this.shawdowRoot.addEventListener(wheelEventName, this, true);
this.shawdowRoot.addEventListener("scroll", this, true);
}
document.addEventListener(wheelEventName, this, true);
document.addEventListener("scroll", this, true);
}
},
_removeEventListeners: {
value: function () {
if (window.PointerEvent) {
if (this.shawdowRoot) {
this.shawdowRoot.removeEventListener("pointerup", this, false);
this.shawdowRoot.removeEventListener("pointermove", this, false);
this.shawdowRoot.removeEventListener("pointercancel", this, false);
}
document.removeEventListener("pointerup", this, false);
document.removeEventListener("pointermove", this, false);
document.removeEventListener("pointercancel", this, false);
} else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
if (this.shawdowRoot) {
this.shawdowRoot.removeEventListener("MSPointerUp", this, false);
this.shawdowRoot.removeEventListener("MSPointerMove", this, false);
this.shawdowRoot.removeEventListener("MSPointerCancel", this, false);
}
document.removeEventListener("MSPointerUp", this, false);
document.removeEventListener("MSPointerMove", this, false);
document.removeEventListener("MSPointerCancel", this, false);
} else {
if (this._observedPointer === "mouse") {
if (this.shawdowRoot) {
this.shawdowRoot.removeEventListener("mouseup", this, false);
this.shawdowRoot.removeEventListener("mousemove", this, false);
this.shawdowRoot.removeEventListener("dragstart", this, false);
}
document.removeEventListener("mouseup", this, false);
document.removeEventListener("mousemove", this, false);
// Needed to cancel the press because once a drag is started
// no mouse events are fired
// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#initiate-the-drag-and-drop-operation
this._element.removeEventListener("dragstart", this, false);
} else {
if (this.shawdowRoot) {
this.shawdowRoot.removeEventListener("touchend", this, false);
this.shawdowRoot.removeEventListener("touchcancel", this, false);
this.shawdowRoot.removeEventListener("touchmove", this, false);
}
document.removeEventListener("touchend", this, false);
document.removeEventListener("touchcancel", this, false);
document.removeEventListener("touchmove", this, false);
}
}
var wheelEventName = typeof window.onwheel !== "undefined" || typeof window.WheelEvent !== "undefined" ?
"wheel" : "mousewheel";
if (this.shawdowRoot) {
this.shawdowRoot.removeEventListener(wheelEventName, this, true);
this.shawdowRoot.removeEventListener("scroll", this, true);
}
document.removeEventListener(wheelEventName, this, true);
document.removeEventListener("scroll", this, true);
}
},
// Event dispatch
_createPressEvent: {
enumerable: false,
value: function (name, event) {
var contactPoint = event,
pressEvent, index;
if (!event) {
event = document.createEvent("CustomEvent");
event.initCustomEvent(name, true, true, null);
}
pressEvent = new PressEvent();
pressEvent.event = event;
pressEvent.type = name;
pressEvent.pointer = this._observedPointer;
pressEvent.targetElement = event.target;
if (event.changedTouches && (index = this._changedTouchisObserved(event.changedTouches)) !== false) {
contactPoint = pressEvent.touch = event.changedTouches[index];
}
if (contactPoint) { // a PressCancel event can be dispatched programtically, so with no event.
pressEvent.clientX = contactPoint.clientX;
pressEvent.clientY = contactPoint.clientY;
pressEvent.pageX = contactPoint.pageX;
pressEvent.pageY = contactPoint.pageY;
}
return pressEvent;
}
},
_dispatchPressStart: {
enumerable: false,
value: function (event) {
this._state = PressComposer.PRESSED;
this.dispatchEvent(this._createPressEvent("pressStart", event));
if (this._shouldDispatchLongPress) {
var self = this;
this._longPressTimeout = setTimeout(function () {
self._dispatchLongPress(event.target);
}, this._longPressThreshold);
}
}
},
_dispatchPress: {
enumerable: false,
value: function (event, touchEndTargetElement) {
if (this._shouldDispatchLongPress) {
clearTimeout(this._longPressTimeout);
this._longPressTimeout = null;
}
var pressEvent = this._createPressEvent("press", event);
// The target of touchend events is actually the same element on which the touch point started.
// So, we override the property targetElement of the PressEvent with the element on which the touch point has been released.
if (touchEndTargetElement) {
pressEvent.targetElement = touchEndTargetElement;
if (this._needDispatchSafePress || event.defaultPrevented) {// no simulated events when a touchMove has been raised
var self = this,
eventManager = document.defaultView.defaultEventManager;
// Raise a Press event after the simulated mousedown event has been raised,
// in order to avoid elements that are not on the same layer to get the focus.
// @example: When a button is pressed in order to hide a overlay that it belong to.
// Knowing that, the simulated mouse events are not dispatched by the event manager, but they are still
// walking the dom. An issue could happen here when the positioning of elements is changing (z-index)
// after the press event has been raised, which could result to giving the focus to a wrong element.
// @example: @see press-composer.info
//@todo: should be deprecated when browsers will support PointerEvents.
var dispatchSafePressCallBack = function (mouseDownEvent) {
if (touchEndTargetElement === mouseDownEvent.target ||
eventManager._couldEmulatedEventHaveWrongTarget(
event.changedTouches[0],
mouseDownEvent,
eventManager._emulatedEventRadiusThreshold,
eventManager._emulatedEventTimestampThreshold
)
) {
self._dispatchSafePress(pressEvent, dispatchSafePressCallBack);
}
};
window.nativeAddEventListener("mousedown", dispatchSafePressCallBack, true);
// -> long press fallBack: no simulated events with long touch press.
dispatchSafePressCallBack.timeoutID = setTimeout(function () {
self._dispatchSafePress(pressEvent, dispatchSafePressCallBack);
}, 300);
return void 0;
}
}
this.dispatchEvent(pressEvent);
this._state = PressComposer.UNPRESSED;
}
},
_dispatchSafePress: {
value: function (pressEvent, dispatchSafePressCallBack) {
clearTimeout(dispatchSafePressCallBack.timeoutID);
dispatchSafePressCallBack.timeoutID = null;
window.nativeRemoveEventListener("mousedown", dispatchSafePressCallBack, true);
this.dispatchEvent(pressEvent);
this._state = PressComposer.UNPRESSED;
}
},
_dispatchLongPress: {
enumerable: false,
value: function (targetElement) {
var event, target;
if (this._shouldDispatchLongPress) {
event = this._createPressEvent("longPress");
event.targetElement = targetElement;
this.dispatchEvent(event);
this._longPressTimeout = null;
}
}
},
_dispatchPressCancel: {
enumerable: false,
value: function (event) {
if (this._shouldDispatchLongPress) {
clearTimeout(this._longPressTimeout);
this._longPressTimeout = null;
}
this._state = PressComposer.CANCELLED;
this.dispatchEvent(this._createPressEvent("pressCancel", event));
}
}
} , {
UNPRESSED: {
value: 0
},
PRESSED: {
value: 1
},
CANCELLED: {
value: 2
}
});
PressComposer.prototype.captureMSPointerDown = PressComposer.prototype.capturePointerdown;
PressComposer.prototype.handleMSPointerUp = PressComposer.prototype.handlePointerup;
PressComposer.prototype.handleMSPointerCancel = PressComposer.prototype.handlePointercancel;
PressComposer.prototype.handleMSPointerMove = PressComposer.prototype._handleMove;
PressComposer.prototype.handlePointermove = PressComposer.prototype._handleMove;
PressComposer.prototype.handleTouchmove = PressComposer.prototype._handleMove;
PressComposer.prototype.handleMousemove = PressComposer.prototype._handleMove;
PressComposer.prototype.handleMousewheel = PressComposer.prototype.handleWheel;
PressComposer.prototype.handleMSPointerDown = PressComposer.prototype._handlePointerDown;
PressComposer.prototype.handlePointerdown = PressComposer.prototype._handlePointerDown;
PressComposer.prototype.handleMousedown = PressComposer.prototype._handlePointerDown;
PressComposer.prototype.handleTouchstart = PressComposer.prototype._handlePointerDown;