Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
define(["./_base/kernel", "./aspect", "./dom", "./dom-class", "./_base/lang", "./on", "./has", "./mouse", "./domReady", "./_base/window"], | ||
function(dojo, aspect, dom, domClass, lang, on, has, mouse, domReady, win){ | ||
|
||
// module: | ||
// dojo/pointer | ||
|
||
var hasTouch = has("touch"), | ||
hasPointer = has("pointer"), | ||
lastTouch, | ||
mouseEventFireThreshold = 1000, | ||
|
||
POINTER_TYPE_TOUCH = "touch", | ||
POINTER_TYPE_PEN = "pen", | ||
POINTER_TYPE_MOUSE = "mouse", | ||
|
||
bindEvent = function(preferredEventName, mouseType, touchType, pointerType) { | ||
|
||
pointerType = browserSpecificEventName(pointerType); | ||
|
||
// Returns synthetic event that listens for pointer or both the specified mouse event and specified touch event. | ||
// But ignore fake mouse events that were generated due to the user touching the screen. | ||
if (hasPointer) { | ||
// Pointer events are designed to handle both mouse and touch in a uniform way, | ||
// so just use that regardless of hasTouch. | ||
return function(node, listener) { | ||
// TODO We may want to normalize Pointer events too since there could be a difference in comparison to the spec; | ||
// for example in IE10 MSPointer.pointerType is int instead of string as per specification. | ||
return on(node, pointerType, listener); | ||
} | ||
} | ||
|
||
if (hasTouch) { | ||
return function(node, listener) { | ||
var touchHandle = on(node, touchType, function(evt) { | ||
var self = this; | ||
lastTouch = (new Date()).getTime(); | ||
|
||
normalizeEvent(evt, POINTER_TYPE_TOUCH, preferredEventName).forEach(function(e){ | ||
listener.call(self, e); | ||
}) | ||
|
||
}), | ||
mouseHandle = on(node, mouseType, function(evt) { | ||
if (!lastTouch || (new Date()).getTime() > lastTouch + mouseEventFireThreshold) { | ||
listener.call(this, normalizeEvent(evt, POINTER_TYPE_MOUSE, preferredEventName)[0]); | ||
} | ||
}); | ||
return { | ||
This comment has been minimized.
Sorry, something went wrong.
wkeese
|
||
remove: function() { | ||
touchHandle.remove(); | ||
mouseHandle.remove(); | ||
} | ||
}; | ||
}; | ||
} | ||
|
||
// no Pointer or Touch support | ||
// Avoid creating listeners for touch events on performance sensitive older browsers like IE6 | ||
return function(node, listener) { | ||
return on(node, mouseType, function(evt) { | ||
listener.call(this, normalizeEvent(evt, POINTER_TYPE_MOUSE, preferredEventName)[0]); | ||
}); | ||
} | ||
|
||
}, | ||
|
||
/** | ||
* Converts given Mouse or Touch event to a Pointer event. | ||
* | ||
* In case of Touch event returns separate Pointer event for each touch (event.changedTouches container). | ||
* | ||
* @param {Event} originalEvent TODO | ||
* @param {Enum} [eventType] TODO | ||
* @return {Array} A list of Pointer events. | ||
*/ | ||
normalizeEvent = function (originalEvent, eventType, preferredEventName) { | ||
// defines extra properties for normalized events (use default values) | ||
var pointerProperties = {"width" : 0, "height" : 0, "pressure" : 0, "tiltX" : 0, "tiltY" : 0, | ||
"type" : preferredEventName, "pointerType" : eventType, "isPrimary" : true, "POINTER_TYPE_TOUCH" : POINTER_TYPE_TOUCH, | ||
"POINTER_TYPE_PEN" : POINTER_TYPE_PEN, "POINTER_TYPE_MOUSE" : POINTER_TYPE_MOUSE}, | ||
normalizedEvents = []; | ||
|
||
if (eventType === POINTER_TYPE_MOUSE) { | ||
|
||
// Mouse is required to have a pointerId of 1 | ||
pointerProperties.pointerId = 1; | ||
|
||
normalizedEvents.push(PointerEvent(originalEvent, pointerProperties)); | ||
|
||
} else if (eventType === POINTER_TYPE_TOUCH) { | ||
|
||
for(var i=0; i<originalEvent.changedTouches.length; i++) { | ||
|
||
var touch = originalEvent.changedTouches[i], | ||
touchProperties = {"isPrimary": touch === originalEvent.touches[0], | ||
"pointerId" : touch.identifier + 2, // Touch identifiers can start at 0 so we add 2 to the touch identifier for compatibility. | ||
This comment has been minimized.
Sorry, something went wrong.
wkeese
|
||
"pageX" : touch.pageX, "pageY" : touch.pageY, | ||
"clientX" : touch.clientX, "clientY" : touch.clientY, | ||
"screenX" : touch.screenX, "screenY" : touch.screenY, | ||
"currentTarget" : touch.target, "target" : touch.target}; | ||
|
||
var pointerPropertiesForTouch = lang.mixin(touchProperties, pointerProperties); | ||
|
||
normalizedEvents.push(PointerEvent(originalEvent, pointerPropertiesForTouch)); | ||
}; | ||
} | ||
|
||
|
||
|
||
|
||
return normalizedEvents; | ||
}, | ||
|
||
/** | ||
* Creates Pointer event from a given original event and properties table. | ||
* | ||
* @param {Event} originalEvent TODO | ||
* @param {Object} [properties] Dictionary of initial event properties. | ||
* @return {Event} A new Pointer event initialized with properties from `properties`. | ||
*/ | ||
PointerEvent = function(originalEvent, properties) { | ||
This comment has been minimized.
Sorry, something went wrong.
wkeese
|
||
var pointerEvent = lang.delegate(properties, originalEvent); | ||
|
||
// override default event type | ||
pointerEvent.type = properties.type; | ||
|
||
var buttons = pointerEvent.buttons; | ||
if (buttons === undefined) { | ||
switch (pointerEvent.which) { | ||
case 1: buttons = 1; break; | ||
case 2: buttons = 4; break; | ||
case 3: buttons = 2; break; | ||
default: buttons = 0; | ||
} | ||
|
||
Object.defineProperty(pointerEvent, 'buttons', {get: function(){ return buttons }, enumerable: true}); | ||
} | ||
|
||
// use 0.5 for down state and 0 for up state. | ||
pointerEvent.pressure = pointerEvent.pressure || (pointerEvent.buttons ? 0.5 : 0); | ||
|
||
return pointerEvent; | ||
|
||
}, | ||
|
||
browserSpecificEventName = function (eventName) { | ||
if(has("ie") == 10) { | ||
This comment has been minimized.
Sorry, something went wrong.
wkeese
|
||
return "MS" + eventName; | ||
} | ||
|
||
return eventName; | ||
} | ||
|
||
|
||
//device touch model agnostic events - pointer.down|move|up|cancel|over|out|enter|leave | ||
var pointer = { | ||
down: bindEvent("pointer.down","mousedown", "touchstart", "PointerDown"), | ||
move: bindEvent("pointer.move", "mousemove", "touchmove", "PointerMove"), | ||
up: bindEvent("pointer.up", "mouseup", "touchend", "PointerUp"), | ||
cancel: bindEvent("pointer.cancel", mouse.leave, "touchcancel", "PointerCancel"), | ||
over: bindEvent("pointer.over", "mouseover", "touchover", "PointerOver"), | ||
out: bindEvent("pointer.out", "mouseout", "touchout", "PointerOut"), | ||
enter: bindEvent("pointer.enter", "mouseover","touchover", "PointerOver"), | ||
leave: bindEvent("pointer.leave", "mouseout", "touchout", "PointerOut") | ||
This comment has been minimized.
Sorry, something went wrong.
wkeese
|
||
}; | ||
|
||
has("extend-dojo") && (dojo.pointer = pointer); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong. |
||
|
||
return pointer; | ||
|
||
|
||
// TODO | ||
// #0 create new pointer event from MouseEvent | ||
// #1 add dojoClick support and the rest dojo specific functionality | ||
// #2 review enter and leave events | ||
// comment/refactor | ||
|
||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | ||
<meta name="viewport" content="width=device-width,maximum-scale=1,minimum-scale=1,user-scalable=no" /> | ||
<title>Dojo Pointer events Testing</title> | ||
<style type="text/css"> | ||
|
||
html, body, #main { | ||
height: 100%; | ||
width: 100%; | ||
margin: 0px; | ||
padding: 0px; | ||
} | ||
|
||
#main > div { | ||
width: 100%; | ||
} | ||
|
||
#touchpad { | ||
height: 100px; | ||
text-align: center; | ||
background-color: #eee; | ||
} | ||
|
||
#log { | ||
height: 500px; | ||
background-color: rgb(3, 38, 38); | ||
color: white; | ||
overflow: hidden; | ||
overflow: scroll; | ||
} | ||
|
||
.box { | ||
display: -webkit-box; | ||
display: -moz-box; | ||
display: -ms-flexbox; | ||
display: box; | ||
|
||
-ms-flex-direction: column; | ||
-webkit-box-orient: vertical; | ||
-moz-box-orient: vertical; | ||
box-orien: vertical; | ||
} | ||
|
||
.flex1 { | ||
-webkit-box-flex: 1; | ||
-moz-box-flex: 1; | ||
-webkit-flex: 1; | ||
-ms-flex: 1; | ||
flex: 1; | ||
} | ||
|
||
</style> | ||
<script type="text/javascript" src="../dojo.js" data-dojo-config="async: true"></script> | ||
<script> | ||
require([ | ||
"dojo/dom", | ||
"dojo/pointer", | ||
"dojo/on", | ||
"dojo/has", | ||
"dojo/domReady!" | ||
], function(dom, pointer, on, has){ | ||
var touchpad = dom.byId("touchpad"), | ||
events = [pointer.down, pointer.move, pointer.up, pointer.cancel, | ||
pointer.over, pointer.out, pointer.enter, pointer.leave], | ||
|
||
onTouchPadEvent = function(event) { | ||
var logEntry = { | ||
event: event.type, | ||
pointerType: event.pointerType, | ||
pointerId: event.pointerId, | ||
clientX: event.clientX, | ||
clientY: event.clientY, | ||
buttons: event.buttons, | ||
target: event.target ? event.target.id : null | ||
} | ||
|
||
var msg = JSON.stringify(logEntry) + "<br/>", | ||
log = dom.byId("log"); | ||
|
||
log.innerHTML = msg + log.innerHTML; | ||
}; | ||
|
||
events.forEach(function(event) { | ||
on(touchpad, event, onTouchPadEvent); | ||
}); | ||
|
||
}); | ||
|
||
|
||
|
||
</script> | ||
</head> | ||
<body> | ||
<div id="main" class="box"> | ||
<div id="touchpad">Touch here!</div> | ||
<div id="log" class="flex1"></div> | ||
</div> | ||
</body> | ||
</html> |
Typically here we would kill two birds with one stone by returning the event name prefix, something like "MSPointer" for IE10 and "Pointer" for IE11, and null for older browsers.