1 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
---|
2 | <html> |
---|
3 | <head> |
---|
4 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
---|
5 | <meta name="viewport" content="width=device-width,maximum-scale=1,minimum-scale=1,user-scalable=no"/> |
---|
6 | <title>Dojo Touch Testing</title> |
---|
7 | <style type="text/css"> |
---|
8 | #test { |
---|
9 | width: 300px; |
---|
10 | height: 150px; |
---|
11 | border: 1px solid #7FB0DB; |
---|
12 | background-color: #7FB0DB; |
---|
13 | } |
---|
14 | #innertest { |
---|
15 | border: 1px solid white; |
---|
16 | width: 100px; |
---|
17 | height: 75px; |
---|
18 | background-color: white; |
---|
19 | } |
---|
20 | #test2 { |
---|
21 | /* for testing touch.move */ |
---|
22 | width: 200px; |
---|
23 | height: 50px; |
---|
24 | border: 1px solid yellow; |
---|
25 | background-color: yellow; |
---|
26 | } |
---|
27 | #test3 { |
---|
28 | width: 300px; |
---|
29 | height: 150px; |
---|
30 | border: 1px solid red; |
---|
31 | background-color: red; |
---|
32 | } |
---|
33 | #innertest3 { |
---|
34 | border: 1px solid white; |
---|
35 | width: 250px; |
---|
36 | height: 75px; |
---|
37 | background-color: white; |
---|
38 | } |
---|
39 | #current, #log { |
---|
40 | width: 300px; |
---|
41 | height: 200px; |
---|
42 | float: left; |
---|
43 | } |
---|
44 | #dohDiv { |
---|
45 | display: none; |
---|
46 | background-color:#800300; |
---|
47 | color: wheat; |
---|
48 | } |
---|
49 | </style> |
---|
50 | <script type="text/javascript" src="../dojo.js" data-dojo-config="async: true"></script> |
---|
51 | <script> |
---|
52 | require([ |
---|
53 | "dojo/_base/array", |
---|
54 | "dojo/dom", |
---|
55 | "dojo/_base/lang", |
---|
56 | "dojo/on", |
---|
57 | "dojo/has", |
---|
58 | "doh/runner", |
---|
59 | "dojo/dom-geometry", |
---|
60 | "dojo/dom-style", |
---|
61 | "dojo/domReady", |
---|
62 | "dojo/touch" |
---|
63 | ], function(array, dom, lang, on, has, doh, domGeom, domStyle, domReady, touch){ |
---|
64 | |
---|
65 | var action = function(comment, e){ |
---|
66 | // summary: |
---|
67 | // Callback to display into when events fire |
---|
68 | // Detailed log of the most recent event: |
---|
69 | |
---|
70 | dom.byId("current").innerHTML = "Most recent non touch.move event:"; |
---|
71 | var info = "[Touch Event]: " + e.type + " on " + comment + |
---|
72 | "<br/> ------ Event Properties: ------<br/>"; |
---|
73 | for(var i in e){ |
---|
74 | if(i == "touches" || i == "targetTouches" || i == "changedTouches"){ |
---|
75 | info += i + ": " + e[i].length + "<br/>"; |
---|
76 | }else{ |
---|
77 | if(typeof e[i] != "function"){ |
---|
78 | info += " " + i + ": " + e[i] + "<br/>"; |
---|
79 | } |
---|
80 | } |
---|
81 | } |
---|
82 | dom.byId("current").innerHTML += info + "<br/>"; |
---|
83 | |
---|
84 | // This is a log of all events, most recent first: |
---|
85 | dom.byId("log").innerHTML = comment + "{type:" + |
---|
86 | e.type + ", target:" + (e.target.id||e.target.tagName) + |
---|
87 | "}<br/>" + dom.byId("log").innerHTML; |
---|
88 | |
---|
89 | e.preventDefault(); |
---|
90 | }; |
---|
91 | |
---|
92 | var node = dom.byId("test"), |
---|
93 | innerNode = dom.byId("innertest"); |
---|
94 | |
---|
95 | //1. should work well on PC and touch devices |
---|
96 | array.forEach(["test", "innertest"], function(name){ |
---|
97 | for(var event in touch){ |
---|
98 | if(event != "move"){ |
---|
99 | on(dom.byId(name), touch[event], lang.hitch(null, action, "on("+name+", touch."+event+")-->")); |
---|
100 | } |
---|
101 | } |
---|
102 | }); |
---|
103 | |
---|
104 | on(dom.byId("test2"), touch.move, function(e){ |
---|
105 | dom.byId("log").innerHTML = "on(touch2, touch.move)--> {type:" + |
---|
106 | e.type + ", target:" + (e.target.id||e.target.tagName) + |
---|
107 | ", pageX = " + e.pageX + ", pageY = " + e.pageY + |
---|
108 | "}<br/>" + dom.byId("log").innerHTML; |
---|
109 | |
---|
110 | |
---|
111 | // this should stop scrolling |
---|
112 | e.preventDefault(); |
---|
113 | |
---|
114 | // stopPropagation() should work too |
---|
115 | e.stopPropagation(); |
---|
116 | }); |
---|
117 | |
---|
118 | // //2. should work well across touch devices |
---|
119 | // on(node, "touchstart", action); |
---|
120 | // on(node, "touchmove", action); |
---|
121 | // on(node, "touchend", action); |
---|
122 | // on(node, "touchcancel", action); |
---|
123 | // on(node, "orientationchange", action); |
---|
124 | |
---|
125 | dom.byId("test3").dojoClick = true; |
---|
126 | on(dom.byId("test3"), "click", function(e){ |
---|
127 | if(has("touch")){ |
---|
128 | // click should be a synthetic click |
---|
129 | dom.byId("log").innerHTML = (e._dojo_click ? "Synthetic click received in test3" : "ERROR: native click received in test3") + "<br/>" + dom.byId("log").innerHTML; |
---|
130 | }else{ |
---|
131 | // click should be a native click |
---|
132 | 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; |
---|
133 | } |
---|
134 | }); |
---|
135 | dom.byId("innertest3").dojoClick = false; |
---|
136 | on(dom.byId("innertest3"), "click", function(e){ |
---|
137 | // click should be a native click |
---|
138 | dom.byId("log").innerHTML = (e._dojo_click ? "ERROR: Synthetic click received in innertest3" : "Native click received in innertest3") + "<br/>" + dom.byId("log").innerHTML;; |
---|
139 | e.stopPropagation(); |
---|
140 | }); |
---|
141 | |
---|
142 | /** |
---|
143 | * Fires an event. All coordinates are defaulted to zero. |
---|
144 | * @param target the target element. |
---|
145 | * @param eventType touchstart, touchmove or touchend, or mouse or MSPointer equivalents. |
---|
146 | */ |
---|
147 | function emit(target, eventType, options){ |
---|
148 | var targetPos = domGeom.position(target); |
---|
149 | |
---|
150 | options = lang.mixin({ |
---|
151 | pageX: targetPos.x + targetPos.w / 2, |
---|
152 | pageY: targetPos.y + targetPos.h / 2 |
---|
153 | }, options || {}); |
---|
154 | |
---|
155 | if(document.createEvent && target.dispatchEvent){ |
---|
156 | var touch = { |
---|
157 | identifier: (new Date()).getTime(), |
---|
158 | target: target, |
---|
159 | screenX: 0, |
---|
160 | screenY: 0, |
---|
161 | clientX: 0, |
---|
162 | clientY: 0, |
---|
163 | pageX: 0, |
---|
164 | pageY: 0 |
---|
165 | }; |
---|
166 | lang.mixin(touch, options || {}); |
---|
167 | |
---|
168 | var mouseEvent = document.createEvent("MouseEvent"); |
---|
169 | mouseEvent.initMouseEvent( |
---|
170 | eventType, |
---|
171 | true, |
---|
172 | true, |
---|
173 | target.ownerDocument.defaultView, |
---|
174 | 0, |
---|
175 | 0, |
---|
176 | 0, |
---|
177 | 0, |
---|
178 | 0, |
---|
179 | false, |
---|
180 | false, |
---|
181 | false, |
---|
182 | false, |
---|
183 | 0, |
---|
184 | document.body // relatedTarget, for mouseout events |
---|
185 | ); |
---|
186 | |
---|
187 | if(/touch/.test(eventType)){ |
---|
188 | mouseEvent['touches'] = [touch]; |
---|
189 | mouseEvent['targetTouches'] = [touch]; |
---|
190 | mouseEvent['changedTouches'] = [touch]; |
---|
191 | } |
---|
192 | |
---|
193 | target.dispatchEvent(mouseEvent); |
---|
194 | }else{ |
---|
195 | options.bubbles = true; |
---|
196 | options.cancelable = true; |
---|
197 | on.emit(target, eventType, options); |
---|
198 | } |
---|
199 | } |
---|
200 | |
---|
201 | // if we declare "dojo/domReady!" touch.js will register its handler *after* the test execution |
---|
202 | // so here we explicitly call domReady. |
---|
203 | domReady(function(){ |
---|
204 | var dohDiv = dom.byId('dohDiv'); |
---|
205 | domStyle.set(dohDiv, {display: 'block'}); |
---|
206 | |
---|
207 | // Function to register tests on mouse events, touch events, or Microsoft's pointer-ish events |
---|
208 | function register(testName, downEvent, moveEvent, upEvent, cancelEvent){ |
---|
209 | doh.register(testName, [ |
---|
210 | function press(){ |
---|
211 | var executed, target; |
---|
212 | on.once(dohDiv, touch.press, function(e){ |
---|
213 | //console.log(e.type); |
---|
214 | executed = true; |
---|
215 | target = e.target; |
---|
216 | }); |
---|
217 | emit(dohDiv, downEvent); |
---|
218 | doh.t(executed, 'dojo.touch.press fired'); |
---|
219 | doh.is(dohDiv, target, "target"); |
---|
220 | }, |
---|
221 | function move(){ |
---|
222 | var executed, target; |
---|
223 | on.once(dohDiv, touch.move, function(e){ |
---|
224 | //console.log(e.type); |
---|
225 | executed = true; |
---|
226 | target = e.target; |
---|
227 | }); |
---|
228 | emit(dohDiv, moveEvent); |
---|
229 | doh.t(executed, 'dojo.touch.move fired'); |
---|
230 | doh.is(dohDiv, target, "target"); |
---|
231 | }, |
---|
232 | function release(){ |
---|
233 | var executed, target; |
---|
234 | on.once(dohDiv, touch.release, function(e){ |
---|
235 | //console.log(e.type); |
---|
236 | executed = true; |
---|
237 | target = e.target; |
---|
238 | }); |
---|
239 | emit(dohDiv, upEvent, {screenX: 0, screenY: 50}); |
---|
240 | doh.t(executed, 'dojo.touch.release fired'); |
---|
241 | doh.is(dohDiv, target, "target"); |
---|
242 | }, |
---|
243 | function cancel(){ |
---|
244 | var executed, target; |
---|
245 | on.once(dohDiv, touch.cancel, function(e){ |
---|
246 | executed = true; |
---|
247 | target = e.target; |
---|
248 | }); |
---|
249 | emit(dohDiv, cancelEvent, { |
---|
250 | relatedTarget: document.body, // needed for mouseout event |
---|
251 | screenX: 0, |
---|
252 | screenY: 50, |
---|
253 | pageX: 0, |
---|
254 | pageY: 0 |
---|
255 | }); |
---|
256 | doh.t(executed, 'dojo.touch.cancel fired'); |
---|
257 | doh.is(dohDiv, target, "target"); |
---|
258 | }, |
---|
259 | function movePreventDefault(){ |
---|
260 | /** |
---|
261 | * checks that calling preventDefault() on dojo "touch.move" event |
---|
262 | * prevents default behavior on the underlying native event |
---|
263 | * Ref. #17220 |
---|
264 | * window |
---|
265 | * | => (1) listen and prevent default on dojo "touch.move" event |
---|
266 | * | => (2) listen and check default behavior status on native "touchmove" event |
---|
267 | * | |
---|
268 | * +--dohDiv => (3) dispatch native "touchmove" event |
---|
269 | **/ |
---|
270 | var prevented = false; |
---|
271 | |
---|
272 | // (1) register dojo "touch.move" listener |
---|
273 | on.once(dohDiv, touch.move, function(e){ |
---|
274 | e.preventDefault(); |
---|
275 | //console.log("prevent default on event " + e.type); |
---|
276 | }); |
---|
277 | |
---|
278 | // (2) register listener for native event (touchmove, mousemove, or MSPointerMove) |
---|
279 | // Call addEventListener() except on IE6-8 where that's not supported |
---|
280 | function listener(e){ |
---|
281 | prevented = e.defaultPrevented; |
---|
282 | //console.log("native listener, prevented = " + prevented); |
---|
283 | } |
---|
284 | if(window.addEventListener){ |
---|
285 | window.addEventListener(moveEvent, listener); |
---|
286 | }else{ |
---|
287 | // IE6-8 code path |
---|
288 | on.once(document.body, moveEvent, listener); |
---|
289 | } |
---|
290 | |
---|
291 | // (3) dispatch native touchmove/mousemove/MSPointerMove event |
---|
292 | emit(dohDiv, moveEvent); |
---|
293 | doh.t(prevented, 'prevented'); |
---|
294 | |
---|
295 | if(window.addEventListener){ |
---|
296 | window.removeEventListener(moveEvent, listener); |
---|
297 | } |
---|
298 | } |
---|
299 | ]); |
---|
300 | } |
---|
301 | |
---|
302 | // Setup tests relevant for this platform |
---|
303 | if(navigator.pointerEnabled){ |
---|
304 | register('Pointer events', 'pointerdown', 'pointermove', 'pointerup', |
---|
305 | has('touch') ? 'pointercancel' : 'mouseout'); |
---|
306 | }else if(navigator.msPointerEnabled){ |
---|
307 | register('MSPointer events', 'MSPointerDown', 'MSPointerMove', 'MSPointerUp', |
---|
308 | has('touch') ? 'MSPointerCancel' : 'mouseout'); |
---|
309 | }else{ |
---|
310 | // Mouse is always supported, even on devices with touch capability. |
---|
311 | // Test mouse first because once we start emitting touch events, dojo/touch ignores mouse events |
---|
312 | // for 1000ms. |
---|
313 | register('mouse events', 'mousedown', 'mousemove', 'mouseup', 'mouseout'); |
---|
314 | |
---|
315 | if(has("touch")){ |
---|
316 | register('touch events', 'touchstart', 'touchmove', 'touchend', 'touchcancel'); |
---|
317 | } |
---|
318 | } |
---|
319 | |
---|
320 | if(has("touch")){ |
---|
321 | doh.registerTest("synthetic clicks", { |
---|
322 | name: "Synthetic click disabled", |
---|
323 | timeout: 1000, |
---|
324 | runTest: function(){ |
---|
325 | /** |
---|
326 | * check that synthetic click is NOT fired when dojoClick value is set |
---|
327 | * to falsy on a dom element and touch is released inside the element. |
---|
328 | * Note that synthetic click is fired ONLY on touch enabled devices (touch or MSPointer). |
---|
329 | */ |
---|
330 | var domEltWithDisabledSyntheticClick = dom.byId("innertest3"); |
---|
331 | var box = domEltWithDisabledSyntheticClick.getBoundingClientRect(); // position in viewport coordinates |
---|
332 | var coordInsideEltWithDisabledSyntheticClick = {x: box.right - box.left, y:box.bottom - box.top}; |
---|
333 | var clicked = false; |
---|
334 | // register the click handler |
---|
335 | function listener(e){ |
---|
336 | alert("click fired ??"); |
---|
337 | clicked = true; |
---|
338 | } |
---|
339 | domEltWithDisabledSyntheticClick.addEventListener("click", listener); |
---|
340 | // emit "touchstart" and "touchend" events inside the element |
---|
341 | emit(domEltWithDisabledSyntheticClick, "touchstart", {screenX: coordInsideEltWithDisabledSyntheticClick.x, screenY: coordInsideEltWithDisabledSyntheticClick.y}); |
---|
342 | emit(domEltWithDisabledSyntheticClick, "touchend", {screenX: coordInsideEltWithDisabledSyntheticClick.x, screenY: coordInsideEltWithDisabledSyntheticClick.y}); |
---|
343 | var deferred = new doh.Deferred(); |
---|
344 | // without deferred the click handler is called after the doh method ends. |
---|
345 | setTimeout(deferred.getTestCallback(function(){ |
---|
346 | doh.t(!clicked, 'synthetic click fired'); |
---|
347 | }), 0); |
---|
348 | return deferred; |
---|
349 | } |
---|
350 | }); |
---|
351 | } |
---|
352 | |
---|
353 | doh.run(); |
---|
354 | }); |
---|
355 | }); |
---|
356 | </script> |
---|
357 | </head> |
---|
358 | <body> |
---|
359 | <div id="test"> |
---|
360 | test |
---|
361 | <div id="innertest"> |
---|
362 | inner test |
---|
363 | </div> |
---|
364 | </div> |
---|
365 | <div id="test2"> |
---|
366 | touch.move |
---|
367 | </div> |
---|
368 | <div id="test3"> |
---|
369 | On touch devices, synthetic clicks are enabled in this area. |
---|
370 | <div id="innertest3"> |
---|
371 | On touch devices, synthetic clicks disabled in this area. |
---|
372 | </div> |
---|
373 | </div> |
---|
374 | <div id="dohDiv">doh</div> |
---|
375 | <div id="current"></div> |
---|
376 | <div id="log"></div> |
---|
377 | <br style="clear:both"/> |
---|
378 | </body> |
---|
379 | </html> |
---|