From 7e4db7460d45f6428fa864a90eb2c34c8138dfe4 Mon Sep 17 00:00:00 2001 From: deepsweet Date: Fri, 27 Sep 2013 20:57:14 +0300 Subject: [PATCH] pointer-events: new polyfill --- .../jquery__event_type_pointerevents.deps.js | 3 + .../_type/jquery__event_type_pointerevents.js | 467 ++++++++++++++++ ...ery__event_type_pointerevents.ru.title.txt | 1 + .../pointer-events/pointer-events.js | 513 ------------------ .../jquery__event_type_pointerevents.deps.js} | 2 +- .../jquery__event_type_pointerevents.test.js | 20 + 6 files changed, 492 insertions(+), 514 deletions(-) create mode 100644 common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.deps.js create mode 100644 common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.js create mode 100644 common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.ru.title.txt delete mode 100644 common.blocks/pointer-events/pointer-events.js rename desktop.blocks/{pointer-events/pointer-events.deps.js => jquery/__event/_type/jquery__event_type_pointerevents.deps.js} (96%) create mode 100644 desktop.blocks/jquery/__event/_type/jquery__event_type_pointerevents.test.js diff --git a/common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.deps.js b/common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.deps.js new file mode 100644 index 000000000..ef7539d72 --- /dev/null +++ b/common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.deps.js @@ -0,0 +1,3 @@ +({ + shouldDeps : 'jquery' +}) diff --git a/common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.js b/common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.js new file mode 100644 index 000000000..9d320e83d --- /dev/null +++ b/common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.js @@ -0,0 +1,467 @@ +/** + * PointerEvents polyfill. + * @see https://dvcs.w3.org/hg/pointerevents/raw-file/tip/pointerEvents.html + * @see http://www.benalman.com/news/2010/03/jquery-special-events/ + * + * @modules pointerevents + * + * @author Kir Belevich + * @copyright Kir Belevich 2013 + * @license MIT + * @version 0.1.0 + */ +modules.define('jquery', function(provide, $) { + + // nothing to do + if(window.navigator.pointerEnabled) { return; } + + var pointerEvents = { + + // current events type and aliases + current : (function() { + + // touch + if('ontouchstart' in window) { + return { + type : 'touch', + enter : 'touchstart', + over : 'touchstart', + down : 'touchstart', + move : 'touchmove', + up : 'touchend', + out : 'touchend', + leave : 'touchend', + cancel : 'touchcancel' + }; + } + + // msPointer + if(window.navigator.msPointerEnabled) { + return { + type : 'mspointer', + enter : 'mouseenter', // :( + over : 'MSPointerOver', + down : 'MSPointerDown', + move : 'MSPointerMove', + up : 'MSPointerUp', + out : 'MSPointerOut', + leave : 'mouseleave', // :( + cancel : 'MSPointerCancel' + }; + } + + // mouse + return { + type : 'mouse', + enter : document.onmouseenter? 'mouseenter' : 'mouseover', + over : 'mouseover', + down : 'mousedown', + move : 'mousemove', + up : 'mouseup', + out : 'mouseout', + leave : document.onmouseleave? 'mouseleave': 'mouseout' + }; + + })(), + + // previous down event info + previousDown : {}, + + /** + * Extend an event to match PointerEvent. + * @see https://dvcs.w3.org/hg/pointerevents/raw-file/tip/pointerEvents.html#pointer-events-and-interfaces + * @see https://dvcs.w3.org/hg/webevents/raw-file/default/touchevents.html + * + * @param [Object] e original event + * @return [Object] extented event + */ + extendToPointer : function(e) { + + e.width = e.width || + e.webkitRadiusX || + e.radiusX || + 0; + + e.height = e.width || + e.webkitRadiusY || + e.radiusY || + 0; + + // TODO: stupid Android somehow could send "force" > 1 ;( + e.pressure = e.pressure || + e.mozPressure || + e.webkitForce || + e.force || + e.which && 0.5 || + 0; + + e.tiltX = e.tiltX || 0; + + e.tiltY = e.tiltY || 0; + + e.pointerType = e.pointerType || pointerEvents.current.type; + + e.isPrimary = pointerEvents.previousDown[e.identifier]? + pointerEvents.previousDown[e.identifier].isPrimary : + e.pointerType === 'mouse'? true : false; + + // "1" is always for mouse, need to +2 for touch which can start from "0" + e.pointerId = e.identifier? e.identifier + 2 : 1; + + return e; + + }, + + /** + * Dispatch PointerEvent. + * + * @param {Object} ctx target context + * @param {Object} e original event + * @param {Object} touchPoint current touch point event + */ + dispatch : function(ctx, e, touchPoint) { + + // try to keep all the possible jQ's normalized event properties + touchPoint = touchPoint || e; + + // http://api.jquery.com/category/events/event-object/ + e.clientX = touchPoint.clientX; + e.clientY = touchPoint.clientY; + e.pageX = touchPoint.pageX; + e.pageY = touchPoint.pageY; + e.screenX = touchPoint.screenX; + e.screenY = touchPoint.screenY; + e.target = touchPoint.target; + e.currentTarget = touchPoint.currentTarget; + e.originalTarget = touchPoint.originalTarget; + e.relatedTarget = touchPoint.relatedTarget; + + // extend an event to match PointerEvent + e = pointerEvents.extendToPointer(e); + + ($.event.handle || $.event.dispatch).call(ctx, e); + + }, + + /** + * "onPointerEvent" helping wrapper. + * + * @param {Object} e original event + * @param {Function} callback + */ + onEvent : function(e, callback) { + + // [multi-]touch + if(pointerEvents.current.type === 'touch') { + + for(var i = 0; i < e.originalEvent.changedTouches.length; i++) { + callback(e.originalEvent.changedTouches[i]); + } + + // single mouse/mspointer event + } else { + pointerEvents.dispatch(this, e); + } + + }, + + /** + * "onPointerEnter" handler. + * + * @param {Object} e original event + */ + onEnter : function(e) { + + e.type = 'pointerenter'; + + pointerEvents.onEvent.call(this, e, function(touchPoint) { + pointerEvents.dispatch(touchPoint.target, e, touchPoint); + }); + + }, + + /** + * "onPointerOver" handler. + * + * @param {Object} e original event + */ + onOver : function(e) { + + e.type = 'pointerover'; + + pointerEvents.onEvent.call(this, e, function(touchPoint) { + pointerEvents.dispatch(touchPoint.target, e, touchPoint); + }); + + }, + + /** + * "onPointerDown" handler. + * + * @param {Object} e original event + */ + onDown : function(e) { + + e.type = 'pointerdown'; + + pointerEvents.onEvent.call(this, e, function(touchPoint) { + + // https://dvcs.w3.org/hg/pointerevents/raw-file/tip/pointerEvents.html#the-primary-pointer + if(e.originalEvent.length === 1) { + touchPoint.isPrimary = true; + } + + // store current target and isPrimary for the future events + pointerEvents.previousDown[touchPoint.identifier] = { + target : touchPoint.target, + isPrimary : touchPoint.isPrimary + }; + + pointerEvents.dispatch(touchPoint.target, e, touchPoint); + + }); + + }, + + /** + * "onPointerMove" handler. + * + * @param {Object} e original event + */ + onMove : function(e) { + + e.type = 'pointermove'; + + pointerEvents.onEvent.call(this, e, function(touchPoint) { + + var newTarget = document.elementFromPoint(touchPoint.clientX, touchPoint.clientY), + currentTarget = pointerEvents.previousDown[touchPoint.identifier].target; + + pointerEvents.dispatch(currentTarget, e, touchPoint); + + if(currentTarget !== newTarget) { + + // out current target + e.type = 'pointerout'; + pointerEvents.dispatch(currentTarget, e, touchPoint); + + // new target is not a child of the current -> leave current target + if(!currentTarget.contains(newTarget)) { + e.type = 'pointerleave'; + pointerEvents.dispatch(currentTarget, e, touchPoint); + } + + // new target is not the parent of the current -> leave new target + if(!newTarget.contains(currentTarget)) { + e.type = 'pointerenter'; + pointerEvents.dispatch(newTarget, e, touchPoint); + } + + // over new target + e.type = 'pointerover'; + pointerEvents.dispatch(newTarget, e, touchPoint); + + // new target -> current target + pointerEvents.previousDown[touchPoint.identifier].target = newTarget; + + } + + }); + + }, + + /** + * "onPointerUp" handler. + * + * @param {Object} e original event + */ + onUp : function(e) { + + e.type = 'pointerup'; + + pointerEvents.onEvent.call(this, e, function(touchPoint) { + + var currentTarget = pointerEvents.previousDown[touchPoint.identifier].target; + pointerEvents.dispatch(currentTarget, e, touchPoint); + + }); + + }, + + /** + * "onPointerOut" handler. + * + * @param {Object} e original event + */ + onOut : function(e) { + + e.type = 'pointerout'; + + pointerEvents.onEvent.call(this, e, function(touchPoint) { + + var currentTarget = pointerEvents.previousDown[touchPoint.identifier].target; + pointerEvents.dispatch(currentTarget, e, touchPoint); + + }); + + }, + + /** + * "onPointerLeave" handler. + * + * @param {Object} e original event + */ + onLeave : function(e) { + + e.type = 'pointerleave'; + + pointerEvents.onEvent.call(this, e, function(touchPoint) { + + var currentTarget = pointerEvents.previousDown[touchPoint.identifier].target; + pointerEvents.dispatch(currentTarget, e, touchPoint); + + }); + + }, + + /** + * "onPointerCancel" handler. + * + * @param {Object} e original event + */ + onCancel : function(e) { + + e.type = 'pointercancel'; + + pointerEvents.onEvent.call(this, e, function(touchPoint) { + + var currentTarget = pointerEvents.previousDown[touchPoint.identifier].target; + pointerEvents.dispatch(currentTarget, e, touchPoint); + + }); + + } + + }; + + // pointerenter + $.event.special.pointerenter = { + + setup : function() { + if(pointerEvents.current.enter === 'mouseover') { + // http://api.jquery.com/mouseenter/ + $(this).mouseenter(pointerEvents.onEnter); + } else { + $(this).on(pointerEvents.current.enter + '.pointerEvents', pointerEvents.onEnter); + } + }, + + teardown : function() { + $(this).off(pointerEvents.current.enter + '.pointerEvents'); + } + + }; + + // pointerover + $.event.special.pointerover = { + + setup : function() { + $(this).on(pointerEvents.current.over + '.pointerEvents', pointerEvents.onOver); + }, + + teardown : function() { + $(this).off(pointerEvents.current.over + '.pointerEvents'); + } + + }; + + // pointerdown + $.event.special.pointerdown = { + + setup : function() { + $(this).on(pointerEvents.current.down + '.pointerEvents', pointerEvents.onDown); + }, + + teardown : function() { + $(this).off(pointerEvents.current.down + '.pointerEvents'); + } + + }; + + // pointermove + $.event.special.pointermove = { + + setup : function() { + $(this).on(pointerEvents.current.move + '.pointerEvents', pointerEvents.onMove); + }, + + teardown : function() { + $(this).off(pointerEvents.current.move + '.pointerEvents'); + } + + }; + + // pointerup + $.event.special.pointerup = { + + setup : function() { + $(this).on(pointerEvents.current.up + '.pointerEvents', pointerEvents.onUp); + }, + + teardown : function() { + $(this).off(pointerEvents.current.up + '.pointerEvents'); + } + + }; + + // pointerout + $.event.special.pointerout = { + + setup : function() { + $(this).on(pointerEvents.current.out + '.pointerEvents', pointerEvents.onOut); + }, + + teardown : function() { + $(this).off(pointerEvents.current.out + '.pointerEvents'); + } + + }; + + // pointerleave + $.event.special.pointerleave = { + + setup : function() { + if(pointerEvents.current.leave === 'mouseout') { + // http://api.jquery.com/mouseleave/ + $(this).mouseleave(pointerEvents.onLeave); + } else { + $(this).on(pointerEvents.current.leave + '.pointerEvents', pointerEvents.onLeave); + } + }, + + teardown : function() { + $(this).off(pointerEvents.current.leave + '.pointerEvents'); + } + + }; + + // pointercancel + if(pointerEvents.current.cancel) { + + $.event.special.pointercancel = { + + setup : function() { + $(this).on(pointerEvents.current.cancel + '.pointerEvents', pointerEvents.onCancel); + }, + + teardown : function() { + $(this).off(pointerEvents.current.cancel + '.pointerEvents'); + } + + }; + + } + + provide($); + +}); diff --git a/common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.ru.title.txt b/common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.ru.title.txt new file mode 100644 index 000000000..236079e62 --- /dev/null +++ b/common.blocks/jquery/__event/_type/jquery__event_type_pointerevents.ru.title.txt @@ -0,0 +1 @@ +Плагин, реализующий PointerEvents diff --git a/common.blocks/pointer-events/pointer-events.js b/common.blocks/pointer-events/pointer-events.js deleted file mode 100644 index 355850fbe..000000000 --- a/common.blocks/pointer-events/pointer-events.js +++ /dev/null @@ -1,513 +0,0 @@ -// https://handjs.codeplex.com/ - -(function () { - // Installing Hand.js - var supportedEventsNames = ["PointerDown", "PointerUp", "PointerMove", "PointerOver", "PointerOut", "PointerCancel", "PointerEnter", "PointerLeave", - "pointerdown", "pointerup", "pointermove", "pointerover", "pointerout", "pointercancel", "pointerenter", "pointerleave" - ]; - - var POINTER_TYPE_TOUCH = "touch"; - var POINTER_TYPE_PEN = "pen"; - var POINTER_TYPE_MOUSE = "mouse"; - - var previousTargets = {}; - - // Touch events - var generateTouchClonedEvent = function (sourceEvent, newName) { - // Considering touch events are almost like super mouse events - var evObj; - - if (document.createEvent) { - evObj = document.createEvent('MouseEvents'); - evObj.initMouseEvent(newName, true, true, window, 1, sourceEvent.screenX, sourceEvent.screenY, - sourceEvent.clientX, sourceEvent.clientY, sourceEvent.ctrlKey, sourceEvent.altKey, - sourceEvent.shiftKey, sourceEvent.metaKey, sourceEvent.button, null); - } - else { - evObj = document.createEventObject(); - evObj.screenX = sourceEvent.screenX; - evObj.screenY = sourceEvent.screenY; - evObj.clientX = sourceEvent.clientX; - evObj.clientY = sourceEvent.clientY; - evObj.ctrlKey = sourceEvent.ctrlKey; - evObj.altKey = sourceEvent.altKey; - evObj.shiftKey = sourceEvent.shiftKey; - evObj.metaKey = sourceEvent.metaKey; - evObj.button = sourceEvent.button; - } - // offsets - if (evObj.offsetX === undefined) { - if (sourceEvent.offsetX !== undefined) { - - // For Opera which creates readonly properties - if (Object && Object.defineProperty !== undefined) { - Object.defineProperty(evObj, "offsetX", { - writable: true - }); - Object.defineProperty(evObj, "offsetY", { - writable: true - }); - } - - evObj.offsetX = sourceEvent.offsetX; - evObj.offsetY = sourceEvent.offsetY; - } - else if (sourceEvent.layerX !== undefined) { - evObj.offsetX = sourceEvent.layerX - sourceEvent.currentTarget.offsetLeft; - evObj.offsetY = sourceEvent.layerY - sourceEvent.currentTarget.offsetTop; - } - } - - // adding missing properties - - if (sourceEvent.isPrimary !== undefined) - evObj.isPrimary = sourceEvent.isPrimary; - else - evObj.isPrimary = true; - - if (sourceEvent.pressure) - evObj.pressure = sourceEvent.pressure; - else { - var button = 0; - - if (sourceEvent.which !== undefined) - button = sourceEvent.which; - else if (sourceEvent.button !== undefined) { - button = sourceEvent.button; - } - evObj.pressure = (button == 0) ? 0 : 0.5; - } - - - if (sourceEvent.rotation) - evObj.rotation = sourceEvent.rotation; - else - evObj.rotation = 0; - - // Timestamp - if (sourceEvent.hwTimestamp) - evObj.hwTimestamp = sourceEvent.hwTimestamp; - else - evObj.hwTimestamp = 0; - - // Tilts - if (sourceEvent.tiltX) - evObj.tiltX = sourceEvent.tiltX; - else - evObj.tiltX = 0; - - if (sourceEvent.tiltY) - evObj.tiltY = sourceEvent.tiltY; - else - evObj.tiltY = 0; - - // Width and Height - if (sourceEvent.height) - evObj.height = sourceEvent.height; - else - evObj.height = 0; - - if (sourceEvent.width) - evObj.width = sourceEvent.width; - else - evObj.width = 0; - - // preventDefault - evObj.preventDefault = function () { - if (sourceEvent.preventDefault !== undefined) - sourceEvent.preventDefault(); - }; - - // stopPropagation - if (evObj.stopPropagation !== undefined) { - var current = evObj.stopPropagation; - evObj.stopPropagation = function () { - if (sourceEvent.stopPropagation !== undefined) - sourceEvent.stopPropagation(); - current.call(this); - }; - } - - // Constants - evObj.POINTER_TYPE_TOUCH = POINTER_TYPE_TOUCH; - evObj.POINTER_TYPE_PEN = POINTER_TYPE_PEN; - evObj.POINTER_TYPE_MOUSE = POINTER_TYPE_MOUSE; - - // Pointer values - evObj.pointerId = sourceEvent.pointerId; - evObj.pointerType = sourceEvent.pointerType; - - switch (evObj.pointerType) {// Old spec version check - case 2: - evObj.pointerType = evObj.POINTER_TYPE_TOUCH; - break; - case 3: - evObj.pointerType = evObj.POINTER_TYPE_PEN; - break; - case 4: - evObj.pointerType = evObj.POINTER_TYPE_MOUSE; - break; - } - - // If force preventDefault - if (sourceEvent.currentTarget && sourceEvent.currentTarget.handjs_forcePreventDefault === true) - evObj.preventDefault(); - - // Fire event - if (sourceEvent.target) { - sourceEvent.target.dispatchEvent(evObj); - } else { - sourceEvent.srcElement.fireEvent("on" + getMouseEquivalentEventName(newName), evObj); // We must fallback to mouse event for very old browsers - } - }; - - var generateMouseProxy = function (evt, eventName) { - if (!evt.button) { - evt.pointerId = 1; - evt.pointerType = POINTER_TYPE_MOUSE; - generateTouchClonedEvent(evt, eventName); - } - }; - - var generateTouchEventProxy = function (name, touchPoint, target, eventObject) { - var touchPointId = touchPoint.identifier + 2; // Just to not override mouse id - - touchPoint.pointerId = touchPointId; - touchPoint.pointerType = POINTER_TYPE_TOUCH; - touchPoint.currentTarget = target; - touchPoint.target = target; - - if (eventObject.preventDefault !== undefined) { - touchPoint.preventDefault = function () { - eventObject.preventDefault(); - }; - } - - generateTouchClonedEvent(touchPoint, name); - }; - - var generateTouchEventProxyIfRegistered = function (eventName, touchPoint, target, eventObject) { // Check if user registered this event - if (target.__handjsGlobalRegisteredEvents && target.__handjsGlobalRegisteredEvents[eventName]) { - generateTouchEventProxy(eventName, touchPoint, target, eventObject); - } - }; - - var handleOtherEvent = function (eventObject, name, useLocalTarget, checkRegistration) { - if (eventObject.preventManipulation) - eventObject.preventManipulation(); - - for (var i = 0; i < eventObject.changedTouches.length; ++i) { - var touchPoint = eventObject.changedTouches[i]; - - if (useLocalTarget) { - previousTargets[touchPoint.identifier] = touchPoint.target; - } - - if (checkRegistration) { - generateTouchEventProxyIfRegistered(name, touchPoint, previousTargets[touchPoint.identifier], eventObject); - } else { - generateTouchEventProxy(name, touchPoint, previousTargets[touchPoint.identifier], eventObject); - } - } - }; - - var getMouseEquivalentEventName = function (eventName) { - return eventName.toLowerCase().replace("pointer", "mouse"); - }; - - var getPrefixEventName = function (item, prefix, eventName) { - var newEventName; - - if (eventName == eventName.toLowerCase()) { - var indexOfUpperCase = supportedEventsNames.indexOf(eventName) - (supportedEventsNames.length / 2); - newEventName = prefix + supportedEventsNames[indexOfUpperCase]; - } - else { - newEventName = prefix + eventName; - } - - // Fallback to PointerOver if PointerEnter is not currently supported - if (newEventName === prefix + "PointerEnter" && item["on" + prefix.toLowerCase() + "pointerenter"] === undefined) { - newEventName = prefix + "PointerOver"; - } - - // Fallback to PointerOut if PointerLeave is not currently supported - if (newEventName === prefix + "PointerLeave" && item["on" + prefix.toLowerCase() + "pointerleave"] === undefined) { - newEventName = prefix + "PointerOut"; - } - - return newEventName; - }; - - var registerOrUnregisterEvent = function (item, name, func, enable) { - if (item.__handjsRegisteredEvents === undefined) { - item.__handjsRegisteredEvents = []; - } - - if (enable) { - if (item.__handjsRegisteredEvents[name] !== undefined) { - item.__handjsRegisteredEvents[name]++; - return; - } - - item.__handjsRegisteredEvents[name] = 1; - item.addEventListener(name, func, false); - } else { - - if (item.__handjsRegisteredEvents.indexOf(name) !== -1) { - item.__handjsRegisteredEvents[name]--; - - if (item.__handjsRegisteredEvents[name] != 0) { - return; - } - } - item.removeEventListener(name, func); - item.__handjsRegisteredEvents[name] = 0; - } - }; - - var setTouchAware = function (item, eventName, enable) { - // If item is already touch aware, do nothing - if (item.onpointerdown !== undefined) { - return; - } - - // IE 10 - if (item.onmspointerdown !== undefined) { - var msEventName = getPrefixEventName(item, "MS", eventName); - - registerOrUnregisterEvent(item, msEventName, function (evt) { generateTouchClonedEvent(evt, eventName); }, enable); - - // We can return because MSPointerXXX integrate mouse support - return; - } - - // Chrome, Firefox - if (item.ontouchstart !== undefined) { - switch (eventName) { - case "pointermove": - registerOrUnregisterEvent(item, "touchmove", function (evt) { handleOtherEvent(evt, eventName); }, enable); - break; - case "pointercancel": - registerOrUnregisterEvent(item, "touchcancel", function (evt) { handleOtherEvent(evt, eventName); }, enable); - break; - case "pointerdown": - case "pointerup": - case "pointerout": - case "pointerover": - case "pointerleave": - case "pointerenter": - // These events will be handled by the window.ontouchmove function - if (!item.__handjsGlobalRegisteredEvents) { - item.__handjsGlobalRegisteredEvents = []; - } - - if (enable) { - if (item.__handjsGlobalRegisteredEvents[eventName] !== undefined) { - item.__handjsGlobalRegisteredEvents[eventName]++; - return; - } - item.__handjsGlobalRegisteredEvents[eventName] = 1; - } else { - if (item.__handjsGlobalRegisteredEvents[eventName] !== undefined) { - item.__handjsGlobalRegisteredEvents[eventName]--; - if (item.__handjsGlobalRegisteredEvents[eventName] < 0) { - item.__handjsGlobalRegisteredEvents[eventName] = 0; - } - } - } - break; - } - } - - // Fallback to mouse - switch (eventName) { - case "pointerdown": - registerOrUnregisterEvent(item, "mousedown", function (evt) { generateMouseProxy(evt, eventName); }, enable); - break; - case "pointermove": - registerOrUnregisterEvent(item, "mousemove", function (evt) { generateMouseProxy(evt, eventName); }, enable); - break; - case "pointerup": - registerOrUnregisterEvent(item, "mouseup", function (evt) { generateMouseProxy(evt, eventName); }, enable); - break; - case "pointerover": - registerOrUnregisterEvent(item, "mouseover", function (evt) { generateMouseProxy(evt, eventName); }, enable); - break; - case "pointerout": - registerOrUnregisterEvent(item, "mouseout", function (evt) { generateMouseProxy(evt, eventName); }, enable); - break; - case "pointerenter": - if (item.onmouseenter === undefined) { // Fallback to mouseover - registerOrUnregisterEvent(item, "mouseover", function (evt) { generateMouseProxy(evt, eventName); }, enable); - } else { - registerOrUnregisterEvent(item, "mouseenter", function (evt) { generateMouseProxy(evt, eventName); }, enable); - } - break; - case "pointerleave": - if (item.onmouseleave === undefined) { // Fallback to mouseout - registerOrUnregisterEvent(item, "mouseout", function (evt) { generateMouseProxy(evt, eventName); }, enable); - } else { - registerOrUnregisterEvent(item, "mouseleave", function (evt) { generateMouseProxy(evt, eventName); }, enable); - } - break; - } - }; - - // Intercept addEventListener calls by changing the prototype - var interceptAddEventListener = function (root) { - var current = root.prototype ? root.prototype.addEventListener : root.addEventListener; - - var customAddEventListener = function (name, func, capture) { - // Branch when a PointerXXX is used - if (supportedEventsNames.indexOf(name) != -1) { - setTouchAware(this, name, true); - } - - if (current === undefined) { - this.attachEvent("on" + getMouseEquivalentEventName(name), func); - } else { - current.call(this, name, func, capture); - } - }; - - if (root.prototype) { - root.prototype.addEventListener = customAddEventListener; - } else { - root.addEventListener = customAddEventListener; - } - }; - - // Intercept removeEventListener calls by changing the prototype - var interceptRemoveEventListener = function (root) { - var current = root.prototype ? root.prototype.removeEventListener : root.removeEventListener; - - var customRemoveEventListener = function (name, func, capture) { - // Release when a PointerXXX is used - if (supportedEventsNames.indexOf(name) != -1) { - setTouchAware(this, name, false); - } - - if (current === undefined) { - this.detachEvent(getMouseEquivalentEventName(name), func); - } else { - current.call(this, name, func, capture); - } - }; - if (root.prototype) { - root.prototype.removeEventListener = customRemoveEventListener; - } else { - root.removeEventListener = customRemoveEventListener; - } - }; - - // Hooks - interceptAddEventListener(HTMLElement); - interceptAddEventListener(document); - interceptAddEventListener(HTMLBodyElement); - interceptAddEventListener(HTMLDivElement); - interceptAddEventListener(HTMLImageElement); - interceptAddEventListener(HTMLUListElement); - interceptAddEventListener(HTMLAnchorElement); - interceptAddEventListener(HTMLLIElement); - interceptAddEventListener(HTMLTableElement); - if (window.HTMLSpanElement) { - interceptAddEventListener(HTMLSpanElement); - } - if (window.HTMLCanvasElement) { - interceptAddEventListener(HTMLCanvasElement); - } - if (window.SVGElement) { - interceptAddEventListener(SVGElement); - } - - interceptRemoveEventListener(HTMLElement); - interceptRemoveEventListener(document); - interceptRemoveEventListener(HTMLBodyElement); - interceptRemoveEventListener(HTMLDivElement); - interceptRemoveEventListener(HTMLImageElement); - interceptRemoveEventListener(HTMLUListElement); - interceptRemoveEventListener(HTMLAnchorElement); - interceptRemoveEventListener(HTMLLIElement); - interceptRemoveEventListener(HTMLTableElement); - if (window.HTMLSpanElement) { - interceptRemoveEventListener(HTMLSpanElement); - } - if (window.HTMLCanvasElement) { - interceptRemoveEventListener(HTMLCanvasElement); - } - if (window.SVGElement) { - interceptRemoveEventListener(SVGElement); - } - - // Handling move on window to detect pointerleave/out/over - if (window.ontouchstart !== undefined) { - window.addEventListener('touchstart', function (eventObject) { - for (var i = 0; i < eventObject.changedTouches.length; ++i) { - var touchPoint = eventObject.changedTouches[i]; - previousTargets[touchPoint.identifier] = touchPoint.target; - - generateTouchEventProxyIfRegistered("pointerenter", touchPoint, touchPoint.target, eventObject); - generateTouchEventProxyIfRegistered("pointerover", touchPoint, touchPoint.target, eventObject); - generateTouchEventProxyIfRegistered("pointerdown", touchPoint, touchPoint.target, eventObject); - } - }); - - window.addEventListener('touchend', function (eventObject) { - for (var i = 0; i < eventObject.changedTouches.length; ++i) { - var touchPoint = eventObject.changedTouches[i]; - var currentTarget = previousTargets[touchPoint.identifier]; - - generateTouchEventProxyIfRegistered("pointerup", touchPoint, currentTarget, eventObject); - generateTouchEventProxyIfRegistered("pointerout", touchPoint, currentTarget, eventObject); - generateTouchEventProxyIfRegistered("pointerleave", touchPoint, currentTarget, eventObject); - } - }); - - window.addEventListener('touchmove', function (eventObject) { - for (var i = 0; i < eventObject.changedTouches.length; ++i) { - var touchPoint = eventObject.changedTouches[i]; - var newTarget = document.elementFromPoint(touchPoint.clientX, touchPoint.clientY); - var currentTarget = previousTargets[touchPoint.identifier]; - - if (currentTarget === newTarget) { - continue; // We can skip this as the pointer is effectively over the current target - } - - if (currentTarget) { - // Raise out - generateTouchEventProxyIfRegistered("pointerout", touchPoint, currentTarget, eventObject); - - // Raise leave - if (!currentTarget.contains(newTarget)) { // Leave must be called if the new target is not a child of the current - generateTouchEventProxyIfRegistered("pointerleave", touchPoint, currentTarget, eventObject); - } - } - - if (newTarget) { - // Raise over - generateTouchEventProxyIfRegistered("pointerover", touchPoint, newTarget, eventObject); - - // Raise enter - if (!newTarget.contains(currentTarget)) { // Leave must be called if the new target is not the parent of the current - generateTouchEventProxyIfRegistered("pointerenter", touchPoint, newTarget, eventObject); - } - } - previousTargets[touchPoint.identifier] = newTarget; - } - }); - } - - // Extension to navigator - if (navigator.pointerEnabled === undefined) { - - // Indicates if the browser will fire pointer events for pointing input - navigator.pointerEnabled = true; - - // IE - if (navigator.msPointerEnabled) { - navigator.maxTouchPoints = navigator.msMaxTouchPoints; - } - } - -})(); diff --git a/desktop.blocks/pointer-events/pointer-events.deps.js b/desktop.blocks/jquery/__event/_type/jquery__event_type_pointerevents.deps.js similarity index 96% rename from desktop.blocks/pointer-events/pointer-events.deps.js rename to desktop.blocks/jquery/__event/_type/jquery__event_type_pointerevents.deps.js index 1810a5b79..357933b72 100644 --- a/desktop.blocks/pointer-events/pointer-events.deps.js +++ b/desktop.blocks/jquery/__event/_type/jquery__event_type_pointerevents.deps.js @@ -1,3 +1,3 @@ ({ shouldDeps : { block : 'jquery', elem : 'event', mods : { type : 'pointerclick' } } -}) \ No newline at end of file +}) diff --git a/desktop.blocks/jquery/__event/_type/jquery__event_type_pointerevents.test.js b/desktop.blocks/jquery/__event/_type/jquery__event_type_pointerevents.test.js new file mode 100644 index 000000000..794b82206 --- /dev/null +++ b/desktop.blocks/jquery/__event/_type/jquery__event_type_pointerevents.test.js @@ -0,0 +1,20 @@ +modules.define( + 'test', + ['jquery', 'sinon'], + function(provide, $, sinon) { + +describe('jquery__event_type_pointerevents', function() { + it('should trigger "pointerdown" event on mousedown', function() { + var spy = sinon.spy(), + elem = $('
'); + + elem.on('pointerdown', spy); + elem.mousedown(); + + spy.should.have.been.calledOnce; + }); +}); + +provide(); + +});