Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Fixes #12569, Feature detect for oldIE/Chrome event bubbling #1054

Closed
wants to merge 5 commits into from

5 participants

Oleg Gaidarenko Rick Waldron Dave Methvin Timo Tijhof Richard Gibson
Oleg Gaidarenko
Collaborator

CSP error is not triggered here, div element has onsubmit and onchange properties, but does not have onfocusin, but it's fine, because you can't bind focusin/focusout events by defining onfocusin/onfocusout prop. Meaning that string in onfocusin will not be "evaled".

Also, in this patch, jQuery.support.focusinBubbles will be true for Chrome and Opera.

/cc @dmethvin

Rick Waldron
Collaborator

@orkel this looks great. Can you add a comment in the source that explains the removal of the IE inference condition—Thanks!

Dave Methvin
Owner

Ah! So Chrome has decided that they just won't support the magical onfocusin inline, so it won't be turned into a function!

Dave Methvin dmethvin closed this
Rick Waldron
Collaborator

Don't think you meant to close this ;)

Rick Waldron rwaldron reopened this
src/support.js
@@ -259,14 +250,23 @@ jQuery.support = (function() {
body.style.zoom = 1;
}
+ if ( !support.focusinBubbles && div.addEventListener ) {
+ div.addEventListener( "focusin", function() {
+ support.focusinBubbles = true;
+ }, false );
+
+ div.appendChild( input );
+ input.focus();
+ }
+
Richard Gibson Collaborator

Thanks for this pull!

You can save six bytes by moving the new block to be the first test after defining div and using isSupported instead of focusinBubbles (since they're identical at that point). If you do so, though, please include a comment to that effect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Oleg Gaidarenko
Collaborator
this looks great

Apparently i submitted this patch too soon.
I rewrite it, with a small refactoring of support module, now it's bigger then i want it to be.

src/event.js
((23 lines not shown))
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ } else {
+
+ // Correct focusin/focusout "bubbling"
+ jQuery.event.special[ orig ].preDispatch = function( event, handlers ) {
+
+ // If we have corresponded events, wait until they fire first
+ if ( handlers[ fix ] ) {
+ setTimeout(function( self ) {
+ jQuery.event.dispatch.call( self, event );
+ }, 0, this );
Richard Gibson Collaborator

On the first point, I'm saying that the anonymous function passed to setTimeout should not have any parameters, but instead close over a var self = this; defined in the outer preDispatch function.

On the second, my intuition was wrong, but you can still save 27 bytes by replacing function fixFocus() {… with fixFocus = function() {…, 5 from moving the fixFocus() call to the very end, and 6 from rearranging jQuery.event.dispatch variables (a total of -38): gibson042@orkel:12569...gibson042:orkel_12569

Oleg Gaidarenko Collaborator
markelog added a note
On the first point

Yeah, i get that, i'm asking why two arguments should be passed to setTimeout function.

You propose this –

setTimeout(function() {
    jQuery.event.dispatch.call( self, event );
}, 0 );

right?

Why not –

setTimeout(function() {
    jQuery.event.dispatch.call( self, event );
});

?

total of -38

Awesome! Can you open pull request to my branch?

Richard Gibson Collaborator

Pass the 0 for consistency, compressibility, and maximum browser support. And I tried a pull request, but couldn't select your repo. Just cherry-pick 775f634.

Oleg Gaidarenko Collaborator
markelog added a note
maximum browser support

All browsers are support that

compressibility

It saves additional 2 bytes

consistency

And 10 bytes if this style will be used in all instances of setTimeout called with second argument being 0 or 1 in the source.

Richard Gibson Collaborator

Cool. Do it as , 0 ) here and open a new PR to standardize the other calls... you might even want to use #10417.

Oleg Gaidarenko Collaborator
markelog added a note

i will start working on that, thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Oleg Gaidarenko
Collaborator

I cherry-picked @gibson042 commit and simplified couple more things

Dave Methvin
Owner

Ouch! This is now +58 against current master. Also, from painful recent experience with focus/blur I am worried this may change behavior yet again. Our only reason for wanting this is that we are currently not using native focusin for Chrome, is that right?, I'm not sure I want to fix it that badly

Oleg Gaidarenko
Collaborator

@dmethvin

Our only reason for wanting this is that we are currently not using native focusin for Chrome, is that right?

All WebKit-based browsers and Opera.

from painful recent experience with focus/blur I am worried this may change behavior yet again.

Fair enough, although i'm sure this fix would be sufficent.

This PR accommodate two patches:
1) Improve feature detect for oldIE event bubbling (#12569)
2) Stop shimming focusin/focusout events

First one can actually save some bytes, second, not so much (+120 bytes or so).
I will try to work on first one in different pull, and forget the second one.

Oleg Gaidarenko markelog closed this
Timo Tijhof

Followed up by pull request gh-1076.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 10, 2012
  1. Oleg Gaidarenko

    Fixes #12569

    markelog authored
  2. Richard Gibson Oleg Gaidarenko

    reduce size

    gibson042 authored markelog committed
  3. Oleg Gaidarenko
  4. Oleg Gaidarenko
  5. Oleg Gaidarenko

    Add a comment

    markelog authored
This page is out of date. Refresh to see the latest.
101 src/event.js
View
@@ -2,7 +2,52 @@ var rformElems = /^(?:input|select|textarea)$/i,
rkeyEvent = /^key/,
rmouseEvent = /^(?:mouse|contextmenu)|click/,
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
- rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)$/,
+
+ // Fixing focusin/focusout events must wait for document.body
+ fixFocus = function() {
+ if ( !jQuery.support.focusinBubbles || !jQuery.support.focusOrder ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler while someone wants focusin/focusout
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ // Create "bubbling" focus and blur events
+ if ( !jQuery.support.focusinBubbles ) {
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ } else {
+
+ // Correct focusin/focusout "bubbling"
+ jQuery.event.special[ orig ].preDispatch = function( event, handlers ) {
+ var self = this;
+
+ // If we have corresponded events, wait until they fire first
+ if ( handlers[ fix ] ) {
+ setTimeout(function() {
+ jQuery.event.dispatch.call( self, event );
+ }, 0 );
+
+ return false;
+ }
+ };
+ }
+ });
+ }
+ };
/*
* Helper functions for managing events -- not part of the public interface.
@@ -328,23 +373,25 @@ jQuery.event = {
},
dispatch: function( event ) {
+ var i, j, cur, ret, selMatch, matched, matches, handleObj, sel, handlers, delegateCount, special,
+ handlerQueue = [],
+ args = core_slice.call( arguments ),
+ events = jQuery._data( this, "events" ) || {},
+ isNative = !event[ jQuery.expando ];
- // Make a writable jQuery.Event from the native event object
- event = jQuery.event.fix( event );
+ // Make a writable jQuery.Event from the native event object if required
+ event = isNative ? jQuery.event.fix( event ) : event;
- var i, j, cur, ret, selMatch, matched, matches, handleObj, sel,
- handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
- delegateCount = handlers.delegateCount,
- args = core_slice.call( arguments ),
- special = jQuery.event.special[ event.type ] || {},
- handlerQueue = [];
+ handlers = events[ event.type ] || [];
+ special = jQuery.event.special[ event.type ] || {};
+ delegateCount = handlers.delegateCount;
// Use the fix-ed jQuery.Event rather than the (read-only) native event
args[0] = event;
event.delegateTarget = this;
// Call the preDispatch hook for the mapped type, and let it bail if desired
- if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ if ( isNative && special.preDispatch && special.preDispatch.call( this, event, events ) === false ) {
return;
}
@@ -818,31 +865,6 @@ if ( !jQuery.support.changeBubbles ) {
};
}
-// Create "bubbling" focus and blur events
-if ( !jQuery.support.focusinBubbles ) {
- jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
-
- // Attach a single capturing handler while someone wants focusin/focusout
- var attaches = 0,
- handler = function( event ) {
- jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
- };
-
- jQuery.event.special[ fix ] = {
- setup: function() {
- if ( attaches++ === 0 ) {
- document.addEventListener( orig, handler, true );
- }
- },
- teardown: function() {
- if ( --attaches === 0 ) {
- document.removeEventListener( orig, handler, true );
- }
- }
- };
- });
-}
-
jQuery.fn.extend({
on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
@@ -992,3 +1014,12 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl
jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
}
});
+
+// We have to wait until document is loaded, support tests rely on that
+// In case jQuery is placed in the end of the document, we have to check for body element
+if ( document.body ) {
+ fixFocus();
+
+} else {
+ jQuery( fixFocus );
+}
124 src/support.js
View
@@ -1,16 +1,6 @@
jQuery.support = (function() {
- var support,
- all,
- a,
- select,
- opt,
- input,
- fragment,
- eventName,
- i,
- isSupported,
- clickFn,
+ var support, all, a, select, opt, input, fragment, eventName, isSupported, i,
div = document.createElement("div");
// Setup
@@ -82,9 +72,7 @@ jQuery.support = (function() {
boxModel: ( document.compatMode === "CSS1Compat" ),
// Will be defined later
- submitBubbles: true,
- changeBubbles: true,
- focusinBubbles: false,
+ focusOrder: true,
deleteExpando: true,
noCloneEvent: true,
inlineBlockNeedsLayout: false,
@@ -111,16 +99,6 @@ jQuery.support = (function() {
support.deleteExpando = false;
}
- if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
- div.attachEvent( "onclick", clickFn = function() {
- // Cloning a node shouldn't copy over any
- // bound event handlers (IE does this)
- support.noCloneEvent = false;
- });
- div.cloneNode( true ).fireEvent("onclick");
- div.detachEvent( "onclick", clickFn );
- }
-
// Check if a radio maintains its value
// after being appended to the DOM
input = document.createElement("input");
@@ -128,14 +106,13 @@ jQuery.support = (function() {
input.setAttribute( "type", "radio" );
support.radioValue = input.value === "t";
- input.setAttribute( "checked", "checked" );
+ input.setAttribute( "checked", "t" );
// #11217 - WebKit loses check when the name is after the checked attribute
input.setAttribute( "name", "t" );
- div.appendChild( input );
fragment = document.createDocumentFragment();
- fragment.appendChild( div.lastChild );
+ fragment.appendChild( input );
// WebKit doesn't clone checked state correctly in fragments
support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
@@ -144,39 +121,45 @@ jQuery.support = (function() {
// value of true after appended to the DOM (IE6/7)
support.appendChecked = input.checked;
- fragment.removeChild( input );
- fragment.appendChild( div );
-
// Technique from Juriy Zaytsev
// http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
- // We only care about the case where non-standard event systems
- // are used, namely in IE. Short-circuiting here helps us to
- // avoid an eval call (in setAttribute) which can cause CSP
- // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
- if ( div.attachEvent ) {
- for ( i in {
- submit: true,
- change: true,
- focusin: true
- }) {
- eventName = "on" + i;
- isSupported = ( eventName in div );
- if ( !isSupported ) {
- div.setAttribute( eventName, "return;" );
- isSupported = ( typeof div[ eventName ] === "function" );
- }
- support[ i + "Bubbles" ] = isSupported;
+ // If you want to change this tests, check it for CSP restrictions (https://developer.mozilla.org/en/Security/CSP), in test/csp.php
+ for ( i in {
+ submit: true,
+ change: true,
+ focusin: true
+ }) {
+ eventName = "on" + i;
+ isSupported = ( eventName in div );
+ if ( !isSupported ) {
+ div.setAttribute( eventName, " " );
+ isSupported = typeof div[ eventName ] === "function";
}
+
+ support[ i + "Bubbles" ] = isSupported;
+ }
+
+ // Cloning a node shouldn't copy over any
+ // bound event handlers (IE does this)
+ if ( div.attachEvent ) {
+ div.attachEvent( "onclick", function() {
+ support.noCloneEvent = false;
+ });
+
+ // attachEvent method exist in Opera and IE9-10, but for them noCloneEvent property will still be true -
+ // Opera does not clone events, IE9-10 does, but only events binded through attachEvent,
+ // those cloned events cannot be triggered like that, you can do that only though fireEvent method.
+ // And that's good, because for these browsers we use addEventListerner method.
+ div.cloneNode( true ).click();
}
div.style.backgroundClip = "content-box";
div.cloneNode( true ).style.backgroundClip = "";
support.clearCloneStyle = div.style.backgroundClip === "content-box";
- // Run tests that need a body at doc ready
- jQuery(function() {
- var container, div, tds, marginDiv,
- divReset = "padding:0;margin:0;border:0;display:block;overflow:hidden;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
+ function withBody() {
+ var container, div, tds, marginDiv, order,
+ divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",
body = document.getElementsByTagName("body")[0];
if ( !body ) {
@@ -185,12 +168,10 @@ jQuery.support = (function() {
}
container = document.createElement("div");
- container.style.cssText = "visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px";
- body.insertBefore( container, body.firstChild );
+ container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";
// Construct the test element
- div = document.createElement("div");
- container.appendChild( div );
+ div = body.appendChild( container ).appendChild( document.createElement("div") );
// Check if table cells still have offsetWidth/Height when they are set
// to display:none and there are still other visible table cells in a
@@ -228,11 +209,11 @@ jQuery.support = (function() {
// info see bug #3333
// Fails in WebKit before Feb 2011 nightlies
// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
- marginDiv = document.createElement("div");
+ marginDiv = div.appendChild( document.createElement("div") );
marginDiv.style.cssText = div.style.cssText = divReset;
marginDiv.style.marginRight = marginDiv.style.width = "0";
div.style.width = "1px";
- div.appendChild( marginDiv );
+
support.reliableMarginRight =
!parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight );
}
@@ -249,7 +230,6 @@ jQuery.support = (function() {
// Check if elements with layout shrink-wrap their children
// (IE 6 does this)
div.style.display = "block";
- div.style.overflow = "visible";
div.innerHTML = "<div></div>";
div.firstChild.style.width = "5px";
support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
@@ -259,14 +239,34 @@ jQuery.support = (function() {
body.style.zoom = 1;
}
+ if ( div.addEventListener ) {
+ input.addEventListener( "focus", function() {
+ order = true;
+ }, false );
+
+ div.addEventListener( "focusin", function() {
+ support.focusinBubbles = true;
+ support.focusOrder = !order;
+ }, false );
+
+ div.appendChild( input ).focus();
+ }
+
// Null elements to avoid leaks in IE
body.removeChild( container );
- container = div = tds = marginDiv = null;
- });
+ container = div = tds = input = marginDiv = null;
+ }
+
+ // Run tests that need a body
+ if ( document.body ) {
+ withBody();
+
+ } else {
+ jQuery( withBody );
+ }
// Null elements to avoid leaks in IE
- fragment.removeChild( div );
- all = a = select = opt = input = fragment = div = null;
+ all = a = select = opt = fragment = div = null;
return support;
})();
5 test/csp.php
View
@@ -1,4 +1,7 @@
-<?php header("X-Content-Security-Policy-Report-Only: allow *"); ?>
+<?php
+ header("X-Content-Security-Policy: default-src localhost 'self';");
+ header("X-WebKit-CSP: script-src 'self'; style-src 'self' 'unsafe-inline'");
+?>
<!DOCTYPE html>
<html>
<head>
26 test/unit/event.js
View
@@ -3104,4 +3104,30 @@ test( "Namespace preserved when passed an Event (#12739)", function() {
equal( triggered, 3, "foo.bar triggered" );
});
+test( "Check order of focusin/focusout events", 2, function() {
+ var focus, blur,
+ input = jQuery("#name");
+
+ input.on("focus", function() {
+ focus = true;
+
+ }).on("focusin", function() {
+ ok( !focus, "Focusin event should fire before focus does" );
+
+ }).on("blur", function() {
+ blur = true;
+
+ }).on("focusout", function() {
+ ok( !blur, "Focusout event should fire before blur does" );
+ });
+
+ // gain focus
+ input.focus();
+
+ // then lose it
+ jQuery("#search").focus();
+
+ // cleanup
+ input.off();
+});
131 test/unit/support.js
View
@@ -44,13 +44,12 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
});
(function() {
-
- var userAgent = window.navigator.userAgent,
- expected;
+ var expected,
+ userAgent = window.navigator.userAgent;
// These tests do not have to stay
// They are here to help with upcoming support changes for 1.8
- if ( /chrome\/19\.0/i.test(userAgent) ) {
+ if ( /chrome/i.test( userAgent ) ) {
expected = {
"leadingWhitespace":true,
"tbody":true,
@@ -66,7 +65,8 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"html5Clone":true,
"submitBubbles":true,
"changeBubbles":true,
- "focusinBubbles":false,
+ "focusOrder": false,
+ "focusinBubbles":true,
"deleteExpando":true,
"noCloneEvent":true,
"inlineBlockNeedsLayout":false,
@@ -83,7 +83,109 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"cors":true,
"doesNotIncludeMarginInBodyOffset":true
};
- } else if ( /msie 8\.0/i.test(userAgent) ) {
+ } else if ( /opera/i.test( userAgent ) ) {
+ expected = {
+ "leadingWhitespace":true,
+ "tbody":true,
+ "htmlSerialize":true,
+ "style":true,
+ "hrefNormalized":true,
+ "opacity":true,
+ "cssFloat":true,
+ "checkOn":true,
+ "optSelected":true,
+ "getSetAttribute":true,
+ "enctype":true,
+ "html5Clone":true,
+ "submitBubbles":true,
+ "changeBubbles":true,
+ "focusOrder": false,
+ "focusinBubbles":true,
+ "deleteExpando":true,
+ "noCloneEvent":true,
+ "inlineBlockNeedsLayout":false,
+ "shrinkWrapBlocks":false,
+ "reliableMarginRight":true,
+ "noCloneChecked":true,
+ "optDisabled":true,
+ "radioValue":false,
+ "checkClone":true,
+ "appendChecked":true,
+ "boxModel":true,
+ "reliableHiddenOffsets":true,
+ "ajax":true,
+ "cors":true,
+ "doesNotIncludeMarginInBodyOffset":true
+ };
+ } else if ( /msie 10\.0/i.test( userAgent ) ) {
+ expected = {
+ "leadingWhitespace":true,
+ "tbody":true,
+ "htmlSerialize":true,
+ "style":true,
+ "hrefNormalized":true,
+ "opacity":true,
+ "cssFloat":true,
+ "checkOn":true,
+ "optSelected":false,
+ "getSetAttribute":true,
+ "enctype":true,
+ "html5Clone":true,
+ "submitBubbles":true,
+ "changeBubbles":true,
+ "focusOrder": true,
+ "focusinBubbles":true,
+ "deleteExpando":true,
+ "noCloneEvent":true,
+ "inlineBlockNeedsLayout":false,
+ "shrinkWrapBlocks":false,
+ "reliableMarginRight":true,
+ "noCloneChecked":false,
+ "optDisabled":true,
+ "radioValue":false,
+ "checkClone":true,
+ "appendChecked":true,
+ "boxModel":true,
+ "reliableHiddenOffsets":true,
+ "ajax":true,
+ "cors":true,
+ "doesNotIncludeMarginInBodyOffset":true
+ };
+ } else if ( /msie 9\.0/i.test( userAgent ) ) {
+ expected = {
+ "leadingWhitespace":true,
+ "tbody":true,
+ "htmlSerialize":true,
+ "style":true,
+ "hrefNormalized":true,
+ "opacity":true,
+ "cssFloat":true,
+ "checkOn":true,
+ "optSelected":false,
+ "getSetAttribute":true,
+ "enctype":true,
+ "html5Clone":true,
+ "submitBubbles":true,
+ "changeBubbles":true,
+ "focusOrder": true,
+ "focusinBubbles":true,
+ "deleteExpando":true,
+ "noCloneEvent":true,
+ "inlineBlockNeedsLayout":false,
+ "shrinkWrapBlocks":false,
+ "reliableMarginRight":true,
+ "noCloneChecked":false,
+ "optDisabled":true,
+ "radioValue":false,
+ "checkClone":true,
+ "appendChecked":true,
+ "boxModel":true,
+ "reliableHiddenOffsets":true,
+ "ajax":true,
+ "cors":false,
+ "doesNotIncludeMarginInBodyOffset":true
+ };
+ } else if ( /msie 8\.0/i.test( userAgent ) ) {
expected = {
"leadingWhitespace":false,
"tbody":true,
@@ -99,6 +201,7 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"html5Clone":false,
"submitBubbles":false,
"changeBubbles":false,
+ "focusOrder": true,
"focusinBubbles":true,
"deleteExpando":false,
"noCloneEvent":false,
@@ -116,7 +219,7 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"cors":false,
"doesNotIncludeMarginInBodyOffset":true
};
- } else if ( /msie 7\.0/i.test(userAgent) ) {
+ } else if ( /msie 7\.0/i.test( userAgent ) ) {
expected = {
"ajax": true,
"appendChecked": false,
@@ -129,6 +232,7 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"deleteExpando": false,
"doesNotIncludeMarginInBodyOffset": true,
"enctype": true,
+ "focusOrder": true,
"focusinBubbles": true,
"getSetAttribute": false,
"hrefNormalized": false,
@@ -149,7 +253,7 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"tbody": false,
"style": false
};
- } else if ( /msie 6\.0/i.test(userAgent) ) {
+ } else if ( /msie 6\.0/i.test( userAgent ) ) {
expected = {
"leadingWhitespace":false,
"tbody":false,
@@ -165,6 +269,7 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"html5Clone":false,
"submitBubbles":false,
"changeBubbles":false,
+ "focusOrder": true,
"focusinBubbles":true,
"deleteExpando":false,
"noCloneEvent":false,
@@ -182,7 +287,7 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"cors":false,
"doesNotIncludeMarginInBodyOffset":true
};
- } else if ( /5\.1\.1 safari/i.test(userAgent) ) {
+ } else if ( /5\.1\.1 safari/i.test( userAgent ) ) {
expected = {
"leadingWhitespace":true,
"tbody":true,
@@ -198,6 +303,7 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"html5Clone":true,
"submitBubbles":true,
"changeBubbles":true,
+ "focusOrder": true,
"focusinBubbles":false,
"deleteExpando":true,
"noCloneEvent":true,
@@ -215,7 +321,7 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"cors":true,
"doesNotIncludeMarginInBodyOffset":true
};
- } else if ( /firefox\/3\.6/i.test(userAgent) ) {
+ } else if ( /firefox/i.test( userAgent ) ) {
expected = {
"leadingWhitespace":true,
"tbody":true,
@@ -227,10 +333,11 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
"checkOn":true,
"optSelected":true,
"getSetAttribute":true,
- "enctype":false,
+ "enctype":true,
"html5Clone":true,
"submitBubbles":true,
"changeBubbles":true,
+ "focusOrder": true,
"focusinBubbles":false,
"deleteExpando":true,
"noCloneEvent":true,
@@ -252,7 +359,7 @@ testIframeWithCallback( "box-sizing does not affect jQuery.support.shrinkWrapBlo
if ( expected ) {
test("Verify that the support tests resolve as expected per browser", function() {
- expect( 30 );
+ expect( 31 );
for ( var i in expected ) {
if ( jQuery.ajax || i !== "ajax" && i !== "cors" ) {
Something went wrong with that request. Please try again.