diff options
author | Mike Sherov <mike.sherov@gmail.com> | 2012-04-23 15:43:26 -0400 |
---|---|---|
committer | Dave Methvin <dave.methvin@gmail.com> | 2012-04-23 15:44:27 -0400 |
commit | 54fab3174c7844959b374e98b453c048b60de0d0 (patch) | |
tree | 1cd99ad3c26d55537d02b03bc3828b5b3ec555ca | |
parent | 58ed62ed12cb48d9224f699e86e197804ca5ece4 (diff) | |
download | jquery-54fab3174c7844959b374e98b453c048b60de0d0.tar.gz jquery-54fab3174c7844959b374e98b453c048b60de0d0.zip |
Fix #10067. Create jQuery.quickReady; closes gh-736.
Allows us to get to the ready state sooner by not waiting for iframes to load. If that causes backcompat pain, use `jQuery.quickReady = false` as prescribed by your developer.
-rw-r--r-- | src/core.js | 16 | ||||
-rw-r--r-- | test/data/event/asyncQuickReadyFalse.html | 32 | ||||
-rw-r--r-- | test/data/event/asyncQuickReadyTrue.html | 30 | ||||
-rw-r--r-- | test/data/event/longLoad.php | 6 | ||||
-rw-r--r-- | test/data/event/syncReady.html | 17 | ||||
-rw-r--r-- | test/data/support/bodyBackground.html | 2 | ||||
-rw-r--r-- | test/data/support/boxModelIE.html | 2 | ||||
-rw-r--r-- | test/data/support/hiddenIFrameFF.html | 7 | ||||
-rw-r--r-- | test/data/support/testElementCrash.html | 7 | ||||
-rw-r--r-- | test/data/testinit.js | 25 | ||||
-rw-r--r-- | test/unit/event.js | 20 | ||||
-rw-r--r-- | test/unit/support.js | 33 |
12 files changed, 149 insertions, 48 deletions
diff --git a/src/core.js b/src/core.js index f317666ce..22f186336 100644 --- a/src/core.js +++ b/src/core.js @@ -375,6 +375,9 @@ jQuery.extend({ // the ready event fires. See #6781 readyWait: 1, + // should we fire ready on readyState "interactive" ? + quickReady: true, + // Hold (or release) the ready event holdReady: function( hold ) { if ( hold ) { @@ -386,6 +389,12 @@ jQuery.extend({ // Handle when the DOM is ready ready: function( wait ) { + // user wasn't necessarily given the chance to set jQuery.quickReady before bindReady + // so we check here for quickReady instead + if ( !jQuery.quickReady && document.readyState === "interactive" ) { + return; + } + // Either a released hold or an DOMready/load event and not yet ready if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). @@ -420,9 +429,9 @@ jQuery.extend({ // Catch cases where $(document).ready() is called after the // browser event has already occurred. - if ( document.readyState === "complete" ) { + if ( document.readyState !== "loading" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready - return setTimeout( jQuery.ready, 1 ); + setTimeout( jQuery.ready, 1 ); } // Mozilla, Opera and webkit nightlies currently support this event @@ -915,6 +924,7 @@ rootjQuery = jQuery(document); // Cleanup functions for the document ready method if ( document.addEventListener ) { DOMContentLoaded = function() { + jQuery.quickReady = true; document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); jQuery.ready(); }; @@ -922,7 +932,7 @@ if ( document.addEventListener ) { } else if ( document.attachEvent ) { DOMContentLoaded = function() { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( document.readyState === "complete" ) { + if ( document.readyState === "complete" || ( jQuery.quickReady && document.readyState === "interactive" ) ) { document.detachEvent( "onreadystatechange", DOMContentLoaded ); jQuery.ready(); } diff --git a/test/data/event/asyncQuickReadyFalse.html b/test/data/event/asyncQuickReadyFalse.html new file mode 100644 index 000000000..935269749 --- /dev/null +++ b/test/data/event/asyncQuickReadyFalse.html @@ -0,0 +1,32 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=utf-8"> +<title>Test case for jQuery ticket #10067</title> +<script type="text/javascript"> + +// ready should fire callback after the iframe fires the callback +setTimeout(function () { + el = document.createElement('script'); + el.type = 'text/javascript'; + el.onload = function () { + jQuery.quickReady = false; + jQuery(document).ready(function () { + // unfortunately, Opera 11.6 and lower has a bug where + // document.readyState is "complete" before all subresources + // are loaded, so we need this check here for tests to pass + if ( document.readyState !== "complete" ) { + window.parent.iframeCallback(false); + } + }); + } + document.getElementsByTagName('head')[0].appendChild(el); + el.src = "../include_js.php"; +}, 1000); +</script> +</head> +<body> +<!-- long loading iframe --> +<iframe src="longLoad.php?sleep=3&return=true" style="width: 1px; height: 1px"></iframe> +</body> +</html>
\ No newline at end of file diff --git a/test/data/event/asyncQuickReadyTrue.html b/test/data/event/asyncQuickReadyTrue.html new file mode 100644 index 000000000..cdcb82128 --- /dev/null +++ b/test/data/event/asyncQuickReadyTrue.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=utf-8"> +<title>Test case for jQuery ticket #10067</title> +<script type="text/javascript"> +// browsers that implement the non-standard event API will load the iframe +// before loading up jQuery, so quickReady has no effect here +if( document.attachEvent ){ + window.parent.iframeCallback(true); +} else { + setTimeout(function () { + el = document.createElement('script'); + el.type = 'text/javascript'; + el.onload = function () { + jQuery(document).ready(function () { + window.parent.iframeCallback(true); + }); + } + document.getElementsByTagName('head')[0].appendChild(el); + el.src = "../include_js.php"; + }, 1000); +} +</script> +</head> +<body> +<!-- long loading iframe --> +<iframe src="longLoad.php?sleep=30&return=false" style="width: 1px; height: 1px"></iframe> +</body> +</html>
\ No newline at end of file diff --git a/test/data/event/longLoad.php b/test/data/event/longLoad.php new file mode 100644 index 000000000..ba1d43f82 --- /dev/null +++ b/test/data/event/longLoad.php @@ -0,0 +1,6 @@ +<?php +sleep((int)$_GET['sleep']); +?> +<script type="text/javascript"> +window.parent.parent.iframeCallback(<?php echo $_GET['return'];?>); +</script>
\ No newline at end of file diff --git a/test/data/event/syncReady.html b/test/data/event/syncReady.html new file mode 100644 index 000000000..b9dbb2280 --- /dev/null +++ b/test/data/event/syncReady.html @@ -0,0 +1,17 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=utf-8"> +<title>Test case for jQuery ticket #10067</title> +<script type="text/javascript" src="../include_js.php"></script> +</head> +<body> +<script type="text/javascript"> +jQuery(document).ready(function () { + window.parent.iframeCallback(true); +}); +</script> +<!-- long loading iframe --> +<iframe src="longLoad.php?sleep=10&return=false" style="width: 1px; height: 1px"></iframe> +</body> +</html>
\ No newline at end of file diff --git a/test/data/support/bodyBackground.html b/test/data/support/bodyBackground.html index 0f12e75f9..4f0105a1d 100644 --- a/test/data/support/bodyBackground.html +++ b/test/data/support/bodyBackground.html @@ -21,7 +21,7 @@ </div> <script> jQuery(function() { - window.parent.supportCallback( jQuery( "body" ).css( "backgroundColor" ), jQuery.support ); + window.parent.iframeCallback( jQuery( "body" ).css( "backgroundColor" ), jQuery.support ); }); </script> </body> diff --git a/test/data/support/boxModelIE.html b/test/data/support/boxModelIE.html index ca647a281..24e4c6100 100644 --- a/test/data/support/boxModelIE.html +++ b/test/data/support/boxModelIE.html @@ -3,7 +3,7 @@ <body> <script src="../include_js.php"></script> <script> - jQuery(function() { window.parent.supportCallback( document.compatMode, jQuery.support.boxModel ) }); + jQuery(function() { window.parent.iframeCallback( document.compatMode, jQuery.support.boxModel ) }); </script> </body> </html> diff --git a/test/data/support/hiddenIFrameFF.html b/test/data/support/hiddenIFrameFF.html deleted file mode 100644 index c2dda8cd4..000000000 --- a/test/data/support/hiddenIFrameFF.html +++ /dev/null @@ -1,7 +0,0 @@ -<html> - <head> - <script src="../include_js.php"></script> - </head> - <body> - </body> -</html> diff --git a/test/data/support/testElementCrash.html b/test/data/support/testElementCrash.html index 583ca7b0f..6ef9651da 100644 --- a/test/data/support/testElementCrash.html +++ b/test/data/support/testElementCrash.html @@ -7,14 +7,11 @@ background: url('http://s1.postimage.org/2d2r8xih0/body_background.png'); } </style> - <script src="../../../src/core.js"></script> - <script src="../../../src/callbacks.js"></script> - <script src="../../../src/deferred.js"></script> - <script src="../../../src/support.js"></script> + <script src="../include_js.php"></script> </head> <body> <script> - window.parent.supportCallback(); + window.parent.iframeCallback(); </script> </body> </html> diff --git a/test/data/testinit.js b/test/data/testinit.js index 1f775c1d7..9a27f5287 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -192,7 +192,7 @@ function url(value) { }); function loadFixture() { - var src = "./data/" + fileName + ".html?" + parseInt( Math.random()*1000, 10 ), + var src = url("./data/" + fileName + ".html"), iframe = jQuery("<iframe />").css({ width: 500, height: 500, position: "absolute", top: -600, left: -600, visibility: "hidden" }).appendTo("body")[0]; @@ -200,6 +200,29 @@ function url(value) { return iframe; } }; + + this.testIframeWithCallback = function( title, fileName, func ) { + + test( title, function() { + var iframe; + + stop(); + window.iframeCallback = function() { + var self = this, + args = arguments; + setTimeout(function() { + window.iframeCallback = undefined; + iframe.remove(); + func.apply( self, args ); + func = function() {}; + start(); + }, 0 ); + }; + iframe = jQuery( "<div/>" ).append( + jQuery( "<iframe/>" ).attr( "src", url("./data/" + fileName + ".html") ) + ).appendTo( "body" ); + }); + } }()); // Sandbox start for great justice diff --git a/test/unit/event.js b/test/unit/event.js index 172f3a82a..545cc05bc 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -2794,6 +2794,26 @@ test("fixHooks extensions", function() { jQuery.event.fixHooks.click = saved; }); +testIframeWithCallback( "jQuery.ready sync load", "event/syncReady", function( isOk ) { + expect(1); + ok( isOk, "jQuery loaded synchronously fires ready before all sub-resources are loaded" ); +}); + +// async loaded tests expect jQuery to be loaded as a single file +// if we're not doing PHP concat, then we fall back to document.write +// which breaks order of execution on async loaded files +if ( hasPHP ) { + testIframeWithCallback( "jQuery.ready async load with quickReady true", "event/asyncQuickReadyTrue", function( isOk ) { + expect(1); + ok( isOk, "jQuery loaded asynchronously with quickReady true fires ready before all sub-resources are loaded" ); + }); + + testIframeWithCallback( "jQuery.ready async load with quickReady false", "event/asyncQuickReadyFalse", function( isOk ) { + expect(1); + ok( isOk, "jQuery loaded asynchronously with quickReady false fires ready after all sub-resources are loaded" ); + }); +} + (function(){ // This code must be run before DOM ready! var notYetReady, noEarlyExecution, diff --git a/test/unit/support.js b/test/unit/support.js index a9243be51..7582d4bc4 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -1,37 +1,10 @@ module("support", { teardown: moduleTeardown }); -function supportIFrameTest( title, url, noDisplay, func ) { - - if ( noDisplay !== true ) { - func = noDisplay; - noDisplay = false; - } - - test( title, function() { - var iframe; - - stop(); - window.supportCallback = function() { - var self = this, - args = arguments; - setTimeout( function() { - window.supportCallback = undefined; - iframe.remove(); - func.apply( self, args ); - start(); - }, 0 ); - }; - iframe = jQuery( "<div/>" ).css( "display", noDisplay ? "none" : "block" ).append( - jQuery( "<iframe/>" ).attr( "src", "data/support/" + url + ".html" ) - ).appendTo( "body" ); - }); -} - -supportIFrameTest( "proper boxModel in compatMode CSS1Compat (IE6 and IE7)", "boxModelIE", function( compatMode, boxModel ) { +testIframeWithCallback( "proper boxModel in compatMode CSS1Compat (IE6 and IE7)", "support/boxModelIE", function( compatMode, boxModel ) { ok( compatMode !== "CSS1Compat" || boxModel, "boxModel properly detected" ); }); -supportIFrameTest( "body background is not lost if set prior to loading jQuery (#9238)", "bodyBackground", function( color, support ) { +testIframeWithCallback( "body background is not lost if set prior to loading jQuery (#9238)", "support/bodyBackground", function( color, support ) { expect( 2 ); var i, passed = true, @@ -56,7 +29,7 @@ supportIFrameTest( "body background is not lost if set prior to loading jQuery ( ok( passed, "Same support properties" ); }); -supportIFrameTest( "A background on the testElement does not cause IE8 to crash (#9823)", "testElementCrash", function() { +testIframeWithCallback( "A background on the testElement does not cause IE8 to crash (#9823)", "support/testElementCrash", function() { expect(1); ok( true, "IE8 does not crash" ); }); |