]> source.dussan.org Git - jquery.git/commitdiff
Fix #12569. Improve feature detect for event bubbling. Close gh-1076.
authorOleg <markelog@gmail.com>
Mon, 17 Dec 2012 14:17:39 +0000 (18:17 +0400)
committerDave Methvin <dave.methvin@gmail.com>
Fri, 21 Dec 2012 03:08:32 +0000 (22:08 -0500)
src/support.js
test/csp.php
test/unit/event.js
test/unit/support.js

index 70f5f114dd4aaff1b521a5319af5d771cad1e97e..c99bb392222c9abdf33b6a1565997da4c9ea049b 100644 (file)
@@ -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;
 })();
+
index e3245149c47a975a0ea1a73ab4c483d7852076bd..9ab18f3920aaa9a7ae69b4325baba7d85fc140d2 100644 (file)
@@ -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>
index 32355c9ad5ee24712ff2b49c655df1332e717aa7..ff2ea1dd5147b04c1e06457c9b2711c1f2f865fd 100644 (file)
@@ -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();
+});
+
index 8d4ac21bcd7584ae4ab63ab3393c2021b03a70e4..94a871ee968588ae46da95ddfb4bccbf4cc33608 100644 (file)
@@ -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,