mirror of
https://github.com/jquery/jquery.git
synced 2026-01-23 04:28:22 -05:00
Fix #12569. Improve feature detect for event bubbling. Close gh-1076.
This commit is contained in:
112
src/support.js
112
src/support.js
@@ -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
|
||||
@@ -80,9 +70,6 @@ jQuery.support = (function() {
|
||||
boxModel: document.compatMode === "CSS1Compat",
|
||||
|
||||
// Will be defined later
|
||||
submitBubbles: true,
|
||||
changeBubbles: true,
|
||||
focusinBubbles: false,
|
||||
deleteExpando: true,
|
||||
noCloneEvent: true,
|
||||
inlineBlockNeedsLayout: false,
|
||||
@@ -101,24 +88,13 @@ jQuery.support = (function() {
|
||||
select.disabled = true;
|
||||
support.optDisabled = !opt.disabled;
|
||||
|
||||
// Test to see if it's possible to delete an expando from an element
|
||||
// Fails in Internet Explorer
|
||||
// Support: IE<9
|
||||
try {
|
||||
delete div.test;
|
||||
} catch( e ) {
|
||||
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 we can trust getAttribute("value")
|
||||
input = document.createElement("input");
|
||||
input.setAttribute( "value", "" );
|
||||
@@ -130,49 +106,42 @@ jQuery.support = (function() {
|
||||
support.radioValue = input.value === "t";
|
||||
|
||||
// #11217 - WebKit loses check when the name is after the checked attribute
|
||||
input.setAttribute( "checked", "checked" );
|
||||
input.setAttribute( "checked", "t" );
|
||||
input.setAttribute( "name", "t" );
|
||||
|
||||
div.appendChild( input );
|
||||
fragment = document.createDocumentFragment();
|
||||
fragment.appendChild( div.lastChild );
|
||||
|
||||
// WebKit doesn't clone checked state correctly in fragments
|
||||
support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
|
||||
fragment.appendChild( input );
|
||||
|
||||
// Check if a disconnected checkbox will retain its checked
|
||||
// value of true after appended to the DOM (IE6/7)
|
||||
support.appendChecked = input.checked;
|
||||
|
||||
fragment.removeChild( input );
|
||||
fragment.appendChild( div );
|
||||
// WebKit doesn't clone checked state correctly in fragments
|
||||
support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
|
||||
|
||||
// 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
|
||||
// Support: IE<9
|
||||
// Opera does not clone events (and typeof div.attachEvent === undefined).
|
||||
// IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
|
||||
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;
|
||||
}
|
||||
div.attachEvent( "onclick", function() {
|
||||
support.noCloneEvent = false;
|
||||
});
|
||||
|
||||
div.cloneNode( true ).click();
|
||||
}
|
||||
|
||||
// Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event)
|
||||
// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php
|
||||
for ( i in { submit: true, change: true, focusin: true }) {
|
||||
div.setAttribute( eventName = "on" + i, "t" );
|
||||
|
||||
support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false;
|
||||
}
|
||||
|
||||
// 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;",
|
||||
var container, marginDiv, tds,
|
||||
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 ) {
|
||||
@@ -181,20 +150,17 @@ 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 );
|
||||
body.appendChild( container ).appendChild( div );
|
||||
|
||||
// Support: IE8
|
||||
// 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
|
||||
// table row; if so, offsetWidth/Height are not reliable for use when
|
||||
// determining if an element has been hidden directly using
|
||||
// display:none (it is still safe to use offsets if a parent element is
|
||||
// hidden; don safety goggles and see bug #4512 for more information).
|
||||
// (only IE 8 fails this test)
|
||||
div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
|
||||
tds = div.getElementsByTagName("td");
|
||||
tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none";
|
||||
@@ -203,8 +169,8 @@ jQuery.support = (function() {
|
||||
tds[ 0 ].style.display = "";
|
||||
tds[ 1 ].style.display = "none";
|
||||
|
||||
// Support: IE8
|
||||
// Check if empty table cells still have offsetWidth/Height
|
||||
// (IE <= 8 fail this test)
|
||||
support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
|
||||
|
||||
// Check box-sizing and margin behavior
|
||||
@@ -213,39 +179,36 @@ jQuery.support = (function() {
|
||||
support.boxSizing = ( div.offsetWidth === 4 );
|
||||
support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 );
|
||||
|
||||
// NOTE: To any future maintainer, we've window.getComputedStyle
|
||||
// because jsdom on node.js will break without it.
|
||||
// Use window.getComputedStyle because jsdom on node.js will break without it.
|
||||
if ( window.getComputedStyle ) {
|
||||
support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
|
||||
support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
|
||||
|
||||
// Check if div with explicit width and no margin-right incorrectly
|
||||
// gets computed margin-right based on width of container. For more
|
||||
// info see bug #3333
|
||||
// gets computed margin-right based on width of container. (#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 );
|
||||
}
|
||||
|
||||
if ( typeof div.style.zoom !== "undefined" ) {
|
||||
// Support: IE<8
|
||||
// Check if natively block-level elements act like inline-block
|
||||
// elements when setting their display to 'inline' and giving
|
||||
// them layout
|
||||
// (IE < 8 does this)
|
||||
div.innerHTML = "";
|
||||
div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1";
|
||||
support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
|
||||
|
||||
// Support: IE6
|
||||
// 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 );
|
||||
@@ -255,14 +218,15 @@ jQuery.support = (function() {
|
||||
body.style.zoom = 1;
|
||||
}
|
||||
|
||||
// Null elements to avoid leaks in IE
|
||||
body.removeChild( container );
|
||||
|
||||
// Null elements to avoid leaks in IE
|
||||
container = div = tds = marginDiv = null;
|
||||
});
|
||||
|
||||
// Null elements to avoid leaks in IE
|
||||
fragment.removeChild( div );
|
||||
all = a = select = opt = input = fragment = div = null;
|
||||
all = select = fragment = opt = a = input = null;
|
||||
|
||||
return support;
|
||||
})();
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -2601,3 +2601,31 @@ test( "make sure events cloned correctly", 18, function() {
|
||||
clone.find("p:first").click(); // 0 should be fired
|
||||
clone.find("#check1").change(); // 0 events should fire
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ test("boxModel", function() {
|
||||
});
|
||||
|
||||
if ( jQuery.css ) {
|
||||
testIframeWithCallback( "body background is not lost if set prior to loading jQuery (#9238)", "support/bodyBackground.html", function( color, support ) {
|
||||
testIframeWithCallback( "body background is not lost if set prior to loading jQuery (#9239)", "support/bodyBackground.html", function( color, support ) {
|
||||
expect( 2 );
|
||||
var i,
|
||||
passed = true,
|
||||
@@ -29,6 +29,7 @@ if ( jQuery.css ) {
|
||||
strictEqual( jQuery.support[ i ], support[ i ], "Unexpected property: " + i );
|
||||
}
|
||||
}
|
||||
|
||||
ok( passed, "Same support properties" );
|
||||
});
|
||||
}
|
||||
@@ -44,13 +45,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,
|
||||
@@ -83,7 +83,106 @@ 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,
|
||||
"focusinBubbles":false,
|
||||
"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,
|
||||
"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,
|
||||
"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,
|
||||
@@ -116,7 +215,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,
|
||||
@@ -149,7 +248,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,
|
||||
@@ -182,7 +281,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,
|
||||
@@ -215,7 +314,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,7 +326,7 @@ 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,
|
||||
|
||||
Reference in New Issue
Block a user