Skip to content
This repository was archived by the owner on Oct 8, 2021. It is now read-only.

Commit 7cce0c5

Browse files
committed
Fixes for issue 1464 - No way to stop a link from being followed with some custom event (tap, taphold)
jquery.mobile.vmouse.js: - Modified triggerVirtualEvent() so that it returns the virtual event instead of the isDefaultPrevented() result of the virtual event. - Updated all references to triggerVirtualEvent() that relied on the boolean return value to instead check the isDefaultPrevented() call on the event now returned. - Updated mouseEventCallback() to propagate the iDefaultPrevented(), isPropagationStopped(), and stopImmediatePropagation() values from the virtual event on to the original mouse event. jquery.mobile.event.js - Modified the "taphold" trigger code to create a new $.Event() instead of passing the stale vmousedown event. - Added clearTapTimer() which is called from a new vmouseup binding, to prevent the timer from firing between the tie the finger/mouse goes up and the click event is dispatched. - Added some propagation tests for the "tap" event. Tests for "taphold" will have to wait until we fix the problem where multiple taphold timers are fired off when an element and one of its ancestors is bound to taphold.
1 parent 0b41fe8 commit 7cce0c5

File tree

3 files changed

+114
-14
lines changed

3 files changed

+114
-14
lines changed

js/jquery.mobile.event.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,19 @@ $.event.special.tap = {
7878
return false;
7979
}
8080

81-
var touching = true,
82-
origTarget = event.target,
81+
var origTarget = event.target,
8382
origEvent = event.originalEvent,
8483
timer;
8584

85+
function clearTapTimer() {
86+
clearTimeout( timer );
87+
}
88+
8689
function clearTapHandlers() {
87-
touching = false;
88-
clearTimeout(timer);
90+
clearTapTimer();
8991

9092
$this.unbind( "vclick", clickHandler )
93+
.unbind( "vmouseup", clearTapTimer )
9194
.unbind( "vmousecancel", clearTapHandlers );
9295
}
9396

@@ -102,12 +105,11 @@ $.event.special.tap = {
102105
}
103106

104107
$this.bind( "vmousecancel", clearTapHandlers )
108+
.bind( "vmouseup", clearTapTimer )
105109
.bind( "vclick", clickHandler );
106110

107111
timer = setTimeout(function() {
108-
if ( touching ) {
109-
triggerCustomEvent( thisObject, "taphold", event );
110-
}
112+
triggerCustomEvent( thisObject, "taphold", $.Event( "taphold" ) );
111113
}, 750 );
112114
});
113115
}

js/jquery.mobile.vmouse.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,27 +164,35 @@ function clearResetTimer() {
164164
}
165165

166166
function triggerVirtualEvent( eventType, event, flags ) {
167-
var defaultPrevented = false,
168-
ve;
167+
var ve;
169168

170169
if ( ( flags && flags[ eventType ] ) ||
171170
( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {
172171

173172
ve = createVirtualEvent( event, eventType );
174173

175174
$( event.target).trigger( ve );
176-
177-
defaultPrevented = ve.isDefaultPrevented();
178175
}
179176

180-
return defaultPrevented;
177+
return ve;
181178
}
182179

183180
function mouseEventCallback( event ) {
184181
var touchID = $.data(event.target, touchTargetPropertyName);
185182

186183
if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ){
187-
triggerVirtualEvent( "v" + event.type, event );
184+
var ve = triggerVirtualEvent( "v" + event.type, event );
185+
if ( ve ) {
186+
if ( ve.isDefaultPrevented() ) {
187+
event.preventDefault();
188+
}
189+
if ( ve.isPropagationStopped() ) {
190+
event.stopPropagation();
191+
}
192+
if ( ve.isImmediatePropagationStopped() ) {
193+
event.stopImmediatePropagation();
194+
}
195+
}
188196
}
189197
}
190198

@@ -264,7 +272,8 @@ function handleTouchEnd( event ) {
264272
triggerVirtualEvent( "vmouseup", event, flags );
265273

266274
if ( !didScroll ) {
267-
if ( triggerVirtualEvent( "vclick", event, flags ) ) {
275+
var ve = triggerVirtualEvent( "vclick", event, flags );
276+
if ( ve && ve.isDefaultPrevented() ) {
268277
// The target of the mouse events that follow the touchend
269278
// event don't necessarily match the target used during the
270279
// touch. This means we need to rely on coordinates for blocking

tests/unit/event/event_core.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,95 @@
241241
}, 40);
242242
});
243243

244+
asyncTest( "tap event propagates up DOM tree", function(){
245+
var tap = 0,
246+
$qf = $( "#qunit-fixture" ),
247+
$doc = $( document ),
248+
docTapCB = function(){
249+
same(++tap, 2, "document tap callback called once after #qunit-fixture callback");
250+
};
251+
252+
$qf.bind( "tap", function() {
253+
same(++tap, 1, "#qunit-fixture tap callback called once");
254+
});
255+
256+
$doc.bind( "tap", docTapCB );
257+
258+
$qf.trigger( "vmousedown" )
259+
.trigger( "vmouseup" )
260+
.trigger( "vclick" );
261+
262+
// tap binding should be triggered twice, once for
263+
// #qunit-fixture, and a second time for document.
264+
same( tap, 2, "final tap callback count is 2" );
265+
266+
$doc.unbind( "tap", docTapCB );
267+
268+
start();
269+
});
270+
271+
asyncTest( "stopPropagation() prevents tap from propagating up DOM tree", function(){
272+
var tap = 0,
273+
$qf = $( "#qunit-fixture" ),
274+
$doc = $( document ),
275+
docTapCB = function(){
276+
ok(false, "tap should NOT be triggered on document");
277+
};
278+
279+
$qf.bind( "tap", function(e) {
280+
same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
281+
e.stopPropagation();
282+
})
283+
.bind( "tap", function(e) {
284+
same(++tap, 2, "tap callback 2 triggered once on #qunit-fixture");
285+
});
286+
287+
$doc.bind( "tap", docTapCB);
288+
289+
$qf.trigger( "vmousedown" )
290+
.trigger( "vmouseup" )
291+
.trigger( "vclick" );
292+
293+
// tap binding should be triggered twice.
294+
same( tap, 2, "final tap count is 2" );
295+
296+
$doc.unbind( "tap", docTapCB );
297+
298+
start();
299+
});
300+
301+
asyncTest( "stopImmediatePropagation() prevents tap propagation and execution of 2nd handler", function(){
302+
var tap = 0,
303+
$cf = $( "#qunit-fixture" );
304+
$doc = $( document ),
305+
docTapCB = function(){
306+
ok(false, "tap should NOT be triggered on document");
307+
};
308+
309+
// Bind 2 tap callbacks on qunit-fixture. Only the first
310+
// one should ever be called.
311+
$cf.bind( "tap", function(e) {
312+
same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
313+
e.stopImmediatePropagation();
314+
})
315+
.bind( "tap", function(e) {
316+
ok(false, "tap callback 2 should NOT be triggered on #qunit-fixture");
317+
});
318+
319+
$doc.bind( "tap", docTapCB);
320+
321+
$cf.trigger( "vmousedown" )
322+
.trigger( "vmouseup" )
323+
.trigger( "vclick" );
324+
325+
// tap binding should be triggered once.
326+
same( tap, 1, "final tap count is 1" );
327+
328+
$doc.unbind( "tap", docTapCB );
329+
330+
start();
331+
});
332+
244333
var swipeTimedTest = function(opts){
245334
var swipe = false;
246335

0 commit comments

Comments
 (0)