mirror of
https://github.com/Hopiu/jquery-mobile.git
synced 2026-03-23 01:10:25 +00:00
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.
531 lines
13 KiB
JavaScript
531 lines
13 KiB
JavaScript
/*
|
|
* mobile event unit tests
|
|
*/
|
|
|
|
(function($){
|
|
var libName = "jquery.mobile.event.js",
|
|
absFn = Math.abs,
|
|
originalEventFn = $.Event.prototype.originalEvent,
|
|
preventDefaultFn = $.Event.prototype.preventDefault,
|
|
events = ("touchstart touchmove touchend orientationchange tap taphold " +
|
|
"swipe swipeleft swiperight scrollstart scrollstop").split( " " );
|
|
|
|
module(libName, {
|
|
setup: function(){
|
|
|
|
// ensure bindings are removed
|
|
$.each(events + "vmouseup vmousedown".split(" "), function(i, name){
|
|
$("#qunit-fixture").unbind();
|
|
});
|
|
|
|
//NOTE unmock
|
|
Math.abs = absFn;
|
|
$.Event.prototype.originalEvent = originalEventFn;
|
|
$.Event.prototype.preventDefault = preventDefaultFn;
|
|
|
|
// make sure the event objects respond to touches to simulate
|
|
// the collections existence in non touch enabled test browsers
|
|
$.Event.prototype.touches = [{pageX: 1, pageY: 1 }];
|
|
|
|
$($.mobile.pageContainer).unbind( "throttledresize" );
|
|
}
|
|
});
|
|
|
|
$.testHelper.excludeFileProtocol(function(){
|
|
test( "new events defined on the jquery object", function(){
|
|
$.each(events, function( i, name ) {
|
|
delete $.fn[name];
|
|
same($.fn[name], undefined);
|
|
});
|
|
|
|
$.testHelper.reloadLib(libName);
|
|
|
|
$.each(events, function( i, name ) {
|
|
ok($.fn[name] !== undefined, name + " is not undefined");
|
|
});
|
|
});
|
|
});
|
|
|
|
asyncTest( "defined event functions bind a closure when passed", function(){
|
|
expect( 1 );
|
|
|
|
$('#qunit-fixture').bind(events[0], function(){
|
|
ok(true, "event fired");
|
|
start();
|
|
});
|
|
|
|
$('#qunit-fixture').trigger(events[0]);
|
|
stop();
|
|
});
|
|
|
|
asyncTest( "defined event functions trigger the event with no arguments", function(){
|
|
expect( 1 );
|
|
|
|
$('#qunit-fixture').bind('touchstart', function(){
|
|
ok(true, "event fired");
|
|
start();
|
|
});
|
|
|
|
$('#qunit-fixture').touchstart();
|
|
stop();
|
|
});
|
|
|
|
test( "defining event functions sets the attrFn to true", function(){
|
|
$.each(events, function(i, name){
|
|
ok($.attrFn[name], "attribute function is true");
|
|
});
|
|
});
|
|
|
|
test( "scrollstart enabled defaults to true", function(){
|
|
$.event.special.scrollstart.enabled = false;
|
|
$.testHelper.reloadLib(libName);
|
|
ok($.event.special.scrollstart.enabled, "scrollstart enabled");
|
|
});
|
|
|
|
asyncTest( "scrollstart setup binds a function that returns when its disabled", function(){
|
|
expect( 1 );
|
|
$.event.special.scrollstart.enabled = false;
|
|
|
|
$( "#qunit-fixture" ).bind("scrollstart", function(){
|
|
ok(false, "scrollstart fired");
|
|
});
|
|
|
|
$( "#qunit-fixture" ).bind("touchmove", function(){
|
|
ok(true, "touchmove fired");
|
|
start();
|
|
});
|
|
|
|
$( "#qunit-fixture" ).trigger("touchmove");
|
|
});
|
|
|
|
asyncTest( "scrollstart setup binds a function that triggers scroll start when enabled", function(){
|
|
$.event.special.scrollstart.enabled = true;
|
|
|
|
$( "#qunit-fixture" ).bind("scrollstart", function(){
|
|
ok(true, "scrollstart fired");
|
|
start();
|
|
});
|
|
|
|
$( "#qunit-fixture" ).trigger("touchmove");
|
|
});
|
|
|
|
asyncTest( "scrollstart setup binds a function that triggers scroll stop after 50 ms", function(){
|
|
var triggered = false;
|
|
$.event.special.scrollstart.enabled = true;
|
|
|
|
$( "#qunit-fixture" ).bind("scrollstop", function(){
|
|
triggered = true;
|
|
});
|
|
|
|
ok(!triggered, "not triggered");
|
|
|
|
$( "#qunit-fixture" ).trigger("touchmove");
|
|
|
|
setTimeout(function(){
|
|
ok(triggered, "triggered");
|
|
start();
|
|
}, 50);
|
|
});
|
|
|
|
var forceTouchSupport = function(){
|
|
$.support.touch = true;
|
|
$.testHelper.reloadLib(libName);
|
|
|
|
//mock originalEvent information
|
|
$.Event.prototype.originalEvent = {
|
|
touches: [{ 'pageX' : 0 }, { 'pageY' : 0 }]
|
|
};
|
|
};
|
|
|
|
asyncTest( "long press fires tap hold after 750 ms", function(){
|
|
var taphold = false;
|
|
|
|
forceTouchSupport();
|
|
|
|
$( "#qunit-fixture" ).bind("taphold", function(){
|
|
taphold = true;
|
|
});
|
|
|
|
$( "#qunit-fixture" ).trigger("vmousedown");
|
|
|
|
setTimeout(function(){
|
|
ok(taphold);
|
|
start();
|
|
}, 751);
|
|
});
|
|
|
|
//NOTE used to simulate movement when checked
|
|
//TODO find a better way ...
|
|
var mockAbs = function(value){
|
|
Math.abs = function(){
|
|
return value;
|
|
};
|
|
};
|
|
|
|
asyncTest( "move prevents taphold", function(){
|
|
expect( 1 );
|
|
var taphold = false;
|
|
|
|
forceTouchSupport();
|
|
mockAbs(100);
|
|
|
|
//NOTE record taphold event
|
|
$( "#qunit-fixture" ).bind("taphold", function(){
|
|
ok(false, "taphold fired");
|
|
taphold = true;
|
|
});
|
|
|
|
//NOTE start the touch events
|
|
$( "#qunit-fixture" ).trigger("vmousedown");
|
|
|
|
//NOTE fire touchmove to push back taphold
|
|
setTimeout(function(){
|
|
$( "#qunit-fixture" ).trigger("vmousecancel");
|
|
}, 100);
|
|
|
|
//NOTE verify that the taphold hasn't been fired
|
|
// with the normal timing
|
|
setTimeout(function(){
|
|
ok(!taphold, "taphold not fired");
|
|
start();
|
|
}, 751);
|
|
});
|
|
|
|
asyncTest( "tap event fired without movement", function(){
|
|
expect( 1 );
|
|
var tap = false,
|
|
checkTap = function(){
|
|
ok(true, "tap fired");
|
|
};
|
|
|
|
forceTouchSupport();
|
|
|
|
//NOTE record the tap event
|
|
$( "#qunit-fixture" ).bind("tap", checkTap);
|
|
|
|
$( "#qunit-fixture" ).trigger("vmousedown");
|
|
$( "#qunit-fixture" ).trigger("vmouseup");
|
|
$( "#qunit-fixture" ).trigger("vclick");
|
|
|
|
setTimeout(function(){
|
|
start();
|
|
}, 400);
|
|
});
|
|
|
|
asyncTest( "tap event not fired when there is movement", function(){
|
|
expect( 1 );
|
|
var tap = false;
|
|
forceTouchSupport();
|
|
|
|
//NOTE record tap event
|
|
$( "#qunit-fixture" ).bind("tap", function(){
|
|
ok(false, "tap fired");
|
|
tap = true;
|
|
});
|
|
|
|
//NOTE make sure movement is recorded
|
|
mockAbs(100);
|
|
|
|
//NOTE start and move right away
|
|
$( "#qunit-fixture" ).trigger("touchstart");
|
|
$( "#qunit-fixture" ).trigger("touchmove");
|
|
|
|
//NOTE end touch sequence after 20 ms
|
|
setTimeout(function(){
|
|
$( "#qunit-fixture" ).trigger("touchend");
|
|
}, 20);
|
|
|
|
setTimeout(function(){
|
|
ok(!tap, "not tapped");
|
|
start();
|
|
}, 40);
|
|
});
|
|
|
|
asyncTest( "tap event propagates up DOM tree", function(){
|
|
var tap = 0,
|
|
$qf = $( "#qunit-fixture" ),
|
|
$doc = $( document ),
|
|
docTapCB = function(){
|
|
same(++tap, 2, "document tap callback called once after #qunit-fixture callback");
|
|
};
|
|
|
|
$qf.bind( "tap", function() {
|
|
same(++tap, 1, "#qunit-fixture tap callback called once");
|
|
});
|
|
|
|
$doc.bind( "tap", docTapCB );
|
|
|
|
$qf.trigger( "vmousedown" )
|
|
.trigger( "vmouseup" )
|
|
.trigger( "vclick" );
|
|
|
|
// tap binding should be triggered twice, once for
|
|
// #qunit-fixture, and a second time for document.
|
|
same( tap, 2, "final tap callback count is 2" );
|
|
|
|
$doc.unbind( "tap", docTapCB );
|
|
|
|
start();
|
|
});
|
|
|
|
asyncTest( "stopPropagation() prevents tap from propagating up DOM tree", function(){
|
|
var tap = 0,
|
|
$qf = $( "#qunit-fixture" ),
|
|
$doc = $( document ),
|
|
docTapCB = function(){
|
|
ok(false, "tap should NOT be triggered on document");
|
|
};
|
|
|
|
$qf.bind( "tap", function(e) {
|
|
same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
|
|
e.stopPropagation();
|
|
})
|
|
.bind( "tap", function(e) {
|
|
same(++tap, 2, "tap callback 2 triggered once on #qunit-fixture");
|
|
});
|
|
|
|
$doc.bind( "tap", docTapCB);
|
|
|
|
$qf.trigger( "vmousedown" )
|
|
.trigger( "vmouseup" )
|
|
.trigger( "vclick" );
|
|
|
|
// tap binding should be triggered twice.
|
|
same( tap, 2, "final tap count is 2" );
|
|
|
|
$doc.unbind( "tap", docTapCB );
|
|
|
|
start();
|
|
});
|
|
|
|
asyncTest( "stopImmediatePropagation() prevents tap propagation and execution of 2nd handler", function(){
|
|
var tap = 0,
|
|
$cf = $( "#qunit-fixture" );
|
|
$doc = $( document ),
|
|
docTapCB = function(){
|
|
ok(false, "tap should NOT be triggered on document");
|
|
};
|
|
|
|
// Bind 2 tap callbacks on qunit-fixture. Only the first
|
|
// one should ever be called.
|
|
$cf.bind( "tap", function(e) {
|
|
same(++tap, 1, "tap callback 1 triggered once on #qunit-fixture");
|
|
e.stopImmediatePropagation();
|
|
})
|
|
.bind( "tap", function(e) {
|
|
ok(false, "tap callback 2 should NOT be triggered on #qunit-fixture");
|
|
});
|
|
|
|
$doc.bind( "tap", docTapCB);
|
|
|
|
$cf.trigger( "vmousedown" )
|
|
.trigger( "vmouseup" )
|
|
.trigger( "vclick" );
|
|
|
|
// tap binding should be triggered once.
|
|
same( tap, 1, "final tap count is 1" );
|
|
|
|
$doc.unbind( "tap", docTapCB );
|
|
|
|
start();
|
|
});
|
|
|
|
var swipeTimedTest = function(opts){
|
|
var swipe = false;
|
|
|
|
forceTouchSupport();
|
|
|
|
$( "#qunit-fixture" ).bind('swipe', function(){
|
|
swipe = true;
|
|
});
|
|
|
|
//NOTE bypass the trigger source check
|
|
$.Event.prototype.originalEvent = {
|
|
touches: false
|
|
};
|
|
|
|
$( "#qunit-fixture" ).trigger("touchstart");
|
|
|
|
//NOTE make sure the coordinates are calculated within range
|
|
// to be registered as a swipe
|
|
mockAbs(opts.coordChange);
|
|
|
|
setTimeout(function(){
|
|
$( "#qunit-fixture" ).trigger("touchmove");
|
|
$( "#qunit-fixture" ).trigger("touchend");
|
|
}, opts.timeout + 100);
|
|
|
|
setTimeout(function(){
|
|
same(swipe, opts.expected, "swipe expected");
|
|
start();
|
|
}, opts.timeout + 200);
|
|
|
|
stop();
|
|
};
|
|
|
|
test( "swipe fired when coordinate change in less than a second", function(){
|
|
swipeTimedTest({ timeout: 10, coordChange: 35, expected: true });
|
|
});
|
|
|
|
test( "swipe not fired when coordinate change takes more than a second", function(){
|
|
swipeTimedTest({ timeout: 1000, coordChange: 35, expected: false });
|
|
});
|
|
|
|
test( "swipe not fired when coordinate change <= 30", function(){
|
|
swipeTimedTest({ timeout: 1000, coordChange: 30, expected: false });
|
|
});
|
|
|
|
test( "swipe not fired when coordinate change >= 75", function(){
|
|
swipeTimedTest({ timeout: 1000, coordChange: 75, expected: false });
|
|
});
|
|
|
|
asyncTest( "scrolling prevented when coordinate change > 10", function(){
|
|
expect( 1 );
|
|
|
|
forceTouchSupport();
|
|
|
|
// ensure the swipe custome event is setup
|
|
$( "#qunit-fixture" ).bind('swipe', function(){});
|
|
|
|
//NOTE bypass the trigger source check
|
|
$.Event.prototype.originalEvent = {
|
|
touches: false
|
|
};
|
|
|
|
$.Event.prototype.preventDefault = function(){
|
|
ok(true, "prevent default called");
|
|
start();
|
|
};
|
|
|
|
mockAbs(11);
|
|
|
|
$( "#qunit-fixture" ).trigger("touchstart");
|
|
$( "#qunit-fixture" ).trigger("touchmove");
|
|
});
|
|
|
|
asyncTest( "move handler returns when touchstart has been fired since touchstop", function(){
|
|
expect( 1 );
|
|
|
|
// bypass triggered event check
|
|
$.Event.prototype.originalEvent = {
|
|
touches: false
|
|
};
|
|
|
|
forceTouchSupport();
|
|
|
|
// ensure the swipe custome event is setup
|
|
$( "#qunit-fixture" ).bind('swipe', function(){});
|
|
|
|
$( "#qunit-fixture" ).trigger("touchstart");
|
|
$( "#qunit-fixture" ).trigger("touchend");
|
|
|
|
$( "#qunit-fixture" ).bind("touchmove", function(){
|
|
ok(true, "touchmove bound functions are fired");
|
|
start();
|
|
});
|
|
|
|
Math.abs = function(){
|
|
ok(false, "shouldn't compare coordinates");
|
|
};
|
|
|
|
$( "#qunit-fixture" ).trigger("touchmove");
|
|
});
|
|
|
|
var nativeSupportTest = function(opts){
|
|
$.support.orientation = opts.orientationSupport;
|
|
same($.event.special.orientationchange[opts.method](), opts.returnValue);
|
|
};
|
|
|
|
test( "orientation change setup should do nothing when natively supported", function(){
|
|
nativeSupportTest({
|
|
method: 'setup',
|
|
orientationSupport: true,
|
|
returnValue: false
|
|
});
|
|
});
|
|
|
|
test( "orientation change setup should bind resize when not supported natively", function(){
|
|
nativeSupportTest({
|
|
method: 'setup',
|
|
orientationSupport: false,
|
|
returnValue: undefined //NOTE result of bind function call
|
|
});
|
|
});
|
|
|
|
test( "orientation change teardown should do nothing when natively supported", function(){
|
|
nativeSupportTest({
|
|
method: 'teardown',
|
|
orientationSupport: true,
|
|
returnValue: false
|
|
});
|
|
});
|
|
|
|
test( "orientation change teardown should unbind resize when not supported natively", function(){
|
|
nativeSupportTest({
|
|
method: 'teardown',
|
|
orientationSupport: false,
|
|
returnValue: undefined //NOTE result of unbind function call
|
|
});
|
|
});
|
|
|
|
/* The following 4 tests are async so that the throttled event triggers don't interfere with subsequent tests */
|
|
|
|
asyncTest( "throttledresize event proxies resize events", function(){
|
|
$( window ).one( "throttledresize", function(){
|
|
ok( true, "throttledresize called");
|
|
start();
|
|
});
|
|
|
|
$( window ).trigger( "resize" );
|
|
});
|
|
|
|
asyncTest( "throttledresize event prevents resize events from firing more frequently than 250ms", function(){
|
|
var called = 0;
|
|
|
|
$(window).bind( "throttledresize", function(){
|
|
called++;
|
|
});
|
|
|
|
// NOTE 250 ms * 3 = 750ms which is plenty of time
|
|
// for the events to trigger before the next test, but
|
|
// not so much time that the second resize will be triggered
|
|
// before the call to same() is made
|
|
$.testHelper.sequence([
|
|
function(){
|
|
$(window).trigger( "resize" ).trigger( "resize" );
|
|
},
|
|
|
|
// verify that only one throttled resize was called after 250ms
|
|
function(){ same( called, 1 ); },
|
|
|
|
function(){
|
|
start();
|
|
}
|
|
], 250);
|
|
});
|
|
|
|
asyncTest( "throttledresize event promises that a held call will execute only once after throttled timeout", function(){
|
|
var called = 0;
|
|
|
|
expect( 2 );
|
|
|
|
$.testHelper.eventSequence( "throttledresize", [
|
|
// ignore the first call
|
|
$.noop,
|
|
|
|
function(){
|
|
ok( true, "second throttled resize should run" );
|
|
},
|
|
|
|
function(timedOut){
|
|
ok( timedOut, "third throttled resize should not run");
|
|
start();
|
|
}
|
|
]);
|
|
|
|
$.mobile.pageContainer
|
|
.trigger( "resize" )
|
|
.trigger( "resize" )
|
|
.trigger( "resize" );
|
|
});
|
|
})(jQuery);
|