Skip to content

Commit 37c3d08

Browse files
committed
Event: improve originalEvent hack
Ref 6df669f Ref gh-2336
1 parent e6a492d commit 37c3d08

File tree

2 files changed

+141
-6
lines changed

2 files changed

+141
-6
lines changed

src/event.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -648,17 +648,22 @@ jQuery.event = {
648648
}
649649
},
650650

651+
// Piggyback on a donor event to simulate a different one
651652
simulate: function( type, elem, event, bubble ) {
652-
// Piggyback on a donor event to simulate a different one.
653-
// Fake originalEvent to avoid donor's stopPropagation, but if the
654-
// simulated event prevents default then we do the same on the donor.
655653
var e = jQuery.extend(
656654
new jQuery.Event(),
657655
event,
658656
{
659657
type: type,
660-
isSimulated: true,
661-
originalEvent: {}
658+
isSimulated: true
659+
// Previously, `originalEvent: {}` was set here, so stopPropagation call
660+
// would not be triggered on donor event, since in our own
661+
// jQuery.event.stopPropagation function we had a check for existence of
662+
// originalEvent.stopPropagation method, so, consequently it would be a noop.
663+
//
664+
// Guard for simulated events was moved to jQuery.event.stopPropagation function
665+
// since `originalEvent` should point to the original event for the
666+
// constancy with other events and for more focused logic
662667
}
663668
);
664669
if ( bubble ) {
@@ -763,7 +768,8 @@ jQuery.Event.prototype = {
763768
var e = this.originalEvent;
764769

765770
this.isPropagationStopped = returnTrue;
766-
if ( !e ) {
771+
772+
if ( !e || this.isSimulated ) {
767773
return;
768774
}
769775
// If stopPropagation exists, run it on the original event

test/unit/event.js

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2686,6 +2686,135 @@ test( "Inline event result is returned (#13993)", function() {
26862686
equal( result, 42, "inline handler returned value" );
26872687
});
26882688

2689+
test( "preventDefault() on focusin does not throw exception", function( assert ) {
2690+
expect( 1 );
2691+
2692+
var done = assert.async(),
2693+
input = jQuery( "<input/>" ).appendTo( "#form" );
2694+
2695+
input.on( "focusin", function( event ) {
2696+
var exceptionCaught;
2697+
2698+
try {
2699+
event.preventDefault();
2700+
} catch ( theException ) {
2701+
exceptionCaught = theException;
2702+
}
2703+
2704+
assert.strictEqual( exceptionCaught, undefined,
2705+
"Preventing default on focusin throws no exception" );
2706+
2707+
done();
2708+
} ).trigger( "focus" );
2709+
} );
2710+
2711+
test( "Donor event interference", function( assert ) {
2712+
assert.expect( 10 );
2713+
2714+
var html = "<div id='donor-outer'>" +
2715+
"<form id='donor-form'>" +
2716+
"<input id='donor-input' type='radio' />" +
2717+
"</form>" +
2718+
"</div>";
2719+
2720+
jQuery( "#qunit-fixture" ).append( html );
2721+
2722+
jQuery( "#donor-outer" ).on( "click", function( event ) {
2723+
assert.ok( true, "click bubbled to outer div" );
2724+
assert.equal( typeof event.originalEvent, "object", "make sure originalEvent exist" );
2725+
assert.equal( event.type, "click", "make sure event type is correct" );
2726+
} );
2727+
jQuery( "#donor-input" ).on( "click", function( event ) {
2728+
assert.ok( true, "got a click event from the input" );
2729+
assert.ok( !event.isPropagationStopped(), "propagation says it's not stopped" );
2730+
assert.equal( event.type, "click", "make sure event type is correct" );
2731+
assert.equal( typeof event.originalEvent, "object", "make sure originalEvent exist" );
2732+
} );
2733+
jQuery( "#donor-input" ).on( "change", function( event ) {
2734+
assert.equal( typeof event.originalEvent, "object", "make sure originalEvent exist" );
2735+
assert.equal( event.type, "change", "make sure event type is correct" );
2736+
assert.ok( true, "got a change event from the input" );
2737+
event.stopPropagation();
2738+
} );
2739+
2740+
jQuery( "#donor-input" )[ 0 ].click();
2741+
} );
2742+
2743+
test( "originalEvent property for IE8", function( assert ) {
2744+
if ( !(/msie 8\.0/i.test( window.navigator.userAgent )) ) {
2745+
assert.expect( 1 );
2746+
assert.ok( true, "Assertions should run only in IE" );
2747+
return;
2748+
}
2749+
2750+
assert.expect( 12 );
2751+
2752+
var html = "<div id='donor-outer'>" +
2753+
"<form id='donor-form'>" +
2754+
"<input id='donor-input' type='radio' />" +
2755+
"</form>" +
2756+
"</div>";
2757+
2758+
jQuery( "#qunit-fixture" ).append( html );
2759+
2760+
jQuery( "#donor-outer" ).on( "change", function( event ) {
2761+
assert.ok( true, "click bubbled to outer div" );
2762+
assert.equal( event.originalEvent.type, "click", "make sure simulated event is a click" );
2763+
assert.equal( event.type, "change", "make sure event type is correct" );
2764+
} );
2765+
2766+
jQuery( "#donor-outer" ).on( "click", function( event ) {
2767+
assert.ok( true, "click bubbled to outer div" );
2768+
assert.equal( event.originalEvent.type, "click", "make sure originalEvent exist" );
2769+
} );
2770+
jQuery( "#donor-input" ).on( "click", function( event ) {
2771+
assert.ok( true, "got a click event from the input" );
2772+
assert.ok( !event.isPropagationStopped(), "propagation says it's not stopped" );
2773+
assert.equal( event.originalEvent.type, "click", "make sure originalEvent exist" );
2774+
assert.equal( event.type, "click", "make sure event type is correct" );
2775+
} );
2776+
jQuery( "#donor-input" ).on( "change", function( event ) {
2777+
assert.equal( event.originalEvent.type, "click", "make sure originalEvent exist" );
2778+
assert.equal( event.type, "change", "make sure event type is correct" );
2779+
assert.ok( true, "got a change event from the input" );
2780+
} );
2781+
2782+
jQuery( "#donor-input" )[ 0 ].click();
2783+
} );
2784+
2785+
test( "originalEvent property for Chrome, Safari and FF of simulated event", function( assert ) {
2786+
var userAgent = window.navigator.userAgent;
2787+
2788+
if ( !(/chrome/i.test( userAgent ) ||
2789+
/firefox/i.test( userAgent ) ||
2790+
/safari/i.test( userAgent ) ) ) {
2791+
assert.expect( 1 );
2792+
assert.ok( true, "Assertions should run only in Chrome, Safari and FF" );
2793+
return;
2794+
}
2795+
2796+
assert.expect( 4 );
2797+
2798+
var html = "<div id='donor-outer'>" +
2799+
"<form id='donor-form'>" +
2800+
"<input id='donor-input' type='radio' />" +
2801+
"</form>" +
2802+
"</div>";
2803+
2804+
jQuery( "#qunit-fixture" ).append( html );
2805+
2806+
jQuery( "#donor-outer" ).on( "focusin", function( event ) {
2807+
assert.ok( true, "focusin bubbled to outer div" );
2808+
assert.equal( event.originalEvent.type, "focus",
2809+
"make sure originalEvent type is correct" );
2810+
assert.equal( event.type, "focusin", "make sure type is correct" );
2811+
} );
2812+
jQuery( "#donor-input" ).on( "focus", function() {
2813+
assert.ok( true, "got a focus event from the input" );
2814+
} );
2815+
jQuery( "#donor-input" ).trigger( "focus" );
2816+
} );
2817+
26892818
// This tests are unreliable in Firefox
26902819
if ( !(/firefox/i.test( window.navigator.userAgent )) ) {
26912820
test( "Check order of focusin/focusout events", 2, function() {

0 commit comments

Comments
 (0)