Skip to content

Commit

Permalink
Add dojo/touch dojoClick "useTarget" feature.
Browse files Browse the repository at this point in the history
The touch.click event is fired if the touchstart and touchend both occurred
within the target element.

Refs #15913.
  • Loading branch information
Sebastien Pereira authored and wkeese committed Sep 10, 2013
1 parent 84aba69 commit 7ec319d
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 10 deletions.
65 changes: 65 additions & 0 deletions tests/test_touch.html
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,71 @@

if(has("touch")){
register('touch events', 'touchstart', 'touchmove', 'touchend', 'touchcancel');

var domElt = dom.byId("innertest");
domElt.dojoClick = "useTarget";
var outsideElt = dom.byId("dohDiv");
var 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;
}
}

]);
}
}

Expand Down
42 changes: 32 additions & 10 deletions touch.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ function(dojo, aspect, dom, domClass, lang, on, has, mouse, domReady, win){
}

function marked(/*DOMNode*/ node){
// Test if a node or its ancestor has been marked with the dojoClick property to indicate special processing,
// Search for node ancestor has been marked with the dojoClick property to indicate special processing.
// Returns marked ancestor.
do{
if(node.dojoClick){ return node.dojoClick; }
if(node.dojoClick){ return node; }
}while(node = node.parentNode);
}

Expand All @@ -62,9 +63,16 @@ function(dojo, aspect, dom, domClass, lang, on, has, mouse, domReady, win){
// was called in an event listener. Synthetic clicks are generated only if a node or one of its ancestors has
// its dojoClick property set to truthy.

clickTracker = !e.target.disabled && marked(e.target); // click threshold = true, number or x/y object
var markedNode = marked(e.target);
clickTracker = !e.target.disabled && markedNode && markedNode.dojoClick; // click threshold = true, number, x/y object, or "useTarget"
if(clickTracker){
clickTarget = e.target;
var useTarget = (clickTracker == "useTarget");
clickTarget = (useTarget?markedNode:e.target);
if(useTarget){
// We expect a click, so prevent any other
// defaut action on "touchpress"
e.preventDefault();
}
clickX = e.touches ? e.touches[0].pageX : e.clientX;
clickY = e.touches ? e.touches[0].pageY : e.clientY;
clickDx = (typeof clickTracker == "object" ? clickTracker.x : (typeof clickTracker == "number" ? clickTracker : 0)) || 4;
Expand All @@ -75,17 +83,31 @@ function(dojo, aspect, dom, domClass, lang, on, has, mouse, domReady, win){
if(!clicksInited){
clicksInited = true;

function updateClickTracker(e){
if(useTarget){
clickTracker = dom.isDescendant(win.doc.elementFromPoint((e.changedTouches ? e.changedTouches[0].pageX : e.clientX),(e.changedTouches ? e.changedTouches[0].pageY : e.clientY)),clickTarget);
}else{
clickTracker = clickTracker &&
e.target == clickTarget &&
Math.abs((e.changedTouches ? e.changedTouches[0].pageX : e.clientX) - clickX) <= clickDx &&
Math.abs((e.changedTouches ? e.changedTouches[0].pageY : e.clientY) - clickY) <= clickDy;
}
}

win.doc.addEventListener(moveType, function(e){
clickTracker = clickTracker &&
e.target == clickTarget &&
Math.abs((e.touches ? e.touches[0].pageX : e.clientX) - clickX) <= clickDx &&
Math.abs((e.touches ? e.touches[0].pageY : e.clientY) - clickY) <= clickDy;
updateClickTracker(e);
if(useTarget){
// prevent native scroll event and ensure touchend is
// fire after touch moves between press and release.
e.preventDefault();
}
}, true);

win.doc.addEventListener(endType, function(e){
updateClickTracker(e);
if(clickTracker){
clickTime = (new Date()).getTime();
var target = e.target;
var target = (useTarget?clickTarget:e.target);
if(target.tagName === "LABEL"){
// when clicking on a label, forward click to its associated input if any
target = dom.byId(target.getAttribute("for")) || target;
Expand All @@ -96,7 +118,7 @@ function(dojo, aspect, dom, domClass, lang, on, has, mouse, domReady, win){
cancelable : true,
_dojo_click : true
});
});
}, 0);
}
}, true);

Expand Down

0 comments on commit 7ec319d

Please sign in to comment.