can
Version:
MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.
464 lines (430 loc) • 16.3 kB
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 Touch Testing</title>
<style type="text/css">
#test {
width: 300px;
height: 150px;
border: 1px solid #7FB0DB;
background-color: #7FB0DB;
touch-action: none;
-ms-touch-action: none;
}
#innertest {
border: 1px solid white;
width: 100px;
height: 75px;
background-color: white;
}
#test2 {
/* for testing touch.move */
width: 200px;
height: 50px;
border: 1px solid yellow;
background-color: yellow;
touch-action: none;
-ms-touch-action: none;
}
#test3 {
width: 300px;
height: 150px;
border: 1px solid red;
background-color: red;
touch-action: none;
-ms-touch-action: none;
}
#innertest3 {
border: 1px solid white;
width: 250px;
height: 75px;
background-color: white;
touch-action: none;
-ms-touch-action: none;
}
#current, #log {
width: 50%;
height: 200px;
float: left;
}
#dohDiv {
display: none;
background-color:#800300;
color: wheat;
}
</style>
<script type="text/javascript" src="../dojo.js" data-dojo-config="async: true"></script>
<script>
require([
"dojo/_base/array",
"dojo/dom",
"dojo/_base/lang",
"dojo/on",
"dojo/has",
"doh/runner",
"dojo/dom-geometry",
"dojo/dom-style",
"dojo/domReady",
"dojo/touch"
], function(array, dom, lang, on, has, doh, domGeom, domStyle, domReady, touch){
var action = function(comment, e){
// summary:
// Callback to display into when events fire
// Detailed log of the most recent event:
dom.byId("current").innerHTML = "Most recent non touch.move event:";
var info = "[Touch Event]: " + e.type + " on " + comment +
"<br/> ------ Event Properties: ------<br/>";
for(var i in e){
if(i == "touches" || i == "targetTouches" || i == "changedTouches"){
info += i + ": " + e[i].length + "<br/>";
}else{
if(typeof e[i] != "function"){
info += " " + i + ": " + e[i] + "<br/>";
}
}
}
dom.byId("current").innerHTML += info + "<br/>";
// This is a log of all events, most recent first:
dom.byId("log").innerHTML = comment + "{type:" +
e.type + ", target:" + (e.target.id||e.target.tagName) +
"}<br/>" + dom.byId("log").innerHTML;
e.preventDefault();
};
var node = dom.byId("test"),
innerNode = dom.byId("innertest");
//1. should work well on PC and touch devices
array.forEach(["test", "innertest"], function(name){
for(var event in touch){
if(event != "move"){
on(dom.byId(name), touch[event], lang.hitch(null, action, "on("+name+", touch."+event+")-->"));
}
}
});
on(dom.byId("test2"), touch.move, function(e){
dom.byId("log").innerHTML = "on(touch2, touch.move)--> {type:" +
e.type + ", target:" + (e.target.id||e.target.tagName) +
", pageX = " + e.pageX + ", pageY = " + e.pageY +
"}<br/>" + dom.byId("log").innerHTML;
// this should stop scrolling
e.preventDefault();
// stopPropagation() should work too
e.stopPropagation();
});
function logClickEvent(e) {
// synthetic click has _dojo_click = true
dom.byId("log").innerHTML = " - _dojo_click [" + e._dojo_click + "]<br/>" + dom.byId("log").innerHTML;
// display mouse event attributes
// http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-mouseevents
var info = "",
mouseEventAttrNames = ["screenX", "screenY", "clientX", "clientY", "ctrlKey", "altKey", "shiftKey", "metaKey", "button"];
for (var attrIdx = 0, name; attrIdx < mouseEventAttrNames.length && (name = mouseEventAttrNames[attrIdx]); attrIdx++) {
info += " - " + name + " [" + e[name] + "]<br/>";
}
dom.byId("log").innerHTML = info + dom.byId("log").innerHTML;
}
dom.byId("test3").dojoClick = true;
on(dom.byId("test3"), "click", function(e){
logClickEvent(e);
if(has("touch")){
// click should be a synthetic click
dom.byId("log").innerHTML = (e._dojo_click ? "Synthetic click received in test3" : "ERROR: native click received in test3") + "<br/>" + dom.byId("log").innerHTML;
}else{
// click should be a native click
dom.byId("log").innerHTML = (e._dojo_click ? "ERROR: Synthetic click received in test3 (non touch device)" : "Native click received in test3 (non touch device)") + "<br/>" + dom.byId("log").innerHTML;
}
});
dom.byId("innertest3").dojoClick = false;
on(dom.byId("innertest3"), "click", function(e){
logClickEvent(e);
// click should be a native click
dom.byId("log").innerHTML = (e._dojo_click ? "ERROR: Synthetic click received in innertest3" : "Native click received in innertest3") + "<br/>" + dom.byId("log").innerHTML;;
e.stopPropagation();
});
// //2. should work well across touch devices
// on(node, "touchstart", action);
// on(node, "touchmove", action);
// on(node, "touchend", action);
// on(node, "touchcancel", action);
// on(node, "orientationchange", action);
/**
* Fires an event. All coordinates are defaulted to zero.
* @param target the target element.
* @param eventType touchstart, touchmove or touchend, or mouse or MSPointer equivalents.
*/
function emit(target, eventType, options){
var targetPos = domGeom.position(target);
options = lang.mixin({
pageX: targetPos.x + targetPos.w / 2,
pageY: targetPos.y + targetPos.h / 2
}, options || {});
if(document.createEvent && target.dispatchEvent){
var touch = {
identifier: (new Date()).getTime(),
target: target,
screenX: 0,
screenY: 0,
clientX: 0,
clientY: 0,
pageX: 0,
pageY: 0
};
lang.mixin(touch, options || {});
var mouseEvent = document.createEvent("MouseEvent");
mouseEvent.initMouseEvent(
eventType,
true,
true,
target.ownerDocument.defaultView,
0,
0,
0,
0,
0,
false,
false,
false,
false,
0,
document.body // relatedTarget, for mouseout events
);
if(/touch/.test(eventType)){
mouseEvent['touches'] = [touch];
mouseEvent['targetTouches'] = [touch];
mouseEvent['changedTouches'] = [touch];
}
target.dispatchEvent(mouseEvent);
}else{
options.bubbles = true;
options.cancelable = true;
on.emit(target, eventType, options);
}
}
// if we declare "dojo/domReady!" touch.js will register its handler *after* the test execution
// so here we explicitly call domReady.
domReady(function(){
var dohDiv = dom.byId('dohDiv');
domStyle.set(dohDiv, {display: 'block'});
// Function to register tests on mouse events, touch events, or Microsoft's pointer-ish events
function register(testName, downEvent, moveEvent, upEvent, cancelEvent){
doh.register(testName, [
function press(){
var executed, target;
on.once(dohDiv, touch.press, function(e){
//console.log(e.type);
executed = true;
target = e.target;
});
emit(dohDiv, downEvent);
doh.t(executed, 'dojo.touch.press fired');
doh.is(dohDiv, target, "target");
},
function move(){
var executed, target;
on.once(dohDiv, touch.move, function(e){
//console.log(e.type);
executed = true;
target = e.target;
});
emit(dohDiv, moveEvent);
doh.t(executed, 'dojo.touch.move fired');
doh.is(dohDiv, target, "target");
},
function release(){
var executed, target;
on.once(dohDiv, touch.release, function(e){
//console.log(e.type);
executed = true;
target = e.target;
});
emit(dohDiv, upEvent, {screenX: 0, screenY: 50});
doh.t(executed, 'dojo.touch.release fired');
doh.is(dohDiv, target, "target");
},
function cancel(){
var executed, target;
on.once(dohDiv, touch.cancel, function(e){
executed = true;
target = e.target;
});
emit(dohDiv, cancelEvent, {
relatedTarget: document.body, // needed for mouseout event
screenX: 0,
screenY: 50,
pageX: 0,
pageY: 0
});
doh.t(executed, 'dojo.touch.cancel fired');
doh.is(dohDiv, target, "target");
},
function movePreventDefault(){
/**
* checks that calling preventDefault() on dojo "touch.move" event
* prevents default behavior on the underlying native event
* Ref. #17220
* window
* | => (1) listen and prevent default on dojo "touch.move" event
* | => (2) listen and check default behavior status on native "touchmove" event
* |
* +--dohDiv => (3) dispatch native "touchmove" event
**/
var prevented = false;
// (1) register dojo "touch.move" listener
on.once(dohDiv, touch.move, function(e){
e.preventDefault();
//console.log("prevent default on event " + e.type);
});
// (2) register listener for native event (touchmove, mousemove, or MSPointerMove)
// Call addEventListener() except on IE6-8 where that's not supported
function listener(e){
prevented = e.defaultPrevented;
//console.log("native listener, prevented = " + prevented);
}
if(window.addEventListener){
window.addEventListener(moveEvent, listener);
}else{
// IE6-8 code path
on.once(document.body, moveEvent, listener);
}
// (3) dispatch native touchmove/mousemove/MSPointerMove event
emit(dohDiv, moveEvent);
doh.t(prevented, 'prevented');
if(window.addEventListener){
window.removeEventListener(moveEvent, listener);
}
}
]);
}
// Setup tests relevant for this platform
if(has("pointer-events")){
register('Pointer events', 'pointerdown', 'pointermove', 'pointerup', 'pointercancel');
}else if(has("MSPointer")){
register('MSPointer events', 'MSPointerDown', 'MSPointerMove', 'MSPointerUp', 'MSPointerCancel');
}else{
// Mouse is always supported, even on devices with touch capability.
// Test mouse first because once we start emitting touch events, dojo/touch ignores mouse events
// for 1000ms.
register('mouse events', 'mousedown', 'mousemove', 'mouseup', 'mouseout');
if(has("touch-events")){
register('touch events', 'touchstart', 'touchmove', 'touchend', 'touchcancel');
var domEltWithDisabledSyntheticClick = dom.byId("innertest3");
var box = domEltWithDisabledSyntheticClick.getBoundingClientRect(); // position in viewport coordinates
var coordInsideEltWithDisabledSyntheticClick = {x: box.right - box.left, y:box.bottom - box.top};
var domElt = dom.byId("innertest");
domElt.dojoClick = "useTarget";
var outsideElt = dom.byId("dohDiv");
box = domElt.getBoundingClientRect(); // position in viewport coordinates
var coordInsideElt = {x: box.right - box.left, y:box.bottom - box.top};
var coordOutsideElt = {x: box.right + 100, y:box.bottom + 100};
doh.register("dojoClick.useTarget", [{
name: "Click inside",
timeout: 1000,
runTest: function(){
/**
* check that synthetic click is fired as expected when dojoClick value is set
* to "useTarget" on a dom element and touchstart/touchend are on that element,
* even if a touchmove happens outside the element.
* Note that synthetic click is fired ONLY on touch enabled devices (touch or MSPointer).
*/
var clicked = false;
// register the click handler
function listener(e){
clicked = true;
}
domElt.addEventListener("click", listener);
// emit "touchstart" then "up" event inside the element
emit(domElt, "touchstart", {screenX: coordInsideElt.x, screenY: coordInsideElt.y});
emit(outsideElt, "touchmove",{screenX: coordOutsideElt.x, screenY: coordOutsideElt.y});
emit(domElt, "touchend", {screenX: coordInsideElt.x, screenY: coordInsideElt.y});
var deferred = new doh.Deferred();
// without deferred the click handler is called after the doh method ends.
setTimeout(deferred.getTestCallback(function(){
doh.t(clicked, 'synthetic click fired');
}), 0);
return deferred;
}
},{
name: "Click outside",
timeout: 1000,
runTest: function(){
/**
* check that synthetic click is NOT fired when dojoClick value is set
* to "useTarget" on a dom element and touch is released outside the element.
* Note that synthetic click is fired ONLY on touch enabled devices (touch or MSPointer).
*/
var clicked = false;
// register the click handler
function listener(e){
alert("click fired ??");
clicked = true;
}
domElt.addEventListener("click", listener);
// emit "touchstart" inside, then "touchend" event outside the element
emit(domElt, "touchstart", {screenX: coordInsideElt.x, screenY: coordInsideElt.y});
emit(outsideElt, "touchmove", {screenX: coordOutsideElt.x, screenY: coordOutsideElt.y});
emit(outsideElt, "touchend", {screenX: coordOutsideElt.x, screenY: coordOutsideElt.y});
var deferred = new doh.Deferred();
// without deferred the click handler is called after the doh method ends.
setTimeout(deferred.getTestCallback(function(){
doh.t(!clicked, 'synthetic click fired');
}), 0);
return deferred;
}
},{
name: "Synthetic click disabled",
timeout: 1000,
runTest: function(){
/**
* check that synthetic click is NOT fired when dojoClick value is set
* to falsy on a dom element and touch is released inside the element.
* Note that synthetic click is fired ONLY on touch enabled devices (touch or MSPointer).
*/
var clicked = false;
// register the click handler
function listener(e){
alert("click fired ??");
clicked = true;
}
domEltWithDisabledSyntheticClick.addEventListener("click", listener);
// emit "touchstart" and "touchend" events inside the element
emit(domEltWithDisabledSyntheticClick, "touchstart", {screenX: coordInsideEltWithDisabledSyntheticClick.x, screenY: coordInsideEltWithDisabledSyntheticClick.y});
emit(domEltWithDisabledSyntheticClick, "touchend", {screenX: coordInsideEltWithDisabledSyntheticClick.x, screenY: coordInsideEltWithDisabledSyntheticClick.y});
var deferred = new doh.Deferred();
// without deferred the click handler is called after the doh method ends.
setTimeout(deferred.getTestCallback(function(){
doh.t(!clicked, 'synthetic click fired');
}), 0);
return deferred;
}
}
]);
}
}
doh.run();
});
});
</script>
</head>
<body>
<div id="test">
test
<div id="innertest">
inner test
</div>
</div>
<div id="test2">
touch.move
</div>
<div id="test3">
On touch devices, synthetic clicks are enabled in this area.
<div id="innertest3">
On touch devices, synthetic clicks disabled in this area.
</div>
</div>
<div id="dohDiv">doh</div>
<div id="current"></div>
<div id="log"></div>
<br style="clear:both"/>
</body>
</html>