From ebbfb1bc5c85bdde5dc3b1fbbf07b668099642fb Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 18:48:50 +0300 Subject: [PATCH 001/114] Revert "Dimensions: Empty sets should return undefined" This reverts commit 97d79ecf6b6c5cc3c1485eb3c46e12986a978f57. --- src/dimensions.js | 2 +- test/unit/dimensions.js | 38 +++++++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/dimensions.js b/src/dimensions.js index 3d4dbff10f..c5f49ac093 100644 --- a/src/dimensions.js +++ b/src/dimensions.js @@ -45,7 +45,7 @@ jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { // Set width or height on the element jQuery.style( elem, type, value, extra ); - }, type, chainable ? margin : undefined, chainable ); + }, type, chainable ? margin : undefined, chainable, null ); }; } ); } ); diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index c681478a00..28f4ecd139 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -30,7 +30,7 @@ function fn( val ) { function testWidth( val, assert ) { assert.expect( 9 ); - var $div, $empty; + var $div, blah; $div = jQuery( "#nothiddendiv" ); $div.width( val( 30 ) ); @@ -51,9 +51,9 @@ function testWidth( val, assert ) { assert.equal( jQuery( "#nothiddendivchild" ).width(), 20, "Test child width with border and padding" ); jQuery( "#nothiddendiv, #nothiddendivchild" ).css( { "border": "", "padding": "", "width": "" } ); - $empty = jQuery(); - assert.equal( $empty.width( val( 10 ) ), $empty, "Make sure that setting a width on an empty set returns the set." ); - assert.strictEqual( $empty.width(), undefined, "Make sure 'undefined' is returned on an empty set" ); + blah = jQuery( "blah" ); + assert.equal( blah.width( val( 10 ) ), blah, "Make sure that setting a width on an empty set returns the set." ); + assert.equal( blah.width(), null, "Make sure 'null' is returned on an empty set" ); assert.equal( jQuery( window ).width(), document.documentElement.clientWidth, "Window width is equal to width reported by window/document." ); } @@ -104,7 +104,7 @@ function testHeight( val, assert ) { blah = jQuery( "blah" ); assert.equal( blah.height( val( 10 ) ), blah, "Make sure that setting a height on an empty set returns the set." ); - assert.strictEqual( blah.height(), undefined, "Make sure 'undefined' is returned on an empty set" ); + assert.equal( blah.height(), null, "Make sure 'null' is returned on an empty set" ); assert.equal( jQuery( window ).height(), document.documentElement.clientHeight, "Window width is equal to width reported by window/document." ); } @@ -130,7 +130,7 @@ QUnit.test( "height(Function(args))", function( assert ) { } ); QUnit.test( "innerWidth()", function( assert ) { - assert.expect( 7 ); + assert.expect( 6 ); var $div, div, $win = jQuery( window ), @@ -138,7 +138,6 @@ QUnit.test( "innerWidth()", function( assert ) { assert.equal( jQuery( window ).innerWidth(), $win.width(), "Test on window" ); assert.equal( jQuery( document ).innerWidth(), $doc.width(), "Test on document" ); - assert.strictEqual( jQuery().innerWidth(), undefined, "Test on empty set" ); $div = jQuery( "#nothiddendiv" ); $div.css( { @@ -165,7 +164,7 @@ QUnit.test( "innerWidth()", function( assert ) { } ); QUnit.test( "innerHeight()", function( assert ) { - assert.expect( 7 ); + assert.expect( 6 ); var $div, div, $win = jQuery( window ), @@ -173,7 +172,6 @@ QUnit.test( "innerHeight()", function( assert ) { assert.equal( jQuery( window ).innerHeight(), $win.height(), "Test on window" ); assert.equal( jQuery( document ).innerHeight(), $doc.height(), "Test on document" ); - assert.strictEqual( jQuery().innerHeight(), undefined, "Test on empty set" ); $div = jQuery( "#nothiddendiv" ); $div.css( { @@ -200,7 +198,7 @@ QUnit.test( "innerHeight()", function( assert ) { } ); QUnit.test( "outerWidth()", function( assert ) { - assert.expect( 12 ); + assert.expect( 11 ); var $div, div, $win = jQuery( window ), @@ -211,7 +209,6 @@ QUnit.test( "outerWidth()", function( assert ) { assert.equal( jQuery( window ).outerWidth( true ), winwidth, "Test on window with margin option" ); assert.equal( jQuery( document ).outerWidth(), $doc.width(), "Test on document without margin option" ); assert.equal( jQuery( document ).outerWidth( true ), $doc.width(), "Test on document with margin option" ); - assert.strictEqual( jQuery().outerWidth(), undefined, "Test on empty set" ); $div = jQuery( "#nothiddendiv" ); $div.css( "width", 30 ); @@ -240,7 +237,7 @@ QUnit.test( "outerWidth()", function( assert ) { } ); QUnit.test( "outerHeight()", function( assert ) { - assert.expect( 12 ); + assert.expect( 11 ); var $div, div, $win = jQuery( window ), @@ -251,7 +248,6 @@ QUnit.test( "outerHeight()", function( assert ) { assert.equal( jQuery( window ).outerHeight( true ), winheight, "Test on window with margin option" ); assert.equal( jQuery( document ).outerHeight(), $doc.height(), "Test on document without margin option" ); assert.equal( jQuery( document ).outerHeight( true ), $doc.height(), "Test on document with margin option" ); - assert.strictEqual( jQuery().outerHeight(), undefined, "Test on empty set" ); $div = jQuery( "#nothiddendiv" ); $div.css( "height", 30 ); @@ -405,6 +401,22 @@ QUnit.test( "passing undefined is a setter #5571", function( assert ) { assert.equal( jQuery( "#nothiddendiv" ).width( 30 ).width( undefined ).width(), 30, ".width(undefined) is chainable (#5571)" ); } ); +QUnit.test( "getters on non elements should return null", function( assert ) { + assert.expect( 8 ); + + var nonElem = jQuery( "notAnElement" ); + + assert.strictEqual( nonElem.width(), null, ".width() is not null (#12283)" ); + assert.strictEqual( nonElem.innerWidth(), null, ".innerWidth() is not null (#12283)" ); + assert.strictEqual( nonElem.outerWidth(), null, ".outerWidth() is not null (#12283)" ); + assert.strictEqual( nonElem.outerWidth( true ), null, ".outerWidth(true) is not null (#12283)" ); + + assert.strictEqual( nonElem.height(), null, ".height() is not null (#12283)" ); + assert.strictEqual( nonElem.innerHeight(), null, ".innerHeight() is not null (#12283)" ); + assert.strictEqual( nonElem.outerHeight(), null, ".outerHeight() is not null (#12283)" ); + assert.strictEqual( nonElem.outerHeight( true ), null, ".outerHeight(true) is not null (#12283)" ); +} ); + QUnit.test( "setters with and without box-sizing:border-box", function( assert ) { assert.expect( 60 ); From ab7ba382bced1dad67c5a523754d03525cb0bacb Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 18:48:58 +0300 Subject: [PATCH 002/114] Revert "Dimensions: outerWidth/Height include scrollbar" This reverts commit 7d44d7f9e7cb73ff2b373f08cea13ea9958bb462. --- src/dimensions.js | 8 ++-- test/unit/dimensions.js | 83 ++++++++++++++++++++--------------------- 2 files changed, 44 insertions(+), 47 deletions(-) diff --git a/src/dimensions.js b/src/dimensions.js index c5f49ac093..30b55fbc0e 100644 --- a/src/dimensions.js +++ b/src/dimensions.js @@ -19,10 +19,10 @@ jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { if ( jQuery.isWindow( elem ) ) { - // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729) - return funcName.indexOf( "outer" ) === 0 ? - elem[ "inner" + name ] : - elem.document.documentElement[ "client" + name ]; + // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there + // isn't a whole lot we can do. See pull request at this URL for discussion: + // https://github.com/jquery/jquery/pull/764 + return elem.document.documentElement[ "client" + name ]; } // Get document width or height diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 28f4ecd139..22b3f01982 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -202,11 +202,10 @@ QUnit.test( "outerWidth()", function( assert ) { var $div, div, $win = jQuery( window ), - $doc = jQuery( document ), - winwidth = $win.prop( "innerWidth" ); + $doc = jQuery( document ); - assert.equal( jQuery( window ).outerWidth(), winwidth, "Test on window without margin option" ); - assert.equal( jQuery( window ).outerWidth( true ), winwidth, "Test on window with margin option" ); + assert.equal( jQuery( window ).outerWidth(), $win.width(), "Test on window without margin option" ); + assert.equal( jQuery( window ).outerWidth( true ), $win.width(), "Test on window with margin option" ); assert.equal( jQuery( document ).outerWidth(), $doc.width(), "Test on document without margin option" ); assert.equal( jQuery( document ).outerWidth( true ), $doc.width(), "Test on document with margin option" ); @@ -236,45 +235,6 @@ QUnit.test( "outerWidth()", function( assert ) { div.remove(); } ); -QUnit.test( "outerHeight()", function( assert ) { - assert.expect( 11 ); - - var $div, div, - $win = jQuery( window ), - $doc = jQuery( document ), - winheight = $win.prop( "innerHeight" ); - - assert.equal( jQuery( window ).outerHeight(), winheight, "Test on window without margin option" ); - assert.equal( jQuery( window ).outerHeight( true ), winheight, "Test on window with margin option" ); - assert.equal( jQuery( document ).outerHeight(), $doc.height(), "Test on document without margin option" ); - assert.equal( jQuery( document ).outerHeight( true ), $doc.height(), "Test on document with margin option" ); - - $div = jQuery( "#nothiddendiv" ); - $div.css( "height", 30 ); - - assert.equal( $div.outerHeight(), 30, "Test with only height set" ); - $div.css( "padding", "20px" ); - assert.equal( $div.outerHeight(), 70, "Test with padding" ); - $div.css( "border", "2px solid #fff" ); - assert.equal( $div.outerHeight(), 74, "Test with padding and border" ); - $div.css( "margin", "10px" ); - assert.equal( $div.outerHeight(), 74, "Test with padding, border and margin without margin option" ); - $div.css( "position", "absolute" ); - assert.equal( $div.outerHeight( true ), 94, "Test with padding, border and margin with margin option" ); - $div.css( "display", "none" ); - assert.equal( $div.outerHeight( true ), 94, "Test hidden div with padding, border and margin with margin option" ); - - // reset styles - $div.css( { "position": "", "display": "", "border": "", "padding": "", "width": "", "height": "" } ); - - div = jQuery( "
" ); - - // Temporarily require 0 for backwards compat - should be auto - assert.equal( div.outerWidth(), 0, "Make sure that disconnected nodes are handled." ); - - div.remove(); -} ); - QUnit.test( "child of a hidden elem (or unconnected node) has accurate inner/outer/Width()/Height() see #9441 #9300", function( assert ) { assert.expect( 16 ); @@ -393,6 +353,43 @@ QUnit.test( "box-sizing:border-box child of a hidden elem (or unconnected node) $divNormal.remove(); } ); +QUnit.test( "outerHeight()", function( assert ) { + assert.expect( 11 ); + + var $div, div, + $win = jQuery( window ), + $doc = jQuery( document ); + + assert.equal( jQuery( window ).outerHeight(), $win.height(), "Test on window without margin option" ); + assert.equal( jQuery( window ).outerHeight( true ), $win.height(), "Test on window with margin option" ); + assert.equal( jQuery( document ).outerHeight(), $doc.height(), "Test on document without margin option" ); + assert.equal( jQuery( document ).outerHeight( true ), $doc.height(), "Test on document with margin option" ); + + $div = jQuery( "#nothiddendiv" ); + $div.css( "height", 30 ); + + assert.equal( $div.outerHeight(), 30, "Test with only width set" ); + $div.css( "padding", "20px" ); + assert.equal( $div.outerHeight(), 70, "Test with padding" ); + $div.css( "border", "2px solid #fff" ); + assert.equal( $div.outerHeight(), 74, "Test with padding and border" ); + $div.css( "margin", "10px" ); + assert.equal( $div.outerHeight(), 74, "Test with padding, border and margin without margin option" ); + assert.equal( $div.outerHeight( true ), 94, "Test with padding, border and margin with margin option" ); + $div.css( "display", "none" ); + assert.equal( $div.outerHeight( true ), 94, "Test hidden div with padding, border and margin with margin option" ); + + // reset styles + $div.css( { "display": "", "border": "", "padding": "", "width": "", "height": "" } ); + + div = jQuery( "
" ); + + // Temporarily require 0 for backwards compat - should be auto + assert.equal( div.outerHeight(), 0, "Make sure that disconnected nodes are handled." ); + + div.remove(); +} ); + QUnit.test( "passing undefined is a setter #5571", function( assert ) { assert.expect( 4 ); assert.equal( jQuery( "#nothiddendiv" ).height( 30 ).height( undefined ).height(), 30, ".height(undefined) is chainable (#5571)" ); From 9fd56078df0bba653ea87153d6378f469842e006 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 18:49:04 +0300 Subject: [PATCH 003/114] Revert "Attributes: return empty array for select-multiple with no values" This reverts commit 79fc806e8500372a2278795c068d039ee287535f. --- src/attributes/val.js | 2 +- test/unit/attributes.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/attributes/val.js b/src/attributes/val.js index 5f0b73e008..caf0126d4c 100644 --- a/src/attributes/val.js +++ b/src/attributes/val.js @@ -90,7 +90,7 @@ jQuery.extend( { var value, option, options = elem.options, index = elem.selectedIndex, - one = elem.type === "select-one", + one = elem.type === "select-one" || index < 0, values = one ? null : [], max = one ? index + 1 : options.length, i = index < 0 ? diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 9bf2876881..9ea29a1053 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -903,10 +903,10 @@ QUnit.test( "val() with non-matching values on dropdown list", function( assert var select6 = jQuery( "" ).appendTo( "#form" ); jQuery( select6 ).val( "nothing" ); - assert.deepEqual( jQuery( select6 ).val(), [], "Non-matching set (single value) on select-multiple" ); + assert.equal( jQuery( select6 ).val(), null, "Non-matching set (single value) on select-multiple" ); jQuery( select6 ).val( [ "nothing1", "nothing2" ] ); - assert.deepEqual( jQuery( select6 ).val(), [], "Non-matching set (array of values) on select-multiple" ); + assert.equal( jQuery( select6 ).val(), null, "Non-matching set (array of values) on select-multiple" ); select6.remove(); } ); From 112f612aaf5e18661d9fce802077e8663f7da928 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 18:51:34 +0300 Subject: [PATCH 004/114] Revert "Ajax: Only form-encode requests with a body" This reverts commit 70605c8e5655da996ebd395e3c43423daaa08d9c. --- src/ajax.js | 6 ------ src/serialize.js | 4 ++-- test/unit/ajax.js | 42 ------------------------------------------ test/unit/serialize.js | 32 ++++++++++++++++---------------- 4 files changed, 18 insertions(+), 66 deletions(-) diff --git a/src/ajax.js b/src/ajax.js index ca2b910dd0..bb69cf1d39 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -14,7 +14,6 @@ define( [ ], function( jQuery, document, rnotwhite, location, nonce, rquery ) { var - r20 = /%20/g, rhash = /#.*$/, rts = /([?&])_=[^&]*/, rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, @@ -604,11 +603,6 @@ jQuery.extend( { // Otherwise add one to the end cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++; } - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); } // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. diff --git a/src/serialize.js b/src/serialize.js index a0b9484606..94698fc2fc 100644 --- a/src/serialize.js +++ b/src/serialize.js @@ -6,7 +6,7 @@ define( [ "./attributes/prop" ], function( jQuery, rcheckableType ) { -var +var r20 = /%20/g, rbracket = /\[\]$/, rCRLF = /\r?\n/g, rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, @@ -85,7 +85,7 @@ jQuery.param = function( a, traditional ) { } // Return the resulting serialization - return s.join( "&" ); + return s.join( "&" ).replace( r20, "+" ); }; jQuery.fn.extend( { diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 12bf2ab31f..4d7dc95e89 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1148,48 +1148,6 @@ QUnit.module( "ajax", { }; } ); - ajaxTest( "jQuery.ajax() - data - x-www-form-urlencoded (gh-2658)", 1, function( assert ) { - return { - url: "bogus.html", - data: { devo: "A Beautiful World" }, - type: "post", - beforeSend: function( _, s ) { - assert.strictEqual( s.data, "devo=A+Beautiful+World", "data is '+'-encoded" ); - return false; - }, - error: true - }; - } ); - - ajaxTest( "jQuery.ajax() - data - text/plain (gh-2658)", 1, function( assert ) { - return { - url: "bogus.html", - data: { devo: "A Beautiful World" }, - type: "post", - contentType: "text/plain", - beforeSend: function( _, s ) { - assert.strictEqual( s.data, "devo=A%20Beautiful%20World", "data is %20-encoded" ); - return false; - }, - error: true - }; - } ); - - ajaxTest( "jQuery.ajax() - data - no processing ", 1, function( assert ) { - return { - url: "bogus.html", - data: { devo: "A Beautiful World" }, - type: "post", - contentType: "x-special-sauce", - processData: false, - beforeSend: function( _, s ) { - assert.deepEqual( s.data, { devo: "A Beautiful World" }, "data is not processed" ); - return false; - }, - error: true - }; - } ); - var ifModifiedNow = new Date(); jQuery.each( diff --git a/test/unit/serialize.js b/test/unit/serialize.js index 65d94171ca..b487602000 100644 --- a/test/unit/serialize.js +++ b/test/unit/serialize.js @@ -8,7 +8,7 @@ QUnit.test( "jQuery.param()", function( assert ) { assert.equal( !( jQuery.ajaxSettings && jQuery.ajaxSettings.traditional ), true, "traditional flag, falsy by default" ); params = { "foo":"bar", "baz":42, "quux":"All your base are belong to us" }; - assert.equal( jQuery.param( params ), "foo=bar&baz=42&quux=All%20your%20base%20are%20belong%20to%20us", "simple" ); + assert.equal( jQuery.param( params ), "foo=bar&baz=42&quux=All+your+base+are+belong+to+us", "simple" ); params = { "string":"foo","null":null,"undefined":undefined }; assert.equal( jQuery.param( params ), "string=foo&null=&undefined=", "handle nulls and undefineds properly" ); @@ -20,19 +20,19 @@ QUnit.test( "jQuery.param()", function( assert ) { assert.equal( jQuery.param( params ), "foo%5B%5D=a&foo%5B%5D=b&foo%5B%5D=c", "with array of strings" ); params = { "foo": [ "baz", 42, "All your base are belong to us" ] }; - assert.equal( jQuery.param( params ), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All%20your%20base%20are%20belong%20to%20us", "more array" ); + assert.equal( jQuery.param( params ), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All+your+base+are+belong+to+us", "more array" ); params = { "foo": { "bar": "baz", "beep": 42, "quux": "All your base are belong to us" } }; - assert.equal( jQuery.param( params ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All%20your%20base%20are%20belong%20to%20us", "even more arrays" ); + assert.equal( jQuery.param( params ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); params = { a:[ 1,2 ], b:{ c:3, d:[ 4,5 ], e:{ x:[ 6 ], y:7, z:[ 8,9 ] }, f:true, g:false, h:undefined }, i:[ 10,11 ], j:true, k:false, l:[ undefined,0 ], m:"cowboy hat?" }; - assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy hat?", "huge structure" ); + assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy+hat?", "huge structure" ); params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, "d": 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=0&a[1][]=1&a[1][]=2&a[2][]=3&a[2][1][]=4&a[2][1][]=5&a[2][2][]=6&a[3][b][]=7&a[3][b][1][]=8&a[3][b][1][]=9&a[3][b][2][0][c]=10&a[3][b][2][0][d]=11&a[3][b][3][0][]=12&a[3][b][4][0][0][]=13&a[3][b][5][e][f][g][]=14&a[3][b][5][e][f][g][1][]=15&a[3][b][]=16&a[]=17", "nested arrays" ); params = { "a":[ 1,2 ], "b":{ "c":3, "d":[ 4,5 ], "e":{ "x":[ 6 ], "y":7, "z":[ 8,9 ] }, "f":true, "g":false, "h":undefined }, "i":[ 10,11 ], "j":true, "k":false, "l":[ undefined,0 ], "m":"cowboy hat?" }; - assert.equal( jQuery.param( params, true ), "a=1&a=2&b=%5Bobject%20Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy%20hat%3F", "huge structure, forced traditional" ); + assert.equal( jQuery.param( params, true ), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy+hat%3F", "huge structure, forced traditional" ); assert.equal( decodeURIComponent( jQuery.param( { "a": [ 1,2,3 ], "b[]": [ 4,5,6 ], "c[d]": [ 7,8,9 ], "e": { "f": [ 10 ], "g": [ 11,12 ], "h": 13 } } ) ), "a[]=1&a[]=2&a[]=3&b[]=4&b[]=5&b[]=6&c[d][]=7&c[d][]=8&c[d][]=9&e[f][]=10&e[g][]=11&e[g][]=12&e[h]=13", "Make sure params are not double-encoded." ); @@ -48,7 +48,7 @@ QUnit.test( "jQuery.param()", function( assert ) { } params = { "foo":"bar", "baz":42, "quux":"All your base are belong to us" }; - assert.equal( jQuery.param( params ), "foo=bar&baz=42&quux=All%20your%20base%20are%20belong%20to%20us", "simple" ); + assert.equal( jQuery.param( params ), "foo=bar&baz=42&quux=All+your+base+are+belong+to+us", "simple" ); params = { "someName": [ 1, 2, 3 ], "regularThing": "blah" }; assert.equal( jQuery.param( params ), "someName=1&someName=2&someName=3®ularThing=blah", "with array" ); @@ -57,19 +57,19 @@ QUnit.test( "jQuery.param()", function( assert ) { assert.equal( jQuery.param( params ), "foo=a&foo=b&foo=c", "with array of strings" ); params = { "foo[]":[ "baz", 42, "All your base are belong to us" ] }; - assert.equal( jQuery.param( params ), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All%20your%20base%20are%20belong%20to%20us", "more array" ); + assert.equal( jQuery.param( params ), "foo%5B%5D=baz&foo%5B%5D=42&foo%5B%5D=All+your+base+are+belong+to+us", "more array" ); params = { "foo[bar]":"baz", "foo[beep]":42, "foo[quux]":"All your base are belong to us" }; - assert.equal( jQuery.param( params ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All%20your%20base%20are%20belong%20to%20us", "even more arrays" ); + assert.equal( jQuery.param( params ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); params = { a:[ 1,2 ], b:{ c:3, d:[ 4,5 ], e:{ x:[ 6 ], y:7, z:[ 8,9 ] }, f:true, g:false, h:undefined }, i:[ 10,11 ], j:true, k:false, l:[ undefined,0 ], m:"cowboy hat?" }; - assert.equal( jQuery.param( params ), "a=1&a=2&b=%5Bobject%20Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy%20hat%3F", "huge structure" ); + assert.equal( jQuery.param( params ), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy+hat%3F", "huge structure" ); params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, d: 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; - assert.equal( jQuery.param( params ), "a=0&a=1%2C2&a=3%2C4%2C5%2C6&a=%5Bobject%20Object%5D&a=17", "nested arrays (not possible when jQuery.param.traditional == true)" ); + assert.equal( jQuery.param( params ), "a=0&a=1%2C2&a=3%2C4%2C5%2C6&a=%5Bobject+Object%5D&a=17", "nested arrays (not possible when jQuery.param.traditional == true)" ); params = { a:[ 1,2 ], b:{ c:3, d:[ 4,5 ], e:{ x:[ 6 ], y:7, z:[ 8,9 ] }, f:true, g:false, h:undefined }, i:[ 10,11 ], j:true, k:false, l:[ undefined,0 ], m:"cowboy hat?" }; - assert.equal( decodeURIComponent( jQuery.param( params, false ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy hat?", "huge structure, forced not traditional" ); + assert.equal( decodeURIComponent( jQuery.param( params, false ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy+hat?", "huge structure, forced not traditional" ); params = { "param1": null }; assert.equal( jQuery.param( params, false ), "param1=", "Make sure that null params aren't traversed." ); @@ -131,19 +131,19 @@ QUnit.test( "serialize()", function( assert ) { "Check input serialization as query string" ); assert.equal( jQuery( "#testForm" ).serialize(), - "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My%20Name=me&S1=abc&S3=YES&S4=", + "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", "Check form serialization as query string" ); assert.equal( jQuery( "input,select,textarea,button", "#testForm" ).serialize(), - "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My%20Name=me&S1=abc&S3=YES&S4=", + "T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", "Check input serialization as query string" ); assert.equal( jQuery( "#form, #testForm" ).serialize(), - "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My%20Name=me&S1=abc&S3=YES&S4=", + "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", "Multiple form serialization as query string" ); - assert.equal( jQuery( "#form, #testForm input, #testForm select, #testForm textarea, #testForm button" ).serialize(), - "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My%20Name=me&S1=abc&S3=YES&S4=", + assert.equal( jQuery( "#form, #testForm :input" ).serialize(), + "action=Test&radio2=on&check=on&hidden=&foo%5Bbar%5D=&name=name&search=search&email=dave%40jquery.com&number=43&select1=&select2=3&select3=1&select3=2&select5=3&T3=%3F%0D%0AZ&H1=x&H2=&PWD=&T1=&T2=YES&My+Name=me&S1=abc&S3=YES&S4=", "Mixed form/input serialization as query string" ); jQuery( "#html5email, #html5number" ).remove(); From 38261772a4054621b24135a5b2266eb2a12798b9 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 18:51:53 +0300 Subject: [PATCH 005/114] Revert "Attributes: remove flakey test for selected attribute" This reverts commit 87bd130289c6ed9bfc355c1f8587ae6ce00a4776. --- test/unit/attributes.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 9ea29a1053..b70022f9e0 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -564,7 +564,7 @@ QUnit.test( "attr('tabindex', value)", function( assert ) { } ); QUnit.test( "removeAttr(String)", function( assert ) { - assert.expect( 12 ); + assert.expect( 13 ); var $first; assert.equal( jQuery( "#mark" ).removeAttr( "class" ).attr( "class" ), undefined, "remove class" ); @@ -576,6 +576,8 @@ QUnit.test( "removeAttr(String)", function( assert ) { jQuery( "#check1" ).removeAttr( "checked" ).prop( "checked", true ).removeAttr( "checked" ); assert.equal( document.getElementById( "check1" ).checked, true, "removeAttr should not set checked to false, since the checked attribute does NOT mirror the checked property" ); + jQuery( "#option1b" ).attr( "selected", "selected" ).removeAttr( "selected" ).attr( "selected", "selected" ); + assert.notEqual( document.getElementById( "select1" ).selectedIndex, 1, "Once the selected attribute is dirty, subsequent settings should not select the option (gh-1759)" ); jQuery( "#text1" ).prop( "readOnly", true ).removeAttr( "readonly" ); assert.equal( document.getElementById( "text1" ).readOnly, false, "removeAttr sets boolean properties to false" ); From 3f7cd73822007d63b6e2d07749900802107490b5 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 18:51:58 +0300 Subject: [PATCH 006/114] Revert "Attributes: do not set properties to false when removing booleans" This reverts commit 47ccf3daadc4b312f850502300129952e70f9d9d. --- src/attributes/attr.js | 12 ++++++++++-- test/unit/attributes.js | 6 ++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/attributes/attr.js b/src/attributes/attr.js index ae48676d1f..f88808324d 100644 --- a/src/attributes/attr.js +++ b/src/attributes/attr.js @@ -86,12 +86,21 @@ jQuery.extend( { }, removeAttr: function( elem, value ) { - var name, + var name, propName, i = 0, attrNames = value && value.match( rnotwhite ); if ( attrNames && elem.nodeType === 1 ) { while ( ( name = attrNames[ i++ ] ) ) { + propName = jQuery.propFix[ name ] || name; + + // Boolean attributes get special treatment (#10870) + if ( jQuery.expr.match.bool.test( name ) ) { + + // Set corresponding property to false + elem[ propName ] = false; + } + elem.removeAttribute( name ); } } @@ -111,7 +120,6 @@ boolHook = { return name; } }; - jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { var getter = attrHandle[ name ] || jQuery.find.attr; diff --git a/test/unit/attributes.js b/test/unit/attributes.js index b70022f9e0..517c907db2 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -564,7 +564,7 @@ QUnit.test( "attr('tabindex', value)", function( assert ) { } ); QUnit.test( "removeAttr(String)", function( assert ) { - assert.expect( 13 ); + assert.expect( 12 ); var $first; assert.equal( jQuery( "#mark" ).removeAttr( "class" ).attr( "class" ), undefined, "remove class" ); @@ -575,9 +575,7 @@ QUnit.test( "removeAttr(String)", function( assert ) { assert.equal( jQuery( "#fx-test-group" ).attr( "height", "3px" ).removeAttr( "height" ).get( 0 ).style.height, "1px", "Removing height attribute has no effect on height set with style attribute" ); jQuery( "#check1" ).removeAttr( "checked" ).prop( "checked", true ).removeAttr( "checked" ); - assert.equal( document.getElementById( "check1" ).checked, true, "removeAttr should not set checked to false, since the checked attribute does NOT mirror the checked property" ); - jQuery( "#option1b" ).attr( "selected", "selected" ).removeAttr( "selected" ).attr( "selected", "selected" ); - assert.notEqual( document.getElementById( "select1" ).selectedIndex, 1, "Once the selected attribute is dirty, subsequent settings should not select the option (gh-1759)" ); + assert.equal( document.getElementById( "check1" ).checked, false, "removeAttr sets boolean properties to false" ); jQuery( "#text1" ).prop( "readOnly", true ).removeAttr( "readonly" ); assert.equal( document.getElementById( "text1" ).readOnly, false, "removeAttr sets boolean properties to false" ); From 8dda094c7caaef7cf1de3acd3e39a3b6dbc7a7ad Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 18:54:44 +0300 Subject: [PATCH 007/114] Revert "Ajax: don't expect cross-origin tests run in envs which not support it" This reverts commit 39cdb8c9aa0fde68f733553ba050a2ba9d86474c. --- test/unit/ajax.js | 51 ++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 4d7dc95e89..4eb70cad89 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -71,6 +71,21 @@ QUnit.module( "ajax", { }; } ); + ajaxTest( "jQuery.ajax() - do not execute js (crossOrigin)", 2, function( assert ) { + return { + create: function( options ) { + options.crossDomain = true; + return jQuery.ajax( url( "data/script.php?header=ecma" ), options ); + }, + success: function() { + assert.ok( true, "success" ); + }, + complete: function() { + assert.ok( true, "complete" ); + } + }; + } ); + ajaxTest( "jQuery.ajax() - execute js for crossOrigin when dataType option is provided", 3, function( assert ) { return { @@ -98,11 +113,6 @@ QUnit.module( "ajax", { success: function() { assert.ok( true, "success" ); }, - fail: function() { - if (jQuery.support.cors === false) { - assert.ok( true, "fail" ); - } - }, complete: function() { assert.ok( true, "complete" ); } @@ -1810,21 +1820,22 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re done: function( data ) { assert.ok( false, "done: " + data ); }, - fail: function( jqXHR, status, error ) { - assert.ok( true, "exception caught: " + error ); - assert.strictEqual( jqXHR.status, 0, "proper status code" ); - assert.strictEqual( status, "error", "proper status" ); - } - }, { - url: "http://" + externalHost + ":80q", - done: function( data ) { - assert.ok( false, "done: " + data ); - }, - fail: function( _, status, error ) { - assert.ok( true, "fail: " + status + " - " + error ); - } - } ]; - } ); + fail: function( jqXHR, status, error ) { + assert.ok( true, "exception caught: " + error ); + assert.strictEqual( jqXHR.status, 0, "proper status code" ); + assert.strictEqual( status, "error", "proper status" ); + } + }, { + url: "http://domain.org:80d", + done: function( data ) { + assert.ok( false, "done: " + data ); + }, + fail: function( _, status, error ) { + assert.ok( true, "fail: " + status + " - " + error ); + } + } ]; + } + ); ajaxTest( "gh-2587 - when content-type not xml, but looks like one", 1, function( assert ) { return { From ad358fd62b0ab548abe379594ea00441940461f6 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 18:55:44 +0300 Subject: [PATCH 008/114] Revert "Ajax: Mitigate possible XSS vulnerability" This reverts commit b078a62013782c7424a4a61a240c23c4c0b42614. --- src/ajax.js | 2 +- src/ajax/script.js | 7 ------- test/unit/ajax.js | 48 ---------------------------------------------- 3 files changed, 1 insertion(+), 56 deletions(-) diff --git a/src/ajax.js b/src/ajax.js index bb69cf1d39..4feed36b57 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -223,7 +223,7 @@ function ajaxConvert( s, response, jqXHR, isSuccess ) { if ( current ) { - // There's only work to do if current dataType is non-auto + // There's only work to do if current dataType is non-auto if ( current === "*" ) { current = prev; diff --git a/src/ajax/script.js b/src/ajax/script.js index 485ba397be..945bea9dae 100644 --- a/src/ajax/script.js +++ b/src/ajax/script.js @@ -4,13 +4,6 @@ define( [ "../ajax" ], function( jQuery, document ) { -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - // Install script dataType jQuery.ajaxSetup( { accepts: { diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 4eb70cad89..8e7cc06f49 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -71,54 +71,6 @@ QUnit.module( "ajax", { }; } ); - ajaxTest( "jQuery.ajax() - do not execute js (crossOrigin)", 2, function( assert ) { - return { - create: function( options ) { - options.crossDomain = true; - return jQuery.ajax( url( "data/script.php?header=ecma" ), options ); - }, - success: function() { - assert.ok( true, "success" ); - }, - complete: function() { - assert.ok( true, "complete" ); - } - }; - } ); - - ajaxTest( "jQuery.ajax() - execute js for crossOrigin when dataType option is provided", 3, - function( assert ) { - return { - create: function( options ) { - options.crossDomain = true; - options.dataType = "script"; - return jQuery.ajax( url( "data/script.php?header=ecma" ), options ); - }, - success: function() { - assert.ok( true, "success" ); - }, - complete: function() { - assert.ok( true, "complete" ); - } - }; - } - ); - - ajaxTest( "jQuery.ajax() - do not execute js (crossOrigin)", 2, function( assert ) { - return { - create: function( options ) { - options.crossDomain = true; - return jQuery.ajax( url( "data/script.php" ), options ); - }, - success: function() { - assert.ok( true, "success" ); - }, - complete: function() { - assert.ok( true, "complete" ); - } - }; - } ); - ajaxTest( "jQuery.ajax() - success callbacks (late binding)", 8, function( assert ) { return { setup: addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), From 82bb2ae719dfe3d7336e12263e30acaff22edb9e Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 18:56:05 +0300 Subject: [PATCH 009/114] Revert "Effects: Remove additional parameters of easings" This reverts commit b7a7dea95f84d6d8e5a8186d4fb09a762baf79bb. --- src/effects/Tween.js | 15 ++++++++++----- test/unit/tween.js | 8 ++++++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/effects/Tween.js b/src/effects/Tween.js index 47f15a9479..d26ddd9189 100644 --- a/src/effects/Tween.js +++ b/src/effects/Tween.js @@ -27,12 +27,17 @@ Tween.prototype = { Tween.propHooks._default.get( this ); }, run: function( percent ) { - var hooks = Tween.propHooks[ this.prop ]; + var eased, + hooks = Tween.propHooks[ this.prop ]; - this.pos = this.options.duration ? - jQuery.easing[ this.easing ]( percent ) : - percent; - this.now = ( this.end - this.start ) * this.pos + this.start; + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; if ( this.options.step ) { this.options.step.call( this.elem, this.now, this ); diff --git a/test/unit/tween.js b/test/unit/tween.js index f66aa37b6a..28fcfad257 100644 --- a/test/unit/tween.js +++ b/test/unit/tween.js @@ -160,7 +160,8 @@ QUnit.test( "jQuery.Tween - Plain Object", function( assert ) { assert.equal( tween.now, 90, "Calculated tween" ); - assert.ok( easingSpy.calledWith( 0.1 ), "...using jQuery.easing.linear" ); + assert.ok( easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ), + "...using jQuery.easing.linear with back-compat arguments" ); assert.equal( testObject.test, 90, "Set value" ); tween.run( 1 ); @@ -199,7 +200,10 @@ QUnit.test( "jQuery.Tween - Element", function( assert ) { eased = 100 - ( jQuery.easing.swing( 0.1 ) * 100 ); assert.equal( tween.now, eased, "Calculated tween" ); - assert.ok( easingSpy.calledWith( 0.1 ), "...using jQuery.easing.linear" ); + assert.ok( + easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ), + "...using jQuery.easing.linear with back-compat arguments" + ); assert.equal( parseFloat( testElement.style.height ).toFixed( 2 ), eased.toFixed( 2 ), "Set value" From 7101ef2be83763cda018d7725cbc883c01cfe020 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:05:14 +0300 Subject: [PATCH 010/114] Revert "CSS: Make .css("width") & .css("height") return fractional values" This reverts commit b60b26e18477d21fa5ec9c6572e114fc5d441730. --- src/css.js | 28 +++++++++---------------- test/unit/css.js | 45 ----------------------------------------- test/unit/dimensions.js | 40 +++++++++++++++--------------------- 3 files changed, 26 insertions(+), 87 deletions(-) diff --git a/src/css.js b/src/css.js index acd4bb3eb4..9b3a463826 100644 --- a/src/css.js +++ b/src/css.js @@ -115,23 +115,22 @@ function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { function getWidthOrHeight( elem, name, extra ) { // Start with offset property, which is equivalent to the border-box value - var val, - valueIsBorderBox = true, + var valueIsBorderBox = true, + val = name === "width" ? elem.offsetWidth : elem.offsetHeight, styles = getStyles( elem ), isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - // Support: IE <= 11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - if ( elem.getClientRects().length ) { - val = elem.getBoundingClientRect()[ name ]; - } - // Support: IE11 only // In IE 11 fullscreen elements inside of an iframe have // 100x too small dimensions (gh-1764). if ( document.msFullscreenElement && window.top !== window ) { - val *= 100; + + // Support: IE11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + if ( elem.getClientRects().length ) { + val = Math.round( elem.getBoundingClientRect()[ name ] * 100 ); + } } // Some non-html elements return undefined for offsetWidth, so check for null/undefined @@ -321,14 +320,7 @@ jQuery.each( [ "height", "width" ], function( i, name ) { // Certain elements can have dimension info if we invisibly show them // but it must have a current display style that would benefit return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <= 11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + elem.offsetWidth === 0 ? swap( elem, cssShow, function() { return getWidthOrHeight( elem, name, extra ); } ) : diff --git a/test/unit/css.js b/test/unit/css.js index 8715c56d5a..a8ab367564 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -884,51 +884,6 @@ testIframeWithCallback( } ); -( function() { - var supportsFractionalGBCR, - qunitFixture = document.getElementById( "qunit-fixture" ), - div = document.createElement( "div" ); - div.style.width = "3.3px"; - qunitFixture.appendChild( div ); - supportsFractionalGBCR = div.getBoundingClientRect().width.toFixed( 1 ) === "3.3"; - qunitFixture.removeChild( div ); - - QUnit.test( "css('width') and css('height') should return fractional values for nodes in the document", function( assert ) { - if ( !supportsFractionalGBCR ) { - assert.expect( 1 ); - assert.ok( true, "This browser doesn't support fractional values in getBoundingClientRect()" ); - return; - } - - assert.expect( 2 ); - - var el = jQuery( "
" ).appendTo( "#qunit-fixture" ); - jQuery( "" ).appendTo( "#qunit-fixture" ); - - assert.equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3", - "css('width') should return fractional values" ); - assert.equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8", - "css('height') should return fractional values" ); - } ); - - QUnit.test( "css('width') and css('height') should return fractional values for disconnected nodes", function( assert ) { - if ( !supportsFractionalGBCR ) { - assert.expect( 1 ); - assert.ok( true, "This browser doesn't support fractional values in getBoundingClientRect()" ); - return; - } - - assert.expect( 2 ); - - var el = jQuery( "
" ); - - assert.equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3", - "css('width') should return fractional values" ); - assert.equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8", - "css('height') should return fractional values" ); - } ); -} )(); - QUnit.test( "certain css values of 'normal' should be convertable to a number, see #8627", function( assert ) { assert.expect( 3 ); diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 22b3f01982..00139a8c2c 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -251,12 +251,10 @@ QUnit.test( "child of a hidden elem (or unconnected node) has accurate inner/out assert.equal( $divChild.outerWidth(), $divNormal.outerWidth(), "child of a hidden element outerWidth() is wrong see #9441" ); assert.equal( $divChild.outerWidth( true ), $divNormal.outerWidth( true ), "child of a hidden element outerWidth( true ) is wrong see #9300" ); - // Support: IE 10-11, Edge - // Child height is not always decimal - assert.equal( $divChild.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "child of a hidden element height() is wrong see #9441" ); - assert.equal( $divChild.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "child of a hidden element innerHeight() is wrong see #9441" ); - assert.equal( $divChild.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "child of a hidden element outerHeight() is wrong see #9441" ); - assert.equal( $divChild.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "child of a hidden element outerHeight( true ) is wrong see #9300" ); + assert.equal( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #9441" ); + assert.equal( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #9441" ); + assert.equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #9441" ); + assert.equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #9300" ); // tests that child div of an unconnected div works the same as a normal div assert.equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #9441" ); @@ -264,12 +262,10 @@ QUnit.test( "child of a hidden elem (or unconnected node) has accurate inner/out assert.equal( $divUnconnected.outerWidth(), $divNormal.outerWidth(), "unconnected element outerWidth() is wrong see #9441" ); assert.equal( $divUnconnected.outerWidth( true ), $divNormal.outerWidth( true ), "unconnected element outerWidth( true ) is wrong see #9300" ); - // Support: IE 10-11, Edge - // Child height is not always decimal - assert.equal( $divUnconnected.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "unconnected element height() is wrong see #9441" ); - assert.equal( $divUnconnected.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "unconnected element innerHeight() is wrong see #9441" ); - assert.equal( $divUnconnected.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "unconnected element outerHeight() is wrong see #9441" ); - assert.equal( $divUnconnected.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "unconnected element outerHeight( true ) is wrong see #9300" ); + assert.equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #9441" ); + assert.equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #9441" ); + assert.equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #9441" ); + assert.equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #9300" ); // teardown html $divHiddenParent.remove(); @@ -328,12 +324,10 @@ QUnit.test( "box-sizing:border-box child of a hidden elem (or unconnected node) assert.equal( $divChild.outerWidth(), $divNormal.outerWidth(), "child of a hidden element outerWidth() is wrong see #10413" ); assert.equal( $divChild.outerWidth( true ), $divNormal.outerWidth( true ), "child of a hidden element outerWidth( true ) is wrong see #10413" ); - // Support: IE 10-11, Edge - // Child height is not always decimal - assert.equal( $divChild.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "child of a hidden element height() is wrong see #10413" ); - assert.equal( $divChild.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "child of a hidden element innerHeight() is wrong see #10413" ); - assert.equal( $divChild.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "child of a hidden element outerHeight() is wrong see #10413" ); - assert.equal( $divChild.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "child of a hidden element outerHeight( true ) is wrong see #10413" ); + assert.equal( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #10413" ); + assert.equal( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #10413" ); + assert.equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #10413" ); + assert.equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #10413" ); // tests that child div of an unconnected div works the same as a normal div assert.equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #10413" ); @@ -341,12 +335,10 @@ QUnit.test( "box-sizing:border-box child of a hidden elem (or unconnected node) assert.equal( $divUnconnected.outerWidth(), $divNormal.outerWidth(), "unconnected element outerWidth() is wrong see #10413" ); assert.equal( $divUnconnected.outerWidth( true ), $divNormal.outerWidth( true ), "unconnected element outerWidth( true ) is wrong see #10413" ); - // Support: IE 10-11, Edge - // Child height is not always decimal - assert.equal( $divUnconnected.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "unconnected element height() is wrong see #10413" ); - assert.equal( $divUnconnected.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "unconnected element innerHeight() is wrong see #10413" ); - assert.equal( $divUnconnected.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "unconnected element outerHeight() is wrong see #10413" ); - assert.equal( $divUnconnected.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "unconnected element outerHeight( true ) is wrong see #10413" ); + assert.equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #10413" ); + assert.equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #10413" ); + assert.equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #10413" ); + assert.equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #10413" ); // teardown html $divHiddenParent.remove(); From 951c4eafa520d1ad51d243ca6dd3f1675336714e Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:07:21 +0300 Subject: [PATCH 011/114] Revert "Deferred: add .catch handler" This reverts commit 84ccf2606c6b97d5875774bf774f9f2aae950ae7. --- src/deferred.js | 3 --- test/unit/deferred.js | 36 ------------------------------------ 2 files changed, 39 deletions(-) diff --git a/src/deferred.js b/src/deferred.js index e1af425d48..6c85dd6fdd 100644 --- a/src/deferred.js +++ b/src/deferred.js @@ -34,9 +34,6 @@ jQuery.extend( { deferred.done( arguments ).fail( arguments ); return this; }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, // Keep pipe for back-compat pipe: function( /* fnDone, fnFail, fnProgress */ ) { diff --git a/test/unit/deferred.js b/test/unit/deferred.js index 2277df1903..a712737276 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -166,42 +166,6 @@ QUnit.test( "jQuery.Deferred.then - filtering (fail)", function( assert ) { } ); } ); -QUnit.test( "jQuery.Deferred.catch", function( assert ) { - assert.expect( 4 ); - - var value1, value2, value3, - defer = jQuery.Deferred(), - piped = defer[ "catch" ]( function( a, b ) { - return a * b; - } ), - done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); - - piped.done( function( result ) { - value3 = result; - } ); - - defer.fail( function( a, b ) { - value1 = a; - value2 = b; - } ); - - defer.reject( 2, 3 )[ "catch" ]( function() { - assert.strictEqual( value1, 2, "first reject value ok" ); - assert.strictEqual( value2, 3, "second reject value ok" ); - assert.strictEqual( value3, 6, "result of filter ok" ); - done.pop().call(); - } ); - - jQuery.Deferred().resolve()[ "catch" ]( function() { - assert.ok( false, "then should not be called on resolve" ); - } ).then( done.pop() ); - - jQuery.Deferred().reject()[ "catch" ]( jQuery.noop ).done( function( value ) { - assert.strictEqual( value, undefined, "then fail callback can return undefined/null" ); - done.pop().call(); - } ); -} ); - QUnit.test( "[PIPE ONLY] jQuery.Deferred.pipe - filtering (fail)", function( assert ) { assert.expect( 4 ); From 999010b2e7abeb493f70bb0d820c8c924a2a36c3 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:34:24 +0300 Subject: [PATCH 012/114] Revert "Revert "Offset: allow offset setter to throw for disconnected elements"" This reverts commit 578dcee96a8d4d759b3a7e623177fa36a5133ba7. --- test/unit/core.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/test/unit/core.js b/test/unit/core.js index ee17b70b0e..3507dee8f7 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -36,10 +36,6 @@ QUnit.test( "jQuery()", function( assert ) { expected++; attrObj[ "width" ] = 10; } - if ( jQuery.fn.offset ) { - expected++; - attrObj[ "offset" ] = { "top": 1, "left": 1 }; - } if ( jQuery.fn.css ) { expected += 2; attrObj[ "css" ] = { "paddingLeft": 1, "paddingRight": 1 }; @@ -111,10 +107,6 @@ QUnit.test( "jQuery()", function( assert ) { assert.equal( elem[ 0 ].style.width, "10px", "jQuery() quick setter width" ); } - if ( jQuery.fn.offset ) { - assert.equal( elem[ 0 ].style.top, "1px", "jQuery() quick setter offset" ); - } - if ( jQuery.fn.css ) { assert.equal( elem[ 0 ].style.paddingLeft, "1px", "jQuery quick setter css" ); assert.equal( elem[ 0 ].style.paddingRight, "1px", "jQuery quick setter css" ); From 778fc5e977976fe81eeb149dd56ce7819412e5b2 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:34:35 +0300 Subject: [PATCH 013/114] Revert "Ajax: Remove remnants of the load event alias handling" This reverts commit 38a669735d08bcbd28cfb0d77eee82c67aa89eeb. --- src/ajax/load.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ajax/load.js b/src/ajax/load.js index 82f0cf3080..0f1b986f80 100644 --- a/src/ajax/load.js +++ b/src/ajax/load.js @@ -4,13 +4,22 @@ define( [ "../ajax", "../traversing", "../manipulation", - "../selector" + "../selector", + // Optional event/alias dependency + "../event/alias" ], function( jQuery ) { +// Keep a copy of the old load method +var _load = jQuery.fn.load; + /** * Load a url into a page */ jQuery.fn.load = function( url, params, callback ) { + if ( typeof url !== "string" && _load ) { + return _load.apply( this, arguments ); + } + var selector, type, response, self = this, off = url.indexOf( " " ); From 4ecb1b7e57e0bfef9e484c3e14a57289a19e6f61 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:43:24 +0300 Subject: [PATCH 014/114] Revert "Event: remove deprecated event aliases" This reverts commit 0705be475092aede1eddae01319ec931fb9c65fc. --- src/event/alias.js | 4 ++-- test/unit/event.js | 52 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/event/alias.js b/src/event/alias.js index b1b8f701f4..161c8935ef 100644 --- a/src/event/alias.js +++ b/src/event/alias.js @@ -5,9 +5,9 @@ define( [ "./trigger" ], function( jQuery ) { -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + +jQuery.each( ( "blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup contextmenu" ).split( " " ), + "change select submit keydown keypress keyup error contextmenu" ).split( " " ), function( i, name ) { // Handle event binding diff --git a/test/unit/event.js b/test/unit/event.js index 4a5611be82..cdebbb4e7d 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -900,7 +900,57 @@ QUnit.test( "mouseenter, mouseleave don't catch exceptions", function( assert ) } } ); -QUnit.test( "trigger() bubbling", function( assert ) { +if ( jQuery.fn.click ) { + + QUnit.test("trigger() shortcuts", function( assert ) { + assert.expect( 6 ); + + var counter, clickCounter, + elem = jQuery("
  • Change location
  • ").prependTo("#firstUL"); + elem.find("a").on("click", function() { + var close = jQuery("spanx", this); // same with jQuery(this).find("span"); + assert.equal( close.length, 0, "Context element does not exist, length must be zero" ); + assert.ok( !close[0], "Context element does not exist, direct access to element must return undefined" ); + return false; + }).click(); + + // manually clean up detached elements + elem.remove(); + + jQuery("#check1").click(function() { + assert.ok( true, "click event handler for checkbox gets fired twice, see #815" ); + }).click(); + + counter = 0; + jQuery("#firstp")[0].onclick = function() { + counter++; + }; + jQuery("#firstp").click(); + assert.equal( counter, 1, "Check that click, triggers onclick event handler also" ); + + clickCounter = 0; + jQuery("#simon1")[0].onclick = function() { + clickCounter++; + }; + jQuery("#simon1").click(); + assert.equal( clickCounter, 1, "Check that click, triggers onclick event handler on an a tag also" ); + + elem = jQuery("").load(function(){ + assert.ok( true, "Trigger the load event, using the shortcut .load() (#2819)"); + }).load(); + + // manually clean up detached elements + elem.remove(); + + // test that special handlers do not blow up with VML elements (#7071) + jQuery("").appendTo("head"); + jQuery(" ").appendTo("#form"); + jQuery("#oval").click().keydown(); + }); + +} + +QUnit.test("trigger() bubbling", function( assert ) { assert.expect( 18 ); var win = 0, doc = 0, html = 0, body = 0, main = 0, ap = 0; From 8a896dfac8ea9d7307d8819ab848fef9b03cd933 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:43:26 +0300 Subject: [PATCH 015/114] Ajax: code style fixes Only for 2.2.0 version --- src/ajax/load.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ajax/load.js b/src/ajax/load.js index 0f1b986f80..9f1599f91c 100644 --- a/src/ajax/load.js +++ b/src/ajax/load.js @@ -5,6 +5,7 @@ define( [ "../traversing", "../manipulation", "../selector", + // Optional event/alias dependency "../event/alias" ], function( jQuery ) { From 1b52d383ce8a23113d48c26c21a3400429d9de1e Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:50:26 +0300 Subject: [PATCH 016/114] Revert "Core: remove custom ready event" This reverts commit c252c5fac2a25869524c2eba2e93d4230e6af25c. --- src/core/ready.js | 7 +++++++ test/unit/ready.js | 35 ++++++++++++++++++++++++----------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/core/ready.js b/src/core/ready.js index 73c3d706a2..7d93e67687 100644 --- a/src/core/ready.js +++ b/src/core/ready.js @@ -1,6 +1,7 @@ define( [ "../core", "../var/document", + "../core/init", "../deferred" ], function( jQuery, document ) { @@ -51,6 +52,12 @@ jQuery.extend( { // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } } } ); diff --git a/test/unit/ready.js b/test/unit/ready.js index 6272dbdd40..337568c8fe 100644 --- a/test/unit/ready.js +++ b/test/unit/ready.js @@ -29,29 +29,34 @@ QUnit.module( "ready" ); // Bind to the ready event in every possible way. jQuery( makeHandler( "a" ) ); jQuery( document ).ready( makeHandler( "b" ) ); + jQuery( document ).on( "ready.readytest", makeHandler( "c" ) ); // Do it twice, just to be sure. - jQuery( makeHandler( "c" ) ); - jQuery( document ).ready( makeHandler( "d" ) ); + jQuery( makeHandler( "d" ) ); + jQuery( document ).ready( makeHandler( "e" ) ); + jQuery( document ).on( "ready.readytest", makeHandler( "f" ) ); noEarlyExecution = order.length === 0; // This assumes that QUnit tests are run on DOM ready! QUnit.test( "jQuery ready", function( assert ) { - assert.expect( 8 ); + assert.expect( 10 ); - assert.ok( noEarlyExecution, - "Handlers bound to DOM ready should not execute before DOM ready" ); + assert.ok( noEarlyExecution, "Handlers bound to DOM ready should not execute before DOM ready" ); // Ensure execution order. - assert.deepEqual( order, [ "a", "b", "c", "d" ], - "Bound DOM ready handlers should execute in on-order" ); + assert.deepEqual( order, [ "a", "b", "d", "e", "c", "f" ], + "Bound DOM ready handlers should execute in on-order, but those bound with" + + "jQuery(document).on( 'ready', fn ) will always execute last" ); // Ensure handler argument is correct. - assert.equal( args.a, jQuery, + assert.equal( args[ "a" ], jQuery, "Argument passed to fn in jQuery( fn ) should be jQuery" ); - assert.equal( args.b, jQuery, + assert.equal( args[ "b" ], jQuery, "Argument passed to fn in jQuery(document).ready( fn ) should be jQuery" ); + assert.ok( args[ "c" ] instanceof jQuery.Event, + "Argument passed to fn in jQuery(document).on( 'ready', fn )" + + " should be an event object" ); order = []; @@ -59,12 +64,20 @@ QUnit.module( "ready" ); // in every possible way. These event handlers should execute immediately. jQuery( makeHandler( "g" ) ); assert.equal( order.pop(), "g", "Event handler should execute immediately" ); - assert.equal( args.g, jQuery, "Argument passed to fn in jQuery( fn ) should be jQuery" ); + assert.equal( args[ "g" ], jQuery, + "Argument passed to fn in jQuery( fn ) should be jQuery" ); jQuery( document ).ready( makeHandler( "h" ) ); assert.equal( order.pop(), "h", "Event handler should execute immediately" ); - assert.equal( args.h, jQuery, + assert.equal( args[ "h" ], jQuery, "Argument passed to fn in jQuery(document).ready( fn ) should be jQuery" ); + + jQuery( document ).on( "ready.readytest", makeHandler( "never" ) ); + assert.equal( order.length, 0, + "Event handler should never execute since DOM ready has already passed" ); + + // Cleanup. + jQuery( document ).off( "ready.readytest" ); } ); } )(); From 43996d166ee72bc5180edeca2b3312d5c40709cd Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:51:35 +0300 Subject: [PATCH 017/114] Revert "Effects: fix loading showHide in AMD mode" This reverts commit ab06be561ec74cccaa2d581830210f82326f05c3. --- src/css/showHide.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/css/showHide.js b/src/css/showHide.js index 29e2d8bc8e..10d2819930 100644 --- a/src/css/showHide.js +++ b/src/css/showHide.js @@ -67,5 +67,4 @@ jQuery.fn.extend( { } } ); -return showHide; } ); From 88df7676d735b4cf16dd56ac55fbdef3319f66e7 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:51:41 +0300 Subject: [PATCH 018/114] Revert "CSS: fix AMD mode for the new showHide module" This reverts commit 32cfc38a9c76d1f9163759c811cb9c82eb47d565. --- src/css/showHide.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/css/showHide.js b/src/css/showHide.js index 10d2819930..327291eb11 100644 --- a/src/css/showHide.js +++ b/src/css/showHide.js @@ -1,8 +1,7 @@ define( [ - "../core", "../data/var/dataPriv", "../css/var/isHidden" -], function( jQuery, dataPriv, isHidden ) { +], function( dataPriv, isHidden ) { function showHide( elements, show ) { var display, elem, From 87db099ed54d0dac624c4ae6b476328e88aef2d7 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 11 Nov 2015 19:56:11 +0300 Subject: [PATCH 019/114] Revert "CSS: Make show/hide/toggle methods a module" This reverts commit 67d7a2eefee768b59eb3d51cb1fb2c671873e58a. --- Gruntfile.js | 1 - README.md | 3 +-- src/css.js | 22 +++++++++++++++++++++- src/css/showHide.js | 27 +++------------------------ test/unit/basic.js | 10 +--------- test/unit/css.js | 30 +++++++++++++----------------- test/unit/dimensions.js | 16 ++++++++-------- test/unit/queue.js | 3 --- 8 files changed, 47 insertions(+), 65 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index dd4b07d308..98e446775e 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -70,7 +70,6 @@ module.exports = function( grunt ) { ajax: [ "manipulation/_evalUrl", "event/ajax" ], callbacks: [ "deferred" ], css: [ "effects", "dimensions", "offset" ], - "css/showHide": [ "effects" ], sizzle: [ "css/hiddenVisibleSelectors", "effects/animatedSelector" ] } } diff --git a/README.md b/README.md index 99bcb2355b..71c015f78b 100644 --- a/README.md +++ b/README.md @@ -81,8 +81,7 @@ Some example modules that can be excluded are: - **ajax/xhr**: The XMLHTTPRequest AJAX transport only. - **ajax/script**: The ` - diff --git a/test/unit/deferred.js b/test/unit/deferred.js index a712737276..e050f0454b 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -14,34 +14,34 @@ jQuery.each( [ "", " - new operator" ], function( _, withNew ) { var defer = createDeferred(); - assert.ok( jQuery.isFunction( defer.pipe ), "defer.pipe is a function" ); + assert.strictEqual( defer.pipe, defer.then, "pipe is an alias of then" ); - createDeferred().resolve().done( function() { + createDeferred().resolve().done(function() { assert.ok( true, "Success on resolve" ); assert.strictEqual( this.state(), "resolved", "Deferred is resolved (state)" ); - } ).fail( function() { + }).fail(function() { assert.ok( false, "Error on resolve" ); - } ).always( function() { + }).always(function() { assert.ok( true, "Always callback on resolve" ); - } ); + }); - createDeferred().reject().done( function() { + createDeferred().reject().done(function() { assert.ok( false, "Success on reject" ); - } ).fail( function() { + }).fail(function() { assert.ok( true, "Error on reject" ); assert.strictEqual( this.state(), "rejected", "Deferred is rejected (state)" ); - } ).always( function() { + }).always(function() { assert.ok( true, "Always callback on reject" ); - } ); + }); - createDeferred( function( defer ) { + createDeferred(function( defer ) { assert.ok( this === defer, "Defer passed as this & first argument" ); - this.resolve( "done" ); - } ).done( function( value ) { + this.resolve("done"); + }).done(function( value ) { assert.strictEqual( value, "done", "Passed function executed" ); - } ); + }); - createDeferred( function( defer ) { + createDeferred(function( defer ) { var promise = defer.promise(), func = function() {}, funcPromise = defer.promise( func ); @@ -93,126 +93,79 @@ QUnit.test( "jQuery.Deferred - chainability", function( assert ) { } ); QUnit.test( "jQuery.Deferred.then - filtering (done)", function( assert ) { - assert.expect( 4 ); var value1, value2, value3, defer = jQuery.Deferred(), - piped = defer.then( function( a, b ) { + piped = defer.then(function( a, b ) { return a * b; - } ), - done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); + }); - piped.done( function( result ) { + piped.done(function( result ) { value3 = result; - } ); + }); - defer.done( function( a, b ) { + defer.done(function( a, b ) { value1 = a; value2 = b; - } ); + }); - defer.resolve( 2, 3 ).then( function() { - assert.strictEqual( value1, 2, "first resolve value ok" ); - assert.strictEqual( value2, 3, "second resolve value ok" ); - assert.strictEqual( value3, 6, "result of filter ok" ); - done.pop().call(); - } ); + defer.resolve( 2, 3 ); - jQuery.Deferred().reject().then( function() { + assert.strictEqual( value1, 2, "first resolve value ok" ); + assert.strictEqual( value2, 3, "second resolve value ok" ); + assert.strictEqual( value3, 6, "result of filter ok" ); + + jQuery.Deferred().reject().then(function() { assert.ok( false, "then should not be called on reject" ); - } ).then( null, done.pop() ); + }); - jQuery.Deferred().resolve().then( jQuery.noop ).done( function( value ) { + jQuery.Deferred().resolve().then( jQuery.noop ).done(function( value ) { assert.strictEqual( value, undefined, "then done callback can return undefined/null" ); - done.pop().call(); - } ); + }); } ); QUnit.test( "jQuery.Deferred.then - filtering (fail)", function( assert ) { - assert.expect( 4 ); var value1, value2, value3, defer = jQuery.Deferred(), piped = defer.then( null, function( a, b ) { return a * b; - } ), - done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); + }); - piped.done( function( result ) { + piped.fail(function( result ) { value3 = result; - } ); + }); - defer.fail( function( a, b ) { + defer.fail(function( a, b ) { value1 = a; value2 = b; - } ); - - defer.reject( 2, 3 ).then( null, function() { - assert.strictEqual( value1, 2, "first reject value ok" ); - assert.strictEqual( value2, 3, "second reject value ok" ); - assert.strictEqual( value3, 6, "result of filter ok" ); - done.pop().call(); - } ); - - jQuery.Deferred().resolve().then( null, function() { - assert.ok( false, "then should not be called on resolve" ); - } ).then( done.pop() ); - - jQuery.Deferred().reject().then( null, jQuery.noop ).done( function( value ) { - assert.strictEqual( value, undefined, "then fail callback can return undefined/null" ); - done.pop().call(); - } ); -} ); - -QUnit.test( "[PIPE ONLY] jQuery.Deferred.pipe - filtering (fail)", function( assert ) { - - assert.expect( 4 ); + }); - var value1, value2, value3, - defer = jQuery.Deferred(), - piped = defer.pipe( null, function( a, b ) { - return a * b; - } ), - done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); - - piped.fail( function( result ) { - value3 = result; - } ); - - defer.fail( function( a, b ) { - value1 = a; - value2 = b; - } ); + defer.reject( 2, 3 ); - defer.reject( 2, 3 ).pipe( null, function() { - assert.strictEqual( value1, 2, "first reject value ok" ); - assert.strictEqual( value2, 3, "second reject value ok" ); - assert.strictEqual( value3, 6, "result of filter ok" ); - done.pop().call(); - } ); + strictEqual( value1, 2, "first reject value ok" ); + strictEqual( value2, 3, "second reject value ok" ); + strictEqual( value3, 6, "result of filter ok" ); - jQuery.Deferred().resolve().pipe( null, function() { - assert.ok( false, "then should not be called on resolve" ); - } ).then( done.pop() ); + jQuery.Deferred().resolve().then( null, function() { + ok( false, "then should not be called on resolve" ); + }); - jQuery.Deferred().reject().pipe( null, jQuery.noop ).fail( function( value ) { - assert.strictEqual( value, undefined, "then fail callback can return undefined/null" ); - done.pop().call(); - } ); -} ); + jQuery.Deferred().reject().then( null, jQuery.noop ).fail(function( value ) { + strictEqual( value, undefined, "then fail callback can return undefined/null" ); + }); +}); QUnit.test( "jQuery.Deferred.then - filtering (progress)", function( assert ) { - assert.expect( 3 ); var value1, value2, value3, defer = jQuery.Deferred(), piped = defer.then( null, null, function( a, b ) { return a * b; - } ), - done = assert.async(); + } ); piped.progress( function( result ) { value3 = result; @@ -223,16 +176,14 @@ QUnit.test( "jQuery.Deferred.then - filtering (progress)", function( assert ) { value2 = b; } ); - defer.notify( 2, 3 ).then( null, null, function() { - assert.strictEqual( value1, 2, "first progress value ok" ); - assert.strictEqual( value2, 3, "second progress value ok" ); - assert.strictEqual( value3, 6, "result of filter ok" ); - done(); - } ); -} ); + defer.notify( 2, 3 ); -QUnit.test( "jQuery.Deferred.then - deferred (done)", function( assert ) { + assert.strictEqual( value1, 2, "first progress value ok" ); + assert.strictEqual( value2, 3, "second progress value ok" ); + assert.strictEqual( value3, 6, "result of filter ok" ); +}); +QUnit.test( "jQuery.Deferred.then - deferred (done)", function( assert ) { assert.expect( 3 ); var value1, value2, value3, @@ -241,8 +192,7 @@ QUnit.test( "jQuery.Deferred.then - deferred (done)", function( assert ) { return jQuery.Deferred( function( defer ) { defer.reject( a * b ); } ); - } ), - done = assert.async(); + } ); piped.fail( function( result ) { value3 = result; @@ -255,16 +205,12 @@ QUnit.test( "jQuery.Deferred.then - deferred (done)", function( assert ) { defer.resolve( 2, 3 ); - piped.fail( function() { - assert.strictEqual( value1, 2, "first resolve value ok" ); - assert.strictEqual( value2, 3, "second resolve value ok" ); - assert.strictEqual( value3, 6, "result of filter ok" ); - done(); - } ); -} ); + assert.strictEqual( value1, 2, "first resolve value ok" ); + assert.strictEqual( value2, 3, "second resolve value ok" ); + assert.strictEqual( value3, 6, "result of filter ok" ); +}); QUnit.test( "jQuery.Deferred.then - deferred (fail)", function( assert ) { - assert.expect( 3 ); var value1, value2, value3, @@ -273,8 +219,7 @@ QUnit.test( "jQuery.Deferred.then - deferred (fail)", function( assert ) { return jQuery.Deferred( function( defer ) { defer.resolve( a * b ); } ); - } ), - done = assert.async(); + } ); piped.done( function( result ) { value3 = result; @@ -287,16 +232,12 @@ QUnit.test( "jQuery.Deferred.then - deferred (fail)", function( assert ) { defer.reject( 2, 3 ); - piped.done( function() { - assert.strictEqual( value1, 2, "first reject value ok" ); - assert.strictEqual( value2, 3, "second reject value ok" ); - assert.strictEqual( value3, 6, "result of filter ok" ); - done(); - } ); -} ); + assert.strictEqual( value1, 2, "first reject value ok" ); + assert.strictEqual( value2, 3, "second reject value ok" ); + assert.strictEqual( value3, 6, "result of filter ok" ); +}); QUnit.test( "jQuery.Deferred.then - deferred (progress)", function( assert ) { - assert.expect( 3 ); var value1, value2, value3, @@ -304,50 +245,8 @@ QUnit.test( "jQuery.Deferred.then - deferred (progress)", function( assert ) { piped = defer.then( null, null, function( a, b ) { return jQuery.Deferred( function( defer ) { defer.resolve( a * b ); - } ); - } ), - done = assert.async(); - - piped.progress( function( result ) { - return jQuery.Deferred().resolve().then( function() { - return result; - } ).then( function( result ) { - value3 = result; - } ); - } ); - - defer.progress( function( a, b ) { - value1 = a; - value2 = b; - } ); - - defer.notify( 2, 3 ); - - piped.then( null, null, function( result ) { - return jQuery.Deferred().resolve().then( function() { - return result; - } ).then( function() { - assert.strictEqual( value1, 2, "first progress value ok" ); - assert.strictEqual( value2, 3, "second progress value ok" ); - assert.strictEqual( value3, 6, "result of filter ok" ); - done(); + } ); } ); - } ); -} ); - -QUnit.test( "[PIPE ONLY] jQuery.Deferred.pipe - deferred (progress)", function( assert ) { - - assert.expect( 3 ); - - var value1, value2, value3, - defer = jQuery.Deferred(), - piped = defer.pipe( null, null, function( a, b ) { - return jQuery.Deferred( function( defer ) { - defer.resolve( a * b ); - } ); - } ), - done = assert.async(); - piped.done( function( result ) { value3 = result; } ); @@ -359,37 +258,29 @@ QUnit.test( "[PIPE ONLY] jQuery.Deferred.pipe - deferred (progress)", function( defer.notify( 2, 3 ); - piped.done( function() { - assert.strictEqual( value1, 2, "first progress value ok" ); - assert.strictEqual( value2, 3, "second progress value ok" ); - assert.strictEqual( value3, 6, "result of filter ok" ); - done(); - } ); -} ); + assert.strictEqual( value1, 2, "first progress value ok" ); + assert.strictEqual( value2, 3, "second progress value ok" ); + assert.strictEqual( value3, 6, "result of filter ok" ); +}); QUnit.test( "jQuery.Deferred.then - context", function( assert ) { - assert.expect( 7 ); var defer, piped, defer2, piped2, - context = {}, - done = jQuery.map( new Array( 4 ), function() { return assert.async(); } ); + context = {}; jQuery.Deferred().resolveWith( context, [ 2 ] ).then( function( value ) { return value * 3; - } ).done( function( value ) { - assert.notStrictEqual( this, context, "custom context not propagated through .then" ); + } ).done(function( value ) { + assert.strictEqual( this, context, "custom context correctly propagated" ); assert.strictEqual( value, 6, "proper value received" ); - done.pop().call(); - } ); + }); - jQuery.Deferred().resolve().then( function() { - return jQuery.Deferred().resolveWith( context ); - } ).done( function() { - assert.strictEqual( this, context, - "custom context of returned deferred correctly propagated" ); - done.pop().call(); - } ); + jQuery.Deferred().resolve().then(function() { + return jQuery.Deferred().resolveWith(context); + }).done(function() { + assert.strictEqual( this, context, "custom context of returned deferred correctly propagated" ); + }); defer = jQuery.Deferred(); piped = defer.then( function( value ) { @@ -398,229 +289,25 @@ QUnit.test( "jQuery.Deferred.then - context", function( assert ) { defer.resolve( 2 ); - piped.done( function( value ) { - assert.strictEqual( this, piped, - "default context gets updated to latest promise in the chain" ); + piped.done(function( value ) { + assert.strictEqual( this, piped, "default context gets updated to latest promise in the chain" ); assert.strictEqual( value, 6, "proper value received" ); - done.pop().call(); - } ); - + }); defer2 = jQuery.Deferred(); piped2 = defer2.then(); defer2.resolve( 2 ); - piped2.done( function( value ) { - assert.strictEqual( this, piped2, - "default context updated to latest promise in the chain (without passing function)" ); - assert.strictEqual( value, 2, "proper value received (without passing function)" ); - done.pop().call(); - } ); -} ); - -QUnit.test( "[PIPE ONLY] jQuery.Deferred.pipe - context", function( assert ) { - - assert.expect( 7 ); - - var defer, piped, defer2, piped2, - context = {}, - done = jQuery.map( new Array( 4 ), function() { return assert.async(); } ); - - jQuery.Deferred().resolveWith( context, [ 2 ] ).pipe( function( value ) { - return value * 3; - } ).done( function( value ) { - assert.strictEqual( this, context, "[PIPE ONLY] custom context correctly propagated" ); - assert.strictEqual( value, 6, "proper value received" ); - done.pop().call(); - } ); - - jQuery.Deferred().resolve().pipe( function() { - return jQuery.Deferred().resolveWith( context ); - } ).done( function() { - assert.strictEqual( this, context, - "custom context of returned deferred correctly propagated" ); - done.pop().call(); - } ); - - defer = jQuery.Deferred(); - piped = defer.pipe( function( value ) { - return value * 3; - } ); - - defer.resolve( 2 ); - - piped.done( function( value ) { - assert.strictEqual( this, piped, - "default context gets updated to latest promise in the chain" ); - assert.strictEqual( value, 6, "proper value received" ); - done.pop().call(); - } ); - - defer2 = jQuery.Deferred(); - piped2 = defer2.pipe(); - - defer2.resolve( 2 ); - - piped2.done( function( value ) { - assert.strictEqual( this, piped2, - "default context updated to latest promise in the chain (without passing function)" ); + piped2.done(function( value ) { + assert.strictEqual( this, piped2, "default context gets updated to latest promise in the chain (without passing function)" ); assert.strictEqual( value, 2, "proper value received (without passing function)" ); - done.pop().call(); - } ); -} ); - -QUnit.test( "jQuery.Deferred.then - spec compatibility", function( assert ) { - - assert.expect( 1 ); - - var done = assert.async(); - - var defer = jQuery.Deferred().done( function() { - setTimeout( done ); - throw new Error(); - } ); - - defer.then( function() { - assert.ok( true, "errors in .done callbacks don't stop .then handlers" ); - } ); - - try { - defer.resolve(); - } catch ( _ ) {} -} ); - -QUnit.test( "jQuery.Deferred - 1.x/2.x compatibility", function( assert ) { - - assert.expect( 8 ); - - var context = { id: "callback context" }, - thenable = jQuery.Deferred().resolve( "thenable fulfillment" ).promise(), - done = jQuery.map( new Array( 8 ), function() { return assert.async(); } ); - - thenable.unwrapped = false; - - jQuery.Deferred().resolve( 1, 2 ).then( function() { - assert.deepEqual( [].slice.call( arguments ), [ 1, 2 ], - ".then fulfillment callbacks receive all resolution values" ); - done.pop().call(); - } ); - jQuery.Deferred().reject( 1, 2 ).then( null, function() { - assert.deepEqual( [].slice.call( arguments ), [ 1, 2 ], - ".then rejection callbacks receive all rejection values" ); - done.pop().call(); - } ); - jQuery.Deferred().notify( 1, 2 ).then( null, null, function() { - assert.deepEqual( [].slice.call( arguments ), [ 1, 2 ], - ".then progress callbacks receive all progress values" ); - done.pop().call(); - } ); - - jQuery.Deferred().resolveWith( context ).then( function() { - assert.deepEqual( this, context, ".then fulfillment callbacks receive context" ); - done.pop().call(); - } ); - jQuery.Deferred().rejectWith( context ).then( null, function() { - assert.deepEqual( this, context, ".then rejection callbacks receive context" ); - done.pop().call(); - } ); - jQuery.Deferred().notifyWith( context ).then( null, null, function() { - assert.deepEqual( this, context, ".then progress callbacks receive context" ); - done.pop().call(); - } ); - - jQuery.Deferred().resolve( thenable ).done( function( value ) { - assert.strictEqual( value, thenable, ".done doesn't unwrap thenables" ); - done.pop().call(); - } ); - - jQuery.Deferred().notify( thenable ).then().then( null, null, function( value ) { - assert.strictEqual( value, "thenable fulfillment", - ".then implicit progress callbacks unwrap thenables" ); - done.pop().call(); - } ); -} ); - -QUnit.test( "jQuery.Deferred.then - progress and thenables", function( assert ) { - - assert.expect( 2 ); - - var trigger = jQuery.Deferred().notify(), - expectedProgress = [ "baz", "baz" ], - done = jQuery.map( new Array( 2 ), function() { return assert.async(); } ), - failer = function( evt ) { - return function() { - assert.ok( false, "no unexpected " + evt ); - }; - }; - - trigger.then( null, null, function() { - var notifier = jQuery.Deferred().notify( "foo" ); - setTimeout( function() { - notifier.notify( "bar" ).resolve( "baz" ); - } ); - return notifier; - } ).then( failer( "fulfill" ), failer( "reject" ), function( v ) { - assert.strictEqual( v, expectedProgress.shift(), "expected progress value" ); - done.pop().call(); - } ); - trigger.notify(); -} ); - -QUnit.test( "jQuery.Deferred - notify and resolve", function( assert ) { - - assert.expect( 7 ); - - var notifiedResolved = jQuery.Deferred().notify( "foo" )/*xxx .resolve( "bar" )*/, - done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); - - notifiedResolved.progress( function( v ) { - assert.strictEqual( v, "foo", "progress value" ); - } ); - - notifiedResolved.pipe().progress( function( v ) { - assert.strictEqual( v, "foo", "piped progress value" ); - } ); - - notifiedResolved.pipe( null, null, function() { - return "baz"; - } ).progress( function( v ) { - assert.strictEqual( v, "baz", "replaced piped progress value" ); - } ); - - notifiedResolved.pipe( null, null, function() { - return jQuery.Deferred().notify( "baz" ).resolve( "quux" ); - } ).progress( function( v ) { - assert.strictEqual( v, "baz", "deferred replaced piped progress value" ); - } ); - - notifiedResolved.then().progress( function( v ) { - assert.strictEqual( v, "foo", "then'd progress value" ); - done.pop().call(); - } ); - - notifiedResolved.then( null, null, function() { - return "baz"; - } ).progress( function( v ) { - assert.strictEqual( v, "baz", "replaced then'd progress value" ); - done.pop().call(); - } ); - - notifiedResolved.then( null, null, function() { - return jQuery.Deferred().notify( "baz" ).resolve( "quux" ); - } ).progress( function( v ) { - - // Progress from the surrogate deferred is ignored - assert.strictEqual( v, "quux", "deferred replaced then'd progress value" ); - done.pop().call(); - } ); -} ); + }); +}); QUnit.test( "jQuery.when", function( assert ) { - assert.expect( 37 ); - // Some other objects - jQuery.each( { + jQuery.each({ "an empty string": "", "a non-empty string": "some string", "zero": 0, @@ -635,21 +322,21 @@ QUnit.test( "jQuery.when", function( assert ) { }, function( message, value ) { assert.ok( jQuery.isFunction( - jQuery.when( value ).done( function( resolveValue ) { + jQuery.when( value ).done(function( resolveValue ) { assert.strictEqual( this, window, "Context is the global object with " + message ); assert.strictEqual( resolveValue, value, "Test the promise was resolved with " + message ); - } ).promise + }).promise ), "Test " + message + " triggers the creation of a new Promise" ); - } ); + }); assert.ok( jQuery.isFunction( - jQuery.when().done( function( resolveValue ) { + jQuery.when().done(function( resolveValue ) { assert.strictEqual( this, window, "Test the promise was resolved with window as its context" ); assert.strictEqual( resolveValue, undefined, "Test the promise was resolved with no parameter" ); - } ).promise + }).promise ), "Test calling when with no parameter triggers the creation of a new Promise" ); @@ -657,63 +344,49 @@ QUnit.test( "jQuery.when", function( assert ) { var cache, context = {}; - jQuery.when( jQuery.Deferred().resolveWith( context ) ).done( function() { + jQuery.when( jQuery.Deferred().resolveWith( context ) ).done(function() { assert.strictEqual( this, context, "when( promise ) propagates context" ); - } ); + }); - jQuery.each( [ 1, 2, 3 ], function( k, i ) { + jQuery.each([ 1, 2, 3 ], function( k, i ) { - jQuery.when( cache || jQuery.Deferred( function() { + jQuery.when( cache || jQuery.Deferred(function() { this.resolve( i ); - } ) - ).done( function( value ) { + }) + ).done(function( value ) { assert.strictEqual( value, 1, "Function executed" + ( i > 1 ? " only once" : "" ) ); cache = value; - } ); + }); - } ); + }); } ); QUnit.test( "jQuery.when - joined", function( assert ) { - - assert.expect( 195 ); + assert.expect( 119 ); var deferreds = { - rawValue: 1, - fulfilled: jQuery.Deferred().resolve( 1 ), - rejected: jQuery.Deferred().reject( 0 ), - notified: jQuery.Deferred().notify( true ), - eventuallyFulfilled: jQuery.Deferred().notify( true ), - eventuallyRejected: jQuery.Deferred().notify( true ), - fulfilledStandardPromise: Promise.resolve( 1 ), - rejectedStandardPromise: Promise.reject( 0 ) + value: 1, + success: jQuery.Deferred().resolve( 1 ), + error: jQuery.Deferred().reject( 0 ), + futureSuccess: jQuery.Deferred().notify( true ), + futureError: jQuery.Deferred().notify( true ), + notify: jQuery.Deferred().notify( true ) }, willSucceed = { - rawValue: true, - fulfilled: true, - eventuallyFulfilled: true, - fulfilledStandardPromise: true + value: true, + success: true, + futureSuccess: true }, willError = { - rejected: true, - eventuallyRejected: true, - rejectedStandardPromise: true + error: true, + futureError: true }, willNotify = { - notified: true, - eventuallyFulfilled: true, - eventuallyRejected: true - }, - counter = 49; - - QUnit.stop(); - - function restart() { - if ( !--counter ) { - QUnit.start(); - } - } + futureSuccess: true, + futureError: true, + notify: true + }; jQuery.each( deferreds, function( id1, defer1 ) { jQuery.each( deferreds, function( id2, defer2 ) { @@ -722,125 +395,53 @@ QUnit.test( "jQuery.when - joined", function( assert ) { shouldNotify = willNotify[ id1 ] || willNotify[ id2 ], expected = shouldResolve ? [ 1, 1 ] : [ 0, undefined ], expectedNotify = shouldNotify && [ willNotify[ id1 ], willNotify[ id2 ] ], - code = "jQuery.when( " + id1 + ", " + id2 + " )", - context1 = defer1 && jQuery.isFunction( defer1.promise ) ? defer1.promise() : - ( defer1.then ? window : undefined ), - context2 = defer2 && jQuery.isFunction( defer2.promise ) ? defer2.promise() : - ( defer2.then ? window : undefined ); + code = id1 + "/" + id2, + context1 = defer1 && jQuery.isFunction( defer1.promise ) ? defer1.promise() : undefined, + context2 = defer2 && jQuery.isFunction( defer2.promise ) ? defer2.promise() : undefined; - jQuery.when( defer1, defer2 ).done( function( a, b ) { + jQuery.when( defer1, defer2 ).done(function( a, b ) { if ( shouldResolve ) { assert.deepEqual( [ a, b ], expected, code + " => resolve" ); assert.strictEqual( this[ 0 ], context1, code + " => first context OK" ); assert.strictEqual( this[ 1 ], context2, code + " => second context OK" ); } else { - assert.ok( false, code + " => resolve" ); + ok( false, code + " => resolve" ); } - } ).fail( function( a, b ) { + }).fail(function( a, b ) { if ( shouldError ) { assert.deepEqual( [ a, b ], expected, code + " => reject" ); } else { - assert.ok( false, code + " => reject" ); + ok( false, code + " => reject" ); } - } ).progress( function( a, b ) { + }).progress(function( a, b ) { assert.deepEqual( [ a, b ], expectedNotify, code + " => progress" ); assert.strictEqual( this[ 0 ], expectedNotify[ 0 ] ? context1 : undefined, code + " => first context OK" ); assert.strictEqual( this[ 1 ], expectedNotify[ 1 ] ? context2 : undefined, code + " => second context OK" ); - } ).always( restart ); - } ); - } ); - deferreds.eventuallyFulfilled.resolve( 1 ); - deferreds.eventuallyRejected.reject( 0 ); -} ); + }); + }); + }); -QUnit.test( "jQuery.when - resolved", function( assert ) { + deferreds.futureSuccess.resolve( 1 ); + deferreds.futureError.reject( 0 ); +}); +QUnit.test( "jQuery.when - resolved", function( assert ) { assert.expect( 6 ); var a = jQuery.Deferred().notify( 1 ).resolve( 4 ), b = jQuery.Deferred().notify( 2 ).resolve( 5 ), c = jQuery.Deferred().notify( 3 ).resolve( 6 ); - jQuery.when( a, b, c ).progress( function( a, b, c ) { + jQuery.when( a, b, c ).progress(function( a, b, c ) { assert.strictEqual( a, 1, "first notify value ok" ); assert.strictEqual( b, 2, "second notify value ok" ); assert.strictEqual( c, 3, "third notify value ok" ); - } ).done( function( a, b, c ) { + }).done(function( a, b, c ) { assert.strictEqual( a, 4, "first resolve value ok" ); assert.strictEqual( b, 5, "second resolve value ok" ); assert.strictEqual( c, 6, "third resolve value ok" ); - } ).fail( function() { + }).fail(function() { assert.ok( false, "Error on resolve" ); - } ); -} ); - -QUnit.test( "jQuery.when - filtering", function( assert ) { + }); - assert.expect( 2 ); - - function increment( x ) { - return x + 1; - } - - QUnit.stop(); - - jQuery.when( - jQuery.Deferred().resolve( 3 ).then( increment ), - jQuery.Deferred().reject( 5 ).then( null, increment ) - ).done( function( four, six ) { - assert.strictEqual( four, 4, "resolved value incremented" ); - assert.strictEqual( six, 6, "rejected value incremented" ); - QUnit.start(); - } ); -} ); - -QUnit.test( "jQuery.when - exceptions", function( assert ) { - - assert.expect( 2 ); - - function woops() { - throw "exception thrown"; - } - - QUnit.stop(); - - jQuery.Deferred().resolve().then( woops ).fail( function( doneException ) { - assert.strictEqual( doneException, "exception thrown", "throwing in done handler" ); - jQuery.Deferred().reject().then( null, woops ).fail( function( failException ) { - assert.strictEqual( failException, "exception thrown", "throwing in fail handler" ); - QUnit.start(); - } ); - } ); -} ); - -QUnit.test( "jQuery.when - chaining", function( assert ) { - - assert.expect( 4 ); - - var defer = jQuery.Deferred(); - - function chain() { - return defer; - } - - function chainStandard() { - return Promise.resolve( "std deferred" ); - } - - QUnit.stop(); - - jQuery.when( - jQuery.Deferred().resolve( 3 ).then( chain ), - jQuery.Deferred().reject( 5 ).then( null, chain ), - jQuery.Deferred().resolve( 3 ).then( chainStandard ), - jQuery.Deferred().reject( 5 ).then( null, chainStandard ) - ).done( function( v1, v2, s1, s2 ) { - assert.strictEqual( v1, "other deferred", "chaining in done handler" ); - assert.strictEqual( v2, "other deferred", "chaining in fail handler" ); - assert.strictEqual( s1, "std deferred", "chaining thenable in done handler" ); - assert.strictEqual( s2, "std deferred", "chaining thenable in fail handler" ); - QUnit.start(); - } ); - - defer.resolve( "other deferred" ); -} ); +}); From c69673fe41ee17f46545e87a31ff96cea6c68a17 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:02:32 +0300 Subject: [PATCH 030/114] Release: remove revert artefacts --- src/data.js | 9 ++- src/data/Data.js | 17 ++-- src/deferred.js | 29 ++++--- src/offset.js | 4 +- src/wrap.js | 4 +- test/data/badjson.js | 2 +- test/data/testinit.js | 2 + test/unit/ajax.js | 6 +- test/unit/attributes.js | 6 +- test/unit/core.js | 30 +++---- test/unit/data.js | 21 ++--- test/unit/deferred.js | 160 +++++++++++++++++++------------------- test/unit/deprecated.js | 7 +- test/unit/dimensions.js | 10 +-- test/unit/effects.js | 95 +++++++++++----------- test/unit/event.js | 45 ++++++----- test/unit/manipulation.js | 2 +- test/unit/offset.js | 8 +- test/unit/selector.js | 30 ++++--- test/unit/serialize.js | 12 +-- test/unit/support.js | 2 +- 21 files changed, 258 insertions(+), 243 deletions(-) diff --git a/src/data.js b/src/data.js index 17e9c64f1a..f7734e7f38 100644 --- a/src/data.js +++ b/src/data.js @@ -120,6 +120,7 @@ jQuery.fn.extend( { // will result in `undefined` for elem = this[ 0 ] which will // throw an exception if an attempt to read a data cache is made. if ( elem && value === undefined ) { + // Attempt to get data from the cache // with the key as-is data = dataUser.get( elem, key ); @@ -128,6 +129,7 @@ jQuery.fn.extend( { } camelKey = jQuery.camelCase( key ); + // Attempt to get data from the cache // with the key camelized data = dataUser.get( elem, camelKey ); @@ -148,7 +150,8 @@ jQuery.fn.extend( { // Set the data... camelKey = jQuery.camelCase( key ); - this.each(function() { + this.each( function() { + // First, attempt to store a copy or reference of any // data that might've been store with a camelCased key. var data = dataUser.get( this, camelKey ); @@ -161,10 +164,10 @@ jQuery.fn.extend( { // *... In the case of properties that might _actually_ // have dashes, we need to also store a copy of that // unchanged property. - if ( key.indexOf("-") > -1 && data !== undefined ) { + if ( key.indexOf( "-" ) > -1 && data !== undefined ) { dataUser.set( this, key, value ); } - }); + } ); }, null, value, arguments.length > 1, null, true ); }, diff --git a/src/data/Data.js b/src/data/Data.js index b33f134972..0e29c1fc63 100644 --- a/src/data/Data.js +++ b/src/data/Data.js @@ -28,11 +28,12 @@ Data.prototype = { value: value, writable: true, configurable: true - }); + } ); } return owner[ this.expando ]; }, - cache: function( owner, initial ) { + cache: function( owner ) { + // We can accept data for non-element nodes in modern browsers, // but we should not, see #8335. // Always return an empty object. @@ -81,6 +82,7 @@ Data.prototype = { // Handle: [ owner, { properties } ] args } else { + // Copy the properties one-by-one to the cache object for ( prop in data ) { cache[ prop ] = data[ prop ]; @@ -91,10 +93,11 @@ Data.prototype = { get: function( owner, key ) { return key === undefined ? this.cache( owner ) : - owner[ this.expando ] && owner[ this.expando ][ key ] + owner[ this.expando ] && owner[ this.expando ][ key ]; }, access: function( owner, key, value ) { var stored; + // In cases where either: // // 1. No key was specified @@ -107,12 +110,12 @@ Data.prototype = { // 2. The data stored at the key // if ( key === undefined || - ((key && typeof key === "string") && value === undefined) ) { + ( ( key && typeof key === "string" ) && value === undefined ) ) { stored = this.get( owner, key ); return stored !== undefined ? - stored : this.get( owner, jQuery.camelCase(key) ); + stored : this.get( owner, jQuery.camelCase( key ) ); } // When the key is not a string, or both a key and value @@ -139,8 +142,10 @@ Data.prototype = { this.register( owner ); } else { + // Support array or space separated string of keys if ( jQuery.isArray( key ) ) { + // If "name" is an array of keys... // When data is initially created, via ("key", "val") signature, // keys will be converted to camelCase. @@ -150,10 +155,12 @@ Data.prototype = { name = key.concat( key.map( jQuery.camelCase ) ); } else { camel = jQuery.camelCase( key ); + // Try the string as a key before any manipulation if ( key in cache ) { name = [ key, camel ]; } else { + // If a key with the spaces exists, use it. // Otherwise, create an array by matching non-whitespace name = camel; diff --git a/src/deferred.js b/src/deferred.js index b56a401045..d2cd6080f8 100644 --- a/src/deferred.js +++ b/src/deferred.js @@ -4,14 +4,15 @@ define( [ "./callbacks" ], function( jQuery, slice ) { -jQuery.extend({ +jQuery.extend( { Deferred: function( func ) { var tuples = [ + // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], - [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], - [ "notify", "progress", jQuery.Callbacks("memory") ] + [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], + [ "notify", "progress", jQuery.Callbacks( "memory" ) ] ], state = "pending", promise = { @@ -24,11 +25,12 @@ jQuery.extend({ }, then: function( /* fnDone, fnFail, fnProgress */ ) { var fns = arguments; - return jQuery.Deferred(function( newDefer ) { + return jQuery.Deferred( function( newDefer ) { jQuery.each( tuples, function( i, tuple ) { var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ](function() { + deferred[ tuple[ 1 ] ]( function() { var returned = fn && fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise() @@ -46,6 +48,7 @@ jQuery.extend({ fns = null; } ).promise(); }, + // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { @@ -63,11 +66,12 @@ jQuery.extend({ stateString = tuple[ 3 ]; // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; + promise[ tuple[ 1 ] ] = list.add; // Handle state if ( stateString ) { - list.add(function() { + list.add( function() { + // state = [ resolved | rejected ] state = stateString; @@ -76,12 +80,13 @@ jQuery.extend({ } // deferred[ resolve | reject | notify ] - deferred[ tuple[0] ] = function() { - deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); return this; }; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + // Make the deferred a promise promise.promise( deferred ); diff --git a/src/offset.js b/src/offset.js index acc41997a9..4352a99954 100644 --- a/src/offset.js +++ b/src/offset.js @@ -77,9 +77,9 @@ jQuery.fn.extend( { if ( arguments.length ) { return options === undefined ? this : - this.each(function( i ) { + this.each( function( i ) { jQuery.offset.setOffset( this, options, i ); - }); + } ); } var docElem, win, diff --git a/src/wrap.js b/src/wrap.js index c85cd304e1..32d1d331f2 100644 --- a/src/wrap.js +++ b/src/wrap.js @@ -64,11 +64,11 @@ jQuery.fn.extend( { }, unwrap: function() { - return this.parent().each(function() { + return this.parent().each( function() { if ( !jQuery.nodeName( this, "body" ) ) { jQuery( this ).replaceWith( this.childNodes ); } - }).end(); + } ).end(); } } ); diff --git a/test/data/badjson.js b/test/data/badjson.js index ad2de7a392..d359e824fb 100644 --- a/test/data/badjson.js +++ b/test/data/badjson.js @@ -1 +1 @@ -{bad: toTheBone} +{bad: toTheBone;} diff --git a/test/data/testinit.js b/test/data/testinit.js index ca8f433d7d..4c8d7d9729 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -269,6 +269,7 @@ this.iframeCallback = undefined; // Tests are always loaded async QUnit.config.autostart = false; this.loadTests = function() { + // Leverage QUnit URL parsing to detect testSwarm environment and "basic" testing mode var loadSwarm = ( QUnit.urlParams[ "swarmURL" ] + "" ).indexOf( "http" ) === 0, basicTests = ( QUnit.urlParams[ "module" ] + "" ) === "basic"; @@ -277,6 +278,7 @@ this.loadTests = function() { require( [ "data/testrunner.js" ], function() { var i = 0, tests = [ + // A special module with basic tests, meant for // not fully supported environments like Android 2.3, // jsdom or PhantomJS. We run it everywhere, though, diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 8e7cc06f49..5110a9795f 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1586,11 +1586,11 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re } else { // No built-in support for binary data, but it's easy to add via a prefilter - jQuery.ajaxPrefilter( "arraybuffer", function ( s ) { + jQuery.ajaxPrefilter( "arraybuffer", function( s ) { s.xhrFields = { responseType: "arraybuffer" }; s.responseFields.arraybuffer = "response"; s.converters[ "binary arraybuffer" ] = true; - }); + } ); ajaxTest( "gh-2498 - jQuery.ajax() - binary data shouldn't throw an exception", 2, function( assert ) { return { @@ -1828,7 +1828,7 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re url: url( "data/ajax/content-type.php" ), data: { "content-type": "test/jsontest", - "response": JSON.stringify({test: "test"}) + "response": JSON.stringify( { test: "test" } ) }, success: function( result ) { assert.strictEqual( diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 517c907db2..f2bcefcad5 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -737,9 +737,9 @@ QUnit.test( "prop('tabindex')", function( assert ) { QUnit.test( "image.prop( 'tabIndex' )", function( assert ) { assert.expect( 1 ); - var image = jQuery("") - .appendTo("#qunit-fixture"); - assert.equal( image.prop("tabIndex" ), -1, "tabIndex on image" ); + var image = jQuery( "" ) + .appendTo( "#qunit-fixture" ); + assert.equal( image.prop( "tabIndex" ), -1, "tabIndex on image" ); } ); QUnit.test( "prop('tabindex', value)", function( assert ) { diff --git a/test/unit/core.js b/test/unit/core.js index 1faf293b0d..e2b4d1b552 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -38,7 +38,7 @@ QUnit.test( "jQuery()", function( assert ) { } if ( jQuery.fn.offset ) { expected++; - attrObj["offset"] = { "top": 1, "left": 1 }; + attrObj[ "offset" ] = { "top": 1, "left": 1 }; } if ( jQuery.fn.css ) { expected += 2; @@ -95,7 +95,7 @@ QUnit.test( "jQuery()", function( assert ) { assert.equal( div.length, 4, "Correct number of elements generated for div hr code b" ); assert.equal( div.parent().length, 0, "Make sure that the generated HTML has no parent." ); - assert.equal( jQuery( [ 1,2,3 ] ).get( 1 ), 2, "Test passing an array to the factory" ); + assert.equal( jQuery( [ 1, 2, 3 ] ).get( 1 ), 2, "Test passing an array to the factory" ); assert.equal( jQuery( document.body ).get( 0 ), jQuery( "body" ).get( 0 ), "Test passing an html node to the factory" ); @@ -105,14 +105,14 @@ QUnit.test( "jQuery()", function( assert ) { elem = jQuery( "\n\nworld" )[ 0 ]; assert.equal( elem.nodeName.toLowerCase(), "em", "leading newlines" ); - elem = jQuery("
    ", attrObj ); + elem = jQuery( "
    ", attrObj ); if ( jQuery.fn.width ) { assert.equal( elem[ 0 ].style.width, "10px", "jQuery() quick setter width" ); } if ( jQuery.fn.offset ) { - equal( elem[0].style.top, "1px", "jQuery() quick setter offset"); + assert.equal( elem[ 0 ].style.top, "1px", "jQuery() quick setter offset" ); } if ( jQuery.fn.css ) { @@ -273,8 +273,9 @@ QUnit.test( "type", function( assert ) { } ); QUnit.test( "type for `Symbol`", function( assert ) { + // Prevent reference errors - if( typeof Symbol !== "function" ) { + if ( typeof Symbol !== "function" ) { assert.expect( 0 ); return; } @@ -283,7 +284,7 @@ QUnit.test( "type for `Symbol`", function( assert ) { assert.equal( jQuery.type( Symbol() ), "symbol", "Symbol" ); assert.equal( jQuery.type( Object( Symbol() ) ), "symbol", "Symbol" ); -}); +} ); QUnit.asyncTest( "isPlainObject", function( assert ) { assert.expect( 15 ); @@ -361,7 +362,6 @@ QUnit[ typeof Symbol === "function" ? "test" : "skip" ]( "isPlainObject(Symbol)" assert.equal( jQuery.isPlainObject( Object( Symbol() ) ), false, "Symbol inside an object" ); } ); - QUnit.test( "isFunction", function( assert ) { assert.expect( 19 ); @@ -913,7 +913,7 @@ QUnit.test( "jQuery.map", function( assert ) { assert.ok( !result, "empty NodeList treated like array" ); result = jQuery.map( Array( 4 ), function( v, k ) { - return k % 2 ? k : [ k,k,k ]; + return k % 2 ? k : [ k, k, k ]; } ); assert.equal( result.join( "" ), "00012223", "Array results flattened (#2616)" ); } ); @@ -1065,7 +1065,7 @@ QUnit.test( "jQuery.grep(Array-like)", function( assert ) { [], "Satisfying elements absent, Array-like object used, and grep explicitly uninverted" ); -}); +} ); QUnit.test( "jQuery.extend(Object, Object)", function( assert ) { assert.expect( 28 ); @@ -1183,19 +1183,19 @@ QUnit.test( "jQuery.extend(Object, Object)", function( assert ) { QUnit.test( "jQuery.extend(Object, Object {created with \"defineProperties\"})", function( assert ) { assert.expect( 2 ); - var definedObj = Object.defineProperties({}, { + var definedObj = Object.defineProperties( {}, { "enumerableProp": { - get: function () { + get: function() { return true; }, enumerable: true }, "nonenumerableProp": { - get: function () { + get: function() { return true; } } - }), + } ), accessorObj = {}; jQuery.extend( accessorObj, definedObj ); @@ -1253,7 +1253,7 @@ QUnit.test( "jQuery.each(Object,Function)", function( assert ) { assert.deepEqual( seen, [ 1, 2 ], "Broken array iteration" ); seen = []; - jQuery.each( { "a": 1, "b": 2,"c": 3 }, function( k, v ) { + jQuery.each( { "a": 1, "b": 2, "c": 3 }, function( k, v ) { seen.push( v ); return false; } ); @@ -1373,7 +1373,7 @@ QUnit.test( "jQuery.makeArray", function( assert ) { assert.equal( ( function() { return jQuery.makeArray( arguments ); } )( 1, 2 ).join( "" ), "12", "Pass makeArray an arguments array" ); - assert.equal( jQuery.makeArray( [ 1,2,3 ] ).join( "" ), "123", "Pass makeArray a real array" ); + assert.equal( jQuery.makeArray( [ 1, 2, 3 ] ).join( "" ), "123", "Pass makeArray a real array" ); assert.equal( jQuery.makeArray().length, 0, "Pass nothing to makeArray and expect an empty array" ); diff --git a/test/unit/data.js b/test/unit/data.js index a333223656..077362edac 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -278,9 +278,9 @@ QUnit.test( "data-* attributes", function( assert ) { var prop, i, l, metadata, elem, obj, obj2, check, num, num2, parseJSON = jQuery.parseJSON, - div = jQuery("
    "), - child = jQuery("
    "), - dummy = jQuery("
    "); + div = jQuery( "
    " ), + child = jQuery( "
    " ), + dummy = jQuery( "
    " ); assert.equal( div.data( "attr" ), undefined, "Check for non-existing data-attr attribute" ); @@ -295,8 +295,8 @@ QUnit.test( "data-* attributes", function( assert ) { div.remove(); - child.appendTo("#qunit-fixture"); - assert.equal( child.data("myobj"), "old data", "Value accessed from data-* attribute"); + child.appendTo( "#qunit-fixture" ); + assert.equal( child.data( "myobj" ), "old data", "Value accessed from data-* attribute" ); child.data( "myobj", "replaced" ); assert.equal( child.data( "myobj" ), "replaced", "Original data overwritten" ); @@ -408,7 +408,7 @@ QUnit.test( "data-* attributes", function( assert ) { break; case 3: assert.equal( jQuery( elem ).data( "number" ), true, "Check number property" ); - assert.deepEqual( jQuery( elem ).data( "stuff" ), [ 2,8 ], "Check stuff property" ); + assert.deepEqual( jQuery( elem ).data( "stuff" ), [ 2, 8 ], "Check stuff property" ); break; default: assert.ok( false, [ "Assertion failed on index ", index, ", with data" ].join( "" ) ); @@ -600,7 +600,7 @@ QUnit.test( ".data should not miss attr() set data-* with hyphenated property na assert.deepEqual( b.data( "long-param" ), { a: 2 }, "data with property long-param was found, 2" ); } ); -QUnit.test(".data supports interoperable hyphenated/camelCase get/set of properties with arbitrary non-null|NaN|undefined values", function( assert ) { +QUnit.test( ".data supports interoperable hyphenated/camelCase get/set of properties with arbitrary non-null|NaN|undefined values", function( assert ) { var div = jQuery( "
    ", { id: "hyphened" } ).appendTo( "#qunit-fixture" ), datas = { "non-empty": "a string", @@ -695,7 +695,7 @@ QUnit.test( ".data supports interoperable removal of properties SET TWICE #13850 } ); QUnit.test( ".removeData supports removal of hyphenated properties via array (#12786)", function( assert ) { - expect( 4 ); + assert.expect( 4 ); var div, plain, compare; @@ -708,6 +708,7 @@ QUnit.test( ".removeData supports removal of hyphenated properties via array (#1 // From batch assignment .data({ "a-a": 1 }) "a-a": 1, + // From property, value assignment .data( "b-b", 1 ) "bB": 1 }; @@ -842,13 +843,13 @@ QUnit.test( "Check that the expando is removed when there's no more data", funct assert.strictEqual( div[ 0 ][ key ], undefined, "Expando was not removed when there was no more data" ); } } -}); +} ); QUnit.test( "Check that the expando is removed when there's no more data on non-nodes", function( assert ) { assert.expect( 1 ); var key, - obj = jQuery( {key: 42} ); + obj = jQuery( { key: 42 } ); obj.data( "some", "data" ); assert.equal( obj.data( "some" ), "data", "Data is added" ); obj.removeData( "some" ); diff --git a/test/unit/deferred.js b/test/unit/deferred.js index e050f0454b..0f55b08439 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -16,32 +16,32 @@ jQuery.each( [ "", " - new operator" ], function( _, withNew ) { assert.strictEqual( defer.pipe, defer.then, "pipe is an alias of then" ); - createDeferred().resolve().done(function() { + createDeferred().resolve().done( function() { assert.ok( true, "Success on resolve" ); assert.strictEqual( this.state(), "resolved", "Deferred is resolved (state)" ); - }).fail(function() { + } ).fail( function() { assert.ok( false, "Error on resolve" ); - }).always(function() { + } ).always( function() { assert.ok( true, "Always callback on resolve" ); - }); + } ); - createDeferred().reject().done(function() { + createDeferred().reject().done( function() { assert.ok( false, "Success on reject" ); - }).fail(function() { + } ).fail( function() { assert.ok( true, "Error on reject" ); assert.strictEqual( this.state(), "rejected", "Deferred is rejected (state)" ); - }).always(function() { + } ).always( function() { assert.ok( true, "Always callback on reject" ); - }); + } ); - createDeferred(function( defer ) { + createDeferred( function( defer ) { assert.ok( this === defer, "Defer passed as this & first argument" ); - this.resolve("done"); - }).done(function( value ) { + this.resolve( "done" ); + } ).done( function( value ) { assert.strictEqual( value, "done", "Passed function executed" ); - }); + } ); - createDeferred(function( defer ) { + createDeferred( function( defer ) { var promise = defer.promise(), func = function() {}, funcPromise = defer.promise( func ); @@ -97,18 +97,18 @@ QUnit.test( "jQuery.Deferred.then - filtering (done)", function( assert ) { var value1, value2, value3, defer = jQuery.Deferred(), - piped = defer.then(function( a, b ) { + piped = defer.then( function( a, b ) { return a * b; - }); + } ); - piped.done(function( result ) { + piped.done( function( result ) { value3 = result; - }); + } ); - defer.done(function( a, b ) { + defer.done( function( a, b ) { value1 = a; value2 = b; - }); + } ); defer.resolve( 2, 3 ); @@ -116,13 +116,13 @@ QUnit.test( "jQuery.Deferred.then - filtering (done)", function( assert ) { assert.strictEqual( value2, 3, "second resolve value ok" ); assert.strictEqual( value3, 6, "result of filter ok" ); - jQuery.Deferred().reject().then(function() { + jQuery.Deferred().reject().then( function() { assert.ok( false, "then should not be called on reject" ); - }); + } ); - jQuery.Deferred().resolve().then( jQuery.noop ).done(function( value ) { + jQuery.Deferred().resolve().then( jQuery.noop ).done( function( value ) { assert.strictEqual( value, undefined, "then done callback can return undefined/null" ); - }); + } ); } ); QUnit.test( "jQuery.Deferred.then - filtering (fail)", function( assert ) { @@ -132,31 +132,31 @@ QUnit.test( "jQuery.Deferred.then - filtering (fail)", function( assert ) { defer = jQuery.Deferred(), piped = defer.then( null, function( a, b ) { return a * b; - }); + } ); - piped.fail(function( result ) { + piped.fail( function( result ) { value3 = result; - }); + } ); - defer.fail(function( a, b ) { + defer.fail( function( a, b ) { value1 = a; value2 = b; - }); + } ); defer.reject( 2, 3 ); - strictEqual( value1, 2, "first reject value ok" ); - strictEqual( value2, 3, "second reject value ok" ); - strictEqual( value3, 6, "result of filter ok" ); + assert.strictEqual( value1, 2, "first reject value ok" ); + assert.strictEqual( value2, 3, "second reject value ok" ); + assert.strictEqual( value3, 6, "result of filter ok" ); jQuery.Deferred().resolve().then( null, function() { - ok( false, "then should not be called on resolve" ); - }); + assert.ok( false, "then should not be called on resolve" ); + } ); - jQuery.Deferred().reject().then( null, jQuery.noop ).fail(function( value ) { - strictEqual( value, undefined, "then fail callback can return undefined/null" ); - }); -}); + jQuery.Deferred().reject().then( null, jQuery.noop ).fail( function( value ) { + assert.strictEqual( value, undefined, "then fail callback can return undefined/null" ); + } ); +} ); QUnit.test( "jQuery.Deferred.then - filtering (progress)", function( assert ) { assert.expect( 3 ); @@ -181,7 +181,7 @@ QUnit.test( "jQuery.Deferred.then - filtering (progress)", function( assert ) { assert.strictEqual( value1, 2, "first progress value ok" ); assert.strictEqual( value2, 3, "second progress value ok" ); assert.strictEqual( value3, 6, "result of filter ok" ); -}); +} ); QUnit.test( "jQuery.Deferred.then - deferred (done)", function( assert ) { assert.expect( 3 ); @@ -208,7 +208,7 @@ QUnit.test( "jQuery.Deferred.then - deferred (done)", function( assert ) { assert.strictEqual( value1, 2, "first resolve value ok" ); assert.strictEqual( value2, 3, "second resolve value ok" ); assert.strictEqual( value3, 6, "result of filter ok" ); -}); +} ); QUnit.test( "jQuery.Deferred.then - deferred (fail)", function( assert ) { assert.expect( 3 ); @@ -235,7 +235,7 @@ QUnit.test( "jQuery.Deferred.then - deferred (fail)", function( assert ) { assert.strictEqual( value1, 2, "first reject value ok" ); assert.strictEqual( value2, 3, "second reject value ok" ); assert.strictEqual( value3, 6, "result of filter ok" ); -}); +} ); QUnit.test( "jQuery.Deferred.then - deferred (progress)", function( assert ) { assert.expect( 3 ); @@ -261,7 +261,7 @@ QUnit.test( "jQuery.Deferred.then - deferred (progress)", function( assert ) { assert.strictEqual( value1, 2, "first progress value ok" ); assert.strictEqual( value2, 3, "second progress value ok" ); assert.strictEqual( value3, 6, "result of filter ok" ); -}); +} ); QUnit.test( "jQuery.Deferred.then - context", function( assert ) { assert.expect( 7 ); @@ -271,16 +271,16 @@ QUnit.test( "jQuery.Deferred.then - context", function( assert ) { jQuery.Deferred().resolveWith( context, [ 2 ] ).then( function( value ) { return value * 3; - } ).done(function( value ) { + } ).done( function( value ) { assert.strictEqual( this, context, "custom context correctly propagated" ); assert.strictEqual( value, 6, "proper value received" ); - }); + } ); - jQuery.Deferred().resolve().then(function() { - return jQuery.Deferred().resolveWith(context); - }).done(function() { + jQuery.Deferred().resolve().then( function() { + return jQuery.Deferred().resolveWith( context ); + } ).done( function() { assert.strictEqual( this, context, "custom context of returned deferred correctly propagated" ); - }); + } ); defer = jQuery.Deferred(); piped = defer.then( function( value ) { @@ -289,25 +289,25 @@ QUnit.test( "jQuery.Deferred.then - context", function( assert ) { defer.resolve( 2 ); - piped.done(function( value ) { + piped.done( function( value ) { assert.strictEqual( this, piped, "default context gets updated to latest promise in the chain" ); assert.strictEqual( value, 6, "proper value received" ); - }); + } ); defer2 = jQuery.Deferred(); piped2 = defer2.then(); defer2.resolve( 2 ); - piped2.done(function( value ) { + piped2.done( function( value ) { assert.strictEqual( this, piped2, "default context gets updated to latest promise in the chain (without passing function)" ); assert.strictEqual( value, 2, "proper value received (without passing function)" ); - }); -}); + } ); +} ); QUnit.test( "jQuery.when", function( assert ) { assert.expect( 37 ); - jQuery.each({ + jQuery.each( { "an empty string": "", "a non-empty string": "some string", "zero": 0, @@ -322,21 +322,21 @@ QUnit.test( "jQuery.when", function( assert ) { }, function( message, value ) { assert.ok( jQuery.isFunction( - jQuery.when( value ).done(function( resolveValue ) { + jQuery.when( value ).done( function( resolveValue ) { assert.strictEqual( this, window, "Context is the global object with " + message ); assert.strictEqual( resolveValue, value, "Test the promise was resolved with " + message ); - }).promise + } ).promise ), "Test " + message + " triggers the creation of a new Promise" ); - }); + } ); assert.ok( jQuery.isFunction( - jQuery.when().done(function( resolveValue ) { + jQuery.when().done( function( resolveValue ) { assert.strictEqual( this, window, "Test the promise was resolved with window as its context" ); assert.strictEqual( resolveValue, undefined, "Test the promise was resolved with no parameter" ); - }).promise + } ).promise ), "Test calling when with no parameter triggers the creation of a new Promise" ); @@ -344,22 +344,22 @@ QUnit.test( "jQuery.when", function( assert ) { var cache, context = {}; - jQuery.when( jQuery.Deferred().resolveWith( context ) ).done(function() { + jQuery.when( jQuery.Deferred().resolveWith( context ) ).done( function() { assert.strictEqual( this, context, "when( promise ) propagates context" ); - }); + } ); - jQuery.each([ 1, 2, 3 ], function( k, i ) { + jQuery.each( [ 1, 2, 3 ], function( k, i ) { - jQuery.when( cache || jQuery.Deferred(function() { + jQuery.when( cache || jQuery.Deferred( function() { this.resolve( i ); - }) - ).done(function( value ) { + } ) + ).done( function( value ) { assert.strictEqual( value, 1, "Function executed" + ( i > 1 ? " only once" : "" ) ); cache = value; - }); + } ); - }); + } ); } ); QUnit.test( "jQuery.when - joined", function( assert ) { @@ -399,31 +399,31 @@ QUnit.test( "jQuery.when - joined", function( assert ) { context1 = defer1 && jQuery.isFunction( defer1.promise ) ? defer1.promise() : undefined, context2 = defer2 && jQuery.isFunction( defer2.promise ) ? defer2.promise() : undefined; - jQuery.when( defer1, defer2 ).done(function( a, b ) { + jQuery.when( defer1, defer2 ).done( function( a, b ) { if ( shouldResolve ) { assert.deepEqual( [ a, b ], expected, code + " => resolve" ); assert.strictEqual( this[ 0 ], context1, code + " => first context OK" ); assert.strictEqual( this[ 1 ], context2, code + " => second context OK" ); } else { - ok( false, code + " => resolve" ); + assert.ok( false, code + " => resolve" ); } - }).fail(function( a, b ) { + } ).fail( function( a, b ) { if ( shouldError ) { assert.deepEqual( [ a, b ], expected, code + " => reject" ); } else { - ok( false, code + " => reject" ); + assert.ok( false, code + " => reject" ); } - }).progress(function( a, b ) { + } ).progress( function( a, b ) { assert.deepEqual( [ a, b ], expectedNotify, code + " => progress" ); assert.strictEqual( this[ 0 ], expectedNotify[ 0 ] ? context1 : undefined, code + " => first context OK" ); assert.strictEqual( this[ 1 ], expectedNotify[ 1 ] ? context2 : undefined, code + " => second context OK" ); - }); - }); - }); + } ); + } ); + } ); deferreds.futureSuccess.resolve( 1 ); deferreds.futureError.reject( 0 ); -}); +} ); QUnit.test( "jQuery.when - resolved", function( assert ) { assert.expect( 6 ); @@ -432,16 +432,16 @@ QUnit.test( "jQuery.when - resolved", function( assert ) { b = jQuery.Deferred().notify( 2 ).resolve( 5 ), c = jQuery.Deferred().notify( 3 ).resolve( 6 ); - jQuery.when( a, b, c ).progress(function( a, b, c ) { + jQuery.when( a, b, c ).progress( function( a, b, c ) { assert.strictEqual( a, 1, "first notify value ok" ); assert.strictEqual( b, 2, "second notify value ok" ); assert.strictEqual( c, 3, "third notify value ok" ); - }).done(function( a, b, c ) { + } ).done( function( a, b, c ) { assert.strictEqual( a, 4, "first resolve value ok" ); assert.strictEqual( b, 5, "second resolve value ok" ); assert.strictEqual( c, 6, "third resolve value ok" ); - }).fail(function() { + } ).fail( function() { assert.ok( false, "Error on resolve" ); - }); + } ); -}); +} ); diff --git a/test/unit/deprecated.js b/test/unit/deprecated.js index 797290f3bf..f474dc6c32 100644 --- a/test/unit/deprecated.js +++ b/test/unit/deprecated.js @@ -1,6 +1,5 @@ QUnit.module( "deprecated", { teardown: moduleTeardown } ); - QUnit.test( "bind/unbind", function( assert ) { assert.expect( 4 ); @@ -14,7 +13,7 @@ QUnit.test( "bind/unbind", function( assert ) { assert.equal( e.type, "click", "correct event type" ); assert.equal( e.data.bindData, 19, "correct trigger data" ); assert.equal( trig, 42, "correct bind data" ); - assert.equal( e.target.nodeName.toLowerCase(), "b" , "correct element" ); + assert.equal( e.target.nodeName.toLowerCase(), "b", "correct element" ); } ) .trigger( "click", [ 42 ] ) .unbind( "click" ) @@ -32,11 +31,11 @@ QUnit.test( "delegate/undelegate", function( assert ) { markup .delegate( "b", "click", function( e ) { assert.equal( e.type, "click", "correct event type" ); - assert.equal( e.target.nodeName.toLowerCase(), "b" , "correct element" ); + assert.equal( e.target.nodeName.toLowerCase(), "b", "correct element" ); } ) .find( "b" ) .trigger( "click" ) .end() .undelegate( "b", "click" ) .remove(); -} ); \ No newline at end of file +} ); diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 20c93f6801..5bd4f33843 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -254,7 +254,7 @@ QUnit.test( "child of a hidden elem (or unconnected node) has accurate inner/out assert.equal( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #9441" ); assert.equal( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #9441" ); assert.equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #9441" ); - assert.equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #9300" ); + assert.equal( $divChild.outerHeight( true ), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #9300" ); // tests that child div of an unconnected div works the same as a normal div assert.equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #9441" ); @@ -265,7 +265,7 @@ QUnit.test( "child of a hidden elem (or unconnected node) has accurate inner/out assert.equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #9441" ); assert.equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #9441" ); assert.equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #9441" ); - assert.equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #9300" ); + assert.equal( $divUnconnected.outerHeight( true ), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #9300" ); // teardown html $divHiddenParent.remove(); @@ -327,7 +327,7 @@ QUnit.test( "box-sizing:border-box child of a hidden elem (or unconnected node) assert.equal( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #10413" ); assert.equal( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #10413" ); assert.equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #10413" ); - assert.equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #10413" ); + assert.equal( $divChild.outerHeight( true ), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #10413" ); // tests that child div of an unconnected div works the same as a normal div assert.equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #10413" ); @@ -338,7 +338,7 @@ QUnit.test( "box-sizing:border-box child of a hidden elem (or unconnected node) assert.equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #10413" ); assert.equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #10413" ); assert.equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #10413" ); - assert.equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #10413" ); + assert.equal( $divUnconnected.outerHeight( true ), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #10413" ); // teardown html $divHiddenParent.remove(); @@ -409,7 +409,7 @@ QUnit.test( "getters on non elements should return null", function( assert ) { QUnit.test( "setters with and without box-sizing:border-box", function( assert ) { assert.expect( 60 ); - var parent = jQuery( "#foo" ).css({ width: "200px", height: "200px", "font-size": "16px" }), + var parent = jQuery( "#foo" ).css( { width: "200px", height: "200px", "font-size": "16px" } ), el_bb = jQuery( "
    " ).appendTo( parent ), el = jQuery( "
    " ).appendTo( parent ); diff --git a/test/unit/effects.js b/test/unit/effects.js index 23dbc1ecf9..20b15a1ca8 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -36,13 +36,13 @@ QUnit.test( "show() basic", function( assert ) { assert.expect( 2 ); var div, - hiddendiv = jQuery("div.hidden"); + hiddendiv = jQuery( "div.hidden" ); hiddendiv.hide().show(); - assert.equal( hiddendiv.css("display"), "block", "Make sure a pre-hidden div is visible." ); + assert.equal( hiddendiv.css( "display" ), "block", "Make sure a pre-hidden div is visible." ); - div = jQuery("
    ").hide().appendTo("#qunit-fixture").show(); + div = jQuery( "
    " ).hide().appendTo( "#qunit-fixture" ).show(); assert.equal( div.css( "display" ), "block", "Make sure pre-hidden divs show" ); @@ -99,7 +99,7 @@ QUnit.test( "show()", function( assert ) { assert.expectJqData( this, div, "olddisplay" ); // #show-tests * is set display: none in CSS - jQuery("#qunit-fixture").append("

    "); + jQuery( "#qunit-fixture" ).append( "

    " ); old = jQuery( "#test-table" ).show().css( "display" ) !== "table"; jQuery( "#test-table" ).remove(); @@ -137,39 +137,39 @@ QUnit.test( "show(Number) - other displays", function( assert ) { assert.expect( 15 ); // #show-tests * is set display: none in CSS - jQuery("#qunit-fixture").append("

    "); + jQuery( "#qunit-fixture" ).append( "

    " ); var test, old = jQuery( "#test-table" ).show().css( "display" ) !== "table"; - jQuery("#test-table").remove(); + jQuery( "#test-table" ).remove(); // Note: inline elements are expected to be inline-block // because we're showing width/height // Can't animate width/height inline // See #14344 test = { - "div" : "block", - "p" : "block", - "a" : "inline-block", - "code" : "inline-block", - "pre" : "block", - "span" : "inline-block", - "table" : old ? "block" : "table", - "thead" : old ? "block" : "table-header-group", - "tbody" : old ? "block" : "table-row-group", - "tr" : old ? "block" : "table-row", - "th" : old ? "block" : "table-cell", - "td" : old ? "block" : "table-cell", - "ul" : "block", - "li" : old ? "block" : "list-item" + "div": "block", + "p": "block", + "a": "inline-block", + "code": "inline-block", + "pre": "block", + "span": "inline-block", + "table": old ? "block" : "table", + "thead": old ? "block" : "table-header-group", + "tbody": old ? "block" : "table-row-group", + "tr": old ? "block" : "table-row", + "th": old ? "block" : "table-cell", + "td": old ? "block" : "table-cell", + "ul": "block", + "li": old ? "block" : "list-item" }; - jQuery.each(test, function(selector, expected) { - var elem = jQuery(selector, "#show-tests").show(1, function() { - assert.equal( elem.css("display"), expected, "Show using correct display type for " + selector ); - }); - }); + jQuery.each( test, function( selector, expected ) { + var elem = jQuery( selector, "#show-tests" ).show( 1, function() { + assert.equal( elem.css( "display" ), expected, "Show using correct display type for " + selector ); + } ); + } ); this.clock.tick( 10 ); jQuery( "#show-tests" ).remove(); @@ -180,7 +180,7 @@ QUnit.test( "Persist correct display value", function( assert ) { assert.expect( 3 ); // #show-tests * is set display: none in CSS - jQuery("#qunit-fixture").append("
    foo
    "); + jQuery( "#qunit-fixture" ).append( "
    foo
    " ); var $span = jQuery( "#show-tests span" ), displayNone = $span.css( "display" ), @@ -524,7 +524,7 @@ QUnit.test( "animate duration 0", function( assert ) { assert.expect( 11 ); var $elem, - $elems = jQuery( [ { a:0 },{ a:0 } ] ), + $elems = jQuery( [ { a:0 }, { a:0 } ] ), counter = 0; assert.equal( jQuery.timers.length, 0, "Make sure no animation was running from another test" ); @@ -929,7 +929,7 @@ jQuery.each( { if ( t_w === "hide" ) {num++;} if ( t_o.constructor === Number ) {num += 2;} if ( t_w.constructor === Number ) {num += 2;} - if ( t_h.constructor === Number ) {num +=2;} + if ( t_h.constructor === Number ) {num += 2;} assert.expect( num ); @@ -937,7 +937,7 @@ jQuery.each( { elem.animate( anim, 50 ); - jQuery.when( elem ).done(function( elem ) { + jQuery.when( elem ).done( function( elem ) { var cur_o, cur_w, cur_h, old_h; elem = elem[ 0 ]; @@ -1539,11 +1539,12 @@ QUnit.test( "animate should set display for disconnected nodes", function( asser show: [ 1 ], animate: [ { width: "show" } ] }, - $divTest = jQuery("
    test
    "), + $divTest = jQuery( "
    test
    " ), + // parentNode = null - $divEmpty = jQuery("
    "), - $divNone = jQuery("
    "), - $divInline = jQuery("
    "), + $divEmpty = jQuery( "
    " ), + $divNone = jQuery( "
    " ), + $divInline = jQuery( "
    " ), clock = this.clock; assert.strictEqual( $divTest.show()[ 0 ].style.display, "block", "set display with show() for element with parentNode = document fragment" ); @@ -1556,24 +1557,24 @@ QUnit.test( "animate should set display for disconnected nodes", function( asser assert.expectJqData( env, $divNone[ 0 ], "olddisplay" ); jQuery.each( methods, function( name, opt ) { - jQuery.each([ + jQuery.each( [ // parentNode = document fragment - jQuery("
    test
    "), + jQuery( "
    test
    " ), // parentNode = null - jQuery("
    ") + jQuery( "
    " ) ], function() { - var callback = [function () { + var callback = [ function() { assert.strictEqual( this.style.display, "block", "set display to block with " + name ); assert.expectJqData( env, this, "olddisplay" ); - }]; + } ]; jQuery.fn[ name ].apply( this, opt.concat( callback ) ); - }); - }); + } ); + } ); clock.tick( 400 ); } ); @@ -1817,7 +1818,7 @@ QUnit.test( "non-px animation handles non-numeric start (#11971)", function( ass this.clock.tick( 10 ); } ); -QUnit.test("Animation callbacks (#11797)", function( assert ) { +QUnit.test( "Animation callbacks (#11797)", function( assert ) { assert.expect( 16 ); var prog = 0, @@ -1938,7 +1939,7 @@ QUnit.test( "Animation callbacks in order (#2292)", function( assert ) { always: function() { assert.step( 5 ); } - }).finish(); + } ).finish(); this.clock.tick( dur + 10 ); } ); @@ -2316,8 +2317,8 @@ QUnit.test( "Respect display value on inline elements (#14824)", function( asser clock.tick( 800 ); } ); -QUnit.test( "Animation should go to its end state if document.hidden = true", function(assert) { - assert.expect(1); +QUnit.test( "Animation should go to its end state if document.hidden = true", function( assert ) { + assert.expect( 1 ); var height; if ( Object.defineProperty ) { @@ -2328,14 +2329,14 @@ QUnit.test( "Animation should go to its end state if document.hidden = true", fu get: function() { return true; } - }); + } ); } catch ( e ) {} } else { document.hidden = true; } if ( document.hidden ) { - height = jQuery( "#qunit-fixture" ).animate({ height: 500 } ).height(); + height = jQuery( "#qunit-fixture" ).animate( { height: 500 } ).height(); assert.equal( height, 500, "Animation should happen immediately if document.hidden = true" ); jQuery( document ).removeProp( "hidden" ); @@ -2343,7 +2344,7 @@ QUnit.test( "Animation should go to its end state if document.hidden = true", fu } else { assert.ok( true, "Can't run the test since we can't reproduce correct environment for it" ); } -}); +} ); QUnit.test( "jQuery.easing._default (gh-2218)", function( assert ) { assert.expect( 2 ); diff --git a/test/unit/event.js b/test/unit/event.js index b207441c9b..12f132e0d9 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -901,55 +901,55 @@ QUnit.test( "mouseenter, mouseleave don't catch exceptions", function( assert ) if ( jQuery.fn.click ) { - QUnit.test("trigger() shortcuts", function( assert ) { + QUnit.test( "trigger() shortcuts", function( assert ) { assert.expect( 6 ); var counter, clickCounter, - elem = jQuery("
  • Change location
  • ").prependTo("#firstUL"); - elem.find("a").on("click", function() { - var close = jQuery("spanx", this); // same with jQuery(this).find("span"); + elem = jQuery( "
  • Change location
  • " ).prependTo( "#firstUL" ); + elem.find( "a" ).on( "click", function() { + var close = jQuery( "spanx", this ); // same with jQuery(this).find("span"); assert.equal( close.length, 0, "Context element does not exist, length must be zero" ); - assert.ok( !close[0], "Context element does not exist, direct access to element must return undefined" ); + assert.ok( !close[ 0 ], "Context element does not exist, direct access to element must return undefined" ); return false; - }).click(); + } ).click(); // manually clean up detached elements elem.remove(); - jQuery("#check1").click(function() { + jQuery( "#check1" ).click( function() { assert.ok( true, "click event handler for checkbox gets fired twice, see #815" ); - }).click(); + } ).click(); counter = 0; - jQuery("#firstp")[0].onclick = function() { + jQuery( "#firstp" )[ 0 ].onclick = function() { counter++; }; - jQuery("#firstp").click(); + jQuery( "#firstp" ).click(); assert.equal( counter, 1, "Check that click, triggers onclick event handler also" ); clickCounter = 0; - jQuery("#simon1")[0].onclick = function() { + jQuery( "#simon1" )[ 0 ].onclick = function() { clickCounter++; }; - jQuery("#simon1").click(); + jQuery( "#simon1" ).click(); assert.equal( clickCounter, 1, "Check that click, triggers onclick event handler on an a tag also" ); - elem = jQuery("").load(function(){ - assert.ok( true, "Trigger the load event, using the shortcut .load() (#2819)"); - }).load(); + elem = jQuery( "" ).load( function() { + assert.ok( true, "Trigger the load event, using the shortcut .load() (#2819)" ); + } ).load(); // manually clean up detached elements elem.remove(); // test that special handlers do not blow up with VML elements (#7071) - jQuery("").appendTo("head"); - jQuery(" ").appendTo("#form"); - jQuery("#oval").click().keydown(); - }); + jQuery( "" ).appendTo( "head" ); + jQuery( " " ).appendTo( "#form" ); + jQuery( "#oval" ).click().keydown(); + } ); } -QUnit.test("trigger() bubbling", function( assert ) { +QUnit.test( "trigger() bubbling", function( assert ) { assert.expect( 18 ); var win = 0, doc = 0, html = 0, body = 0, main = 0, ap = 0; @@ -1226,7 +1226,7 @@ QUnit.test( "trigger(eventObject, [data], [fn])", function( assert ) { //$child.on("foo", error ); event = new jQuery.Event( "foo" ); - $child.trigger( event, [ 1,2,3 ] ).off(); + $child.trigger( event, [ 1, 2, 3 ] ).off(); assert.equal( event.result, "result", "Check event.result attribute" ); // Will error if it bubbles @@ -1882,7 +1882,7 @@ QUnit.test( "ignore comment nodes in event delegation (gh-2055)", function( asse .appendTo( $foo.find( "#sap" ) ); if ( !test() ) { - fireNative( $comment[0], "DOMNodeInserted" ); + fireNative( $comment[ 0 ], "DOMNodeInserted" ); } } ); @@ -2850,7 +2850,6 @@ QUnit.test( "originalEvent property for Chrome, Safari, Fx & Edge of simulated e jQuery( "#donor-input" ).trigger( "focus" ); } ); - QUnit[ jQuery.fn.click ? "test" : "skip" ]( "trigger() shortcuts", function( assert ) { assert.expect( 5 ); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 4d8eed7d9a..2125067b8e 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -1560,7 +1560,7 @@ QUnit.test( "clone(multiple selected options) (Bug #8129)", function( assert ) { var element = jQuery( "" ); function getSelectedOptions( collection ) { - return collection.find( "option" ).filter(function( option ) { + return collection.find( "option" ).filter( function( option ) { return option.selected; } ); } diff --git a/test/unit/offset.js b/test/unit/offset.js index ea2c266069..88e75950b4 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -52,10 +52,10 @@ QUnit.test( "object without getBoundingClientRect", function( assert ) { assert.expect( 2 ); // Simulates a browser without gBCR on elements, we just want to return 0,0 - var result = jQuery({ ownerDocument: document }).offset(); + var result = jQuery( { ownerDocument: document } ).offset(); assert.equal( result.top, 0, "Check top" ); assert.equal( result.left, 0, "Check left" ); -}); +} ); QUnit.test( "disconnected node", function( assert ) { assert.expect( 2 ); @@ -65,8 +65,8 @@ QUnit.test( "disconnected node", function( assert ) { // These tests are solely for master/compat consistency // Retrieving offset on disconnected/hidden elements is not officially // valid input, but will return zeros for back-compat - equal( result.top, 0, "Check top" ); - equal( result.left, 0, "Check left" ); + assert.equal( result.top, 0, "Check top" ); + assert.equal( result.left, 0, "Check left" ); } ); QUnit.test( "hidden (display: none) element", function( assert ) { diff --git a/test/unit/selector.js b/test/unit/selector.js index 2f6e9affda..a3c7aba905 100644 --- a/test/unit/selector.js +++ b/test/unit/selector.js @@ -32,7 +32,7 @@ QUnit.test( "id", function( assert ) { assert.t( "ID selector with existing ID descendant", "#firstp #simon1", [ "simon1" ] ); assert.t( "ID selector with non-existent descendant", "#firstp #foobar", [] ); assert.t( "ID selector using UTF8", "#台北Táiběi", [ "台北Táiběi" ] ); - assert.t( "Multiple ID selectors using UTF8", "#台北Táiběi, #台北", [ "台北Táiběi","台北" ] ); + assert.t( "Multiple ID selectors using UTF8", "#台北Táiběi, #台北", [ "台北Táiběi", "台北" ] ); assert.t( "Descendant ID selector using UTF8", "div #台北", [ "台北" ] ); assert.t( "Child ID selector using UTF8", "form > #台北", [ "台北" ] ); @@ -103,14 +103,14 @@ QUnit.test( "selectors with comma", function( assert ) { QUnit.test( "child and adjacent", function( assert ) { assert.expect( 27 ); - assert.t( "Child", "p > a", [ "simon1","google","groups","mark","yahoo","simon" ] ); - assert.t( "Child", "p> a", [ "simon1","google","groups","mark","yahoo","simon" ] ); - assert.t( "Child", "p >a", [ "simon1","google","groups","mark","yahoo","simon" ] ); - assert.t( "Child", "p>a", [ "simon1","google","groups","mark","yahoo","simon" ] ); - assert.t( "Child w/ Class", "p > a.blog", [ "mark","simon" ] ); - assert.t( "All Children", "code > *", [ "anchor1","anchor2" ] ); - assert.t( "All Grandchildren", "p > * > *", [ "anchor1","anchor2" ] ); - assert.t( "Adjacent", "p + p", [ "ap","en","sap" ] ); + assert.t( "Child", "p > a", [ "simon1", "google", "groups", "mark", "yahoo", "simon" ] ); + assert.t( "Child", "p> a", [ "simon1", "google", "groups", "mark", "yahoo", "simon" ] ); + assert.t( "Child", "p >a", [ "simon1", "google", "groups", "mark", "yahoo", "simon" ] ); + assert.t( "Child", "p>a", [ "simon1", "google", "groups", "mark", "yahoo", "simon" ] ); + assert.t( "Child w/ Class", "p > a.blog", [ "mark", "simon" ] ); + assert.t( "All Children", "code > *", [ "anchor1", "anchor2" ] ); + assert.t( "All Grandchildren", "p > * > *", [ "anchor1", "anchor2" ] ); + assert.t( "Adjacent", "p + p", [ "ap", "en", "sap" ] ); assert.t( "Adjacent", "p#firstp + p", [ "ap" ] ); assert.t( "Adjacent", "p[lang=en] + p", [ "sap" ] ); assert.t( "Adjacent", "a.GROUPS + code + a", [ "mark" ] ); @@ -163,7 +163,7 @@ QUnit.test( "attributes", function( assert ) { assert.t( "Attribute Equals", "#qunit-fixture a[rel=bookmark]", [ "simon1" ] ); assert.t( "Attribute Equals", "#qunit-fixture a[href='http://www.google.com/']", [ "google" ] ); assert.t( "Attribute Equals", "#qunit-fixture a[ rel = 'bookmark' ]", [ "simon1" ] ); - assert.t( "Attribute Equals Number", "#qunit-fixture option[value='1']", [ "option1b","option2b","option3b","option4b","option5c" ] ); + assert.t( "Attribute Equals Number", "#qunit-fixture option[value='1']", [ "option1b", "option2b", "option3b", "option4b", "option5c" ] ); assert.t( "Attribute Equals Number", "#qunit-fixture li[tabIndex='-1']", [ "foodWithNegativeTabIndex" ] ); document.getElementById( "anchor2" ).href = "#2"; @@ -187,13 +187,13 @@ QUnit.test( "attributes", function( assert ) { assert.t( "Attribute selector using UTF8", "span[lang=中文]", [ "台北" ] ); - assert.t( "Attribute Begins With", "a[href ^= 'http://www']", [ "google","yahoo" ] ); + assert.t( "Attribute Begins With", "a[href ^= 'http://www']", [ "google", "yahoo" ] ); assert.t( "Attribute Ends With", "a[href $= 'org/']", [ "mark" ] ); - assert.t( "Attribute Contains", "a[href *= 'google']", [ "google","groups" ] ); + assert.t( "Attribute Contains", "a[href *= 'google']", [ "google", "groups" ] ); if ( jQuery.find.compile ) { - assert.t( "Empty values", "#select1 option[value!='']", [ "option1b","option1c","option1d" ] ); - assert.t( "Attribute Is Not Equal", "#ap a[hreflang!='en']", [ "google","groups","anchor1" ] ); + assert.t( "Empty values", "#select1 option[value!='']", [ "option1b", "option1c", "option1d" ] ); + assert.t( "Attribute Is Not Equal", "#ap a[hreflang!='en']", [ "google", "groups", "anchor1" ] ); assert.t( "Select options via :selected", "#select1 option:selected", [ "option1a" ] ); assert.t( "Select options via :selected", "#select2 option:selected", [ "option2d" ] ); assert.t( "Select options via :selected", "#select3 option:selected", [ "option3b", "option3c" ] ); @@ -209,7 +209,6 @@ QUnit.test( "attributes", function( assert ) { assert.t( "Empty values", "#select1 option[value='']", [ "option1a" ] ); - assert.t( "Grouped Form Elements", "input[name='foo[bar]']", [ "hidden2" ] ); // Make sure attribute value quoting works correctly. See jQuery #6093; #6428; #13894 @@ -262,7 +261,6 @@ QUnit.test( "attributes", function( assert ) { assert.ok( "skip", ":input not supported in selector-native" ); } - // #11115 assert.ok( jQuery( "" ).prop( "checked", false ).is( "[checked]" ), "[checked] selects by attribute (positive)" diff --git a/test/unit/serialize.js b/test/unit/serialize.js index b487602000..6e250244d4 100644 --- a/test/unit/serialize.js +++ b/test/unit/serialize.js @@ -10,7 +10,7 @@ QUnit.test( "jQuery.param()", function( assert ) { params = { "foo":"bar", "baz":42, "quux":"All your base are belong to us" }; assert.equal( jQuery.param( params ), "foo=bar&baz=42&quux=All+your+base+are+belong+to+us", "simple" ); - params = { "string":"foo","null":null,"undefined":undefined }; + params = { "string":"foo", "null":null, "undefined":undefined }; assert.equal( jQuery.param( params ), "string=foo&null=&undefined=", "handle nulls and undefineds properly" ); params = { "someName": [ 1, 2, 3 ], "regularThing": "blah" }; @@ -25,16 +25,16 @@ QUnit.test( "jQuery.param()", function( assert ) { params = { "foo": { "bar": "baz", "beep": 42, "quux": "All your base are belong to us" } }; assert.equal( jQuery.param( params ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); - params = { a:[ 1,2 ], b:{ c:3, d:[ 4,5 ], e:{ x:[ 6 ], y:7, z:[ 8,9 ] }, f:true, g:false, h:undefined }, i:[ 10,11 ], j:true, k:false, l:[ undefined,0 ], m:"cowboy hat?" }; + params = { a:[ 1, 2 ], b:{ c:3, d:[ 4, 5 ], e:{ x:[ 6 ], y:7, z:[ 8, 9 ] }, f:true, g:false, h:undefined }, i:[ 10, 11 ], j:true, k:false, l:[ undefined, 0 ], m:"cowboy hat?" }; assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy+hat?", "huge structure" ); params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, "d": 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; assert.equal( decodeURIComponent( jQuery.param( params ) ), "a[]=0&a[1][]=1&a[1][]=2&a[2][]=3&a[2][1][]=4&a[2][1][]=5&a[2][2][]=6&a[3][b][]=7&a[3][b][1][]=8&a[3][b][1][]=9&a[3][b][2][0][c]=10&a[3][b][2][0][d]=11&a[3][b][3][0][]=12&a[3][b][4][0][0][]=13&a[3][b][5][e][f][g][]=14&a[3][b][5][e][f][g][1][]=15&a[3][b][]=16&a[]=17", "nested arrays" ); - params = { "a":[ 1,2 ], "b":{ "c":3, "d":[ 4,5 ], "e":{ "x":[ 6 ], "y":7, "z":[ 8,9 ] }, "f":true, "g":false, "h":undefined }, "i":[ 10,11 ], "j":true, "k":false, "l":[ undefined,0 ], "m":"cowboy hat?" }; + params = { "a":[ 1, 2 ], "b":{ "c":3, "d":[ 4, 5 ], "e":{ "x":[ 6 ], "y":7, "z":[ 8, 9 ] }, "f":true, "g":false, "h":undefined }, "i":[ 10, 11 ], "j":true, "k":false, "l":[ undefined, 0 ], "m":"cowboy hat?" }; assert.equal( jQuery.param( params, true ), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy+hat%3F", "huge structure, forced traditional" ); - assert.equal( decodeURIComponent( jQuery.param( { "a": [ 1,2,3 ], "b[]": [ 4,5,6 ], "c[d]": [ 7,8,9 ], "e": { "f": [ 10 ], "g": [ 11,12 ], "h": 13 } } ) ), "a[]=1&a[]=2&a[]=3&b[]=4&b[]=5&b[]=6&c[d][]=7&c[d][]=8&c[d][]=9&e[f][]=10&e[g][]=11&e[g][]=12&e[h]=13", "Make sure params are not double-encoded." ); + assert.equal( decodeURIComponent( jQuery.param( { "a": [ 1, 2, 3 ], "b[]": [ 4, 5, 6 ], "c[d]": [ 7, 8, 9 ], "e": { "f": [ 10 ], "g": [ 11, 12 ], "h": 13 } } ) ), "a[]=1&a[]=2&a[]=3&b[]=4&b[]=5&b[]=6&c[d][]=7&c[d][]=8&c[d][]=9&e[f][]=10&e[g][]=11&e[g][]=12&e[h]=13", "Make sure params are not double-encoded." ); // #7945 assert.equal( jQuery.param( { "jquery": "1.4.2" } ), "jquery=1.4.2", "Check that object with a jQuery property get serialized correctly" ); @@ -62,13 +62,13 @@ QUnit.test( "jQuery.param()", function( assert ) { params = { "foo[bar]":"baz", "foo[beep]":42, "foo[quux]":"All your base are belong to us" }; assert.equal( jQuery.param( params ), "foo%5Bbar%5D=baz&foo%5Bbeep%5D=42&foo%5Bquux%5D=All+your+base+are+belong+to+us", "even more arrays" ); - params = { a:[ 1,2 ], b:{ c:3, d:[ 4,5 ], e:{ x:[ 6 ], y:7, z:[ 8,9 ] }, f:true, g:false, h:undefined }, i:[ 10,11 ], j:true, k:false, l:[ undefined,0 ], m:"cowboy hat?" }; + params = { a:[ 1, 2 ], b:{ c:3, d:[ 4, 5 ], e:{ x:[ 6 ], y:7, z:[ 8, 9 ] }, f:true, g:false, h:undefined }, i:[ 10, 11 ], j:true, k:false, l:[ undefined, 0 ], m:"cowboy hat?" }; assert.equal( jQuery.param( params ), "a=1&a=2&b=%5Bobject+Object%5D&i=10&i=11&j=true&k=false&l=&l=0&m=cowboy+hat%3F", "huge structure" ); params = { "a": [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ], { "b": [ 7, [ 8, 9 ], [ { "c": 10, d: 11 } ], [ [ 12 ] ], [ [ [ 13 ] ] ], { "e": { "f": { "g": [ 14, [ 15 ] ] } } }, 16 ] }, 17 ] }; assert.equal( jQuery.param( params ), "a=0&a=1%2C2&a=3%2C4%2C5%2C6&a=%5Bobject+Object%5D&a=17", "nested arrays (not possible when jQuery.param.traditional == true)" ); - params = { a:[ 1,2 ], b:{ c:3, d:[ 4,5 ], e:{ x:[ 6 ], y:7, z:[ 8,9 ] }, f:true, g:false, h:undefined }, i:[ 10,11 ], j:true, k:false, l:[ undefined,0 ], m:"cowboy hat?" }; + params = { a:[ 1, 2 ], b:{ c:3, d:[ 4, 5 ], e:{ x:[ 6 ], y:7, z:[ 8, 9 ] }, f:true, g:false, h:undefined }, i:[ 10, 11 ], j:true, k:false, l:[ undefined, 0 ], m:"cowboy hat?" }; assert.equal( decodeURIComponent( jQuery.param( params, false ) ), "a[]=1&a[]=2&b[c]=3&b[d][]=4&b[d][]=5&b[e][x][]=6&b[e][y]=7&b[e][z][]=8&b[e][z][]=9&b[f]=true&b[g]=false&b[h]=&i[]=10&i[]=11&j=true&k=false&l[]=&l[]=0&m=cowboy+hat?", "huge structure, forced not traditional" ); params = { "param1": null }; diff --git a/test/unit/support.js b/test/unit/support.js index 6a51ccb8ab..80ea58ef01 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -272,6 +272,6 @@ testIframeWithCallback( assert.ok( true, "no ajax; skipping jQuery.support['" + i + "']" ); } } - }); + } ); } )(); From 8a0176279f3bc095fb3c57d8b2c58420534857cc Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:17:36 +0300 Subject: [PATCH 031/114] Revert "Ajax: remove deprecated extensions from ajax promise" This reverts commit 9d1b989f20b550af3590691723b0620f6914626e. --- src/ajax.js | 10 ++++++---- src/effects.js | 9 +++++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/ajax.js b/src/ajax.js index 4feed36b57..ba32248324 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -513,7 +513,9 @@ jQuery.extend( { }; // Attach deferreds - deferred.promise( jqXHR ); + deferred.promise( jqXHR ).complete = completeDeferred.add; + jqXHR.success = jqXHR.done; + jqXHR.error = jqXHR.fail; // Remove hash character (#7531: and string promotion) // Add protocol if not provided (prefilters might expect it) @@ -646,9 +648,9 @@ jQuery.extend( { strAbort = "abort"; // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); + for ( i in { success: 1, error: 1, complete: 1 } ) { + jqXHR[ i ]( s[ i ] ); + } // Get transport transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); diff --git a/src/effects.js b/src/effects.js index 8594fd6283..ab6fe6d79a 100644 --- a/src/effects.js +++ b/src/effects.js @@ -3,6 +3,7 @@ define( [ "./var/document", "./var/rcssNum", "./css/var/cssExpand", + "./var/rnotwhite", "./css/var/isHidden", "./css/adjustCSS", "./css/defaultDisplay", @@ -14,7 +15,7 @@ define( [ "./css", "./deferred", "./traversing" -], function( jQuery, document, rcssNum, cssExpand, +], function( jQuery, document, rcssNum, cssExpand, rnotwhite, isHidden, adjustCSS, defaultDisplay, dataPriv ) { var @@ -331,6 +332,10 @@ function Animation( elem, properties, options ) { for ( ; index < length ; index++ ) { result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); if ( result ) { + if ( jQuery.isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + jQuery.proxy( result.stop, result ); + } return result; } } @@ -370,7 +375,7 @@ jQuery.Animation = jQuery.extend( Animation, { callback = props; props = [ "*" ]; } else { - props = props.split( " " ); + props = props.match( rnotwhite ); } var prop, From 3748c647f3f49a3c2e54082532e3a29a9f6b6a5a Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:19:33 +0300 Subject: [PATCH 032/114] Revert "Manipulation: increase delay of data-URI test" This reverts commit 4fae91141c04dffb5094b5961eb5d7b2a1f3f423. --- test/unit/manipulation.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 2125067b8e..cd9fb21c46 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2701,6 +2701,6 @@ QUnit.test( "Insert script with data-URI (gh-1887)", 1, function( assert ) { assert.ok( true, "data-URI script is not supported by this environment" ); } - done(); - }, 100 ); -} ); + start(); + }); +}); From 7a7801975128839775fe4fce7785fa2b73fc2a70 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:21:08 +0300 Subject: [PATCH 033/114] Revert "Core: Return empty array instead of null for parseHTML("")" This reverts commit 4116914dcac32868c2c822366785e3dd2ccc69d4. --- src/core/parseHTML.js | 4 ++-- test/unit/core.js | 43 +++++++++++++++++++------------------------ 2 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/core/parseHTML.js b/src/core/parseHTML.js index 30405363cc..87c2147d14 100644 --- a/src/core/parseHTML.js +++ b/src/core/parseHTML.js @@ -13,8 +13,8 @@ define( [ // defaults to document // keepScripts (optional): If true, will include scripts passed in the html string jQuery.parseHTML = function( data, context, keepScripts ) { - if ( typeof data !== "string" ) { - return []; + if ( !data || typeof data !== "string" ) { + return null; } if ( typeof context === "boolean" ) { keepScripts = context; diff --git a/test/unit/core.js b/test/unit/core.js index e2b4d1b552..49ad240234 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1470,50 +1470,45 @@ QUnit.test( "jQuery.proxy", function( assert ) { cb.call( thisObject, "arg3" ); } ); -QUnit.test( "jQuery.parseHTML", function( assert ) { - assert.expect( 23 ); +QUnit.test("jQuery.parseHTML", function( assert ) { + assert.expect( 18 ); var html, nodes; - assert.deepEqual( jQuery.parseHTML(), [], "Without arguments" ); - assert.deepEqual( jQuery.parseHTML( undefined ), [], "Undefined" ); - assert.deepEqual( jQuery.parseHTML( null ), [], "Null" ); - assert.deepEqual( jQuery.parseHTML( false ), [], "Boolean false" ); - assert.deepEqual( jQuery.parseHTML( 0 ), [], "Zero" ); - assert.deepEqual( jQuery.parseHTML( true ), [], "Boolean true" ); - assert.deepEqual( jQuery.parseHTML( 42 ), [], "Positive number" ); - assert.deepEqual( jQuery.parseHTML( "" ), [], "Empty string" ); - assert.throws( function() { - jQuery.parseHTML( "
    ", document.getElementById( "form" ) ); - }, "Passing an element as the context raises an exception (context should be a document)" ); + assert.equal( jQuery.parseHTML(), null, "Nothing in, null out." ); + assert.equal( jQuery.parseHTML( null ), null, "Null in, null out." ); + assert.equal( jQuery.parseHTML( "" ), null, "Empty string in, null out." ); + throws(function() { + jQuery.parseHTML( "
    ", document.getElementById("form") ); + }, "Passing an element as the context raises an exception (context should be a document)"); - nodes = jQuery.parseHTML( jQuery( "body" )[ 0 ].innerHTML ); + nodes = jQuery.parseHTML( jQuery("body")[0].innerHTML ); assert.ok( nodes.length > 4, "Parse a large html string" ); assert.equal( jQuery.type( nodes ), "array", "parseHTML returns an array rather than a nodelist" ); html = ""; assert.equal( jQuery.parseHTML( html ).length, 0, "Ignore scripts by default" ); - assert.equal( jQuery.parseHTML( html, true )[ 0 ].nodeName.toLowerCase(), "script", "Preserve scripts when requested" ); + assert.equal( jQuery.parseHTML( html, true )[0].nodeName.toLowerCase(), "script", "Preserve scripts when requested" ); html += "
    "; - assert.equal( jQuery.parseHTML( html )[ 0 ].nodeName.toLowerCase(), "div", "Preserve non-script nodes" ); - assert.equal( jQuery.parseHTML( html, true )[ 0 ].nodeName.toLowerCase(), "script", "Preserve script position" ); + assert.equal( jQuery.parseHTML( html )[0].nodeName.toLowerCase(), "div", "Preserve non-script nodes" ); + assert.equal( jQuery.parseHTML( html, true )[0].nodeName.toLowerCase(), "script", "Preserve script position"); - assert.equal( jQuery.parseHTML( "text" )[ 0 ].nodeType, 3, "Parsing text returns a text node" ); - assert.equal( jQuery.parseHTML( "\t
    " )[ 0 ].nodeValue, "\t", "Preserve leading whitespace" ); + assert.equal( jQuery.parseHTML("text")[0].nodeType, 3, "Parsing text returns a text node" ); + assert.equal( jQuery.parseHTML( "\t
    " )[0].nodeValue, "\t", "Preserve leading whitespace" ); - assert.equal( jQuery.parseHTML( "
    " )[ 0 ].nodeType, 3, "Leading spaces are treated as text nodes (#11290)" ); + assert.equal( jQuery.parseHTML("
    ")[0].nodeType, 3, "Leading spaces are treated as text nodes (#11290)" ); html = jQuery.parseHTML( "
    test div
    " ); assert.equal( html[ 0 ].parentNode.nodeType, 11, "parentNode should be documentFragment" ); assert.equal( html[ 0 ].innerHTML, "test div", "Content should be preserved" ); - assert.equal( jQuery.parseHTML( "" ).length, 1, "Incorrect html-strings should not break anything" ); - assert.equal( jQuery.parseHTML( "" )[ 1 ].parentNode.nodeType, 11, + assert.equal( jQuery.parseHTML("").length, 1, "Incorrect html-strings should not break anything" ); + assert.equal( jQuery.parseHTML("")[ 1 ].parentNode.nodeType, 11, "parentNode should be documentFragment for wrapMap (variable in manipulation module) elements too" ); - assert.ok( jQuery.parseHTML( "<#if>

    This is a test.

    <#/if>" ) || true, "Garbage input should not cause error" ); -} ); + assert.ok( jQuery.parseHTML("<#if>

    This is a test.

    <#/if>") || true, "Garbage input should not cause error" ); +}); if ( jQuery.support.createHTMLDocument ) { QUnit.asyncTest( "jQuery.parseHTML", function( assert ) { From c7e372b9fdf6c510ee0f9fb7cd78b892cbee27c9 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:27:18 +0300 Subject: [PATCH 034/114] Revert "Core: Remove deprecated context and selector properties" This reverts commit 0ea8c32863af31fb5cfc184e8d513bbae35583e8. --- src/core.js | 4 ++++ src/core/init.js | 12 ++++++++++-- src/traversing/findFilter.js | 5 ++++- test/unit/core.js | 9 +++++---- test/unit/offset.js | 8 ++++---- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/core.js b/src/core.js index 771a30f809..72f4de2a05 100644 --- a/src/core.js +++ b/src/core.js @@ -42,6 +42,9 @@ jQuery.fn = jQuery.prototype = { constructor: jQuery, + // Start with an empty selector + selector: "", + // The default length of a jQuery object is 0 length: 0, @@ -70,6 +73,7 @@ jQuery.fn = jQuery.prototype = { // Add the old object onto the stack (as a reference) ret.prevObject = this; + ret.context = this.context; // Return the newly-formed element set return ret; diff --git a/src/core/init.js b/src/core/init.js index a00d587915..915d992b3c 100644 --- a/src/core/init.js +++ b/src/core/init.js @@ -79,9 +79,12 @@ var rootjQuery, if ( elem ) { // Inject the element directly into the jQuery object - this[ 0 ] = elem; this.length = 1; + this[0] = elem; } + + this.context = document; + this.selector = selector; return this; } @@ -97,7 +100,7 @@ var rootjQuery, // HANDLE: $(DOMElement) } else if ( selector.nodeType ) { - this[ 0 ] = selector; + this.context = this[0] = selector; this.length = 1; return this; @@ -111,6 +114,11 @@ var rootjQuery, selector( jQuery ); } + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + return jQuery.makeArray( selector, this ); }; diff --git a/src/traversing/findFilter.js b/src/traversing/findFilter.js index ee76a57a75..7d4b2cab9e 100644 --- a/src/traversing/findFilter.js +++ b/src/traversing/findFilter.js @@ -72,7 +72,10 @@ jQuery.fn.extend( { jQuery.find( selector, self[ i ], ret ); } - return this.pushStack( len > 1 ? jQuery.uniqueSort( ret ) : ret ); + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; }, filter: function( selector ) { return this.pushStack( winnow( this, selector || [], false ) ); diff --git a/test/unit/core.js b/test/unit/core.js index 49ad240234..528d5f593f 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -53,10 +53,10 @@ QUnit.test( "jQuery()", function( assert ) { // Basic constructor's behavior assert.equal( jQuery().length, 0, "jQuery() === jQuery([])" ); - assert.equal( jQuery( undefined ).length, 0, "jQuery(undefined) === jQuery([])" ); - assert.equal( jQuery( null ).length, 0, "jQuery(null) === jQuery([])" ); - assert.equal( jQuery( "" ).length, 0, "jQuery('') === jQuery([])" ); - assert.deepEqual( jQuery( obj ).get(), obj.get(), "jQuery(jQueryObj) == jQueryObj" ); + assert.equal( jQuery(undefined).length, 0, "jQuery(undefined) === jQuery([])" ); + assert.equal( jQuery(null).length, 0, "jQuery(null) === jQuery([])" ); + assert.equal( jQuery("").length, 0, "jQuery('') === jQuery([])" ); + assert.equal( jQuery(obj).selector, "div", "jQuery(jQueryObj) == jQueryObj" ); // Invalid #id goes to Sizzle which will throw an error (gh-1682) try { @@ -166,6 +166,7 @@ QUnit.test( "globalEval", function( assert ) { assert.equal( window.globalEvalTest, 3, "Test context (this) is the window object" ); } ); + QUnit.test( "globalEval with 'use strict'", function( assert ) { assert.expect( 1 ); Globals.register( "strictEvalTest" ); diff --git a/test/unit/offset.js b/test/unit/offset.js index 88e75950b4..2ee0c12ead 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -496,10 +496,10 @@ testIframe( "offset/body", "body", function( $, window, document, assert ) { QUnit.test( "chaining", function( assert ) { assert.expect( 3 ); var coords = { "top": 1, "left": 1 }; - assert.equal( jQuery( "#absolute-1" ).offset( coords ).jquery, jQuery.fn.jquery, "offset(coords) returns jQuery object" ); - assert.equal( jQuery( "#non-existent" ).offset( coords ).jquery, jQuery.fn.jquery, "offset(coords) with empty jQuery set returns jQuery object" ); - assert.equal( jQuery( "#absolute-1" ).offset( undefined ).jquery, jQuery.fn.jquery, "offset(undefined) returns jQuery object (#5571)" ); -} ); + assert.equal( jQuery("#absolute-1").offset(coords).selector, "#absolute-1", "offset(coords) returns jQuery object" ); + assert.equal( jQuery("#non-existent").offset(coords).selector, "#non-existent", "offset(coords) with empty jQuery set returns jQuery object" ); + assert.equal( jQuery("#absolute-1").offset(undefined).selector, "#absolute-1", "offset(undefined) returns jQuery object (#5571)" ); +}); QUnit.test( "offsetParent", function( assert ) { assert.expect( 13 ); From cad0f469a8b6785643fe2ca08fe1dae3e49046b1 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:32:36 +0300 Subject: [PATCH 035/114] Revert "Callbacks: Reduce size" This reverts commit 4cbf02df84dbcaa44b75a64ed832f7dbff2231dd. --- src/callbacks.js | 158 ++++++++++++++++++++++++++--------------------- 1 file changed, 87 insertions(+), 71 deletions(-) diff --git a/src/callbacks.js b/src/callbacks.js index b032c8f1ce..58a9a58007 100644 --- a/src/callbacks.js +++ b/src/callbacks.js @@ -3,9 +3,12 @@ define( [ "./var/rnotwhite" ], function( jQuery, rnotwhite ) { -// Convert String-formatted options into Object-formatted ones +// String to Object options format cache +var optionsCache = {}; + +// Convert String-formatted options into Object-formatted ones and store in cache function createOptions( options ) { - var object = {}; + var object = optionsCache[ options ] = {}; jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { object[ flag ] = true; } ); @@ -39,71 +42,71 @@ jQuery.Callbacks = function( options ) { // Convert options from String-formatted to Object-formatted if needed // (we check in cache first) options = typeof options === "string" ? - createOptions( options ) : + ( optionsCache[ options ] || createOptions( options ) ) : jQuery.extend( {}, options ); var // Flag to know if list is currently firing firing, - // Last fire value for non-forgettable lists + // Last fire value (for non-forgettable lists) memory, // Flag to know if list was already fired fired, - // Flag to prevent firing + // Flag to prevent .fire/.fireWith locked, + // End of the loop when firing + firingLength, + + // Index of currently firing callback (modified by remove if needed) + firingIndex, + + // First callback to fire (used internally by add and fireWith) + firingStart, + // Actual callback list list = [], - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, + // Stack of fire calls for repeatable lists + stack = !options.once && [], // Fire callbacks - fire = function() { - - // Enforce single-firing + fire = function( data ) { locked = options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } + memory = options.memory && data; + fired = true; + firingIndex = firingStart || 0; + firingStart = 0; + firingLength = list.length; + firing = true; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { + if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && + options.stopOnFalse ) { + + memory = false; // To prevent further calls using add + break; } } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - firing = false; - // Clean up if we're done firing for good - if ( locked ) { + // If not disabled, + if ( list ) { + + // If repeatable, check for pending execution + if ( stack ) { + if ( stack.length ) { + fire( stack.shift() ); + } - // Keep an empty list if we have data for future add calls - if ( memory ) { + // If not repeatable but with memory, clear out spent callbacks + } else if ( memory ) { list = []; - // Otherwise, this object is spent + // Else, disable } else { - list = ""; + self.disable(); } } }, @@ -115,19 +118,16 @@ jQuery.Callbacks = function( options ) { add: function() { if ( list ) { - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - + // First, we save the current length + var start = list.length; ( function add( args ) { jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { + var type = jQuery.type( arg ); + if ( type === "function" ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } - } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + } else if ( arg && arg.length && type !== "string" ) { // Inspect recursively add( arg ); @@ -135,8 +135,16 @@ jQuery.Callbacks = function( options ) { } ); } )( arguments ); - if ( memory && !firing ) { - fire(); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + firingLength = list.length; + + // With memory, if we're not firing then + // we should call right away + } else if ( memory ) { + firingStart = start; + fire( memory ); } } return this; @@ -144,32 +152,38 @@ jQuery.Callbacks = function( options ) { // Remove a callback from the list remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; + if ( list ) { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( firing ) { + if ( index <= firingLength ) { + firingLength--; + } + if ( index <= firingIndex ) { + firingIndex--; + } + } } - } - } ); + } ); + } return this; }, // Check if a given callback is in the list. // If no argument is given, return whether or not list has callbacks attached. has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; + return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); }, // Remove all callbacks from the list empty: function() { if ( list ) { list = []; + firingLength = 0; } return this; }, @@ -178,8 +192,8 @@ jQuery.Callbacks = function( options ) { // Abort any current/pending executions // Clear all callbacks and values disable: function() { - locked = queue = []; - list = memory = ""; + list = stack = memory = undefined; + locked = true; return this; }, disabled: function() { @@ -190,9 +204,10 @@ jQuery.Callbacks = function( options ) { // Also disable .add unless we have memory (since it would have no effect) // Abort any pending executions lock: function() { - locked = queue = []; + stack = undefined; + locked = true; if ( !memory && !firing ) { - list = memory = ""; + self.disable(); } return this; }, @@ -205,9 +220,10 @@ jQuery.Callbacks = function( options ) { if ( !locked ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); + if ( firing ) { + stack.push( args ); + } else { + fire( args ); } } return this; From 793925ff3be0a185ba5d2c733252eac324fb3cd5 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:38:00 +0300 Subject: [PATCH 036/114] Revert "Callbacks: Don't abort execution on .lock()" This reverts commit 32bf9178cace8c52a31c468a28adde9a4fdc4671. --- src/callbacks.js | 2 +- test/unit/callbacks.js | 64 ++++++++++++++++++------------------------ 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/callbacks.js b/src/callbacks.js index 58a9a58007..ce21571eda 100644 --- a/src/callbacks.js +++ b/src/callbacks.js @@ -206,7 +206,7 @@ jQuery.Callbacks = function( options ) { lock: function() { stack = undefined; locked = true; - if ( !memory && !firing ) { + if ( !memory ) { self.disable(); } return this; diff --git a/test/unit/callbacks.js b/test/unit/callbacks.js index c6c379dede..0bae02a876 100644 --- a/test/unit/callbacks.js +++ b/test/unit/callbacks.js @@ -65,7 +65,7 @@ jQuery.each( tests, function( strFlags, resultString ) { QUnit.test( "jQuery.Callbacks( " + showFlags( flags ) + " ) - " + filterLabel, function( assert ) { - assert.expect( 29 ); + assert.expect( 28 ); var cblist, results = resultString.split( /\s+/ ); @@ -76,20 +76,20 @@ jQuery.each( tests, function( strFlags, resultString ) { assert.strictEqual( cblist.locked(), false, ".locked() initially false" ); assert.strictEqual( cblist.disabled(), false, ".disabled() initially false" ); assert.strictEqual( cblist.fired(), false, ".fired() initially false" ); - cblist.add( function( str ) { + cblist.add(function( str ) { output += str; - } ); + }); assert.strictEqual( cblist.fired(), false, ".fired() still false after .add" ); cblist.fire( "A" ); assert.strictEqual( output, "XA", "Basic binding and firing" ); assert.strictEqual( cblist.fired(), true, ".fired() detects firing" ); output = "X"; cblist.disable(); - cblist.add( function( str ) { + cblist.add(function( str ) { output += str; - } ); + }); assert.strictEqual( output, "X", "Adding a callback after disabling" ); - cblist.fire( "A" ); + cblist.fire("A"); assert.strictEqual( output, "X", "Firing after disabling" ); assert.strictEqual( cblist.disabled(), true, ".disabled() becomes true" ); assert.strictEqual( cblist.locked(), true, "disabling locks" ); @@ -113,20 +113,20 @@ jQuery.each( tests, function( strFlags, resultString ) { // Basic binding and firing (context, arguments) output = "X"; cblist = jQuery.Callbacks( flags ); - cblist.add( function() { + cblist.add(function() { assert.equal( this, window, "Basic binding and firing (context)" ); output += Array.prototype.join.call( arguments, "" ); - } ); + }); cblist.fireWith( window, [ "A", "B" ] ); assert.strictEqual( output, "XAB", "Basic binding and firing (arguments)" ); // fireWith with no arguments output = ""; cblist = jQuery.Callbacks( flags ); - cblist.add( function() { + cblist.add(function() { assert.equal( this, window, "fireWith with no arguments (context is window)" ); assert.strictEqual( arguments.length, 0, "fireWith with no arguments (no arguments)" ); - } ); + }); cblist.fireWith(); // Basic binding, removing and firing @@ -150,34 +150,24 @@ jQuery.each( tests, function( strFlags, resultString ) { // Locking output = "X"; cblist = jQuery.Callbacks( flags ); - cblist.add( function( str ) { + cblist.add(function( str ) { output += str; - } ); + }); cblist.lock(); - cblist.add( function( str ) { + cblist.add(function( str ) { output += str; - } ); - cblist.fire( "A" ); - cblist.add( function( str ) { + }); + cblist.fire("A"); + cblist.add(function( str ) { output += str; - } ); + }); assert.strictEqual( output, "X", "Lock early" ); assert.strictEqual( cblist.locked(), true, "Locking reflected in accessor" ); - // Locking while firing (gh-1990) - output = "X"; - cblist = jQuery.Callbacks( flags ); - cblist.add( cblist.lock ); - cblist.add( function( str ) { - output += str; - } ); - cblist.fire( "A" ); - assert.strictEqual( output, "XA", "Locking doesn't abort execution (gh-1990)" ); - // Ordering output = "X"; cblist = jQuery.Callbacks( flags ); - cblist.add( function() { + cblist.add(function() { cblist.add( outputC ); outputA(); }, outputB ); @@ -186,7 +176,7 @@ jQuery.each( tests, function( strFlags, resultString ) { // Add and fire again output = "X"; - cblist.add( function() { + cblist.add(function() { cblist.add( outputC ); outputA(); }, outputB ); @@ -199,23 +189,23 @@ jQuery.each( tests, function( strFlags, resultString ) { // Multiple fire output = "X"; cblist = jQuery.Callbacks( flags ); - cblist.add( function( str ) { + cblist.add(function( str ) { output += str; - } ); - cblist.fire( "A" ); + }); + cblist.fire("A"); assert.strictEqual( output, "XA", "Multiple fire (first fire)" ); output = "X"; - cblist.add( function( str ) { + cblist.add(function( str ) { output += str; - } ); + }); assert.strictEqual( output, results.shift(), "Multiple fire (first new callback)" ); output = "X"; - cblist.fire( "B" ); + cblist.fire("B"); assert.strictEqual( output, results.shift(), "Multiple fire (second fire)" ); output = "X"; - cblist.add( function( str ) { + cblist.add(function( str ) { output += str; - } ); + }); assert.strictEqual( output, results.shift(), "Multiple fire (second new callback)" ); // Return false From 3655260866cdcfe42a1117bfb9603144c9e4d829 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:39:32 +0300 Subject: [PATCH 037/114] Release: remove revert artefacts --- src/core/init.js | 4 ++-- test/unit/core.js | 2 +- test/unit/manipulation.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/init.js b/src/core/init.js index 915d992b3c..c4e1da33dc 100644 --- a/src/core/init.js +++ b/src/core/init.js @@ -80,7 +80,7 @@ var rootjQuery, // Inject the element directly into the jQuery object this.length = 1; - this[0] = elem; + this[ 0 ] = elem; } this.context = document; @@ -100,7 +100,7 @@ var rootjQuery, // HANDLE: $(DOMElement) } else if ( selector.nodeType ) { - this.context = this[0] = selector; + this.context = this[ 0 ] = selector; this.length = 1; return this; diff --git a/test/unit/core.js b/test/unit/core.js index 528d5f593f..694f667644 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1479,7 +1479,7 @@ QUnit.test("jQuery.parseHTML", function( assert ) { assert.equal( jQuery.parseHTML(), null, "Nothing in, null out." ); assert.equal( jQuery.parseHTML( null ), null, "Null in, null out." ); assert.equal( jQuery.parseHTML( "" ), null, "Empty string in, null out." ); - throws(function() { + assert.throws(function() { jQuery.parseHTML( "
    ", document.getElementById("form") ); }, "Passing an element as the context raises an exception (context should be a document)"); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index cd9fb21c46..3000a83930 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2701,6 +2701,6 @@ QUnit.test( "Insert script with data-URI (gh-1887)", 1, function( assert ) { assert.ok( true, "data-URI script is not supported by this environment" ); } - start(); + done(); }); }); From 276282146ad6b847bb7bec2cfaab8efc327e86b8 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:41:51 +0300 Subject: [PATCH 038/114] Revert "Manipulation: make wrapAll funarg execute only once" This reverts commit 359b03cac74d7336676a6992f14b7ccab9b28659. --- src/wrap.js | 9 ++++++--- test/unit/wrap.js | 51 ----------------------------------------------- 2 files changed, 6 insertions(+), 54 deletions(-) diff --git a/src/wrap.js b/src/wrap.js index 32d1d331f2..e43794448a 100644 --- a/src/wrap.js +++ b/src/wrap.js @@ -9,10 +9,13 @@ jQuery.fn.extend( { wrapAll: function( html ) { var wrap; + if ( jQuery.isFunction( html ) ) { + return this.each(function( i ) { + jQuery( this ).wrapAll( html.call(this, i) ); + }); + } + if ( this[ 0 ] ) { - if ( jQuery.isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } // The elements to wrap the target around wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); diff --git a/test/unit/wrap.js b/test/unit/wrap.js index d7ba80d172..84f827db36 100644 --- a/test/unit/wrap.js +++ b/test/unit/wrap.js @@ -206,58 +206,7 @@ QUnit.test( "wrapAll(String)", function( assert ) { } ); -QUnit.test( "wrapAll(Function)", function( assert ) { - assert.expect( 5 ); - - var prev = jQuery( "#firstp" )[ 0 ].previousSibling, - p = jQuery( "#firstp,#first" )[ 0 ].parentNode, - result = jQuery( "#firstp,#first" ).wrapAll( function() { - return "
    "; - } ); - - assert.equal( - result.parent().length, 1, "Check for wrapping of on-the-fly html" - ); - assert.ok( - jQuery( "#first" ).parent().parent().is( ".red" ), "Check if wrapper has class 'red'" - ); - assert.ok( - jQuery( "#firstp" ).parent().parent().is( ".red" ), "Check if wrapper has class 'red'" - ); - assert.ok( - jQuery( "#first" ).parent().parent().parent().is( p ), "Correct Parent" - ); - assert.strictEqual( - jQuery( "#first" ).parent().parent()[ 0 ].previousSibling, prev, "Correct Previous Sibling" - ); -} ); - -QUnit.test( "wrapAll(Function) check execution characteristics", function( assert ) { - assert.expect( 3 ); - - var i = 0; - - jQuery( "non-existent" ).wrapAll( function() { - i++; - return ""; - } ); - - assert.ok( - !i, "should not execute function argument if target element does not exist" - ); - - jQuery( "#firstp" ).wrapAll( function( index ) { - assert.strictEqual( - this, jQuery( "#firstp" )[ 0 ], "context must be the first found element" - ); - assert.strictEqual( - index, undefined, "index argument should not be included in function execution" - ); - } ); -} ); - QUnit.test( "wrapAll(Element)", function( assert ) { - assert.expect( 3 ); var prev, p; From f1fb094d8efffb2f69bafd5b44873b266aace7ac Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:44:35 +0300 Subject: [PATCH 039/114] Revert "Manipulation: improve test for data-URI" This reverts commit dd596ccf729b2f39d44b73bc54b53bd41c880146. --- test/unit/manipulation.js | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 3000a83930..492390adf1 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2679,28 +2679,11 @@ QUnit.test( "Make sure col element is appended correctly", function( assert ) { assert.strictEqual( table.find( "td" ).width(), 150 ); } ); -QUnit.test( "Insert script with data-URI (gh-1887)", 1, function( assert ) { +asyncTest( "Insert script with data-URI (gh-1887)", 1, function() { Globals.register( "testFoo" ); - Globals.register( "testSrcFoo" ); - - var script = document.createElement( "script" ), - fixture = document.getElementById( "qunit-fixture" ), - done = assert.async(); - - script.src = "data:text/javascript,testSrcFoo = 'foo';"; - - fixture.appendChild( script ); - - jQuery( fixture ).append( "" ); - - setTimeout( function() { - if ( window[ "testSrcFoo" ] === "foo" ) { - assert.strictEqual( window[ "testFoo" ], window[ "testSrcFoo" ], "data-URI script executed" ); - - } else { - assert.ok( true, "data-URI script is not supported by this environment" ); - } - - done(); - }); + jQuery( "#qunit-fixture" ).append( "" ); + setTimeout(function() { + strictEqual( window[ "testFoo" ], "foo", "data-URI script executed" ); + start(); + }, 100 ); }); From bbd453c0587b970cf714761fb1894231490bac93 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:47:41 +0300 Subject: [PATCH 040/114] Revert "Core: Throw an error on $("#") rather than returning 0-length collection" This reverts commit 80022c81ce4a07a232afd3c580b0977555a2daec. --- src/core/init.js | 3 +-- test/unit/core.js | 9 ++------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/core/init.js b/src/core/init.js index c4e1da33dc..7748c38fb4 100644 --- a/src/core/init.js +++ b/src/core/init.js @@ -12,8 +12,7 @@ var rootjQuery, // A simple way to check for HTML strings // Prioritize #id over to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, init = jQuery.fn.init = function( selector, context, root ) { var match, elem; diff --git a/test/unit/core.js b/test/unit/core.js index 694f667644..33a98cedcf 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -56,14 +56,9 @@ QUnit.test( "jQuery()", function( assert ) { assert.equal( jQuery(undefined).length, 0, "jQuery(undefined) === jQuery([])" ); assert.equal( jQuery(null).length, 0, "jQuery(null) === jQuery([])" ); assert.equal( jQuery("").length, 0, "jQuery('') === jQuery([])" ); - assert.equal( jQuery(obj).selector, "div", "jQuery(jQueryObj) == jQueryObj" ); + assert.equal( jQuery("#").length, 0, "jQuery('#') === jQuery([])" ); - // Invalid #id goes to Sizzle which will throw an error (gh-1682) - try { - jQuery( "#" ); - } catch ( e ) { - assert.ok( true, "Threw an error on #id with no id" ); - } + assert.equal( jQuery(obj).selector, "div", "jQuery(jQueryObj) == jQueryObj" ); // can actually yield more than one, when iframes are included, the window is an array as well assert.equal( jQuery( window ).length, 1, "Correct number of elements generated for jQuery(window)" ); From ea2f10c104e4cf3ada1c0da12ebf4fac0d2801ca Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 16:48:03 +0300 Subject: [PATCH 041/114] Revert "Manipulation: support data-URI scripts insertion" This reverts commit 15f4dec7894f1e00adbfb9bce4f870441a527bd6. --- src/manipulation/_evalUrl.js | 1 - test/unit/manipulation.js | 9 --------- 2 files changed, 10 deletions(-) diff --git a/src/manipulation/_evalUrl.js b/src/manipulation/_evalUrl.js index 572fe30c71..85ca2c62a4 100644 --- a/src/manipulation/_evalUrl.js +++ b/src/manipulation/_evalUrl.js @@ -9,7 +9,6 @@ jQuery._evalUrl = function( url ) { // Make this explicit, since user can override this through ajaxSetup (#11264) type: "GET", dataType: "script", - cache: true, async: false, global: false, "throws": true diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 492390adf1..2069ee5c50 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2678,12 +2678,3 @@ QUnit.test( "Make sure col element is appended correctly", function( assert ) { assert.strictEqual( table.find( "td" ).width(), 150 ); } ); - -asyncTest( "Insert script with data-URI (gh-1887)", 1, function() { - Globals.register( "testFoo" ); - jQuery( "#qunit-fixture" ).append( "" ); - setTimeout(function() { - strictEqual( window[ "testFoo" ], "foo", "data-URI script executed" ); - start(); - }, 100 ); -}); From de30e4a73d0591127c1cfbf20867b59469b2d51f Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 17:01:53 +0300 Subject: [PATCH 042/114] Revert "Deprecated: Drop size and andSelf methods" This reverts commit f110360f65a268e959ae892ca36e85da3d91e606. --- src/deprecated.js | 8 ++++++++ test/unit/deprecated.js | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/src/deprecated.js b/src/deprecated.js index 78885266dd..dfd06826a2 100644 --- a/src/deprecated.js +++ b/src/deprecated.js @@ -20,7 +20,15 @@ jQuery.fn.extend( { return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); + }, + size: function() { + return this.length; } } ); +jQuery.fn.andSelf = jQuery.fn.addBack; + } ); + + + diff --git a/test/unit/deprecated.js b/test/unit/deprecated.js index f474dc6c32..a033135bff 100644 --- a/test/unit/deprecated.js +++ b/test/unit/deprecated.js @@ -39,3 +39,9 @@ QUnit.test( "delegate/undelegate", function( assert ) { .undelegate( "b", "click" ) .remove(); } ); +if ( jQuery.fn.size ) { + test("size()", function() { + expect(1); + equal( jQuery("#qunit-fixture p").size(), 6, "Get Number of Elements Found" ); + }); +} From e2af987877c83e5b054e1f9cac1a8534ebed0b18 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 17:03:05 +0300 Subject: [PATCH 043/114] Release: fix revert artefacts --- src/deprecated.js | 2 -- src/wrap.js | 6 +++--- test/unit/deprecated.js | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/deprecated.js b/src/deprecated.js index dfd06826a2..c82989007c 100644 --- a/src/deprecated.js +++ b/src/deprecated.js @@ -30,5 +30,3 @@ jQuery.fn.andSelf = jQuery.fn.addBack; } ); - - diff --git a/src/wrap.js b/src/wrap.js index e43794448a..4d2c3b2044 100644 --- a/src/wrap.js +++ b/src/wrap.js @@ -10,9 +10,9 @@ jQuery.fn.extend( { var wrap; if ( jQuery.isFunction( html ) ) { - return this.each(function( i ) { - jQuery( this ).wrapAll( html.call(this, i) ); - }); + return this.each( function( i ) { + jQuery( this ).wrapAll( html.call( this, i ) ); + } ); } if ( this[ 0 ] ) { diff --git a/test/unit/deprecated.js b/test/unit/deprecated.js index a033135bff..9dfd515cea 100644 --- a/test/unit/deprecated.js +++ b/test/unit/deprecated.js @@ -40,8 +40,8 @@ QUnit.test( "delegate/undelegate", function( assert ) { .remove(); } ); if ( jQuery.fn.size ) { - test("size()", function() { - expect(1); - equal( jQuery("#qunit-fixture p").size(), 6, "Get Number of Elements Found" ); + QUnit.test("size()", function( assert ) { + assert.expect( 1 ); + assert.equal( jQuery("#qunit-fixture p").size(), 6, "Get Number of Elements Found" ); }); } From f0532a29e38d01d6f3e44435198527323d507cf9 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 17:22:36 +0300 Subject: [PATCH 044/114] Callbacks: bring back size reduction Ref 4cbf02df84dbcaa44b75a64ed832f7dbff2231dd --- src/callbacks.js | 158 +++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 87 deletions(-) diff --git a/src/callbacks.js b/src/callbacks.js index ce21571eda..df7c7cf0ef 100644 --- a/src/callbacks.js +++ b/src/callbacks.js @@ -3,12 +3,9 @@ define( [ "./var/rnotwhite" ], function( jQuery, rnotwhite ) { -// String to Object options format cache -var optionsCache = {}; - -// Convert String-formatted options into Object-formatted ones and store in cache +// Convert String-formatted options into Object-formatted ones function createOptions( options ) { - var object = optionsCache[ options ] = {}; + var object = {}; jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { object[ flag ] = true; } ); @@ -42,71 +39,71 @@ jQuery.Callbacks = function( options ) { // Convert options from String-formatted to Object-formatted if needed // (we check in cache first) options = typeof options === "string" ? - ( optionsCache[ options ] || createOptions( options ) ) : + createOptions( options ) : jQuery.extend( {}, options ); var // Flag to know if list is currently firing firing, - // Last fire value (for non-forgettable lists) + // Last fire value for non-forgettable lists memory, // Flag to know if list was already fired fired, - // Flag to prevent .fire/.fireWith + // Flag to prevent firing locked, - // End of the loop when firing - firingLength, - - // Index of currently firing callback (modified by remove if needed) - firingIndex, - - // First callback to fire (used internally by add and fireWith) - firingStart, - // Actual callback list list = [], - // Stack of fire calls for repeatable lists - stack = !options.once && [], + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, // Fire callbacks - fire = function( data ) { + fire = function() { + + // Enforce single-firing locked = options.once; - memory = options.memory && data; - fired = true; - firingIndex = firingStart || 0; - firingStart = 0; - firingLength = list.length; - firing = true; - for ( ; list && firingIndex < firingLength; firingIndex++ ) { - if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && - options.stopOnFalse ) { - - memory = false; // To prevent further calls using add - break; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } } } - firing = false; - // If not disabled, - if ( list ) { + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; - // If repeatable, check for pending execution - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } + // Clean up if we're done firing for good + if ( locked ) { - // If not repeatable but with memory, clear out spent callbacks - } else if ( memory ) { + // Keep an empty list if we have data for future add calls + if ( memory ) { list = []; - // Else, disable + // Otherwise, this object is spent } else { - self.disable(); + list = ""; } } }, @@ -118,16 +115,19 @@ jQuery.Callbacks = function( options ) { add: function() { if ( list ) { - // First, we save the current length - var start = list.length; + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + ( function add( args ) { jQuery.each( args, function( _, arg ) { - var type = jQuery.type( arg ); - if ( type === "function" ) { + if ( jQuery.isFunction( arg ) ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } - } else if ( arg && arg.length && type !== "string" ) { + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { // Inspect recursively add( arg ); @@ -135,16 +135,8 @@ jQuery.Callbacks = function( options ) { } ); } )( arguments ); - // Do we need to add the callbacks to the - // current firing batch? - if ( firing ) { - firingLength = list.length; - - // With memory, if we're not firing then - // we should call right away - } else if ( memory ) { - firingStart = start; - fire( memory ); + if ( memory && !firing ) { + fire(); } } return this; @@ -152,38 +144,32 @@ jQuery.Callbacks = function( options ) { // Remove a callback from the list remove: function() { - if ( list ) { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( firing ) { - if ( index <= firingLength ) { - firingLength--; - } - if ( index <= firingIndex ) { - firingIndex--; - } - } + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; } - } ); - } + } + } ); return this; }, // Check if a given callback is in the list. // If no argument is given, return whether or not list has callbacks attached. has: function( fn ) { - return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; }, // Remove all callbacks from the list empty: function() { if ( list ) { list = []; - firingLength = 0; } return this; }, @@ -192,8 +178,8 @@ jQuery.Callbacks = function( options ) { // Abort any current/pending executions // Clear all callbacks and values disable: function() { - list = stack = memory = undefined; - locked = true; + locked = queue = []; + list = memory = ""; return this; }, disabled: function() { @@ -204,10 +190,9 @@ jQuery.Callbacks = function( options ) { // Also disable .add unless we have memory (since it would have no effect) // Abort any pending executions lock: function() { - stack = undefined; - locked = true; + locked = queue = []; if ( !memory ) { - self.disable(); + list = memory = ""; } return this; }, @@ -220,10 +205,9 @@ jQuery.Callbacks = function( options ) { if ( !locked ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; - if ( firing ) { - stack.push( args ); - } else { - fire( args ); + queue.push( args ); + if ( !firing ) { + fire(); } } return this; From 9d1d4c272a58ced36242d90b3f0462c2bbb972a3 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 19:16:30 +0300 Subject: [PATCH 045/114] Offset: do not run tests which break without back-incompat change --- test/unit/offset.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/offset.js b/test/unit/offset.js index 2ee0c12ead..ff1f02099c 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -415,7 +415,7 @@ testIframe( "offset/table", "table", function( $, window, document, assert ) { } ); testIframe( "offset/scroll", "scroll", function( $, win, doc, assert ) { - assert.expect( 30 ); + assert.expect( 28 ); assert.equal( $( "#scroll-1" ).offset().top, 7, "jQuery('#scroll-1').offset().top" ); assert.equal( $( "#scroll-1" ).offset().left, 7, "jQuery('#scroll-1').offset().left" ); @@ -426,8 +426,8 @@ testIframe( "offset/scroll", "scroll", function( $, win, doc, assert ) { // These tests are solely for master/compat consistency // Retrieving offset on disconnected/hidden elements is not officially // valid input, but will return zeros for back-compat - assert.equal( $( "#hidden" ).offset().top, 0, "Hidden elements do not subtract scroll" ); - assert.equal( $( "#hidden" ).offset().left, 0, "Hidden elements do not subtract scroll" ); + // assert.equal( $( "#hidden" ).offset().top, 0, "Hidden elements do not subtract scroll" ); + // assert.equal( $( "#hidden" ).offset().left, 0, "Hidden elements do not subtract scroll" ); // scroll offset tests .scrollTop/Left assert.equal( $( "#scroll-1" ).scrollTop(), 5, "jQuery('#scroll-1').scrollTop()" ); From 91acd85b167e39e05e8f4fb1be6f75cdcac9c466 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 19:48:45 +0300 Subject: [PATCH 046/114] Revert "Ajax: Always use script injection in globalEval" This reverts commit bbdfbb4ee859fe9319b348d88120ddc2c9efbd63. --- src/core.js | 26 +++++++++--- test/data/{ => event}/longLoadScript.php | 0 test/data/event/syncReady.html | 2 +- test/unit/ajax.js | 14 +++++-- test/unit/core.js | 15 ------- test/unit/manipulation.js | 53 ++++++++---------------- 6 files changed, 50 insertions(+), 60 deletions(-) rename test/data/{ => event}/longLoadScript.php (100%) diff --git a/src/core.js b/src/core.js index 72f4de2a05..d3c08c636a 100644 --- a/src/core.js +++ b/src/core.js @@ -262,12 +262,26 @@ jQuery.extend( { }, // Evaluates a script in a global context - globalEval: function( code, context ) { - context = context || document; - var script = context.createElement( "script" ); - - script.text = code; - context.head.appendChild( script ).parentNode.removeChild( script ); + globalEval: function( code ) { + var script, + indirect = eval; + + code = jQuery.trim( code ); + + if ( code ) { + // If the code includes a valid, prologue position + // strict mode pragma, execute code by injecting a + // script tag into the document. + if ( code.indexOf("use strict") === 1 ) { + script = document.createElement("script"); + script.text = code; + document.head.appendChild( script ).parentNode.removeChild( script ); + } else { + // Otherwise, avoid the DOM node creation, insertion + // and removal by using an indirect global eval + indirect( code ); + } + } }, // Convert dashed to camelCase; used by the css and data modules diff --git a/test/data/longLoadScript.php b/test/data/event/longLoadScript.php similarity index 100% rename from test/data/longLoadScript.php rename to test/data/event/longLoadScript.php diff --git a/test/data/event/syncReady.html b/test/data/event/syncReady.html index dfa9ac3371..e0885707ed 100644 --- a/test/data/event/syncReady.html +++ b/test/data/event/syncReady.html @@ -17,7 +17,7 @@ oldIE into thinking the dom is ready, but it's not... leaving this check here for future trailblazers to attempt fixing this...--> - +
    diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 5110a9795f..3d3bfb9aa8 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1624,9 +1624,17 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re jQuery.ajax( { url: "data/badjson.js", dataType: "script", - throws: true - } ); - } ); + throws: true, + // Global events get confused by the exception + global: false, + success: function() { + ok( false, "Success." ); + }, + error: function() { + ok( false, "Error." ); + } + }); + }); jQuery.each( [ "method", "type" ], function( _, globalOption ) { function request( assert, option ) { diff --git a/test/unit/core.js b/test/unit/core.js index 33a98cedcf..6aa2a3d63d 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -170,21 +170,6 @@ QUnit.test( "globalEval with 'use strict'", function( assert ) { assert.equal( window.strictEvalTest, 1, "Test variable declarations are global (strict mode)" ); } ); -QUnit.test( "globalEval execution after script injection (#7862)", function( assert ) { - assert.expect( 1 ); - - var now, - script = document.createElement( "script" ); - - script.src = "data/longLoadScript.php?sleep=2"; - - now = jQuery.now(); - document.body.appendChild( script ); - - jQuery.globalEval( "var strictEvalTest = " + jQuery.now() + ";" ); - assert.ok( window.strictEvalTest - now < 500, "Code executed synchronously" ); -} ); - // This is not run in AMD mode if ( jQuery.noConflict ) { QUnit.test( "noConflict", function( assert ) { diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 2069ee5c50..e62eae16b2 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2297,45 +2297,28 @@ QUnit.test( "Ensure oldIE creates a new set on appendTo (#8894)", function( asse assert.strictEqual( jQuery( "

    " ).appendTo( "

    " ).end().length, jQuery( "

    test

    " ).appendTo( "
    " ).end().length, "Elements created with createElement and with createDocumentFragment should be treated alike" ); } ); -QUnit.asyncTest( "html() - script exceptions bubble (#11743)", 2, function( assert ) { +QUnit.test( "html() - script exceptions bubble (#11743)", function( assert ) { + assert.expect( 3 ); - // Support: Android 2.3 only - // Android 2.3 doesn't fire the window.onerror handler, just accept the reality there. - if ( /android 2\.3/i.test( navigator.userAgent ) ) { - assert.ok( true, "Test skipped, Android 2.3 doesn't fire window.onerror for " + - "errors in dynamically included scripts" ); - assert.ok( true, "Test skipped, Android 2.3 doesn't fire window.onerror for " + - "errors in dynamically included scripts" ); - QUnit.start(); - return; - } + assert.throws(function() { + jQuery("#qunit-fixture").html(""); + assert.ok( false, "Exception ignored" ); + }, "Exception bubbled from inline script" ); - var onerror = window.onerror; + if ( jQuery.ajax ) { + var onerror = window.onerror; + window.onerror = function() { + ok( true, "Exception thrown in remote script" ); + }; - setTimeout( function() { + jQuery("#qunit-fixture").html(""); + assert.ok( true, "Exception ignored" ); window.onerror = onerror; - - QUnit.start(); - }, 1000 ); - - window.onerror = function() { - assert.ok( true, "Exception thrown" ); - - if ( jQuery.ajax ) { - window.onerror = function() { - assert.ok( true, "Exception thrown in remote script" ); - }; - - jQuery( "#qunit-fixture" ).html( "" ); - assert.ok( true, "Exception ignored" ); - } else { - assert.ok( true, "No jQuery.ajax" ); - assert.ok( true, "No jQuery.ajax" ); - } - }; - - jQuery( "#qunit-fixture" ).html( "" ); -} ); + } else { + assert.ok( true, "No jQuery.ajax" ); + assert.ok( true, "No jQuery.ajax" ); + } +}); QUnit.test( "checked state is cloned with clone()", function( assert ) { From 741fe39ac874ee585c7d762dc7272386841827b8 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 19:49:10 +0300 Subject: [PATCH 047/114] Revert "Manipulation: execute scripts from iframe in the iframe's context" This reverts commit 22449eb968622c2e14d6c8d8de2cf1e1ba4adccd. --- src/manipulation.js | 2 +- test/data/manipulation/scripts-context.html | 18 ------------------ test/unit/manipulation.js | 11 ----------- 3 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 test/data/manipulation/scripts-context.html diff --git a/src/manipulation.js b/src/manipulation.js index eaf2e09983..ceb970cbd5 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -192,7 +192,7 @@ function domManip( collection, args, callback, ignored ) { jQuery._evalUrl( node.src ); } } else { - jQuery.globalEval( node.textContent.replace( rcleanScript, "" ), doc ); + jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) ); } } } diff --git a/test/data/manipulation/scripts-context.html b/test/data/manipulation/scripts-context.html deleted file mode 100644 index 6958453c5b..0000000000 --- a/test/data/manipulation/scripts-context.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - body - - -
    - - - - diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index e62eae16b2..050853bf5e 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2183,17 +2183,6 @@ testIframeWithCallback( } ); -testIframeWithCallback( - "domManip executes scripts in iframes in the iframes' context", - "manipulation/scripts-context.html", - function( frameWindow, bodyElement, html, assert ) { - assert.expect( 2 ); - jQuery( bodyElement ).append( html ); - assert.ok( !window.scriptTest, "script executed in iframe context" ); - assert.ok( frameWindow.scriptTest, "script executed in iframe context" ); - } -); - QUnit.test( "jQuery.clone - no exceptions for object elements #9587", function( assert ) { assert.expect( 1 ); From 0a98623abb85bdce079b400ed3bf3d87ddc6b1da Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 20:00:39 +0300 Subject: [PATCH 048/114] Effects: manually revert two `requestAnimationFrame` commits 72119e0023dcc0d9807caf6d988598b74abdc937 and bbdfbb4ee859fe9319b348d88120ddc2c9efbd63 --- src/effects.js | 28 ++++------------------------ test/unit/effects.js | 33 --------------------------------- 2 files changed, 4 insertions(+), 57 deletions(-) diff --git a/src/effects.js b/src/effects.js index ab6fe6d79a..d8997f4be9 100644 --- a/src/effects.js +++ b/src/effects.js @@ -23,13 +23,6 @@ var rfxtypes = /^(?:toggle|show|hide)$/, rrun = /queueHooks$/; -function raf() { - if ( timerId ) { - window.requestAnimationFrame( raf ); - jQuery.fx.tick(); - } -} - // Animations created synchronously will run synchronously function createFxNow() { window.setTimeout( function() { @@ -408,15 +401,8 @@ jQuery.speed = function( speed, easing, fn ) { easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing }; - // Go to the end state if fx are off or if document is hidden - if ( jQuery.fx.off || document.hidden ) { - opt.duration = 0; - - } else { - opt.duration = typeof opt.duration === "number" ? - opt.duration : opt.duration in jQuery.fx.speeds ? - jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; - } + opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : + opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; // Normalize opt.queue - true/undefined/null -> "fx" if ( opt.queue == null || opt.queue === true ) { @@ -620,18 +606,12 @@ jQuery.fx.timer = function( timer ) { jQuery.fx.interval = 13; jQuery.fx.start = function() { if ( !timerId ) { - timerId = window.requestAnimationFrame ? - window.requestAnimationFrame( raf ) : - window.setInterval( jQuery.fx.tick, jQuery.fx.interval ); + timerId = window.setInterval( jQuery.fx.tick, jQuery.fx.interval ); } }; jQuery.fx.stop = function() { - if ( window.cancelAnimationFrame ) { - window.cancelAnimationFrame( timerId ); - } else { - window.clearInterval( timerId ); - } + window.clearInterval( timerId ); timerId = null; }; diff --git a/test/unit/effects.js b/test/unit/effects.js index 20b15a1ca8..8d5b2b485d 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -5,11 +5,8 @@ if ( !jQuery.fx ) { return; } -var oldRaf = window.requestAnimationFrame; - QUnit.module( "effects", { setup: function() { - window.requestAnimationFrame = null; this.sandbox = sinon.sandbox.create(); this.clock = this.sandbox.useFakeTimers( 505877050 ); this._oldInterval = jQuery.fx.interval; @@ -22,7 +19,6 @@ QUnit.module( "effects", { jQuery.now = Date.now; jQuery.fx.stop(); jQuery.fx.interval = this._oldInterval; - window.requestAnimationFrame = oldRaf; return moduleTeardown.apply( this, arguments ); } } ); @@ -2317,35 +2313,6 @@ QUnit.test( "Respect display value on inline elements (#14824)", function( asser clock.tick( 800 ); } ); -QUnit.test( "Animation should go to its end state if document.hidden = true", function( assert ) { - assert.expect( 1 ); - - var height; - if ( Object.defineProperty ) { - - // Can't rewrite document.hidden property if its host property - try { - Object.defineProperty( document, "hidden", { - get: function() { - return true; - } - } ); - } catch ( e ) {} - } else { - document.hidden = true; - } - - if ( document.hidden ) { - height = jQuery( "#qunit-fixture" ).animate( { height: 500 } ).height(); - - assert.equal( height, 500, "Animation should happen immediately if document.hidden = true" ); - jQuery( document ).removeProp( "hidden" ); - - } else { - assert.ok( true, "Can't run the test since we can't reproduce correct environment for it" ); - } -} ); - QUnit.test( "jQuery.easing._default (gh-2218)", function( assert ) { assert.expect( 2 ); From ae88b3971c38e0d32a8b927d597426bb50263c6f Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 13 Nov 2015 20:03:14 +0300 Subject: [PATCH 049/114] Release: fix revert artefacts --- src/core.js | 11 +++++++---- src/css.js | 13 +++++++++++++ src/effects.js | 5 +++-- test/unit/ajax.js | 4 ++-- test/unit/manipulation.js | 2 +- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/core.js b/src/core.js index d3c08c636a..ab172bb4fc 100644 --- a/src/core.js +++ b/src/core.js @@ -269,16 +269,19 @@ jQuery.extend( { code = jQuery.trim( code ); if ( code ) { + // If the code includes a valid, prologue position // strict mode pragma, execute code by injecting a // script tag into the document. - if ( code.indexOf("use strict") === 1 ) { - script = document.createElement("script"); + if ( code.indexOf( "use strict" ) === 1 ) { + script = document.createElement( "script" ); script.text = code; document.head.appendChild( script ).parentNode.removeChild( script ); } else { - // Otherwise, avoid the DOM node creation, insertion - // and removal by using an indirect global eval + + // Otherwise, avoid the DOM node creation, insertion + // and removal by using an indirect global eval + indirect( code ); } } diff --git a/src/css.js b/src/css.js index 7f085560e9..7bff81440a 100644 --- a/src/css.js +++ b/src/css.js @@ -415,6 +415,19 @@ jQuery.each( [ "height", "width" ], function( i, name ) { }; } ); +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + // These hooks are used by animate to expand properties jQuery.each( { margin: "", diff --git a/src/effects.js b/src/effects.js index d8997f4be9..178fa42f06 100644 --- a/src/effects.js +++ b/src/effects.js @@ -401,8 +401,9 @@ jQuery.speed = function( speed, easing, fn ) { easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing }; - opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : - opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; + opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? + opt.duration : opt.duration in jQuery.fx.speeds ? + jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; // Normalize opt.queue - true/undefined/null -> "fx" if ( opt.queue == null || opt.queue === true ) { diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 3d3bfb9aa8..69eae32112 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1628,10 +1628,10 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re // Global events get confused by the exception global: false, success: function() { - ok( false, "Success." ); + assert.ok( false, "Success." ); }, error: function() { - ok( false, "Error." ); + assert.ok( false, "Error." ); } }); }); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 050853bf5e..e5c65e32ae 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2297,7 +2297,7 @@ QUnit.test( "html() - script exceptions bubble (#11743)", function( assert ) { if ( jQuery.ajax ) { var onerror = window.onerror; window.onerror = function() { - ok( true, "Exception thrown in remote script" ); + assert.ok( true, "Exception thrown in remote script" ); }; jQuery("#qunit-fixture").html(""); From 65d71843b7c37dbdba2cfcb1bc7055cb522c5af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 16 Nov 2015 21:25:05 +0100 Subject: [PATCH 050/114] Revert "Misc: Drop support for older browsers; update support comments" This reverts commit 740e190223d19a114d5373758127285d14d6b71e. --- src/attributes/support.js | 2 +- src/core.js | 4 +--- src/core/init.js | 4 +++- src/css.js | 2 +- src/css/curCSS.js | 11 +++++----- src/css/hiddenVisibleSelectors.js | 7 ++++++- src/css/support.js | 10 +++++---- src/event.js | 8 ++++++- src/manipulation.js | 4 ++-- src/manipulation/support.js | 4 ++-- src/offset.js | 6 +++++- test/unit/css.js | 9 +++++--- test/unit/dimensions.js | 5 +++-- test/unit/event.js | 15 ++++++++----- test/unit/support.js | 35 ++++++++++++++++++++++++++++++- 15 files changed, 93 insertions(+), 33 deletions(-) diff --git a/src/attributes/support.js b/src/attributes/support.js index f93ba01816..5b8118bb51 100644 --- a/src/attributes/support.js +++ b/src/attributes/support.js @@ -10,7 +10,7 @@ define( [ input.type = "checkbox"; - // Support: Android<4.4 + // Support: iOS<=5.1, Android<=4.2+ // Default value for a checkbox should be "on" support.checkOn = input.value !== ""; diff --git a/src/core.js b/src/core.js index ab172bb4fc..e8f0d9d379 100644 --- a/src/core.js +++ b/src/core.js @@ -255,7 +255,7 @@ jQuery.extend( { return obj + ""; } - // Support: Android<4.0 (functionish RegExp) + // Support: Android<4.0, iOS<6 (functionish RegExp) return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call( obj ) ] || "object" : typeof obj; @@ -348,8 +348,6 @@ jQuery.extend( { return arr == null ? -1 : indexOf.call( arr, elem, i ); }, - // Support: Android<4.1, PhantomJS<2 - // push.apply(_, arraylike) throws on ancient WebKit merge: function( first, second ) { var len = +second.length, j = 0, diff --git a/src/core/init.js b/src/core/init.js index 7748c38fb4..c2b6c94d78 100644 --- a/src/core/init.js +++ b/src/core/init.js @@ -75,7 +75,9 @@ var rootjQuery, } else { elem = document.getElementById( match[ 2 ] ); - if ( elem ) { + // Support: Blackberry 4.6 + // gEBID returns nodes no longer in the document (#6963) + if ( elem && elem.parentNode ) { // Inject the element directly into the jQuery object this.length = 1; diff --git a/src/css.js b/src/css.js index 7bff81440a..0aa9d0e9c0 100644 --- a/src/css.js +++ b/src/css.js @@ -36,7 +36,7 @@ var fontWeight: "400" }, - cssPrefixes = [ "Webkit", "Moz", "ms" ], + cssPrefixes = [ "Webkit", "O", "Moz", "ms" ], emptyStyle = document.createElement( "div" ).style; // Return a css property mapped to a potentially vendor prefixed property diff --git a/src/css/curCSS.js b/src/css/curCSS.js index be643ab547..d95e287cfa 100644 --- a/src/css/curCSS.js +++ b/src/css/curCSS.js @@ -5,7 +5,7 @@ define( [ "./var/getStyles", "./support", "../selector" // Get jQuery.contains -], function( jQuery, rnumnonpx, rmargin, getStyles, support ) { +], function( jQuery, rnumnonpx, rmargin, getStyles ) { function curCSS( elem, name, computed ) { var width, minWidth, maxWidth, ret, @@ -22,12 +22,13 @@ function curCSS( elem, name, computed ) { ret = jQuery.style( elem, name ); } + // Support: iOS < 6, Android 4.0-4.3 only // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: + // iOS < 6 (at least) returns percentage for a larger set of values, + // but width seems to be reliably pixels + // this is against the CSSOM draft spec: // http://dev.w3.org/csswg/cssom/#resolved-values - if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { + if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { // Remember the original values width = style.width; diff --git a/src/css/hiddenVisibleSelectors.js b/src/css/hiddenVisibleSelectors.js index 9a8a28cf8d..0d05be97e7 100644 --- a/src/css/hiddenVisibleSelectors.js +++ b/src/css/hiddenVisibleSelectors.js @@ -4,7 +4,12 @@ define( [ ], function( jQuery ) { jQuery.expr.filters.hidden = function( elem ) { - return !jQuery.expr.filters.visible( elem ); + + // Support: Opera <= 12.12 + // Opera reports offsetWidths and offsetHeights less than zero on some elements + // Use OR instead of AND as the element is not visible if either is true + // See tickets #10406 and #13132 + return elem.offsetWidth <= 0 || elem.offsetHeight <= 0; }; jQuery.expr.filters.visible = function( elem ) { return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); diff --git a/src/css/support.js b/src/css/support.js index f8e02d0488..54d0d9c701 100644 --- a/src/css/support.js +++ b/src/css/support.js @@ -29,10 +29,12 @@ define( [ // so they're executed at the same time to save the second computation. function computeStyleTests() { div.style.cssText = - "box-sizing:border-box;" + - "position:relative;display:block;" + - "margin:auto;border:1px;padding:1px;" + - "top:1%;width:50%"; + + // Support: Firefox<29, Android 2.3 + // Vendor-prefix box-sizing + "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" + + "box-sizing:border-box;display:block;margin-top:1%;top:1%;" + + "border:1px;padding:1px;width:4px;position:absolute"; div.innerHTML = ""; documentElement.appendChild( container ); diff --git a/src/event.js b/src/event.js index 2805812495..e9d1053dc8 100644 --- a/src/event.js +++ b/src/event.js @@ -469,7 +469,13 @@ jQuery.event = { event[ prop ] = originalEvent[ prop ]; } - // Support: Safari 6-8+ + // Support: Cordova 2.5 (WebKit) (#13255) + // All events should have a target; Cordova deviceready doesn't + if ( !event.target ) { + event.target = document; + } + + // Support: Safari 6.0+, Chrome<28 // Target should not be a text node (#504, #13143) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; diff --git a/src/manipulation.js b/src/manipulation.js index ceb970cbd5..046424a78f 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -464,8 +464,8 @@ jQuery.each( { elems = i === last ? this : this.clone( true ); jQuery( insert[ i ] )[ original ]( elems ); - // Support: Android<4.1, PhantomJS<2 - // .get() because push.apply(_, arraylike) throws on ancient WebKit + // Support: QtWebKit + // .get() because push.apply(_, arraylike) throws push.apply( ret, elems.get() ); } diff --git a/src/manipulation/support.js b/src/manipulation/support.js index 4f6b9de87f..cd4081ebb2 100644 --- a/src/manipulation/support.js +++ b/src/manipulation/support.js @@ -8,7 +8,7 @@ define( [ div = fragment.appendChild( document.createElement( "div" ) ), input = document.createElement( "input" ); - // Support: Android 4.0-4.3 + // Support: Android 4.0-4.3, Safari<=5.1 // Check state lost if the name is set (#11217) // Support: Windows Web Apps (WWA) // `name` and `type` must use .setAttribute for WWA (#14901) @@ -18,7 +18,7 @@ define( [ div.appendChild( input ); - // Support: Android<4.2 + // Support: Safari<=5.1, Android<4.2 // Older WebKit doesn't clone checked state correctly in fragments support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; diff --git a/src/offset.js b/src/offset.js index 4352a99954..ae9ccc119f 100644 --- a/src/offset.js +++ b/src/offset.js @@ -98,7 +98,11 @@ jQuery.fn.extend( { return box; } - box = elem.getBoundingClientRect(); + // Support: BlackBerry 5, iOS 3 (original iPhone) + // If we don't have gBCR, just use 0,0 rather than error + if ( elem.getBoundingClientRect ) { + box = elem.getBoundingClientRect(); + } win = getWindow( doc ); return { top: box.top + win.pageYOffset - docElem.clientTop, diff --git a/test/unit/css.js b/test/unit/css.js index 7aa87d85fc..09db057299 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -293,6 +293,9 @@ QUnit.test( "css(String, Object)", function( assert ) { j = jQuery( "#nonnodes" ).contents(); j.css( "overflow", "visible" ); assert.equal( j.css( "overflow" ), "visible", "Check node,textnode,comment css works" ); + + // Opera sometimes doesn't update 'display' correctly, see #2037 + jQuery( "#t2037" )[ 0 ].innerHTML = jQuery( "#t2037" )[ 0 ].innerHTML; assert.equal( jQuery( "#t2037 .hidden" ).css( "display" ), "none", "Make sure browser thinks it is hidden" ); div = jQuery( "#nothiddendiv" ); @@ -867,9 +870,9 @@ QUnit.test( "Do not append px (#9548, #12990)", function( assert ) { QUnit.test( "css('width') and css('height') should respect box-sizing, see #11004", function( assert ) { assert.expect( 4 ); - // Support: Android 2.3 (-webkit-box-sizing). - var el_dis = jQuery( "
    test
    " ), - el = el_dis.clone().appendTo( "#qunit-fixture" ); + // Support: Firefox<29, Android 2.3 (Prefixed box-sizing versions). + var el_dis = jQuery("
    test
    "), + el = el_dis.clone().appendTo("#qunit-fixture"); assert.equal( el.css( "width" ), el.css( "width", el.css( "width" ) ).css( "width" ), "css('width') is not respecting box-sizing, see #11004" ); assert.equal( el_dis.css( "width" ), el_dis.css( "width", el_dis.css( "width" ) ).css( "width" ), "css('width') is not respecting box-sizing for disconnected element, see #11004" ); diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 5bd4f33843..9ffc6083cf 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -409,9 +409,10 @@ QUnit.test( "getters on non elements should return null", function( assert ) { QUnit.test( "setters with and without box-sizing:border-box", function( assert ) { assert.expect( 60 ); + // Support: Firefox<29, Android 2.3 (Prefixed box-sizing versions). var parent = jQuery( "#foo" ).css( { width: "200px", height: "200px", "font-size": "16px" } ), - el_bb = jQuery( "
    " ).appendTo( parent ), - el = jQuery( "
    " ).appendTo( parent ); + el_bb = jQuery( "
    test
    " ).appendTo( parent ), + el = jQuery( "
    test
    " ).appendTo( parent ); jQuery.each( { "number": { set: 100, expected: 100 }, diff --git a/test/unit/event.js b/test/unit/event.js index 12f132e0d9..804ece2caf 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -1416,7 +1416,7 @@ QUnit.test( "Submit event can be stopped (#11049)", function( assert ) { form.remove(); } ); -// Test beforeunload event only if it supported. +// Test beforeunload event only if it supported (i.e. not Opera) // Support: iOS 7+, Android<4.0 // iOS & old Android have the window.onbeforeunload field but don't support the beforeunload // handler making it impossible to feature-detect the support. @@ -2520,14 +2520,15 @@ testIframeWithCallback( var input = jQuery( frameDoc ).find( "#frame-input" ); + if ( input.length ) { // Create a focusin handler on the parent; shouldn't affect the iframe's fate - jQuery( "body" ).on( "focusin.iframeTest", function() { + jQuery ( "body" ).on( "focusin.iframeTest", function() { assert.ok( false, "fired a focusin event in the parent document" ); - } ); + }); input.on( "focusin", function() { assert.ok( true, "fired a focusin event in the iframe" ); - } ); + }); // Avoid a native event; Chrome can't force focus to another frame input.trigger( "focusin" ); @@ -2540,8 +2541,12 @@ testIframeWithCallback( // Remove body handler manually since it's outside the fixture jQuery( "body" ).off( "focusin.iframeTest" ); + + } else { + // Opera 12 (pre-Blink) doesn't select anything + assert.ok( true, "SOFTFAIL: no focus event fired in the iframe" ); } -); +}); testIframeWithCallback( "jQuery.ready promise", diff --git a/test/unit/support.js b/test/unit/support.js index 80ea58ef01..93fba8701f 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -73,6 +73,23 @@ testIframeWithCallback( "radioValue": true, "reliableMarginLeft": true }; + } else if ( /opera.*version\/12\.1/i.test( userAgent ) ) { + expected = { + "ajax": true, + "boxSizingReliable": true, + "checkClone": true, + "checkOn": true, + "clearCloneStyle": true, + "cors": true, + "createHTMLDocument": true, + "focusin": false, + "noCloneChecked": true, + "optSelected": true, + "pixelMarginRight": true, + "pixelPosition": true, + "radioValue": false, + "reliableMarginLeft": false + }; } else if ( /(msie 10\.0|trident\/7\.0)/i.test( userAgent ) ) { expected = { "ajax": true, @@ -161,6 +178,22 @@ testIframeWithCallback( "radioValue": true, "reliableMarginLeft": true }; + } else if ( /5\.1(\.\d+|) safari/i.test( userAgent ) ) { + expected = { + "ajax": true, + "boxSizingReliable": true, + "checkClone": false, + "checkOn": false, + "clearCloneStyle": true, + "cors": true, + "focusinBubbles": false, + "noCloneChecked": true, + "optDisabled": true, + "optSelected": true, + "pixelPosition": false, + "radioValue": true, + "reliableMarginRight": true + }; } else if ( /firefox/i.test( userAgent ) ) { expected = { "ajax": true, @@ -212,7 +245,7 @@ testIframeWithCallback( "radioValue": true, "reliableMarginLeft": true }; - } else if ( /iphone os 7_/i.test( userAgent ) ) { + } else if ( /iphone os (?:6|7)_/i.test( userAgent ) ) { expected = { "ajax": true, "boxSizingReliable": true, From 1ad9915d11e27ebce8016ef81163206fb68b2335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 16 Nov 2015 21:55:08 +0100 Subject: [PATCH 051/114] Misc: Fix the tests, revert some unneeded/broken reverts Refs 65d71843b7c37dbdba2cfcb1bc7055cb522c5af6 --- src/css/curCSS.js | 11 +++++------ src/css/hiddenVisibleSelectors.js | 8 ++++---- src/css/support.js | 7 ++++--- src/offset.js | 6 +----- test/unit/dimensions.js | 4 ++-- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/css/curCSS.js b/src/css/curCSS.js index d95e287cfa..be643ab547 100644 --- a/src/css/curCSS.js +++ b/src/css/curCSS.js @@ -5,7 +5,7 @@ define( [ "./var/getStyles", "./support", "../selector" // Get jQuery.contains -], function( jQuery, rnumnonpx, rmargin, getStyles ) { +], function( jQuery, rnumnonpx, rmargin, getStyles, support ) { function curCSS( elem, name, computed ) { var width, minWidth, maxWidth, ret, @@ -22,13 +22,12 @@ function curCSS( elem, name, computed ) { ret = jQuery.style( elem, name ); } - // Support: iOS < 6, Android 4.0-4.3 only // A tribute to the "awesome hack by Dean Edwards" - // iOS < 6 (at least) returns percentage for a larger set of values, - // but width seems to be reliably pixels - // this is against the CSSOM draft spec: + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: // http://dev.w3.org/csswg/cssom/#resolved-values - if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { + if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { // Remember the original values width = style.width; diff --git a/src/css/hiddenVisibleSelectors.js b/src/css/hiddenVisibleSelectors.js index 0d05be97e7..cf0955d3eb 100644 --- a/src/css/hiddenVisibleSelectors.js +++ b/src/css/hiddenVisibleSelectors.js @@ -4,15 +4,15 @@ define( [ ], function( jQuery ) { jQuery.expr.filters.hidden = function( elem ) { + return !jQuery.expr.filters.visible( elem ); +}; +jQuery.expr.filters.visible = function( elem ) { // Support: Opera <= 12.12 // Opera reports offsetWidths and offsetHeights less than zero on some elements // Use OR instead of AND as the element is not visible if either is true // See tickets #10406 and #13132 - return elem.offsetWidth <= 0 || elem.offsetHeight <= 0; -}; -jQuery.expr.filters.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); + return elem.offsetWidth > 0 || elem.offsetHeight > 0 || elem.getClientRects().length > 0; }; } ); diff --git a/src/css/support.js b/src/css/support.js index 54d0d9c701..6070eb4492 100644 --- a/src/css/support.js +++ b/src/css/support.js @@ -32,9 +32,10 @@ define( [ // Support: Firefox<29, Android 2.3 // Vendor-prefix box-sizing - "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" + - "box-sizing:border-box;display:block;margin-top:1%;top:1%;" + - "border:1px;padding:1px;width:4px;position:absolute"; + "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;" + + "position:relative;display:block;" + + "margin:auto;border:1px;padding:1px;" + + "top:1%;width:50%"; div.innerHTML = ""; documentElement.appendChild( container ); diff --git a/src/offset.js b/src/offset.js index ae9ccc119f..4352a99954 100644 --- a/src/offset.js +++ b/src/offset.js @@ -98,11 +98,7 @@ jQuery.fn.extend( { return box; } - // Support: BlackBerry 5, iOS 3 (original iPhone) - // If we don't have gBCR, just use 0,0 rather than error - if ( elem.getBoundingClientRect ) { - box = elem.getBoundingClientRect(); - } + box = elem.getBoundingClientRect(); win = getWindow( doc ); return { top: box.top + win.pageYOffset - docElem.clientTop, diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 9ffc6083cf..44a7291130 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -411,8 +411,8 @@ QUnit.test( "setters with and without box-sizing:border-box", function( assert ) // Support: Firefox<29, Android 2.3 (Prefixed box-sizing versions). var parent = jQuery( "#foo" ).css( { width: "200px", height: "200px", "font-size": "16px" } ), - el_bb = jQuery( "
    test
    " ).appendTo( parent ), - el = jQuery( "
    test
    " ).appendTo( parent ); + el_bb = jQuery( "
    " ).appendTo( parent ), + el = jQuery( "
    " ).appendTo( parent ); jQuery.each( { "number": { set: 100, expected: 100 }, From afe40dd4d3d0c21e9c447eedb0a0382e8d1af5c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 16 Nov 2015 21:39:00 +0100 Subject: [PATCH 052/114] Revert "Ajax:Attributes:CSS:Manipulation: Reduce Android 2.3 support" This reverts commit ce3b4a62427c5a3a6669dcb8bf8e27a6287990d5. --- src/ajax/parseJSON.js | 6 ++- src/attributes/support.js | 5 +++ src/attributes/val.js | 3 +- src/css.js | 10 +++++ src/css/support.js | 28 ++++++++++++ test/unit/support.js | 91 +++++++++++++++++++++++++++++++++------ 6 files changed, 128 insertions(+), 15 deletions(-) diff --git a/src/ajax/parseJSON.js b/src/ajax/parseJSON.js index c2aeb6aaec..11918b06d6 100644 --- a/src/ajax/parseJSON.js +++ b/src/ajax/parseJSON.js @@ -2,7 +2,11 @@ define( [ "../core" ], function( jQuery ) { -jQuery.parseJSON = JSON.parse; +// Support: Android 2.3 +// Workaround failure to string-cast null input +jQuery.parseJSON = function( data ) { + return JSON.parse( data + "" ); +}; return jQuery.parseJSON; diff --git a/src/attributes/support.js b/src/attributes/support.js index 5b8118bb51..e8d02b5c90 100644 --- a/src/attributes/support.js +++ b/src/attributes/support.js @@ -18,6 +18,11 @@ define( [ // Must access selectedIndex to make default options select support.optSelected = opt.selected; + // Support: Android<=2.3 + // Options inside disabled selects are incorrectly marked as disabled + select.disabled = true; + support.optDisabled = !opt.disabled; + // Support: IE<=11+ // An input loses its value after becoming a radio input = document.createElement( "input" ); diff --git a/src/attributes/val.js b/src/attributes/val.js index caf0126d4c..9999d985b6 100644 --- a/src/attributes/val.js +++ b/src/attributes/val.js @@ -105,7 +105,8 @@ jQuery.extend( { if ( ( option.selected || i === index ) && // Don't return options that are disabled or in a disabled optgroup - !option.disabled && + ( support.optDisabled ? + !option.disabled : option.getAttribute( "disabled" ) === null ) && ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { diff --git a/src/css.js b/src/css.js index 0aa9d0e9c0..d9104ad3f7 100644 --- a/src/css.js +++ b/src/css.js @@ -428,6 +428,16 @@ jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, } ); +// Support: Android 2.3 +jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight, + function( elem, computed ) { + if ( computed ) { + return swap( elem, { "display": "inline-block" }, + curCSS, [ elem, "marginRight" ] ); + } + } +); + // These hooks are used by animate to expand properties jQuery.each( { margin: "", diff --git a/src/css/support.js b/src/css/support.js index 6070eb4492..7e6e51334b 100644 --- a/src/css/support.js +++ b/src/css/support.js @@ -84,6 +84,34 @@ define( [ computeStyleTests(); } return reliableMarginLeftVal; + }, + reliableMarginRight: function() { + + // Support: Android 2.3 + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. (#3333) + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + // This support function is only executed once so no memoizing is needed. + var ret, + marginDiv = div.appendChild( document.createElement( "div" ) ); + + // Reset CSS: box-sizing; display; margin; border; padding + marginDiv.style.cssText = div.style.cssText = + + // Support: Android 2.3 + // Vendor-prefix box-sizing + "-webkit-box-sizing:content-box;box-sizing:content-box;" + + "display:block;margin:0;border:0;padding:0"; + marginDiv.style.marginRight = marginDiv.style.width = "0"; + div.style.width = "1px"; + documentElement.appendChild( container ); + + ret = !parseFloat( window.getComputedStyle( marginDiv ).marginRight ); + + documentElement.removeChild( container ); + div.removeChild( marginDiv ); + + return ret; } } ); } )(); diff --git a/test/unit/support.js b/test/unit/support.js index 93fba8701f..32ae175919 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -67,11 +67,13 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": true, "pixelPosition": true, "radioValue": true, - "reliableMarginLeft": true + "reliableMarginLeft": true, + "reliableMarginLRight": true }; } else if ( /opera.*version\/12\.1/i.test( userAgent ) ) { expected = { @@ -84,11 +86,13 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": true, "pixelPosition": true, "radioValue": false, - "reliableMarginLeft": false + "reliableMarginLeft": false, + "reliableMarginRight": true }; } else if ( /(msie 10\.0|trident\/7\.0)/i.test( userAgent ) ) { expected = { @@ -101,11 +105,13 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": true, "noCloneChecked": false, + "optDisabled": true, "optSelected": false, "pixelMarginRight": true, "pixelPosition": true, "radioValue": false, - "reliableMarginLeft": true + "reliableMarginLeft": true, + "reliableMarginRight": true }; } else if ( /msie 9\.0/i.test( userAgent ) ) { expected = { @@ -118,11 +124,13 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": true, "noCloneChecked": false, + "optDisabled": true, "optSelected": false, "pixelMarginRight": true, "pixelPosition": true, "radioValue": false, - "reliableMarginLeft": true + "reliableMarginLeft": true, + "reliableMarginRight": true }; } else if ( /chrome/i.test( userAgent ) ) { @@ -138,11 +146,13 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": true, "pixelPosition": true, "radioValue": true, - "reliableMarginLeft": true + "reliableMarginLeft": true, + "reliableMarginRight": true }; } else if ( /9\.0(\.\d+|) safari/i.test( userAgent ) ) { expected = { @@ -155,11 +165,13 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": true, "pixelPosition": false, "radioValue": true, - "reliableMarginLeft": true + "reliableMarginLeft": true, + "reliableMarginRight": true }; } else if ( /8\.0(\.\d+|) safari/i.test( userAgent ) ) { expected = { @@ -172,11 +184,32 @@ testIframeWithCallback( "createHTMLDocument": false, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": true, "pixelPosition": false, "radioValue": true, - "reliableMarginLeft": true + "reliableMarginLeft": true, + "reliableMarginRight": true + }; + } else if ( /(?:6|7)\.0(\.\d+|) safari/i.test( userAgent ) ) { + expected = { + "ajax": true, + "boxSizingReliable": true, + "checkClone": true, + "checkOn": true, + "clearCloneStyle": true, + "cors": true, + "createHTMLDocument": true, + "focusin": false, + "noCloneChecked": true, + "optDisabled": true, + "optSelected": true, + "pixelMarginRight": true, + "pixelPosition": false, + "radioValue": true, + "reliableMarginLeft": true, + "reliableMarginRight": true }; } else if ( /5\.1(\.\d+|) safari/i.test( userAgent ) ) { expected = { @@ -186,12 +219,15 @@ testIframeWithCallback( "checkOn": false, "clearCloneStyle": true, "cors": true, - "focusinBubbles": false, + "createHTMLDocument": true, + "focusin": false, "noCloneChecked": true, "optDisabled": true, "optSelected": true, + "pixelMarginRight": true, "pixelPosition": false, "radioValue": true, + "reliableMarginLeft": true, "reliableMarginRight": true }; } else if ( /firefox/i.test( userAgent ) ) { @@ -205,11 +241,13 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": true, "pixelPosition": true, "radioValue": true, - "reliableMarginLeft": false + "reliableMarginLeft": false, + "reliableMarginRight": true }; } else if ( /iphone os 9_/i.test( userAgent ) ) { expected = { @@ -222,11 +260,13 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": true, "pixelPosition": false, "radioValue": true, - "reliableMarginLeft": true + "reliableMarginLeft": true, + "reliableMarginLRight": true }; } else if ( /iphone os 8_/i.test( userAgent ) ) { expected = { @@ -239,11 +279,13 @@ testIframeWithCallback( "createHTMLDocument": false, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": true, "pixelPosition": false, "radioValue": true, - "reliableMarginLeft": true + "reliableMarginLeft": true, + "reliableMarginRight": true }; } else if ( /iphone os (?:6|7)_/i.test( userAgent ) ) { expected = { @@ -256,11 +298,13 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": true, "pixelPosition": false, "radioValue": true, - "reliableMarginLeft": true + "reliableMarginLeft": true, + "reliableMarginRight": true }; } else if ( /android 4\.[0-3]/i.test( userAgent ) ) { expected = { @@ -273,11 +317,32 @@ testIframeWithCallback( "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, + "optDisabled": true, "optSelected": true, "pixelMarginRight": false, "pixelPosition": false, "radioValue": true, - "reliableMarginLeft": false + "reliableMarginLeft": false, + "reliableMarginRight": true + }; + } else if ( /android 2\.3/i.test( userAgent ) ) { + expected = { + "ajax": true, + "boxSizingReliable": true, + "checkClone": true, + "checkOn": false, + "clearCloneStyle": false, + "cors": true, + "createHTMLDocument": true, + "focusin": false, + "noCloneChecked": true, + "optDisabled": false, + "optSelected": true, + "pixelMarginRight": true, + "pixelPosition": false, + "radioValue": true, + "reliableMarginLeft": false, + "reliableMarginRight": false }; } From c56e8b680dbfcbcdff77d982618a8c6eda68cb49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 16 Nov 2015 22:09:55 +0100 Subject: [PATCH 053/114] Build: Change the 2.2-stable version to 2.2.0-pre --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fbd98c91d1..9ee4ef8401 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "jquery", "title": "jQuery", "description": "JavaScript library for DOM operations", - "version": "3.0.0-pre", + "version": "2.2.0-pre", "main": "dist/jquery.js", "homepage": "http://jquery.com", "author": { From f6dd76709a4173be5e8d45c3f901a330f751c382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 16 Nov 2015 22:11:39 +0100 Subject: [PATCH 054/114] Tests: Fix support tests results --- test/unit/support.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/support.js b/test/unit/support.js index 32ae175919..05f946c679 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -73,7 +73,7 @@ testIframeWithCallback( "pixelPosition": true, "radioValue": true, "reliableMarginLeft": true, - "reliableMarginLRight": true + "reliableMarginRight": true }; } else if ( /opera.*version\/12\.1/i.test( userAgent ) ) { expected = { @@ -227,8 +227,8 @@ testIframeWithCallback( "pixelMarginRight": true, "pixelPosition": false, "radioValue": true, - "reliableMarginLeft": true, - "reliableMarginRight": true + "reliableMarginLeft": false, + "reliableMarginRight": false }; } else if ( /firefox/i.test( userAgent ) ) { expected = { @@ -266,7 +266,7 @@ testIframeWithCallback( "pixelPosition": false, "radioValue": true, "reliableMarginLeft": true, - "reliableMarginLRight": true + "reliableMarginRight": true }; } else if ( /iphone os 8_/i.test( userAgent ) ) { expected = { From 283a1949550e1bf1284ddf89a472b3c8b4a97c60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 16 Nov 2015 22:16:10 +0100 Subject: [PATCH 055/114] Tests: Blacklist the iframe scrollTop test in Opera 12.1x --- test/unit/offset.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit/offset.js b/test/unit/offset.js index ff1f02099c..11b4feb978 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -575,9 +575,11 @@ QUnit.test( "iframe scrollTop/Left (see gh-1945)", function( assert ) { // Mobile Safari and Android 2.3 resize the iframe by its content // meaning it's not possible to scroll the iframe only its parent element. // It seems (not confirmed) in android 4.0 it's not possible to scroll iframes from the code. + // Opera 12.1x also has problems with this test. if ( /iphone os/i.test( navigator.userAgent ) || /android 2\.3/i.test( navigator.userAgent ) || - /android 4\.0/i.test( navigator.userAgent ) ) { + /android 4\.0/i.test( navigator.userAgent ) || + /opera.*version\/12\.1/i.test( navigator.userAgent ) ) { assert.equal( true, true, "Can't scroll iframes in this environment" ); assert.equal( true, true, "Can't scroll iframes in this environment" ); From e904249ee00c3375fad461c47150627fce0b02d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 16 Nov 2015 22:48:14 +0100 Subject: [PATCH 056/114] Tests: Fix Safari 5.1 support tests results --- test/unit/support.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/support.js b/test/unit/support.js index 05f946c679..0d9276d698 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -224,11 +224,11 @@ testIframeWithCallback( "noCloneChecked": true, "optDisabled": true, "optSelected": true, - "pixelMarginRight": true, + "pixelMarginRight": false, "pixelPosition": false, "radioValue": true, "reliableMarginLeft": false, - "reliableMarginRight": false + "reliableMarginRight": true }; } else if ( /firefox/i.test( userAgent ) ) { expected = { From a5864aefdfadfee16522456c82139fa10360d8fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Tue, 17 Nov 2015 03:16:44 +0100 Subject: [PATCH 057/114] Effects: Remove tests for jQuery.Animation & jQuery.Tween We'll officially support those APIs in jQuery 3.0 but we don't want to have to support them in 1.12/2.2. The code is left untouched, only tests (& official support) are removed. Refs b3b2d6c3dd51fbdc69e1942e9af75cc99a1834c2 Refs cdaed15c7ea1bbfdde5a5bea691c583ce7961526 --- Gruntfile.js | 6 +- test/data/testinit.js | 4 +- test/unit/animation.js | 263 --------------------------------- test/unit/tween.js | 319 ----------------------------------------- 4 files changed, 2 insertions(+), 590 deletions(-) delete mode 100644 test/unit/animation.js delete mode 100644 test/unit/tween.js diff --git a/Gruntfile.js b/Gruntfile.js index 43f57a0bfb..bc010c9beb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -127,9 +127,7 @@ module.exports = function( grunt ) { // Check parts of tests that pass test: [ "test/data/testrunner.js", - "test/unit/animation.js", "test/unit/basic.js", - "test/unit/tween.js", "test/unit/wrap.js" ], build: "build" @@ -144,7 +142,6 @@ module.exports = function( grunt ) { "basic", "ajax", - "animation", "attributes", "callbacks", "core", @@ -161,8 +158,7 @@ module.exports = function( grunt ) { "selector", "serialize", "support", - "traversing", - "tween" + "traversing" ] }, watch: { diff --git a/test/data/testinit.js b/test/data/testinit.js index 4c8d7d9729..977847e9de 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -303,9 +303,7 @@ this.loadTests = function() { "unit/ajax.js", "unit/effects.js", "unit/offset.js", - "unit/dimensions.js", - "unit/animation.js", - "unit/tween.js" + "unit/dimensions.js" ]; // Ensure load order (to preserve test numbers) diff --git a/test/unit/animation.js b/test/unit/animation.js deleted file mode 100644 index 3b1479432c..0000000000 --- a/test/unit/animation.js +++ /dev/null @@ -1,263 +0,0 @@ -( function() { - -// Can't test what ain't there -if ( !jQuery.fx ) { - return; -} - -var oldRaf = window.requestAnimationFrame, - defaultPrefilter = jQuery.Animation.prefilters[ 0 ], - defaultTweener = jQuery.Animation.tweeners[ "*" ][ 0 ], - startTime = 505877050; - -// This module tests jQuery.Animation and the corresponding 1.8+ effects APIs -QUnit.module( "animation", { - setup: function() { - window.requestAnimationFrame = null; - this.sandbox = sinon.sandbox.create(); - this.clock = this.sandbox.useFakeTimers( startTime ); - this._oldInterval = jQuery.fx.interval; - jQuery.fx.step = {}; - jQuery.fx.interval = 10; - jQuery.now = Date.now; - jQuery.Animation.prefilters = [ defaultPrefilter ]; - jQuery.Animation.tweeners = { "*": [ defaultTweener ] }; - }, - teardown: function() { - this.sandbox.restore(); - jQuery.now = Date.now; - jQuery.fx.stop(); - jQuery.fx.interval = this._oldInterval; - window.requestAnimationFrame = oldRaf; - return moduleTeardown.apply( this, arguments ); - } -} ); - -QUnit.test( "Animation( subject, props, opts ) - shape", function( assert ) { - assert.expect( 20 ); - - var subject = { test: 0 }, - props = { test: 1 }, - opts = { queue: "fx", duration: 100 }, - animation = jQuery.Animation( subject, props, opts ); - - assert.equal( - animation.elem, - subject, - ".elem is set to the exact object passed" - ); - assert.equal( - animation.originalOptions, - opts, - ".originalOptions is set to options passed" - ); - assert.equal( - animation.originalProperties, - props, - ".originalProperties is set to props passed" - ); - - assert.notEqual( animation.props, props, ".props is not the original however" ); - assert.deepEqual( animation.props, props, ".props is a copy of the original" ); - - assert.deepEqual( animation.opts, { - duration: 100, - queue: "fx", - specialEasing: { test: undefined }, - easing: jQuery.easing._default - }, ".options is filled with default easing and specialEasing" ); - - assert.equal( animation.startTime, startTime, "startTime was set" ); - assert.equal( animation.duration, 100, ".duration is set" ); - - assert.equal( animation.tweens.length, 1, ".tweens has one Tween" ); - assert.equal( typeof animation.tweens[ 0 ].run, "function", "which has a .run function" ); - - assert.equal( typeof animation.createTween, "function", ".createTween is a function" ); - assert.equal( typeof animation.stop, "function", ".stop is a function" ); - - assert.equal( typeof animation.done, "function", ".done is a function" ); - assert.equal( typeof animation.fail, "function", ".fail is a function" ); - assert.equal( typeof animation.always, "function", ".always is a function" ); - assert.equal( typeof animation.progress, "function", ".progress is a function" ); - - assert.equal( jQuery.timers.length, 1, "Added a timers function" ); - assert.equal( jQuery.timers[ 0 ].elem, subject, "...with .elem as the subject" ); - assert.equal( jQuery.timers[ 0 ].anim, animation, "...with .anim as the animation" ); - assert.equal( jQuery.timers[ 0 ].queue, opts.queue, "...with .queue" ); - - // Cleanup after ourselves by ticking to the end - this.clock.tick( 100 ); -} ); - -QUnit.test( "Animation.prefilter( fn ) - calls prefilter after defaultPrefilter", - function( assert ) { - assert.expect( 1 ); - - var prefilter = this.sandbox.stub(), - defaultSpy = this.sandbox.spy( jQuery.Animation.prefilters, 0 ); - - jQuery.Animation.prefilter( prefilter ); - - jQuery.Animation( {}, {}, {} ); - assert.ok( prefilter.calledAfter( defaultSpy ), "our prefilter called after" ); - } -); - -QUnit.test( "Animation.prefilter( fn, true ) - calls prefilter before defaultPrefilter", - function( assert ) { - assert.expect( 1 ); - - var prefilter = this.sandbox.stub(), - defaultSpy = this.sandbox.spy( jQuery.Animation.prefilters, 0 ); - - jQuery.Animation.prefilter( prefilter, true ); - - jQuery.Animation( {}, {}, {} ); - assert.ok( prefilter.calledBefore( defaultSpy ), "our prefilter called before" ); - } -); - -QUnit.test( "Animation.prefilter - prefilter return hooks", function( assert ) { - assert.expect( 34 ); - - var animation, realAnimation, element, - sandbox = this.sandbox, - ourAnimation = { stop: this.sandbox.spy() }, - target = { height: 50 }, - props = { height: 100 }, - opts = { duration: 100 }, - prefilter = this.sandbox.spy( function() { - realAnimation = this; - sandbox.spy( realAnimation, "createTween" ); - - assert.deepEqual( realAnimation.originalProperties, props, "originalProperties" ); - assert.equal( arguments[ 0 ], this.elem, "first param elem" ); - assert.equal( arguments[ 1 ], this.props, "second param props" ); - assert.equal( arguments[ 2 ], this.opts, "third param opts" ); - return ourAnimation; - } ), - defaultSpy = sandbox.spy( jQuery.Animation.prefilters, 0 ), - queueSpy = sandbox.spy( function( next ) { - next(); - } ), - TweenSpy = sandbox.spy( jQuery, "Tween" ); - - jQuery.Animation.prefilter( prefilter, true ); - - sandbox.stub( jQuery.fx, "timer" ); - - animation = jQuery.Animation( target, props, opts ); - - assert.equal( prefilter.callCount, 1, "Called prefilter" ); - - assert.equal( - defaultSpy.callCount, - 0, - "Returning something from a prefilter caused remaining prefilters to not run" - ); - assert.equal( jQuery.fx.timer.callCount, 0, "Returning something never queues a timer" ); - assert.equal( - animation, - ourAnimation, - "Returning something returned it from jQuery.Animation" - ); - assert.equal( - realAnimation.createTween.callCount, - 0, - "Returning something never creates tweens" - ); - assert.equal( TweenSpy.callCount, 0, "Returning something never creates tweens" ); - - // Test overriden usage on queues: - prefilter.reset(); - element = jQuery( "
    " ) - .css( "height", 50 ) - .animate( props, 100 ) - .queue( queueSpy ) - .animate( props, 100 ) - .queue( queueSpy ) - .animate( props, 100 ) - .queue( queueSpy ); - - assert.equal( prefilter.callCount, 1, "Called prefilter" ); - assert.equal( queueSpy.callCount, 0, "Next function in queue not called" ); - - realAnimation.opts.complete.call( realAnimation.elem ); - assert.equal( queueSpy.callCount, 1, "Next function in queue called after complete" ); - - assert.equal( prefilter.callCount, 2, "Called prefilter again - animation #2" ); - assert.equal( ourAnimation.stop.callCount, 0, ".stop() on our animation hasn't been called" ); - - element.stop(); - assert.equal( ourAnimation.stop.callCount, 1, ".stop() called ourAnimation.stop()" ); - assert.ok( - !ourAnimation.stop.args[ 0 ][ 0 ], - ".stop( falsy ) (undefined or false are both valid)" - ); - - assert.equal( queueSpy.callCount, 2, "Next queue function called" ); - assert.ok( queueSpy.calledAfter( ourAnimation.stop ), "After our animation was told to stop" ); - - // ourAnimation.stop.reset(); - assert.equal( prefilter.callCount, 3, "Got the next animation" ); - - ourAnimation.stop.reset(); - - // do not clear queue, gotoEnd - element.stop( false, true ); - assert.ok( ourAnimation.stop.calledWith( true ), ".stop(true) calls .stop(true)" ); - assert.ok( queueSpy.calledAfter( ourAnimation.stop ), - "and the next queue function ran after we were told" ); -} ); - -QUnit.test( "Animation.tweener( fn ) - unshifts a * tweener", function( assert ) { - assert.expect( 2 ); - var starTweeners = jQuery.Animation.tweeners[ "*" ]; - - jQuery.Animation.tweener( jQuery.noop ); - assert.equal( starTweeners.length, 2 ); - assert.deepEqual( starTweeners, [ jQuery.noop, defaultTweener ] ); -} ); - -QUnit.test( "Animation.tweener( 'prop', fn ) - unshifts a 'prop' tweener", function( assert ) { - assert.expect( 4 ); - var tweeners = jQuery.Animation.tweeners, - fn = function() {}; - - jQuery.Animation.tweener( "prop", jQuery.noop ); - assert.equal( tweeners.prop.length, 1 ); - assert.deepEqual( tweeners.prop, [ jQuery.noop ] ); - - jQuery.Animation.tweener( "prop", fn ); - assert.equal( tweeners.prop.length, 2 ); - assert.deepEqual( tweeners.prop, [ fn, jQuery.noop ] ); -} ); - -QUnit.test( - "Animation.tweener( 'list of props', fn ) - unshifts a tweener to each prop", - function( assert ) { - assert.expect( 2 ); - var tweeners = jQuery.Animation.tweeners, - fn = function() {}; - - jQuery.Animation.tweener( "list of props", jQuery.noop ); - assert.deepEqual( tweeners, { - list: [ jQuery.noop ], - of: [ jQuery.noop ], - props: [ jQuery.noop ], - "*": [ defaultTweener ] - } ); - - // Test with extra whitespaces - jQuery.Animation.tweener( " list\t of \tprops\n*", fn ); - assert.deepEqual( tweeners, { - list: [ fn, jQuery.noop ], - of: [ fn, jQuery.noop ], - props: [ fn, jQuery.noop ], - "*": [ fn, defaultTweener ] - } ); - } -); - -} )(); diff --git a/test/unit/tween.js b/test/unit/tween.js deleted file mode 100644 index 28fcfad257..0000000000 --- a/test/unit/tween.js +++ /dev/null @@ -1,319 +0,0 @@ -( function() { - -// Can't test what ain't there -if ( !jQuery.fx ) { - return; -} - -var oldRaf = window.requestAnimationFrame; - -QUnit.module( "tween", { - setup: function() { - window.requestAnimationFrame = null; - this.sandbox = sinon.sandbox.create(); - this.clock = this.sandbox.useFakeTimers( 505877050 ); - this._oldInterval = jQuery.fx.interval; - jQuery.fx.step = {}; - jQuery.fx.interval = 10; - jQuery.now = Date.now; - }, - teardown: function() { - this.sandbox.restore(); - jQuery.now = Date.now; - jQuery.fx.stop(); - jQuery.fx.interval = this._oldInterval; - window.requestAnimationFrame = oldRaf; - return moduleTeardown.apply( this, arguments ); - } -} ); - -QUnit.test( "jQuery.Tween - Default propHooks on plain objects", function( assert ) { - assert.expect( 8 ); - var propHooks, defaultHook, testObject, fakeTween, stepSpy; - - propHooks = jQuery.Tween.propHooks; - assert.equal( typeof propHooks, "object", "jQuery.Tween.propHooks exists" ); - - defaultHook = propHooks._default; - assert.ok( defaultHook, "_default propHook exists" ); - - testObject = { test: 0 }; - fakeTween = { elem: testObject, prop: "test", now: 10, unit: "px" }; - - assert.equal( defaultHook.get( fakeTween ), 0, "Can get property of object" ); - - fakeTween.prop = "testMissing"; - assert.equal( defaultHook.get( fakeTween ), undefined, "Can get missing property on object" ); - - defaultHook.set( fakeTween ); - assert.equal( testObject.testMissing, 10, "Sets missing value properly on plain object" ); - - fakeTween.prop = "opacity"; - defaultHook.set( fakeTween ); - assert.equal( testObject.opacity, 10, "Correctly set opacity on plain object" ); - - fakeTween.prop = "test"; - stepSpy = jQuery.fx.step.test = this.sandbox.spy(); - - defaultHook.set( fakeTween ); - assert.ok( stepSpy.calledWith( fakeTween ), "Step function called with Tween" ); - assert.equal( testObject.test, 0, "Because step didn't set, value is unchanged" ); -} ); - -QUnit.test( "jQuery.Tween - Default propHooks on elements", function( assert ) { - assert.expect( 19 ); - var propHooks, defaultHook, testElement, fakeTween, cssStub, styleStub, stepSpy; - - propHooks = jQuery.Tween.propHooks; - assert.equal( typeof propHooks, "object", "jQuery.Tween.propHooks exists" ); - - defaultHook = propHooks._default; - assert.ok( defaultHook, "_default propHook exists" ); - - testElement = jQuery( "
    " )[ 0 ]; - fakeTween = { elem: testElement, prop: "height", now: 10, unit: "px" }; - - cssStub = this.sandbox.stub( jQuery, "css" ).returns( 10 ); - - assert.equal( defaultHook.get( fakeTween ), 10, "Gets expected style value" ); - assert.ok( cssStub.calledWith( testElement, "height", "" ), "Calls jQuery.css correctly" ); - - fakeTween.prop = "testOpti"; - testElement.testOpti = 15; - cssStub.reset(); - - assert.equal( defaultHook.get( fakeTween ), 15, "Gets expected value not defined on style" ); - assert.equal( cssStub.callCount, 0, "Did not call jQuery.css" ); - - fakeTween.prop = "testMissing"; - assert.equal( defaultHook.get( fakeTween ), 10, "Can get missing property on element" ); - assert.ok( cssStub.calledWith( testElement, "testMissing", "" ), "...using jQuery.css" ); - - cssStub.returns( "" ); - assert.equal( defaultHook.get( fakeTween ), 0, "Uses 0 for empty string" ); - - cssStub.returns( "auto" ); - assert.equal( defaultHook.get( fakeTween ), 0, "Uses 0 for 'auto'" ); - - cssStub.returns( null ); - assert.equal( defaultHook.get( fakeTween ), 0, "Uses 0 for null" ); - - cssStub.returns( undefined ); - assert.equal( defaultHook.get( fakeTween ), 0, "Uses 0 for undefined" ); - - cssStub.reset(); - - // Setters - styleStub = this.sandbox.stub( jQuery, "style" ); - fakeTween.prop = "height"; - - defaultHook.set( fakeTween ); - assert.ok( styleStub.calledWith( testElement, "height", "10px" ), - "Calls jQuery.style with elem, prop, now+unit" ); - - styleStub.reset(); - fakeTween.prop = "testMissing"; - - defaultHook.set( fakeTween ); - assert.equal( styleStub.callCount, 0, "Did not call jQuery.style for non css property" ); - assert.equal( testElement.testMissing, 10, "Instead, set value on element directly" ); - - jQuery.cssHooks.testMissing = jQuery.noop; - fakeTween.now = 11; - - defaultHook.set( fakeTween ); - delete jQuery.cssHooks.testMissing; - - assert.ok( styleStub.calledWith( testElement, "testMissing", "11px" ), - "Presence of cssHooks causes jQuery.style with elem, prop, now+unit" ); - assert.equal( testElement.testMissing, 10, "And value was unchanged" ); - - stepSpy = jQuery.fx.step.test = this.sandbox.spy(); - styleStub.reset(); - - fakeTween.prop = "test"; - defaultHook.set( fakeTween ); - assert.ok( stepSpy.calledWith( fakeTween ), "Step function called with Tween" ); - assert.equal( styleStub.callCount, 0, "Did not call jQuery.style" ); -} ); - -QUnit.test( "jQuery.Tween - Plain Object", function( assert ) { - assert.expect( 13 ); - var testObject = { test: 100 }, - testOptions = { duration: 100 }, - tween, easingSpy; - - tween = jQuery.Tween( testObject, testOptions, "test", 0, "linear" ); - assert.equal( tween.elem, testObject, "Sets .element" ); - assert.equal( tween.options, testOptions, "sets .options" ); - assert.equal( tween.prop, "test", "sets .prop" ); - assert.equal( tween.end, 0, "sets .end" ); - - assert.equal( tween.easing, "linear", "sets .easing when provided" ); - - assert.equal( tween.start, 100, "Reads .start value during construction" ); - assert.equal( tween.now, 100, "Reads .now value during construction" ); - - easingSpy = this.sandbox.spy( jQuery.easing, "linear" ); - - assert.equal( tween.run( 0.1 ), tween, ".run() returns this" ); - - assert.equal( tween.now, 90, "Calculated tween" ); - - assert.ok( easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ), - "...using jQuery.easing.linear with back-compat arguments" ); - assert.equal( testObject.test, 90, "Set value" ); - - tween.run( 1 ); - assert.equal( testObject.test, 0, "Checking another value" ); - - tween.run( 0 ); - assert.equal( testObject.test, 100, "Can even go back in time" ); -} ); - -QUnit.test( "jQuery.Tween - Element", function( assert ) { - assert.expect( 15 ); - var testElement = jQuery( "
    " ).css( "height", 100 )[ 0 ], - testOptions = { duration: 100 }, - tween, easingSpy, eased; - - tween = jQuery.Tween( testElement, testOptions, "height", 0 ); - assert.equal( tween.elem, testElement, "Sets .element" ); - assert.equal( tween.options, testOptions, "sets .options" ); - assert.equal( tween.prop, "height", "sets .prop" ); - assert.equal( tween.end, 0, "sets .end" ); - - assert.equal( - tween.easing, - jQuery.easing._default, - "sets .easing to default when not provided" - ); - assert.equal( tween.unit, "px", "sets .unit to px when not provided" ); - - assert.equal( tween.start, 100, "Reads .start value during construction" ); - assert.equal( tween.now, 100, "Reads .now value during construction" ); - - easingSpy = this.sandbox.spy( jQuery.easing, "swing" ); - - assert.equal( tween.run( 0.1 ), tween, ".run() returns this" ); - assert.equal( tween.pos, jQuery.easing.swing( 0.1 ), "set .pos" ); - eased = 100 - ( jQuery.easing.swing( 0.1 ) * 100 ); - assert.equal( tween.now, eased, "Calculated tween" ); - - assert.ok( - easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ), - "...using jQuery.easing.linear with back-compat arguments" - ); - assert.equal( - parseFloat( testElement.style.height ).toFixed( 2 ), - eased.toFixed( 2 ), "Set value" - ); - - tween.run( 1 ); - assert.equal( testElement.style.height, "0px", "Checking another value" ); - - tween.run( 0 ); - assert.equal( testElement.style.height, "100px", "Can even go back in time" ); -} ); - -QUnit.test( "jQuery.Tween - No duration", function( assert ) { - assert.expect( 3 ); - - var testObject = { test: 100 }, - testOptions = { duration: 0 }, - tween, easingSpy; - - tween = jQuery.Tween( testObject, testOptions, "test", 0 ); - easingSpy = this.sandbox.spy( jQuery.easing, "swing" ); - tween.run( 0.5 ); - - assert.equal( tween.pos, 0.5, "set .pos correctly" ); - assert.equal( testObject.test, 50, "set value on object correctly" ); - assert.equal( easingSpy.callCount, 0, "didn't ease the value" ); -} ); - -QUnit.test( "jQuery.Tween - step function option", function( assert ) { - assert.expect( 4 ); - - var testObject = { test: 100 }, - testOptions = { duration: 100, step: this.sandbox.spy() }, - tween, propHookSpy; - - propHookSpy = this.sandbox.spy( jQuery.Tween.propHooks._default, "set" ); - - tween = jQuery.Tween( testObject, testOptions, "test", 0, "linear" ); - assert.equal( testOptions.step.callCount, 0, "didn't call step on create" ); - - tween.run( 0.5 ); - assert.ok( - testOptions.step.calledOn( testObject ), - "Called step function in context of animated object" - ); - assert.ok( - testOptions.step.calledWith( 50, tween ), - "Called step function with correct parameters" - ); - assert.ok( - testOptions.step.calledBefore( propHookSpy ), - "Called step function before calling propHook.set" - ); - -} ); - -QUnit.test( "jQuery.Tween - custom propHooks", function( assert ) { - assert.expect( 3 ); - - var testObject = {}, - testOptions = { duration: 100, step: this.sandbox.spy() }, - propHook = { - get: sinon.stub().returns( 100 ), - set: sinon.stub() - }, - tween; - - jQuery.Tween.propHooks.testHooked = propHook; - - tween = jQuery.Tween( testObject, testOptions, "testHooked", 0, "linear" ); - assert.ok( propHook.get.calledWith( tween ), "called propHook.get on create" ); - assert.equal( tween.now, 100, "Used return value from propHook.get" ); - - tween.run( 0.5 ); - assert.ok( - propHook.set.calledWith( tween ), - "Called propHook.set function with correct parameters" - ); - - delete jQuery.Tween.propHooks.testHooked; -} ); - -QUnit.test( "jQuery.Tween - custom propHooks - advanced values", function( assert ) { - assert.expect( 5 ); - - var testObject = {}, - testOptions = { duration: 100, step: this.sandbox.spy() }, - propHook = { - get: sinon.stub().returns( [ 0, 0 ] ), - set: sinon.spy() - }, - tween; - - jQuery.Tween.propHooks.testHooked = propHook; - - tween = jQuery.Tween( testObject, testOptions, "testHooked", [ 1, 1 ], "linear" ); - assert.ok( propHook.get.calledWith( tween ), "called propHook.get on create" ); - assert.deepEqual( tween.start, [ 0, 0 ], "Used return value from get" ); - - tween.run( 0.5 ); - - // Some day this NaN assumption might change - perhaps add a "calc" helper to the hooks? - assert.ok( isNaN( tween.now ), "Used return value from propHook.get" ); - assert.equal( tween.pos, 0.5, "But the eased percent is still available" ); - assert.ok( - propHook.set.calledWith( tween ), - "Called propHook.set function with correct parameters" - ); - - delete jQuery.Tween.propHooks.testHooked; -} ); - -} )(); From 4fea389ad2b7515bc3a9081245979ab7be566b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Tue, 17 Nov 2015 03:50:56 +0100 Subject: [PATCH 058/114] Tests: Fix support tests results for Android 2.3 --- test/unit/support.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/support.js b/test/unit/support.js index 0d9276d698..9f0937a93d 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -341,7 +341,7 @@ testIframeWithCallback( "pixelMarginRight": true, "pixelPosition": false, "radioValue": true, - "reliableMarginLeft": false, + "reliableMarginLeft": true, "reliableMarginRight": false }; } From 077bf7341e0ea9276da018613bc8676b91b02bdb Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 9 Dec 2015 18:41:41 +0300 Subject: [PATCH 059/114] Revert "Core: make isNumeric limited to strings and numbers" This reverts commit 15ac848868e993dfe5ccd7751a94f5c8edc288bc. --- src/core.js | 12 ++++++------ test/unit/core.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core.js b/src/core.js index e8f0d9d379..f273065870 100644 --- a/src/core.js +++ b/src/core.js @@ -214,12 +214,12 @@ jQuery.extend( { isNumeric: function( obj ) { - // As of jQuery 3.0, isNumeric is limited to - // strings and numbers (primitives or objects) - // that can be coerced to finite numbers (gh-2662) - var type = jQuery.type( obj ); - return ( type === "number" || type === "string" ) && - ( obj - parseFloat( obj ) + 1 ) >= 0; + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + // adding 1 corrects loss of precision from parseFloat (#15100) + var realStringObj = obj && obj.toString(); + return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; }, isPlainObject: function( obj ) { diff --git a/test/unit/core.js b/test/unit/core.js index 6aa2a3d63d..dc083de31a 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -455,8 +455,8 @@ QUnit.test( "isNumeric", function( assert ) { assert.ok( t( 1.5999999999999999 ), "Very precise floating point number" ); assert.ok( t( 8e5 ), "Exponential notation" ); assert.ok( t( "123e-2" ), "Exponential notation string" ); + assert.ok( t( new ToString( "42" ) ), "Custom .toString returning number" ); - assert.equal( t( new ToString( "42" ) ), false, "Custom .toString returning number" ); assert.equal( t( "" ), false, "Empty string" ); assert.equal( t( " " ), false, "Whitespace characters string" ); assert.equal( t( "\t\t" ), false, "Tab characters string" ); From 13d2de7efc1146bac018d2de49029e33b7b33af2 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 6 Jan 2016 17:00:50 -0500 Subject: [PATCH 060/114] Core:CSS: disable 2 tests for Opera 12 --- test/unit/core.js | 2 +- test/unit/css.js | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/unit/core.js b/test/unit/core.js index dc083de31a..a9e93989c5 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1491,7 +1491,7 @@ QUnit.test("jQuery.parseHTML", function( assert ) { assert.ok( jQuery.parseHTML("<#if>

    This is a test.

    <#/if>") || true, "Garbage input should not cause error" ); }); -if ( jQuery.support.createHTMLDocument ) { +if ( jQuery.support.createHTMLDocument && !/opera.*version\/12\.1/i.test( navigator.userAgent ) ) { QUnit.asyncTest( "jQuery.parseHTML", function( assert ) { assert.expect( 1 ); diff --git a/test/unit/css.js b/test/unit/css.js index 09db057299..71c82e9935 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -206,7 +206,7 @@ QUnit.test( "css() explicit and relative values", function( assert ) { } ); QUnit.test( "css() non-px relative values (gh-1711)", function( assert ) { - assert.expect( 17 ); + assert.expect( 16 ); var cssCurrent, units = {}, @@ -268,7 +268,10 @@ QUnit.test( "css() non-px relative values (gh-1711)", function( assert ) { add( "lineHeight", 30, "pc" ); add( "lineHeight", 1, "cm" ); add( "lineHeight", -20, "mm" ); - add( "lineHeight", 50, "%" ); + + // Opera 12 does something funky for this one + // Just disabling for 2.2 + // add( "lineHeight", 50, "%" ); } ); QUnit.test( "css(String, Object)", function( assert ) { From fea7da7ea22b754fbf73bfbd2282f8cc66909920 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Thu, 7 Jan 2016 13:06:10 -0500 Subject: [PATCH 061/114] Revert "Attributes: Remove undocumented .toggleClass( boolean ) signature" This reverts commit 53f798cf4d783bb813b4d1ba97411bc752b275f3. --- src/attributes/classes.js | 69 +++++++++++++++++++++++++++++---------- test/unit/attributes.js | 25 +++++++++++++- 2 files changed, 76 insertions(+), 18 deletions(-) diff --git a/src/attributes/classes.js b/src/attributes/classes.js index 6ab6f6efa5..7933873c4f 100644 --- a/src/attributes/classes.js +++ b/src/attributes/classes.js @@ -1,8 +1,9 @@ define( [ "../core", "../var/rnotwhite", + "../data/var/dataPriv", "../core/init" -], function( jQuery, rnotwhite ) { +], function( jQuery, rnotwhite, dataPriv ) { var rclass = /[\t\r\n\f]/g; @@ -96,26 +97,60 @@ jQuery.fn.extend( { }, toggleClass: function( value, stateVal ) { - var type = typeof value, - classNames = type === "string" ? value.match( rnotwhite ) : []; + var type = typeof value; - return this.each( function( i ) { - var className, - self = jQuery( this ), - c = 0; + if ( typeof stateVal === "boolean" && type === "string" ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } - if ( type === "function" ) { - classNames = value.call( this, i, getClass( this ), stateVal ) - .match( rnotwhite ) || []; - } + if ( jQuery.isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( type === "string" ) { - // Toggle individual class names based on presence or stateVal - while ( ( className = classNames[ c++ ] ) ) { + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = value.match( rnotwhite ) || []; + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } - if ( stateVal === false || stateVal !== true && self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); } } } ); diff --git a/test/unit/attributes.js b/test/unit/attributes.js index f2bcefcad5..8b31b72a6e 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -1228,7 +1228,7 @@ QUnit.test( "removeClass(undefined) is a no-op", function( assert ) { } ); var testToggleClass = function( valueObj, assert ) { - assert.expect( 11 ); + assert.expect( 19 ); var e = jQuery( "#firstp" ); assert.ok( !e.is( ".test" ), "Assert class not present" ); @@ -1256,6 +1256,29 @@ var testToggleClass = function( valueObj, assert ) { assert.ok( ( e.is( ".testA.testC" ) && !e.is( ".testB" ) ), "Assert 1 class added, 1 class removed, and 1 class kept" ); e.toggleClass( valueObj( "testA testC" ) ); assert.ok( ( !e.is( ".testA" ) && !e.is( ".testB" ) && !e.is( ".testC" ) ), "Assert no class present" ); + + // toggleClass storage + e.toggleClass( true ); + assert.ok( e[ 0 ].className === "", "Assert class is empty (data was empty)" ); + e.addClass( "testD testE" ); + assert.ok( e.is( ".testD.testE" ), "Assert class present" ); + e.toggleClass(); + assert.ok( !e.is( ".testD.testE" ), "Assert class not present" ); + assert.ok( jQuery._data( e[ 0 ], "__className__" ) === "testD testE", "Assert data was stored" ); + e.toggleClass(); + assert.ok( e.is( ".testD.testE" ), "Assert class present (restored from data)" ); + e.toggleClass( false ); + assert.ok( !e.is( ".testD.testE" ), "Assert class not present" ); + e.toggleClass( true ); + assert.ok( e.is( ".testD.testE" ), "Assert class present (restored from data)" ); + e.toggleClass(); + e.toggleClass( false ); + e.toggleClass(); + assert.ok( e.is( ".testD.testE" ), "Assert class present (restored from data)" ); + + // Cleanup + e.removeClass( "testD" ); + assert.expectJqData( this, e[ 0 ], "__className__" ); }; QUnit.test( "toggleClass(String|boolean|undefined[, boolean])", function( assert ) { From 0ee94bcb9d49acb0706921b1ab4b13883b1fdd7f Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Thu, 7 Jan 2016 14:03:04 -0500 Subject: [PATCH 062/114] Revert "Event: remove guard for falsy handler argument of jQuery#on method" This reverts commit fac67a984268ef8f7de952666fda6d8d32754f5f. --- test/unit/event.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/unit/event.js b/test/unit/event.js index 804ece2caf..b574efc7e0 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -5,6 +5,21 @@ QUnit.module( "event", { teardown: moduleTeardown } ); +QUnit.test( "null or undefined handler", function( assert ) { + assert.expect( 2 ); + + // Supports Fixes bug #7229 + try { + jQuery( "#firstp" ).on( "click", null ); + ok( true, "Passing a null handler will not throw an exception" ); + } catch ( e ) {} + + try { + jQuery( "#firstp" ).on( "click", undefined ); + ok( true, "Passing an undefined handler will not throw an exception" ); + } catch ( e ) {} +} ); + QUnit.test( "on() with non-null,defined data", function( assert ) { assert.expect( 2 ); From 636a2bd4e080f80e3dcc1eb00a5222d8c1eee617 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Thu, 7 Jan 2016 14:08:43 -0500 Subject: [PATCH 063/114] Tests: fix lint in restored test --- test/unit/event.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/event.js b/test/unit/event.js index b574efc7e0..6cccb8d1af 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -11,12 +11,12 @@ QUnit.test( "null or undefined handler", function( assert ) { // Supports Fixes bug #7229 try { jQuery( "#firstp" ).on( "click", null ); - ok( true, "Passing a null handler will not throw an exception" ); + assert.ok( true, "Passing a null handler will not throw an exception" ); } catch ( e ) {} try { jQuery( "#firstp" ).on( "click", undefined ); - ok( true, "Passing an undefined handler will not throw an exception" ); + assert.ok( true, "Passing an undefined handler will not throw an exception" ); } catch ( e ) {} } ); From b9a695865b4eb3916f7320026d028a2866da6e4e Mon Sep 17 00:00:00 2001 From: Jun Sun Date: Wed, 30 Dec 2015 15:40:08 +0800 Subject: [PATCH 064/114] CSS: Add animation-iteration-count to cssNumber, fix tests Fixes gh-2792 Closes gh-2793 --- src/css.js | 1 + test/unit/css.js | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/css.js b/src/css.js index d9104ad3f7..ec55a24115 100644 --- a/src/css.js +++ b/src/css.js @@ -252,6 +252,7 @@ jQuery.extend( { // Don't automatically add "px" to these possibly-unitless properties cssNumber: { + "animationIterationCount": true, "columnCount": true, "fillOpacity": true, "flexGrow": true, diff --git a/test/unit/css.js b/test/unit/css.js index 71c82e9935..c2213b2482 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -848,26 +848,35 @@ if ( jQuery.fn.offset ) { } ); } -QUnit.test( "Do not append px (#9548, #12990)", function( assert ) { - assert.expect( 2 ); +QUnit.test( "Do not append px (#9548, #12990, #2792)", function( assert ) { + assert.expect( 3 ); var $div = jQuery( "
    " ).appendTo( "#qunit-fixture" ); $div.css( "fill-opacity", 1 ); // Support: Android 2.3 (no support for fill-opacity) - if ( $div.css( "fill-opacity" ) ) { + if ( $div.css( "fill-opacity" ) !== undefined ) { assert.equal( $div.css( "fill-opacity" ), 1, "Do not append px to 'fill-opacity'" ); } else { assert.ok( true, "No support for fill-opacity CSS property" ); } $div.css( "column-count", 1 ); - if ( $div.css( "column-count" ) ) { + if ( $div.css( "column-count" ) !== undefined ) { assert.equal( $div.css( "column-count" ), 1, "Do not append px to 'column-count'" ); } else { assert.ok( true, "No support for column-count CSS property" ); } + + $div.css( "animation-iteration-count", 2 ); + if ( $div.css( "animation-iteration-count" ) !== undefined ) { + // if $div.css( "animation-iteration-count" ) return "1", + // it actually return the default value of animation-iteration-count + assert.equal( $div.css( "animation-iteration-count" ), 2, "Do not append px to 'animation-iteration-count'" ); + } else { + assert.ok( true, "No support for animation-iteration-count CSS property" ); + } } ); QUnit.test( "css('width') and css('height') should respect box-sizing, see #11004", function( assert ) { From c1511c673148208ab17cafa0faf37bce3b4ae392 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Thu, 7 Jan 2016 16:50:26 -0500 Subject: [PATCH 065/114] Data: find hyphenated data with camelCased key Fixes gh-2779 --- src/data.js | 7 ++++++- test/unit/data.js | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/data.js b/src/data.js index f7734e7f38..b626fda457 100644 --- a/src/data.js +++ b/src/data.js @@ -123,7 +123,12 @@ jQuery.fn.extend( { // Attempt to get data from the cache // with the key as-is - data = dataUser.get( elem, key ); + data = dataUser.get( elem, key ) || + + // Try to find dashed key if it exists (gh-2779) + // This is for 2.2.x only + dataUser.get( elem, key.replace( rmultiDash, "-$&" ).toLowerCase() ); + if ( data !== undefined ) { return data; } diff --git a/test/unit/data.js b/test/unit/data.js index 077362edac..00eb9b48e7 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -878,3 +878,12 @@ QUnit.test( ".data(prop) does not create expando", function( assert ) { } } } ); + +QUnit.test( ".data(camelCase) retrieves hyphenated keys", function( assert ) { + assert.expect( 1 ); + + var div = jQuery( "
    " ); + + $.data( div[ 0 ], "data-test", "data" ); + assert.equal( div.data( "dataTest" ), "data" ); +} ); From 1a9c9b079177a1d6420efb876e8e66bf1fb4cbe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Thu, 7 Jan 2016 23:14:55 +0100 Subject: [PATCH 066/114] Tests: Disable/relax a few tests failing in Android 2.3 (cherry-picked from 704de8180f220afa1efd7bd65e9aeb9007a4f238) Fixes gh-1785 --- test/unit/manipulation.js | 12 +++++++++--- test/unit/offset.js | 20 ++++++++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index e5c65e32ae..acf71635a7 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -302,9 +302,15 @@ function testAppend( valueObj, assert ) { assert.equal( jQuery( "
    " ).append( valueObj( "option" ) )[ 0 ].childNodes.length, 2, "HTML-string with leading text should be processed correctly" ); } -QUnit.test( "append(String|Element|Array|jQuery)", function( assert ) { - testAppend( manipulationBareObj, assert ); -} ); +// Support: Android 2.3 only +// Android 2.3 fails a lot of these tests and we accept it. +// See https://github.com/jquery/jquery/issues/1785 +QUnit[ /android 2\.3/i.test( navigator.userAgent ) ? "skip" : "test" ]( + "append(String|Element|Array|jQuery)", + function( assert ) { + testAppend( manipulationBareObj, assert ); + } +); QUnit.test( "append(Function)", function( assert ) { testAppend( manipulationFunctionReturningObj, assert ); diff --git a/test/unit/offset.js b/test/unit/offset.js index 11b4feb978..317f410537 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -458,10 +458,26 @@ testIframe( "offset/scroll", "scroll", function( $, win, doc, assert ) { // test jQuery using parent window/document // jQuery reference here is in the iframe + // Support: Android 2.3 only + // Android 2.3 is sometimes off by a few pixels. window.scrollTo( 0, 0 ); - assert.equal( $( window ).scrollTop(), 0, "jQuery(window).scrollTop() other window" ); + if ( /android 2\.3/i.test( navigator.userAgent ) ) { + assert.ok( + Math.abs( $( window ).scrollTop() ) < 5, + "jQuery(window).scrollTop() other window" + ); + } else { + assert.equal( $( window ).scrollTop(), 0, "jQuery(window).scrollTop() other window" ); + } assert.equal( $( window ).scrollLeft(), 0, "jQuery(window).scrollLeft() other window" ); - assert.equal( $( document ).scrollTop(), 0, "jQuery(window).scrollTop() other document" ); + if ( /android 2\.3/i.test( navigator.userAgent ) ) { + assert.ok( + Math.abs( $( window ).scrollTop() ) < 5, + "jQuery(window).scrollTop() other document" + ); + } else { + assert.equal( $( document ).scrollTop(), 0, "jQuery(window).scrollTop() other document" ); + } assert.equal( $( document ).scrollLeft(), 0, "jQuery(window).scrollLeft() other document" ); // Tests scrollTop/Left with empty jquery objects From 27325311db4807f52d66e592d832c55ab0a203df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Thu, 7 Jan 2016 23:26:12 +0100 Subject: [PATCH 067/114] Tests: Accept Android 2.3 doesn't fire window.onerror for remote scripts A followup to 1a9c9b079177a1d6420efb876e8e66bf1fb4cbe2 --- test/unit/manipulation.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index acf71635a7..f4687dcb0c 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2293,7 +2293,10 @@ QUnit.test( "Ensure oldIE creates a new set on appendTo (#8894)", function( asse } ); QUnit.test( "html() - script exceptions bubble (#11743)", function( assert ) { - assert.expect( 3 ); + // Support: Android 2.3 only + // Android 2.3 doesn't fire window.onerror for errors in remote scripts + // but we accept this reality. + assert.expect( /android 2\.3/i.test( navigator.userAgent ) ? 2 : 3 ); assert.throws(function() { jQuery("#qunit-fixture").html(""); From 3f839af50b83903279b1f3b614b86c6d4c2b72fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Thu, 7 Jan 2016 23:30:51 +0100 Subject: [PATCH 068/114] Tests: hotfix for c1511c673148208ab17cafa0faf37bce3b4ae392 Refs c1511c673148208ab17cafa0faf37bce3b4ae392 --- test/unit/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/data.js b/test/unit/data.js index 00eb9b48e7..7bd7d298f2 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -884,6 +884,6 @@ QUnit.test( ".data(camelCase) retrieves hyphenated keys", function( assert ) { var div = jQuery( "
    " ); - $.data( div[ 0 ], "data-test", "data" ); + jQuery.data( div[ 0 ], "data-test", "data" ); assert.equal( div.data( "dataTest" ), "data" ); } ); From ae3229c805705a01603b8f1fb094528f43b05168 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Fri, 8 Jan 2016 13:35:31 -0500 Subject: [PATCH 069/114] Release: update AUTHORS.txt --- AUTHORS.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 58c73afbc9..feb0a43fc7 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -259,3 +259,17 @@ Chris Rebert Gabriel Schulhof Gilad Peleg Martin Naumann +Marek Lewandowski +Bruno Pérel +Reed Loden +Daniel Nill +Yongwoo Jeon +Sean Henderson +Richard Kraaijenhagen +Connor Atherton +Gary Ye +Christian Grete +Liza Ramo +Julian Alexander Murillo +Joelle Fleurantin +Jun Sun From 47c21efce522204d0c3e779faa10de2ee63cedd7 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Fri, 8 Jan 2016 13:20:19 -0500 Subject: [PATCH 070/114] Release: allow local and github dists --- build/release/dist.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/release/dist.js b/build/release/dist.js index 32053eafb0..6439f6b319 100644 --- a/build/release/dist.js +++ b/build/release/dist.js @@ -4,7 +4,10 @@ module.exports = function( Release, complete ) { fs = require( "fs" ), shell = require( "shelljs" ), pkg = require( Release.dir.repo + "/package.json" ), - distRemote = Release.remote.replace( "jquery.git", "jquery-dist.git" ), + distRemote = Release.remote + + // For local and github dists + .replace( /jquery(\.git|$)/, "jquery-dist$1" ), // These files are included with the distribution files = [ From b4e139cb7bdd890c0bf7d1c64f112e44100598a5 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Fri, 8 Jan 2016 13:26:58 -0500 Subject: [PATCH 071/114] Release: ensure files are copied to dist --- build/release/dist.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/release/dist.js b/build/release/dist.js index 6439f6b319..35d074ae88 100644 --- a/build/release/dist.js +++ b/build/release/dist.js @@ -62,12 +62,12 @@ module.exports = function( Release, complete ) { "dist/jquery.min.js", "dist/jquery.min.map" ].forEach( function( file ) { - shell.cp( Release.dir.repo + "/" + file, distFolder ); + shell.cp( "-f", Release.dir.repo + "/" + file, distFolder ); } ); // Copy other files files.forEach( function( file ) { - shell.cp( "-r", Release.dir.repo + "/" + file, Release.dir.dist ); + shell.cp( "-rf", Release.dir.repo + "/" + file, Release.dir.dist ); } ); // Write generated bower file From 6ed6bc335f98352acfc7c07249bc4e936099aecf Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Fri, 8 Jan 2016 13:59:53 -0500 Subject: [PATCH 072/114] Manipulation: re-expose domManip until 3.0 Fixes gh-2225 --- src/manipulation.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/manipulation.js b/src/manipulation.js index 046424a78f..b65699bacd 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -307,6 +307,10 @@ jQuery.extend( { } ); jQuery.fn.extend( { + + // Keep domManip exposed until 3.0 (gh-2225) + domManip: domManip, + detach: function( selector ) { return remove( this, selector, true ); }, From 66a4ab0e353a8bf4b3dcf698380924a3a85bd8f8 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Fri, 8 Jan 2016 15:03:45 -0500 Subject: [PATCH 073/114] Build: Updating the 2.2-stable version to 2.2.1-pre. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9ee4ef8401..ca45cde5b7 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "jquery", "title": "jQuery", "description": "JavaScript library for DOM operations", - "version": "2.2.0-pre", + "version": "2.2.1-pre", "main": "dist/jquery.js", "homepage": "http://jquery.com", "author": { From 3c56eac50725c2548c3abc0159841c3354936ac4 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Fri, 8 Jan 2016 12:38:18 -0500 Subject: [PATCH 074/114] Release: compat -> 1.x. Remove compat-specific release semantics (cherry-picked from 25d0afa51e08c00556c9e6906851d771a851ae23) --- CONTRIBUTING.md | 2 +- README.md | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3f6547c568..e4373785f2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -129,4 +129,4 @@ This will only run the "css" module tests. This will significantly speed up your Remember that jQuery supports multiple browsers and their versions; any contributed code must work in all of them. You can refer to the [browser support page](http://jquery.com/browser-support/) for the current list of supported browsers. -Note that browser support differs depending on whether you are targeting the `master` or `compat` branch. +Note that browser support differs depending on whether you are targeting the `master` or `1.x` branch. diff --git a/README.md b/README.md index 71c015f78b..b6ad406cd6 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ In the spirit of open source software development, jQuery always encourages comm Environments in which to use jQuery -------------------------------------- -- [Browser support](http://jquery.com/browser-support/) differs between the master branch and the compat branch. Specifically, the master branch does not support legacy browsers such as IE8. The jQuery team continues to provide support for legacy browsers on the compat branch. Use the latest compat release if support for those browsers is required. See [browser support](http://jquery.com/browser-support/) for more info. -- To use jQuery in Node, browser extensions, and other non-browser environments, use only master branch releases given the name "jquery" rather than "jquery-compat". The compat branch does not support these environments. +- [Browser support](http://jquery.com/browser-support/) differs between the master branch and the 1.x branch. Specifically, the master branch does not support legacy browsers such as IE6-8. The jQuery team continues to provide support for legacy browsers on the 1.x branch. Use the latest 1.x release if support for those browsers is required. See [browser support](http://jquery.com/browser-support/) for more info. +- To use jQuery in Node, browser extensions, and other non-browser environments, use only master branch releases (2.x). The 1.x branch does not support these environments. What you need to build your own jQuery @@ -102,7 +102,7 @@ As a special case, you may also replace Sizzle by using a special flag `grunt cu *Note*: Excluding Sizzle will also exclude all jQuery selector extensions (such as `effects/animatedSelector` and `css/hiddenVisibleSelectors`). -*Note*: Removing Sizzle is not supported on the `compat` branch. +*Note*: Removing Sizzle is not supported on the `1.x` branch. The build process shows a message for each dependent module it excludes or includes. @@ -128,7 +128,7 @@ To create a custom build, first check out the version: git pull; git checkout VERSION ``` -Where VERSION is the version you want to customize. Then, make sure all Node dependencies are installed: +where VERSION is the version you want to customize. Then, make sure all Node dependencies are installed: ```bash npm install @@ -154,7 +154,7 @@ Exclude a bunch of modules: grunt custom:-ajax,-css,-deprecated,-dimensions,-effects,-event/alias,-offset,-wrap ``` -For questions or requests regarding custom builds, please start a thread on the [Developing jQuery Core](https://forum.jquery.com/developing-jquery-core) section of the forum. Due to the combinatorics and custom nature of these builds, they are not regularly tested in jQuery's unit test process. The non-Sizzle selector engine currently does not pass unit tests because it is missing too much essential functionality. +For questions or requests regarding custom builds, please start a thread on the [Developing jQuery Core](https://forum.jquery.com/developing-jquery-core) section of the forum. Due to the combinatorics and custom nature of these builds, they are not regularly tested in jQuery's unit test process. Running the Unit Tests -------------------------------------- @@ -261,7 +261,7 @@ start(); ``` -*Note*: QUnit's eventual addition of an argument to stop/start is ignored in this test suite so that start and stop can be passed as callbacks without worrying about their parameters. +Note: QUnit's eventual addition of an argument to stop/start is ignored in this test suite so that start and stop can be passed as callbacks without worrying about their parameters ### Test assertions ### From df31b88135f94f903c8a887085d30d085a9c62f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Mon, 11 Jan 2016 19:21:45 +0100 Subject: [PATCH 075/114] Event: compat -> 1.x in comments Ref 3c56eac50725c2548c3abc0159841c3354936ac4 --- src/event/trigger.js | 2 +- test/unit/offset.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/event/trigger.js b/src/event/trigger.js index 448f90878d..a6fac70ea9 100644 --- a/src/event/trigger.js +++ b/src/event/trigger.js @@ -164,7 +164,7 @@ jQuery.extend( jQuery.event, { // But now, this "simulate" function is used only for events // for which stopPropagation() is noop, so there is no need for that anymore. // - // For the compat branch though, guard for "click" and "submit" + // For the 1.x branch though, guard for "click" and "submit" // events is still used, but was moved to jQuery.event.stopPropagation function // because `originalEvent` should point to the original event for the constancy // with other events and for more focused logic diff --git a/test/unit/offset.js b/test/unit/offset.js index 317f410537..5100dbf34d 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -62,7 +62,7 @@ QUnit.test( "disconnected node", function( assert ) { var result = jQuery( document.createElement( "div" ) ).offset(); - // These tests are solely for master/compat consistency + // These tests are solely for 2.x/1.x consistency // Retrieving offset on disconnected/hidden elements is not officially // valid input, but will return zeros for back-compat assert.equal( result.top, 0, "Check top" ); @@ -77,7 +77,7 @@ QUnit.test( "hidden (display: none) element", function( assert ) { node.remove(); - // These tests are solely for master/compat consistency + // These tests are solely for 2.x/1.x consistency // Retrieving offset on disconnected/hidden elements is not officially // valid input, but will return zeros for back-compat assert.equal( result.top, 0, "Retrieving offset on hidden elements returns zeros (gh-2310)" ); @@ -423,7 +423,7 @@ testIframe( "offset/scroll", "scroll", function( $, win, doc, assert ) { assert.equal( $( "#scroll-1-1" ).offset().top, 11, "jQuery('#scroll-1-1').offset().top" ); assert.equal( $( "#scroll-1-1" ).offset().left, 11, "jQuery('#scroll-1-1').offset().left" ); - // These tests are solely for master/compat consistency + // These tests are solely for 2.x/1.x consistency // Retrieving offset on disconnected/hidden elements is not officially // valid input, but will return zeros for back-compat // assert.equal( $( "#hidden" ).offset().top, 0, "Hidden elements do not subtract scroll" ); From c4d9eac930b86c192b0f96210d88bb7d91e697e1 Mon Sep 17 00:00:00 2001 From: Devin Wilson Date: Wed, 13 Jan 2016 21:06:43 -0700 Subject: [PATCH 076/114] Event: Fix chaining .on() with null handlers Fixes gh-2812 Close gh-2825 --- src/event.js | 2 +- test/unit/event.js | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/event.js b/src/event.js index e9d1053dc8..6d60b4c115 100644 --- a/src/event.js +++ b/src/event.js @@ -71,7 +71,7 @@ function on( elem, types, selector, data, fn, one ) { if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { - return this; + return elem; } if ( one === 1 ) { diff --git a/test/unit/event.js b/test/unit/event.js index 6cccb8d1af..04ca615eb0 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -6,7 +6,7 @@ QUnit.module( "event", { } ); QUnit.test( "null or undefined handler", function( assert ) { - assert.expect( 2 ); + assert.expect( 4 ); // Supports Fixes bug #7229 try { @@ -18,6 +18,13 @@ QUnit.test( "null or undefined handler", function( assert ) { jQuery( "#firstp" ).on( "click", undefined ); assert.ok( true, "Passing an undefined handler will not throw an exception" ); } catch ( e ) {} + + var expectedElem = jQuery( "#firstp" ); + var actualElem = expectedElem.on( "click", null ); + assert.equal(actualElem, expectedElem, "Passing a null handler should return the original element"); + + actualElem = expectedElem.on( "click", undefined ); + assert.equal(actualElem, expectedElem, "Passing a null handler should return the original element"); } ); QUnit.test( "on() with non-null,defined data", function( assert ) { From 182294539e1a439103bd027452ed9af11c0b9070 Mon Sep 17 00:00:00 2001 From: Todor Prikumov Date: Tue, 26 Jan 2016 11:58:34 +0200 Subject: [PATCH 077/114] CSS: Make sure elem.ownerDocument.defaultView is not null Fixes gh-2866 Close gh-2867 --- src/css/var/getStyles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/var/getStyles.js b/src/css/var/getStyles.js index 1fa915d58a..02a4b8194e 100644 --- a/src/css/var/getStyles.js +++ b/src/css/var/getStyles.js @@ -6,7 +6,7 @@ define( function() { // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" var view = elem.ownerDocument.defaultView; - if ( !view.opener ) { + if ( !view || !view.opener ) { view = window; } From cff39574576766b6057c5363e4f38976b1680b92 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 27 Jan 2016 11:36:34 -0500 Subject: [PATCH 078/114] CSS: Add test for gh-2867 --- test/unit/css.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/unit/css.js b/test/unit/css.js index c2213b2482..8ccc6b5dad 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -814,6 +814,16 @@ QUnit.test( "can't get css for disconnected in IE<9, see #10254 and #8388", func assert.equal( div.css( "top" ), "10px", "can't get top in IE<9, see #8388" ); } ); +QUnit.test( "Ensure styles are retrieving from parsed html on document fragments", function( assert ) { + assert.expect( 1 ); + + var $span = jQuery( + jQuery.parseHTML( "some text" ) + ); + + assert.equal( $span.css( "font-size" ), "14px", "Font-size retrievable on parsed HTML node" ); +} ); + QUnit.test( "can't get background-position in IE<9, see #10796", function( assert ) { var div = jQuery( "
    " ).appendTo( "#qunit-fixture" ), units = [ From 412c5dfb0d6301dc0b3d7c98325cc9908dd97511 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 27 Jan 2016 12:19:29 -0500 Subject: [PATCH 079/114] Revert "Manipulation: don't auto-insert tbody" This reverts commit e984d1c79cc476062818e03df04a366baa13d197. Fixes gh-2861 --- src/manipulation.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/manipulation.js b/src/manipulation.js index b65699bacd..afd5091dda 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -38,14 +38,14 @@ var rscriptTypeMasked = /^true\/(.*)/, rcleanScript = /^\s*\s*$/g; +// Manipulating tables requires a tbody function manipulationTarget( elem, content ) { - if ( jQuery.nodeName( elem, "table" ) && - jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? - return elem.getElementsByTagName( "tbody" )[ 0 ] || elem; - } - - return elem; + elem.getElementsByTagName( "tbody" )[ 0 ] || + elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : + elem; } // Replace/restore the type attribute of script elements for safe DOM manipulation From ee0f61647cb93d587764280b1278807d9ff86fc9 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Tue, 9 Feb 2016 00:14:19 +0300 Subject: [PATCH 080/114] Revert "Offset: account for scroll when calculating position" This reverts commit 2d715940b9b6fdeed005cd006c8bf63951cf7fb2. This commit provoked new issues: gh-2836, gh-2828. At the meeting, we decided to revert offending commit (in all three branches - 2.2-stable, 1.12-stable and master) and tackle this issue in 3.x. Fixes gh-2828 --- src/offset.js | 7 ++----- test/unit/offset.js | 14 ++------------ 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/offset.js b/src/offset.js index 4352a99954..08a4543e43 100644 --- a/src/offset.js +++ b/src/offset.js @@ -134,11 +134,8 @@ jQuery.fn.extend( { } // Add offsetParent borders - // Subtract offsetParent scroll positions - parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ) - - offsetParent.scrollTop(); - parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ) - - offsetParent.scrollLeft(); + parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ); + parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ); } // Subtract parent offsets and element margins diff --git a/test/unit/offset.js b/test/unit/offset.js index 5100dbf34d..cacfe67503 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -415,7 +415,7 @@ testIframe( "offset/table", "table", function( $, window, document, assert ) { } ); testIframe( "offset/scroll", "scroll", function( $, win, doc, assert ) { - assert.expect( 28 ); + assert.expect( 24 ); assert.equal( $( "#scroll-1" ).offset().top, 7, "jQuery('#scroll-1').offset().top" ); assert.equal( $( "#scroll-1" ).offset().left, 7, "jQuery('#scroll-1').offset().left" ); @@ -487,17 +487,6 @@ testIframe( "offset/scroll", "scroll", function( $, win, doc, assert ) { assert.notEqual( $().scrollLeft( null ), null, "jQuery().scrollLeft(null) testing setter on empty jquery object" ); assert.strictEqual( $().scrollTop(), undefined, "jQuery().scrollTop() testing getter on empty jquery object" ); assert.strictEqual( $().scrollLeft(), undefined, "jQuery().scrollLeft() testing getter on empty jquery object" ); - - // Tests position after parent scrolling (#15239) - $( "#scroll-1" ).scrollTop( 0 ); - $( "#scroll-1" ).scrollLeft( 0 ); - assert.equal( $( "#scroll-1-1" ).position().top, 6, "jQuery('#scroll-1-1').position().top unaffected by parent scrolling" ); - assert.equal( $( "#scroll-1-1" ).position().left, 6, "jQuery('#scroll-1-1').position().left unaffected by parent scrolling" ); - - $( "#scroll-1" ).scrollTop( 5 ); - $( "#scroll-1" ).scrollLeft( 5 ); - assert.equal( $( "#scroll-1-1" ).position().top, 6, "jQuery('#scroll-1-1').position().top unaffected by parent scrolling" ); - assert.equal( $( "#scroll-1-1" ).position().left, 6, "jQuery('#scroll-1-1').position().left unaffected by parent scrolling" ); } ); testIframe( "offset/body", "body", function( $, window, document, assert ) { @@ -511,6 +500,7 @@ testIframe( "offset/body", "body", function( $, window, document, assert ) { QUnit.test( "chaining", function( assert ) { assert.expect( 3 ); + var coords = { "top": 1, "left": 1 }; assert.equal( jQuery("#absolute-1").offset(coords).selector, "#absolute-1", "offset(coords) returns jQuery object" ); assert.equal( jQuery("#non-existent").offset(coords).selector, "#non-existent", "offset(coords) with empty jQuery set returns jQuery object" ); From 30202be6e1730d46eec1966e2d78db7860935df9 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Thu, 11 Feb 2016 22:31:49 +0300 Subject: [PATCH 081/114] Tests: test element position outside view Ref ee0f61647cb93d587764280b1278807d9ff86fc9 Ref gh-2828 Ref gh-2836 Fixes gh-2909 --- test/data/testsuite.css | 12 ++++++++++++ test/unit/dimensions.js | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/test/data/testsuite.css b/test/data/testsuite.css index cf2ba8c205..3dbf834fda 100644 --- a/test/data/testsuite.css +++ b/test/data/testsuite.css @@ -142,3 +142,15 @@ section { background:#f0f; display:block; } #span-14824 { display: block; } #display { display: list-item !important; } + +#div-gh-2836 { + position: relative; + overflow: auto; + height: 100px; +} +#div-gh-2836 div { + position: relative; + height: 100%; + padding: 0; + margin: 0; +} diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 44a7291130..af269de90e 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -473,4 +473,34 @@ QUnit.test( "allow modification of coordinates argument (gh-1848)", function( as "coordinates are modified (got offset.top: " + offsetTop + ")" ); } ); +QUnit.test( "outside view position (gh-2836)", function( assert ) { + + // This test ported from gh-2836 example + assert.expect( 1 ); + + var parent, + html = [ + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    ", + "
    " + ].join( "" ), + stop = assert.async(); + + parent = $( html ); + parent.appendTo( "#qunit-fixture" ); + + parent.one( "scroll", function() { + var pos = parent.find( "div" ).eq( 3 ).position(); + + assert.strictEqual(pos.top, -100); + stop(); + }); + + parent.scrollTop( 400 ); +} ); + } )(); From 1b4435bb47765bc69f35221343ba45af95811320 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Thu, 11 Feb 2016 22:47:36 +0300 Subject: [PATCH 082/114] Build: simplify and correct .editorconfig --- .editorconfig | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/.editorconfig b/.editorconfig index 06dbe065b1..b5bd7f60ec 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,25 +3,14 @@ root = true - [*] +indent_style = tab end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -# Tabs in JS unless otherwise specified -[**.js] -indent_style = tab - -[test/**.xml] -indent_style = tab - -[test/**.php] -indent_style = tab +[package.json] +indent_style = space +indent_size = 2 -[test/**.html] -indent_style = tab - -[test/**.css] -indent_style = tab From b3517760a36247edd03c0a1a9fb91ffd62b71893 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Sat, 13 Feb 2016 21:14:46 +0300 Subject: [PATCH 083/114] Tests: use `jQuery` variable instead of `$` For some reason that works with `amd` but not with builded version Fixes gh-2909 --- test/unit/dimensions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index af269de90e..6e850f2086 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -490,7 +490,7 @@ QUnit.test( "outside view position (gh-2836)", function( assert ) { ].join( "" ), stop = assert.async(); - parent = $( html ); + parent = jQuery( html ); parent.appendTo( "#qunit-fixture" ); parent.one( "scroll", function() { From 76ca957dac6aaa17c9d46c19351b8a993b23ebcd Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Sat, 13 Feb 2016 22:35:59 +0300 Subject: [PATCH 084/114] Build: add `npm-debug.log` to `.gitignore` --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index eae5df6e6c..e1e7dbfe4f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ .bower.json .sizecache.json +npm-debug.log + /dist /node_modules From d230d51731869827e00202c7850680a5c438e678 Mon Sep 17 00:00:00 2001 From: Zack Hall Date: Thu, 21 Jan 2016 16:24:42 -0800 Subject: [PATCH 085/114] Tests: Set Edge's expected support for clearCloneStyle to true This is done for a version 13 or newer as the bug still exists in Edge 12. (cherry-picked from 28f0329a02c453ae26b6bc028b6aaeec578bef6f) Closes gh-2857 --- test/unit/support.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/unit/support.js b/test/unit/support.js index 9f0937a93d..5d3e38a4b7 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -53,16 +53,17 @@ testIframeWithCallback( ); ( function() { - var expected, + var expected, version, userAgent = window.navigator.userAgent; if ( /edge\//i.test( userAgent ) ) { + version = userAgent.match( /edge\/(\d+)/i )[ 1 ]; expected = { "ajax": true, "boxSizingReliable": true, "checkClone": true, "checkOn": true, - "clearCloneStyle": false, + "clearCloneStyle": version >= 13, "cors": true, "createHTMLDocument": true, "focusin": false, From b536cd561ff1276f7094968aed2f1aa7d70bb5ae Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 10 Feb 2016 13:47:25 -0800 Subject: [PATCH 086/114] Build: use hard-coded path to sizzle in selector-sizzle Fixes gh-2898 --- build/tasks/build.js | 5 +---- src/selector-sizzle.js | 2 +- test/jquery.js | 5 +---- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/build/tasks/build.js b/build/tasks/build.js index 74fa47fde4..6825fc4419 100644 --- a/build/tasks/build.js +++ b/build/tasks/build.js @@ -32,9 +32,6 @@ module.exports = function( grunt ) { startFile: "src/intro.js", endFile: [ "src/exports/global.js", "src/outro.js" ] }, - paths: { - sizzle: "../external/sizzle/dist/sizzle" - }, rawText: {}, onBuildWrite: convert }; @@ -59,7 +56,7 @@ module.exports = function( grunt ) { .replace( rdefineEnd, "" ); // Sizzle treatment - } else if ( /^sizzle$/.test( name ) ) { + } else if ( /\/sizzle$/.test( name ) ) { contents = "var Sizzle =\n" + contents // Remove EXPOSE lines from Sizzle diff --git a/src/selector-sizzle.js b/src/selector-sizzle.js index dcee45f37f..9728a1f57e 100644 --- a/src/selector-sizzle.js +++ b/src/selector-sizzle.js @@ -1,6 +1,6 @@ define( [ "./core", - "sizzle" + "../external/sizzle/dist/sizzle" ], function( jQuery, Sizzle ) { jQuery.find = Sizzle; diff --git a/test/jquery.js b/test/jquery.js index 233e696d9d..8119d3fc04 100644 --- a/test/jquery.js +++ b/test/jquery.js @@ -18,10 +18,7 @@ // This detection allows AMD tests to be run in an iframe if ( QUnit.urlParams.amd && window.QUnit ) { require.config( { - baseUrl: path, - paths: { - sizzle: "external/sizzle/dist/sizzle" - } + baseUrl: path } ); src = "src/jquery"; From f1d1d399ece1ef51d993143077a597bf11d3e2dd Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 22 Feb 2016 11:24:52 -0500 Subject: [PATCH 087/114] CSS: fix for disconnected elems on doc fragments in Opera 12 --- src/css/curCSS.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/css/curCSS.js b/src/css/curCSS.js index be643ab547..084f8c7bde 100644 --- a/src/css/curCSS.js +++ b/src/css/curCSS.js @@ -12,15 +12,18 @@ function curCSS( elem, name, computed ) { style = elem.style; computed = computed || getStyles( elem ); + ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined; + + // Support: Opera 12.1x only + // Fall back to style even without computed + // computed is undefined for elems on document fragments + if ( ( ret === "" || ret === undefined ) && !jQuery.contains( elem.ownerDocument, elem ) ) { + ret = jQuery.style( elem, name ); + } // Support: IE9 // getPropertyValue is only needed for .css('filter') (#12537) if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } // A tribute to the "awesome hack by Dean Edwards" // Android Browser returns percentage for some values, From d0491733c487c281f75853e2ebbe2b59f2955344 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 22 Feb 2016 13:23:21 -0500 Subject: [PATCH 088/114] Build: update AUTHORS --- AUTHORS.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index feb0a43fc7..dde64cac7a 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -273,3 +273,6 @@ Liza Ramo Julian Alexander Murillo Joelle Fleurantin Jun Sun +Devin Wilson +Todor Prikumov +Zack Hall From 7d856124afaecae63a36da28921552ac7a0eb00e Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 22 Feb 2016 14:12:11 -0500 Subject: [PATCH 089/114] Build: Updating the 2.2-stable version to 2.2.2-pre. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ca45cde5b7..43f729fa27 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "jquery", "title": "jQuery", "description": "JavaScript library for DOM operations", - "version": "2.2.1-pre", + "version": "2.2.2-pre", "main": "dist/jquery.js", "homepage": "http://jquery.com", "author": { From 5d620be42054e8a326bc29493728e80381ebf473 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 24 Feb 2016 10:20:22 -0500 Subject: [PATCH 090/114] Release: include external/sizzle in releases Ref gh-2945 --- build/release/dist.js | 1 + 1 file changed, 1 insertion(+) diff --git a/build/release/dist.js b/build/release/dist.js index 35d074ae88..178e38cabb 100644 --- a/build/release/dist.js +++ b/build/release/dist.js @@ -12,6 +12,7 @@ module.exports = function( Release, complete ) { // These files are included with the distribution files = [ "src", + "external/sizzle", "LICENSE.txt", "AUTHORS.txt", "package.json" From c5c30735311c74c60689fcabdcf2cb192524000e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Wed, 2 Mar 2016 12:28:00 +0100 Subject: [PATCH 091/114] Core: drop the document.implementation.createHTMLDocument usage The document.implementation.createHTMLDocument("") method creates inert documents which is good but using it has introduced issues around anchor elements href property not resolving according to the current document. Because of that, this patch is getting backed out on 1.x/2.x branches. Refs cfe468f29c4cbe1a457d0feb17dec90dcfd7c280 Refs gh-1505 Fixes gh-2941 --- src/core/parseHTML.js | 14 +++----------- src/core/support.js | 18 ------------------ test/unit/core.js | 16 ---------------- test/unit/support.js | 15 --------------- 4 files changed, 3 insertions(+), 60 deletions(-) delete mode 100644 src/core/support.js diff --git a/src/core/parseHTML.js b/src/core/parseHTML.js index 87c2147d14..3524abd632 100644 --- a/src/core/parseHTML.js +++ b/src/core/parseHTML.js @@ -2,11 +2,8 @@ define( [ "../core", "../var/document", "./var/rsingleTag", - "../manipulation/buildFragment", - - // This is the only module that needs core/support - "./support" -], function( jQuery, document, rsingleTag, buildFragment, support ) { + "../manipulation/buildFragment" +], function( jQuery, document, rsingleTag, buildFragment ) { // Argument "data" should be string of html // context (optional): If specified, the fragment will be created in this context, @@ -20,12 +17,7 @@ jQuery.parseHTML = function( data, context, keepScripts ) { keepScripts = context; context = false; } - - // Stop scripts or inline event handlers from being executed immediately - // by using document.implementation - context = context || ( support.createHTMLDocument ? - document.implementation.createHTMLDocument( "" ) : - document ); + context = context || document; var parsed = rsingleTag.exec( data ), scripts = !keepScripts && []; diff --git a/src/core/support.js b/src/core/support.js deleted file mode 100644 index 0609a700b6..0000000000 --- a/src/core/support.js +++ /dev/null @@ -1,18 +0,0 @@ -define( [ - "../var/document", - "../var/support" -], function( document, support ) { - -// Support: Safari 8+ -// In Safari 8 documents created via document.implementation.createHTMLDocument -// collapse sibling forms: the second one becomes a child of the first one. -// Because of that, this security measure has to be disabled in Safari 8. -// https://bugs.webkit.org/show_bug.cgi?id=137337 -support.createHTMLDocument = ( function() { - var body = document.implementation.createHTMLDocument( "" ).body; - body.innerHTML = "
    "; - return body.childNodes.length === 2; -} )(); - -return support; -} ); diff --git a/test/unit/core.js b/test/unit/core.js index a9e93989c5..accdae8e1d 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1491,22 +1491,6 @@ QUnit.test("jQuery.parseHTML", function( assert ) { assert.ok( jQuery.parseHTML("<#if>

    This is a test.

    <#/if>") || true, "Garbage input should not cause error" ); }); -if ( jQuery.support.createHTMLDocument && !/opera.*version\/12\.1/i.test( navigator.userAgent ) ) { - QUnit.asyncTest( "jQuery.parseHTML", function( assert ) { - assert.expect( 1 ); - - Globals.register( "parseHTMLError" ); - - jQuery.globalEval( "parseHTMLError = false;" ); - jQuery.parseHTML( "" ); - - window.setTimeout( function() { - QUnit.start(); - assert.equal( window.parseHTMLError, false, "onerror eventhandler has not been called." ); - }, 2000 ); - } ); -} - QUnit.test( "jQuery.parseJSON", function( assert ) { assert.expect( 20 ); diff --git a/test/unit/support.js b/test/unit/support.js index 5d3e38a4b7..af2bd92389 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -65,7 +65,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": version >= 13, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -84,7 +83,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -103,7 +101,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": false, "cors": true, - "createHTMLDocument": true, "focusin": true, "noCloneChecked": false, "optDisabled": true, @@ -122,7 +119,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": false, "cors": false, - "createHTMLDocument": true, "focusin": true, "noCloneChecked": false, "optDisabled": true, @@ -144,7 +140,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -163,7 +158,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -182,7 +176,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": false, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -201,7 +194,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -220,7 +212,6 @@ testIframeWithCallback( "checkOn": false, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -239,7 +230,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -258,7 +248,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -277,7 +266,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": false, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -296,7 +284,6 @@ testIframeWithCallback( "checkOn": true, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -315,7 +302,6 @@ testIframeWithCallback( "checkOn": false, "clearCloneStyle": true, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": true, @@ -334,7 +320,6 @@ testIframeWithCallback( "checkOn": false, "clearCloneStyle": false, "cors": true, - "createHTMLDocument": true, "focusin": false, "noCloneChecked": true, "optDisabled": false, From 63397aaaeaca78dc79e7d9a0860e529c2b7194ec Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Thu, 3 Mar 2016 18:29:45 -0500 Subject: [PATCH 092/114] Core: restore enumeration behavior in isPlainObject Fixes gh-2968 Close gh-2970 --- src/core.js | 9 ++++++--- test/unit/core.js | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/core.js b/src/core.js index f273065870..967fa8e26c 100644 --- a/src/core.js +++ b/src/core.js @@ -223,6 +223,7 @@ jQuery.extend( { }, isPlainObject: function( obj ) { + var key; // Not plain objects: // - Any object or value whose internal [[Class]] property is not "[object Object]" @@ -237,9 +238,11 @@ jQuery.extend( { return false; } - // If the function hasn't returned already, we're confident that - // |obj| is a plain object, created by {} or constructed with new Object - return true; + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); }, isEmptyObject: function( obj ) { diff --git a/test/unit/core.js b/test/unit/core.js index accdae8e1d..e33f653588 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -268,13 +268,21 @@ QUnit.test( "type for `Symbol`", function( assert ) { } ); QUnit.asyncTest( "isPlainObject", function( assert ) { - assert.expect( 15 ); + assert.expect( 19 ); - var pass, iframe, doc, + var pass, iframe, doc, parentObj, childObj, deep, fn = function() {}; // The use case that we want to match assert.ok( jQuery.isPlainObject( {} ), "{}" ); + assert.ok( jQuery.isPlainObject( new window.Object() ), "new Object" ); + + parentObj = { foo: "bar" }; + childObj = Object.create( parentObj ); + + assert.ok( !jQuery.isPlainObject( childObj ), "isPlainObject(Object.create({}))" ); + childObj.bar = "foo"; + assert.ok( !jQuery.isPlainObject( childObj ), "isPlainObject(Object.create({}))" ); // Not objects shouldn't be matched assert.ok( !jQuery.isPlainObject( "" ), "string" ); @@ -302,6 +310,10 @@ QUnit.asyncTest( "isPlainObject", function( assert ) { // Again, instantiated objects shouldn't be matched assert.ok( !jQuery.isPlainObject( new fn() ), "new fn" ); + // Deep object + deep = { "foo": { "baz": true }, "foo2": document }; + assert.ok( jQuery.isPlainObject( deep ), "Object with objects is still plain" ); + // DOM Element assert.ok( !jQuery.isPlainObject( document.createElement( "div" ) ), "DOM Element" ); From 67d4aebda7da4eaeff8cd4c2c0a66718504f339e Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Fri, 15 Jan 2016 16:48:52 -0500 Subject: [PATCH 093/114] Attributes: fix setting selected on an option in IE<=11 Fixes gh-2732 Close gh-2840 --- src/attributes/prop.js | 16 ++++++++++++++++ test/unit/attributes.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/attributes/prop.js b/src/attributes/prop.js index da7bc1e86d..15128b8cef 100644 --- a/src/attributes/prop.js +++ b/src/attributes/prop.js @@ -79,6 +79,12 @@ jQuery.extend( { } } ); +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup if ( !support.optSelected ) { jQuery.propHooks.selected = { get: function( elem ) { @@ -87,6 +93,16 @@ if ( !support.optSelected ) { parent.parentNode.selectedIndex; } return null; + }, + set: function( elem ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } } }; } diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 8b31b72a6e..e52e85b490 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -785,6 +785,37 @@ QUnit.test( "prop('tabindex', value)", function( assert ) { assert.equal( clone[ 0 ].getAttribute( "tabindex" ), "1", "set tabindex on cloned element" ); } ); +QUnit.test( "option.prop('selected', true) affects select.selectedIndex (gh-2732)", function( assert ) { + assert.expect( 2 ); + + function addOptions( $elem ) { + return $elem.append( + jQuery( ""; + html += ""; + html += ""; + } ); + $select.html( html ); + + jQuery.each( spaces, function( key, obj ) { + var val = obj.val || obj; + $select.val( "attr" + val ); + assert.equal( $select.val(), "attr" + val, "Value ending with space character (" + key + ") selected (attr)" ); + + $select.val( "at" + val + "tr" ); + assert.equal( $select.val(), "at" + val + "tr", "Value with space character (" + key + ") in the middle selected (attr)" ); + + $select.val( val + "attr" ); + assert.equal( $select.val(), val + "attr", "Value starting with space character (" + key + ") selected (attr)" ); + } ); + + jQuery.each( spaces, function( key, obj ) { + var value = obj.html || obj, + val = obj.val || obj; + html = ""; + html += ""; + html += ""; + html += ""; + $select.html( html ); + + $select.val( "text" ); + assert.equal( $select.val(), "text", "Value with space character at beginning or end is stripped (" + key + ") selected (text)" ); + + if ( /^\\u/.test( key ) ) { + $select.val( "te" + val + "xt" ); + assert.equal( $select.val(), "te" + val + "xt", "Value with non-space whitespace character (" + key + ") in the middle selected (text)" ); + } else { + $select.val( "te xt" ); + assert.equal( $select.val(), "te xt", "Value with space character (" + key + ") in the middle selected (text)" ); + } + } ); +} ); + var testAddClass = function( valueObj, assert ) { assert.expect( 9 ); @@ -1511,17 +1576,22 @@ QUnit.test( "option value not trimmed when setting via parent select", function( assert.equal( jQuery( "" ).val( "2" ).val(), "2" ); } ); -QUnit.test( "Insignificant white space returned for $(option).val() (#14858)", function( assert ) { - assert.expect( 3 ); +QUnit.test( "Insignificant white space returned for $(option).val() (#14858, gh-2978)", function( assert ) { + assert.expect( 16 ); var val = jQuery( "" ).val(); assert.equal( val.length, 0, "Empty option should have no value" ); - val = jQuery( "" ).val(); - assert.equal( val.length, 0, "insignificant white-space returned for value" ); + jQuery.each( [ " ", "\n", "\t", "\f", "\r" ], function( i, character ) { + var val = jQuery( "" ).val(); + assert.equal( val.length, 0, "insignificant white-space returned for value" ); + + val = jQuery( "" ).val(); + assert.equal( val.length, 4, "insignificant white-space returned for value" ); - val = jQuery( "" ).val(); - assert.equal( val.length, 4, "insignificant white-space returned for value" ); + val = jQuery( "" ).val(); + assert.equal( val, "te st", "Whitespace is collapsed in values" ); + } ); } ); QUnit.test( "SVG class manipulation (gh-2199)", function( assert ) { From 1f4817d19aab6cd5572349a35a5495f06ea6f5ba Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Thu, 17 Mar 2016 13:52:32 -0400 Subject: [PATCH 097/114] Build: Updating the 2.2-stable version to 2.2.3-pre. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 43f729fa27..3e3210be75 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "jquery", "title": "jQuery", "description": "JavaScript library for DOM operations", - "version": "2.2.2-pre", + "version": "2.2.3-pre", "main": "dist/jquery.js", "homepage": "http://jquery.com", "author": { From ac13b23bf062242f8490fe1f2d6a234a94750f79 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Mon, 4 Apr 2016 22:42:01 +0300 Subject: [PATCH 098/114] Ajax: execute jQuery#load callback with correct context Thanks @blq (Fredrik Blomqvist) Fixes gh-3035 Close gh-3039 --- src/ajax/load.js | 2 +- test/unit/ajax.js | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/ajax/load.js b/src/ajax/load.js index 9f1599f91c..5ec3fa2525 100644 --- a/src/ajax/load.js +++ b/src/ajax/load.js @@ -72,7 +72,7 @@ jQuery.fn.load = function( url, params, callback ) { // If it fails, this function gets "jqXHR", "status", "error" } ).always( callback && function( jqXHR, status ) { self.each( function() { - callback.apply( self, response || [ jqXHR.responseText, status, jqXHR ] ); + callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); } ); } ); } diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 69eae32112..8b46c57c2c 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -2017,6 +2017,25 @@ if ( typeof window.ArrayBuffer === "undefined" || typeof new XMLHttpRequest().re } ); + QUnit.test( + "jQuery#load() - should resolve with correct context", 2, + function( assert ) { + var done = assert.async(); + var ps = jQuery( "

    " ); + var i = 0; + + ps.appendTo( "#qunit-fixture" ); + + ps.load( "data/ajax/method.php", function() { + assert.strictEqual( this, ps[ i++ ] ); + + if ( i === 2 ) { + done(); + } + } ); + } + ); + QUnit.test( "#11402 - jQuery.domManip() - script in comments are properly evaluated", 2, function( assert ) { From 49f830a261429d1787c980e66a18a6d5ae2827ba Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Tue, 5 Apr 2016 15:27:20 -0400 Subject: [PATCH 099/114] Build: Updating the 2.2-stable version to 2.2.4-pre. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3e3210be75..6070c26131 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "jquery", "title": "jQuery", "description": "JavaScript library for DOM operations", - "version": "2.2.3-pre", + "version": "2.2.4-pre", "main": "dist/jquery.js", "homepage": "http://jquery.com", "author": { From fb9adb9f0511ac2993e664697aa26e97d0a4d213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Tue, 26 Apr 2016 21:25:30 +0200 Subject: [PATCH 100/114] CSS: Don't workaround the IE 11 iframe-in-fullscreen sizing issues IE 11 used to have an issue where if an element inside an iframe was put in fullscreen mode, the element dimensions started being 100 times too small; we've added a workaround that would multiply them by 100. However, the IE 11 issue has been unexpectedly fixed and since our detection was really detecting the browser and not a bug, we've started breaking the browser instead of fixing it. Since there's no good way to detect if the bug exists, we have to back the workaround out completely. Refs ff1a0822f72d2b39fac691dfcceab6ede5623b90 Fixes gh-3041 Refs gh-1764 Refs gh-2401 Refs 90d828bad0d6d318d73d6cf6209d9dc7ac13878c --- src/css.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/css.js b/src/css.js index ec55a24115..bd131399a3 100644 --- a/src/css.js +++ b/src/css.js @@ -123,19 +123,6 @@ function getWidthOrHeight( elem, name, extra ) { styles = getStyles( elem ), isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - // Support: IE11 only - // In IE 11 fullscreen elements inside of an iframe have - // 100x too small dimensions (gh-1764). - if ( document.msFullscreenElement && window.top !== window ) { - - // Support: IE11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - if ( elem.getClientRects().length ) { - val = Math.round( elem.getBoundingClientRect()[ name ] * 100 ); - } - } - // Some non-html elements return undefined for offsetWidth, so check for null/undefined // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 From 70025d0e651560d033c4d3cbc802389527fcf0b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Tue, 26 Apr 2016 22:44:11 +0200 Subject: [PATCH 101/114] Build: test on Node.js 6 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 5e3f4a3a8d..34f4d9aece 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,4 @@ node_js: - "0.12" - "4" - "5" +- "6" From b9272aaedcc63a37c859e07418bce4ad5a874571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 2 May 2016 22:49:17 +0200 Subject: [PATCH 102/114] Tests: take Safari 9.1 into account Safari 9.1 shares its support test results with Safari 9.0 but it's been excluded from the regex catching Safari 9.0. This has been fixed. (cherry-picked from 234a2d828021b6eb36d83d83cc30c5a09045e781) --- test/unit/support.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/support.js b/test/unit/support.js index af2bd92389..f1ad75bb35 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -150,7 +150,7 @@ testIframeWithCallback( "reliableMarginLeft": true, "reliableMarginRight": true }; - } else if ( /9\.0(\.\d+|) safari/i.test( userAgent ) ) { + } else if ( /9(\.\d+|) safari/i.test( userAgent ) ) { expected = { "ajax": true, "boxSizingReliable": true, From b052e16cd35ba430e93738e90a628c638c335d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 2 May 2016 23:05:56 +0200 Subject: [PATCH 103/114] Tests: Make the regex catching Safari 9.0/9.1 more resilient The word boundary character will prevent iOS from being a false positive. (cherry-picked from 7f2ebd2c4dea186d7d981b939e6e2983a9d7f9c1) --- test/unit/support.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/support.js b/test/unit/support.js index f1ad75bb35..e8d3715b8e 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -150,7 +150,7 @@ testIframeWithCallback( "reliableMarginLeft": true, "reliableMarginRight": true }; - } else if ( /9(\.\d+|) safari/i.test( userAgent ) ) { + } else if ( /\b9\.\d(\.\d+)* safari/i.test( userAgent ) ) { expected = { "ajax": true, "boxSizingReliable": true, From f4253b8ef50f0d16ac62108699fef83e8d3662ad Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 9 May 2016 11:57:31 -0400 Subject: [PATCH 104/114] Release: copy sizzle separately into an 'external' folder Fixes gh-2945 --- build/release/dist.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build/release/dist.js b/build/release/dist.js index 178e38cabb..3ad00c5901 100644 --- a/build/release/dist.js +++ b/build/release/dist.js @@ -12,7 +12,6 @@ module.exports = function( Release, complete ) { // These files are included with the distribution files = [ "src", - "external/sizzle", "LICENSE.txt", "AUTHORS.txt", "package.json" @@ -56,7 +55,9 @@ module.exports = function( Release, complete ) { function copy() { // Copy dist files - var distFolder = Release.dir.dist + "/dist"; + var distFolder = Release.dir.dist + "/dist", + externalFolder = Release.dir.dist + "/external"; + shell.mkdir( "-p", distFolder ); [ "dist/jquery.js", @@ -66,6 +67,10 @@ module.exports = function( Release, complete ) { shell.cp( "-f", Release.dir.repo + "/" + file, distFolder ); } ); + // Copy Sizzle + shell.mkdir( "-p", externalFolder ); + shell.cp( "-rf", Release.dir.repo + "/external/sizzle", externalFolder ); + // Copy other files files.forEach( function( file ) { shell.cp( "-rf", Release.dir.repo + "/" + file, Release.dir.dist ); From a15da4129a2ca4728a433ff3d108ec066ce6cc32 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 9 May 2016 13:53:03 -0400 Subject: [PATCH 105/114] Release: remove extraneous files from dist during release Fixes gh-3094 Close gh-3116 --- build/release.js | 2 +- build/release/dist.js | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/build/release.js b/build/release.js index 7fd00bd8c2..f3ba4c8f3c 100644 --- a/build/release.js +++ b/build/release.js @@ -55,6 +55,6 @@ module.exports = function( Release ) { module.exports.dependencies = [ "archiver@0.14.2", - "shelljs@0.2.6", + "shelljs@0.7.0", "npm@2.3.0" ]; diff --git a/build/release/dist.js b/build/release/dist.js index 3ad00c5901..ffa6e1768b 100644 --- a/build/release/dist.js +++ b/build/release/dist.js @@ -56,7 +56,20 @@ module.exports = function( Release, complete ) { // Copy dist files var distFolder = Release.dir.dist + "/dist", - externalFolder = Release.dir.dist + "/external"; + externalFolder = Release.dir.dist + "/external", + rmIgnore = [ + "README.md", + "node_modules" + ].map( function( file ) { + return Release.dir.dist + "/" + file; + } ); + + shell.config.globOptions = { + ignore: rmIgnore + }; + + // Remove extraneous files before copy + shell.rm( "-rf", Release.dir.dist + "/**/*" ); shell.mkdir( "-p", distFolder ); [ From 66b840618da4d8e7ac8a83b856df6dd07892947f Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Thu, 19 May 2016 21:56:39 +0400 Subject: [PATCH 106/114] Event: don't execute native stop(Immediate)Propagation from simulation In Firefox, called `stop(Immediate)Propagation` methods, in capturing phase prevents receiving focus Cherry-picked from 94efb7992911b6698f900f5b816d043b468bc277 Fixes gh-3111 --- src/event.js | 7 ++-- src/event/trigger.js | 18 +-------- test/unit/event.js | 96 +++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 95 insertions(+), 26 deletions(-) diff --git a/src/event.js b/src/event.js index 6d60b4c115..9ebbe2f7e4 100644 --- a/src/event.js +++ b/src/event.js @@ -593,13 +593,14 @@ jQuery.Event.prototype = { isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse, + isSimulated: false, preventDefault: function() { var e = this.originalEvent; this.isDefaultPrevented = returnTrue; - if ( e ) { + if ( e && !this.isSimulated ) { e.preventDefault(); } }, @@ -608,7 +609,7 @@ jQuery.Event.prototype = { this.isPropagationStopped = returnTrue; - if ( e ) { + if ( e && !this.isSimulated ) { e.stopPropagation(); } }, @@ -617,7 +618,7 @@ jQuery.Event.prototype = { this.isImmediatePropagationStopped = returnTrue; - if ( e ) { + if ( e && !this.isSimulated ) { e.stopImmediatePropagation(); } diff --git a/src/event/trigger.js b/src/event/trigger.js index a6fac70ea9..75b9dd2851 100644 --- a/src/event/trigger.js +++ b/src/event/trigger.js @@ -148,6 +148,7 @@ jQuery.extend( jQuery.event, { }, // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events simulate: function( type, elem, event ) { var e = jQuery.extend( new jQuery.Event(), @@ -155,27 +156,10 @@ jQuery.extend( jQuery.event, { { type: type, isSimulated: true - - // Previously, `originalEvent: {}` was set here, so stopPropagation call - // would not be triggered on donor event, since in our own - // jQuery.event.stopPropagation function we had a check for existence of - // originalEvent.stopPropagation method, so, consequently it would be a noop. - // - // But now, this "simulate" function is used only for events - // for which stopPropagation() is noop, so there is no need for that anymore. - // - // For the 1.x branch though, guard for "click" and "submit" - // events is still used, but was moved to jQuery.event.stopPropagation function - // because `originalEvent` should point to the original event for the constancy - // with other events and for more focused logic } ); jQuery.event.trigger( e, null, elem ); - - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } } } ); diff --git a/test/unit/event.js b/test/unit/event.js index 04ca615eb0..20c2a6dafc 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -2846,6 +2846,81 @@ QUnit.test( "Donor event interference", function( assert ) { jQuery( "#donor-input" )[ 0 ].click(); } ); +QUnit.test( + "native stop(Immediate)Propagation/preventDefault methods shouldn't be called", + function( assert ) { + var userAgent = window.navigator.userAgent; + + if ( !( /firefox/i.test( userAgent ) || /safari/i.test( userAgent ) ) ) { + assert.expect( 1 ); + assert.ok( true, "Assertions should run only in Chrome, Safari, Fx & Edge" ); + return; + } + + assert.expect( 3 ); + + var checker = {}; + + var html = "
    " + + "
    " + + "" + + "
    " + + "
    "; + + jQuery( "#qunit-fixture" ).append( html ); + var outer = jQuery( "#donor-outer" ); + + outer + .on( "focusin", function( event ) { + checker.prevent = sinon.stub( event.originalEvent, "preventDefault" ); + event.preventDefault(); + } ) + .on( "focusin", function( event ) { + checker.simple = sinon.stub( event.originalEvent, "stopPropagation" ); + event.stopPropagation(); + } ) + .on( "focusin", function( event ) { + checker.immediate = sinon.stub( event.originalEvent, "stopImmediatePropagation" ); + event.stopImmediatePropagation(); + } ); + + jQuery( "#donor-input" ).trigger( "focus" ); + assert.strictEqual( checker.simple.called, false ); + assert.strictEqual( checker.immediate.called, false ); + assert.strictEqual( checker.prevent.called, false ); + + // We need to "off" it, since yes QUnit always update the fixtures + // but "focus" event listener is attached to document for focus(in | out) + // event and document doesn't get cleared obviously :) + outer.off( "focusin" ); + } +); + +QUnit.test( + "isSimulated property always exist on event object", + function( assert ) { + var userAgent = window.navigator.userAgent; + + if ( !( /firefox/i.test( userAgent ) || /safari/i.test( userAgent ) ) ) { + assert.expect( 1 ); + assert.ok( true, "Assertions should run only in Chrome, Safari, Fx & Edge" ); + return; + } + + assert.expect( 1 ); + + var element = jQuery( "" ); + + jQuery( "#qunit-fixture" ).append( element ); + + element.on( "focus", function( event ) { + assert.notOk( event.isSimulated ); + } ); + + element.trigger( "focus" ); + } +); + QUnit.test( "originalEvent property for Chrome, Safari, Fx & Edge of simulated event", function( assert ) { var userAgent = window.navigator.userAgent; @@ -2856,6 +2931,7 @@ QUnit.test( "originalEvent property for Chrome, Safari, Fx & Edge of simulated e } assert.expect( 4 ); + var done = assert.async(); var html = "
    " + "
    " + @@ -2864,17 +2940,25 @@ QUnit.test( "originalEvent property for Chrome, Safari, Fx & Edge of simulated e "
    "; jQuery( "#qunit-fixture" ).append( html ); + var outer = jQuery( "#donor-outer" ); - jQuery( "#donor-outer" ).on( "focusin", function( event ) { - assert.ok( true, "focusin bubbled to outer div" ); - assert.equal( event.originalEvent.type, "focus", - "make sure originalEvent type is correct" ); - assert.equal( event.type, "focusin", "make sure type is correct" ); - } ); + outer + .on( "focusin", function( event ) { + assert.ok( true, "focusin bubbled to outer div" ); + assert.equal( event.originalEvent.type, "focus", + "make sure originalEvent type is correct" ); + assert.equal( event.type, "focusin", "make sure type is correct" ); + } ); jQuery( "#donor-input" ).on( "focus", function() { assert.ok( true, "got a focus event from the input" ); + done(); } ); jQuery( "#donor-input" ).trigger( "focus" ); + + // We need to "off" it, since yes QUnit always update the fixtures + // but "focus" event listener is attached to document for focus(in | out) + // event and document doesn't get cleared obviously :) + outer.off( "focusin" ); } ); QUnit[ jQuery.fn.click ? "test" : "skip" ]( "trigger() shortcuts", function( assert ) { From afe2727c5610ba9cd5ffbec5c34f15d38538b05f Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Thu, 19 May 2016 22:24:46 +0300 Subject: [PATCH 107/114] Build: Bump qunit version So it would correspond to one in master --- external/qunit/LICENSE.txt | 7 +- external/qunit/qunit.css | 41 +- external/qunit/qunit.js | 3841 +++++++++++++++++++++++++----------- package.json | 2 +- 4 files changed, 2687 insertions(+), 1204 deletions(-) diff --git a/external/qunit/LICENSE.txt b/external/qunit/LICENSE.txt index fb928a5432..a3a9b5120d 100644 --- a/external/qunit/LICENSE.txt +++ b/external/qunit/LICENSE.txt @@ -30,7 +30,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ==== -All files located in the node_modules and external directories are -externally maintained libraries used by this software which have their -own licenses; we recommend you read them, as their terms may differ from -the terms above. +All files located in the node_modules directory are externally maintained +libraries used by this software which have their own licenses; we +recommend you read them, as their terms may differ from the terms above. diff --git a/external/qunit/qunit.css b/external/qunit/qunit.css index 0eb0b0171d..ae68fc412e 100644 --- a/external/qunit/qunit.css +++ b/external/qunit/qunit.css @@ -1,27 +1,27 @@ /*! - * QUnit 1.17.1 - * http://qunitjs.com/ + * QUnit 1.23.1 + * https://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license - * http://jquery.org/license + * https://jquery.org/license * - * Date: 2015-01-20T19:39Z + * Date: 2016-04-12T17:29Z */ /** Font Family and Sizes */ -#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult { font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; } -#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } #qunit-tests { font-size: smaller; } /** Resets */ -#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { +#qunit-tests, #qunit-header, #qunit-banner, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { margin: 0; padding: 0; } @@ -68,6 +68,12 @@ overflow: hidden; } +#qunit-filteredTest { + padding: 0.5em 1em 0.5em 1em; + background-color: #F4FF77; + color: #366097; +} + #qunit-userAgent { padding: 0.5em 1em 0.5em 1em; background-color: #2B81AF; @@ -114,9 +120,19 @@ display: list-item; } +#qunit-tests.hidepass { + position: relative; +} + #qunit-tests.hidepass li.running, #qunit-tests.hidepass li.pass { - display: none; + visibility: hidden; + position: absolute; + width: 0; + height: 0; + padding: 0; + border: 0; + margin: 0; } #qunit-tests li strong { @@ -132,6 +148,11 @@ color: #C2CCD1; text-decoration: none; } + +#qunit-tests li p a { + padding: 0.25em; + color: #6B6464; +} #qunit-tests li a:hover, #qunit-tests li a:focus { color: #000; @@ -151,6 +172,10 @@ border-radius: 5px; } +.qunit-source { + margin: 0.6em 0 0.3em; +} + .qunit-collapsed { display: none; } diff --git a/external/qunit/qunit.js b/external/qunit/qunit.js index 006ca47474..5df0822ea4 100644 --- a/external/qunit/qunit.js +++ b/external/qunit/qunit.js @@ -1,146 +1,259 @@ /*! - * QUnit 1.17.1 - * http://qunitjs.com/ + * QUnit 1.23.1 + * https://qunitjs.com/ * * Copyright jQuery Foundation and other contributors * Released under the MIT license - * http://jquery.org/license + * https://jquery.org/license * - * Date: 2015-01-20T19:39Z + * Date: 2016-04-12T17:29Z */ -(function( window ) { +( function( global ) { -var QUnit, - config, - onErrorFnPrev, - loggingCallbacks = {}, - fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ), - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - // Keep a local reference to Date (GH-283) - Date = window.Date, - now = Date.now || function() { - return new Date().getTime(); - }, - globalStartCalled = false, - runStarted = false, - setTimeout = window.setTimeout, - clearTimeout = window.clearTimeout, - defined = { - document: window.document !== undefined, - setTimeout: window.setTimeout !== undefined, - sessionStorage: (function() { - var x = "qunit-test-string"; - try { - sessionStorage.setItem( x, x ); - sessionStorage.removeItem( x ); - return true; - } catch ( e ) { - return false; +var QUnit = {}; + +var Date = global.Date; +var now = Date.now || function() { + return new Date().getTime(); +}; + +var setTimeout = global.setTimeout; +var clearTimeout = global.clearTimeout; + +// Store a local window from the global to allow direct references. +var window = global.window; + +var defined = { + document: window && window.document !== undefined, + setTimeout: setTimeout !== undefined, + sessionStorage: ( function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch ( e ) { + return false; + } + }() ) +}; + +var fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ); +var globalStartCalled = false; +var runStarted = false; + +var toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty; + +// Returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { + if ( result[ i ] === b[ j ] ) { + result.splice( i, 1 ); + i--; + break; } - }()) - }, - /** - * Provides a normalized error string, correcting an issue - * with IE 7 (and prior) where Error.prototype.toString is - * not properly implemented - * - * Based on http://es5.github.com/#x15.11.4.4 - * - * @param {String|Error} error - * @return {String} error message - */ - errorString = function( error ) { - var name, message, - errorString = error.toString(); - if ( errorString.substring( 0, 7 ) === "[object" ) { - name = error.name ? error.name.toString() : "Error"; - message = error.message ? error.message.toString() : ""; - if ( name && message ) { - return name + ": " + message; - } else if ( name ) { - return name; - } else if ( message ) { - return message; - } else { - return "Error"; + } + } + return result; +} + +// From jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +/** + * Makes a clone of an object using only Array or Object as base, + * and copies over the own enumerable properties. + * + * @param {Object} obj + * @return {Object} New object with only the own properties (recursively). + */ +function objectValues ( obj ) { + var key, val, + vals = QUnit.is( "array", obj ) ? [] : {}; + for ( key in obj ) { + if ( hasOwn.call( obj, key ) ) { + val = obj[ key ]; + vals[ key ] = val === Object( val ) ? objectValues( val ) : val; + } + } + return vals; +} + +function extend( a, b, undefOnly ) { + for ( var prop in b ) { + if ( hasOwn.call( b, prop ) ) { + + // Avoid "Member not found" error in IE8 caused by messing with window.constructor + // This block runs on every environment, so `global` is being used instead of `window` + // to avoid errors on node. + if ( prop !== "constructor" || a !== global ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) { + a[ prop ] = b[ prop ]; + } } - } else { - return errorString; } - }, - /** - * Makes a clone of an object using only Array or Object as base, - * and copies over the own enumerable properties. - * - * @param {Object} obj - * @return {Object} New object with only the own properties (recursively). - */ - objectValues = function( obj ) { - var key, val, - vals = QUnit.is( "array", obj ) ? [] : {}; - for ( key in obj ) { - if ( hasOwn.call( obj, key ) ) { - val = obj[ key ]; - vals[ key ] = val === Object( val ) ? objectValues( val ) : val; + } + + return a; +} + +function objectType( obj ) { + if ( typeof obj === "undefined" ) { + return "undefined"; + } + + // Consider: typeof null === object + if ( obj === null ) { + return "null"; + } + + var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ), + type = match && match[ 1 ]; + + switch ( type ) { + case "Number": + if ( isNaN( obj ) ) { + return "nan"; + } + return "number"; + case "String": + case "Boolean": + case "Array": + case "Set": + case "Map": + case "Date": + case "RegExp": + case "Function": + case "Symbol": + return type.toLowerCase(); + } + if ( typeof obj === "object" ) { + return "object"; + } +} + +// Safe object type checking +function is( type, obj ) { + return QUnit.objectType( obj ) === type; +} + +// Doesn't support IE6 to IE9, it will return undefined on these browsers +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 4 : offset; + + var stack, include, i; + + if ( e.stack ) { + stack = e.stack.split( "\n" ); + if ( /^error$/i.test( stack[ 0 ] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) !== -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); } } - return vals; - }; + return stack[ offset ]; + + // Support: Safari <=6 only + } else if ( e.sourceURL ) { + + // Exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + + // For actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} + +function sourceFromStacktrace( offset ) { + var error = new Error(); + + // Support: Safari <=7 only, IE <=10 - 11 only + // Not all browsers generate the `stack` property for `new Error()`, see also #636 + if ( !error.stack ) { + try { + throw error; + } catch ( err ) { + error = err; + } + } -QUnit = {}; + return extractStacktrace( error, offset ); +} /** * Config object: Maintain internal state * Later exposed as QUnit.config * `config` initialized at top of scope */ -config = { +var config = { + // The queue of tests to run queue: [], - // block until document ready + // Block until document ready blocking: true, - // by default, run previously failed tests first + // By default, run previously failed tests first // very useful in combination with "Hide passed tests" checked reorder: true, - // by default, modify document.title when suite is done + // By default, modify document.title when suite is done altertitle: true, - // by default, scroll to top of the page when suite is done + // HTML Reporter: collapse every test except the first failing test + // If false, all failing tests will be expanded + collapse: true, + + // By default, scroll to top of the page when suite is done scrolltop: true, - // when enabled, all tests must call expect() + // Depth up-to which object will be dumped + maxDepth: 5, + + // When enabled, all tests must call expect() requireExpects: false, - // add checkboxes that are persisted in the query-string - // when enabled, the id is set to `true` as a `QUnit.config` property - urlConfig: [ - { - id: "hidepassed", - label: "Hide passed tests", - tooltip: "Only show tests and assertions that fail. Stored as query-strings." - }, - { - id: "noglobals", - label: "Check for Globals", - tooltip: "Enabling this will test if any test introduces new properties on the " + - "`window` object. Stored as query-strings." - }, - { - id: "notrycatch", - label: "No try-catch", - tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " + - "exceptions in IE reasonable. Stored as query-strings." - } - ], + // Placeholder for user-configurable form-exposed URL parameters + urlConfig: [], // Set of all modules. modules: [], + // Stack of nested modules + moduleStack: [], + // The first unnamed module currentModule: { name: "", @@ -153,63 +266,139 @@ config = { // Push a loose unnamed module to the modules collection config.modules.push( config.currentModule ); -// Initialize more QUnit.config and QUnit.urlParams -(function() { - var i, current, - location = window.location || { search: "", protocol: "file:" }, - params = location.search.slice( 1 ).split( "&" ), - length = params.length, - urlParams = {}; - - if ( params[ 0 ] ) { - for ( i = 0; i < length; i++ ) { - current = params[ i ].split( "=" ); - current[ 0 ] = decodeURIComponent( current[ 0 ] ); - - // allow just a key to turn on a flag, e.g., test.html?noglobals - current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; - if ( urlParams[ current[ 0 ] ] ) { - urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] ); - } else { - urlParams[ current[ 0 ] ] = current[ 1 ]; +var loggingCallbacks = {}; + +// Register logging callbacks +function registerLoggingCallbacks( obj ) { + var i, l, key, + callbackNames = [ "begin", "done", "log", "testStart", "testDone", + "moduleStart", "moduleDone" ]; + + function registerLoggingCallback( key ) { + var loggingCallback = function( callback ) { + if ( objectType( callback ) !== "function" ) { + throw new Error( + "QUnit logging methods require a callback function as their first parameters." + ); } + + config.callbacks[ key ].push( callback ); + }; + + // DEPRECATED: This will be removed on QUnit 2.0.0+ + // Stores the registered functions allowing restoring + // at verifyLoggingCallbacks() if modified + loggingCallbacks[ key ] = loggingCallback; + + return loggingCallback; + } + + for ( i = 0, l = callbackNames.length; i < l; i++ ) { + key = callbackNames[ i ]; + + // Initialize key collection of logging callback + if ( objectType( config.callbacks[ key ] ) === "undefined" ) { + config.callbacks[ key ] = []; } + + obj[ key ] = registerLoggingCallback( key ); } +} + +function runLoggingCallbacks( key, args ) { + var i, l, callbacks; - if ( urlParams.filter === true ) { - delete urlParams.filter; + callbacks = config.callbacks[ key ]; + for ( i = 0, l = callbacks.length; i < l; i++ ) { + callbacks[ i ]( args ); } +} + +// DEPRECATED: This will be removed on 2.0.0+ +// This function verifies if the loggingCallbacks were modified by the user +// If so, it will restore it, assign the given callback and print a console warning +function verifyLoggingCallbacks() { + var loggingCallback, userCallback; + + for ( loggingCallback in loggingCallbacks ) { + if ( QUnit[ loggingCallback ] !== loggingCallbacks[ loggingCallback ] ) { - QUnit.urlParams = urlParams; + userCallback = QUnit[ loggingCallback ]; - // String search anywhere in moduleName+testName - config.filter = urlParams.filter; + // Restore the callback function + QUnit[ loggingCallback ] = loggingCallbacks[ loggingCallback ]; - config.testId = []; - if ( urlParams.testId ) { + // Assign the deprecated given callback + QUnit[ loggingCallback ]( userCallback ); - // Ensure that urlParams.testId is an array - urlParams.testId = [].concat( urlParams.testId ); - for ( i = 0; i < urlParams.testId.length; i++ ) { - config.testId.push( urlParams.testId[ i ] ); + if ( global.console && global.console.warn ) { + global.console.warn( + "QUnit." + loggingCallback + " was replaced with a new value.\n" + + "Please, check out the documentation on how to apply logging callbacks.\n" + + "Reference: https://api.qunitjs.com/category/callbacks/" + ); + } } } +} + +( function() { + if ( !defined.document ) { + return; + } + + // `onErrorFnPrev` initialized at top of scope + // Preserve other handlers + var onErrorFnPrev = window.onerror; + + // Cover uncaught exceptions + // Returning true will suppress the default browser handler, + // returning false will let it run. + window.onerror = function( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not suppressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", extend( function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }, { validTest: true } ) ); + } + return false; + } + + return ret; + }; +}() ); + +// Figure out if we're running the tests from a server or not +QUnit.isLocal = !( defined.document && window.location.protocol !== "file:" ); - // Figure out if we're running the tests from a server or not - QUnit.isLocal = location.protocol === "file:"; -}()); +// Expose the current QUnit version +QUnit.version = "1.23.1"; -// Root QUnit object. -// `QUnit` initialized at top of scope extend( QUnit, { - // call on start of module test to prepend name to all tests - module: function( name, testEnvironment ) { - var currentModule = { - name: name, - testEnvironment: testEnvironment, - tests: [] - }; + // Call on start of module test to prepend name to all tests + module: function( name, testEnvironment, executeNow ) { + var module, moduleFns; + var currentModule = config.currentModule; + + if ( arguments.length === 2 ) { + if ( objectType( testEnvironment ) === "function" ) { + executeNow = testEnvironment; + testEnvironment = undefined; + } + } // DEPRECATED: handles setup/teardown functions, // beforeEach and afterEach should be used instead @@ -222,46 +411,62 @@ extend( QUnit, { delete testEnvironment.teardown; } - config.modules.push( currentModule ); - config.currentModule = currentModule; - }, + module = createModule(); - // DEPRECATED: QUnit.asyncTest() will be removed in QUnit 2.0. - asyncTest: function( testName, expected, callback ) { - if ( arguments.length === 2 ) { - callback = expected; - expected = null; + moduleFns = { + beforeEach: setHook( module, "beforeEach" ), + afterEach: setHook( module, "afterEach" ) + }; + + if ( objectType( executeNow ) === "function" ) { + config.moduleStack.push( module ); + setCurrentModule( module ); + executeNow.call( module.testEnvironment, moduleFns ); + config.moduleStack.pop(); + module = module.parentModule || currentModule; } - QUnit.test( testName, expected, callback, true ); - }, + setCurrentModule( module ); + + function createModule() { + var parentModule = config.moduleStack.length ? + config.moduleStack.slice( -1 )[ 0 ] : null; + var moduleName = parentModule !== null ? + [ parentModule.name, name ].join( " > " ) : name; + var module = { + name: moduleName, + parentModule: parentModule, + tests: [], + moduleId: generateHash( moduleName ) + }; - test: function( testName, expected, callback, async ) { - var test; + var env = {}; + if ( parentModule ) { + extend( env, parentModule.testEnvironment ); + delete env.beforeEach; + delete env.afterEach; + } + extend( env, testEnvironment ); + module.testEnvironment = env; - if ( arguments.length === 2 ) { - callback = expected; - expected = null; + config.modules.push( module ); + return module; } - test = new Test({ - testName: testName, - expected: expected, - async: async, - callback: callback - }); + function setCurrentModule( module ) { + config.currentModule = module; + } - test.queue(); }, - skip: function( testName ) { - var test = new Test({ - testName: testName, - skip: true - }); + // DEPRECATED: QUnit.asyncTest() will be removed in QUnit 2.0. + asyncTest: asyncTest, - test.queue(); - }, + test: test, + + skip: skip, + + only: only, // DEPRECATED: The functionality of QUnit.start() will be altered in QUnit 2.0. // In QUnit 2.0, invoking it will ONLY affect the `QUnit.config.autostart` blocking behavior. @@ -289,12 +494,23 @@ extend( QUnit, { // If a test is running, adjust its semaphore config.current.semaphore -= count || 1; + // If semaphore is non-numeric, throw error + if ( isNaN( config.current.semaphore ) ) { + config.current.semaphore = 0; + + QUnit.pushFailure( + "Called start() with a non-numeric decrement.", + sourceFromStacktrace( 2 ) + ); + return; + } + // Don't start until equal number of stop-calls if ( config.current.semaphore > 0 ) { return; } - // throw an Error if start is called more often than stop + // Throw an Error if start is called more often than stop if ( config.current.semaphore < 0 ) { config.current.semaphore = 0; @@ -325,43 +541,9 @@ extend( QUnit, { config: config, - // Safe object type checking - is: function( type, obj ) { - return QUnit.objectType( obj ) === type; - }, - - objectType: function( obj ) { - if ( typeof obj === "undefined" ) { - return "undefined"; - } - - // Consider: typeof null === object - if ( obj === null ) { - return "null"; - } - - var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ), - type = match && match[ 1 ] || ""; + is: is, - switch ( type ) { - case "Number": - if ( isNaN( obj ) ) { - return "nan"; - } - return "number"; - case "String": - case "Boolean": - case "Array": - case "Date": - case "RegExp": - case "Function": - return type.toLowerCase(); - } - if ( typeof obj === "object" ) { - return "object"; - } - return undefined; - }, + objectType: objectType, extend: extend, @@ -383,176 +565,50 @@ extend( QUnit, { if ( config.autostart ) { resumeProcessing(); } + }, + + stack: function( offset ) { + offset = ( offset || 0 ) + 2; + return sourceFromStacktrace( offset ); } -}); +} ); -// Register logging callbacks -(function() { - var i, l, key, - callbacks = [ "begin", "done", "log", "testStart", "testDone", - "moduleStart", "moduleDone" ]; +registerLoggingCallbacks( QUnit ); - function registerLoggingCallback( key ) { - var loggingCallback = function( callback ) { - if ( QUnit.objectType( callback ) !== "function" ) { - throw new Error( - "QUnit logging methods require a callback function as their first parameters." - ); - } - - config.callbacks[ key ].push( callback ); - }; - - // DEPRECATED: This will be removed on QUnit 2.0.0+ - // Stores the registered functions allowing restoring - // at verifyLoggingCallbacks() if modified - loggingCallbacks[ key ] = loggingCallback; - - return loggingCallback; - } - - for ( i = 0, l = callbacks.length; i < l; i++ ) { - key = callbacks[ i ]; - - // Initialize key collection of logging callback - if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) { - config.callbacks[ key ] = []; - } - - QUnit[ key ] = registerLoggingCallback( key ); - } -})(); - -// `onErrorFnPrev` initialized at top of scope -// Preserve other handlers -onErrorFnPrev = window.onerror; - -// Cover uncaught exceptions -// Returning true will suppress the default browser handler, -// returning false will let it run. -window.onerror = function( error, filePath, linerNr ) { - var ret = false; - if ( onErrorFnPrev ) { - ret = onErrorFnPrev( error, filePath, linerNr ); - } - - // Treat return value as window.onerror itself does, - // Only do our handling if not suppressed. - if ( ret !== true ) { - if ( QUnit.config.current ) { - if ( QUnit.config.current.ignoreGlobalErrors ) { - return true; - } - QUnit.pushFailure( error, filePath + ":" + linerNr ); - } else { - QUnit.test( "global failure", extend(function() { - QUnit.pushFailure( error, filePath + ":" + linerNr ); - }, { validTest: true } ) ); - } - return false; - } - - return ret; -}; - -function done() { - var runtime, passed; - - config.autorun = true; - - // Log the last module results - if ( config.previousModule ) { - runLoggingCallbacks( "moduleDone", { - name: config.previousModule.name, - tests: config.previousModule.tests, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all, - runtime: now() - config.moduleStats.started - }); - } - delete config.previousModule; - - runtime = now() - config.started; - passed = config.stats.all - config.stats.bad; - - runLoggingCallbacks( "done", { - failed: config.stats.bad, - passed: passed, - total: config.stats.all, - runtime: runtime - }); -} - -// Doesn't support IE6 to IE9 -// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack -function extractStacktrace( e, offset ) { - offset = offset === undefined ? 4 : offset; - - var stack, include, i; +function begin() { + var i, l, + modulesLog = []; - if ( e.stacktrace ) { + // If the test run hasn't officially begun yet + if ( !config.started ) { - // Opera 12.x - return e.stacktrace.split( "\n" )[ offset + 3 ]; - } else if ( e.stack ) { + // Record the time of the test run's beginning + config.started = now(); - // Firefox, Chrome, Safari 6+, IE10+, PhantomJS and Node - stack = e.stack.split( "\n" ); - if ( /^error$/i.test( stack[ 0 ] ) ) { - stack.shift(); - } - if ( fileName ) { - include = []; - for ( i = offset; i < stack.length; i++ ) { - if ( stack[ i ].indexOf( fileName ) !== -1 ) { - break; - } - include.push( stack[ i ] ); - } - if ( include.length ) { - return include.join( "\n" ); - } - } - return stack[ offset ]; - } else if ( e.sourceURL ) { + verifyLoggingCallbacks(); - // Safari < 6 - // exclude useless self-reference for generated Error objects - if ( /qunit.js$/.test( e.sourceURL ) ) { - return; + // Delete the loose unnamed module if unused. + if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) { + config.modules.shift(); } - // for actual exceptions, this is useful - return e.sourceURL + ":" + e.line; - } -} - -function sourceFromStacktrace( offset ) { - var e = new Error(); - if ( !e.stack ) { - try { - throw e; - } catch ( err ) { - // This should already be true in most browsers - e = err; + // Avoid unnecessary information by not logging modules' test environments + for ( i = 0, l = config.modules.length; i < l; i++ ) { + modulesLog.push( { + name: config.modules[ i ].name, + tests: config.modules[ i ].tests + } ); } - } - return extractStacktrace( e, offset ); -} -function synchronize( callback, last ) { - if ( QUnit.objectType( callback ) === "array" ) { - while ( callback.length ) { - synchronize( callback.shift() ); - } - return; + // The test run is officially beginning now + runLoggingCallbacks( "begin", { + totalTests: Test.count, + modules: modulesLog + } ); } - config.queue.push( callback ); - if ( config.autorun && !config.blocking ) { - process( last ); - } + config.blocking = false; + process( true ); } function process( last ) { @@ -582,40 +638,21 @@ function process( last ) { } } -function begin() { - var i, l, - modulesLog = []; - - // If the test run hasn't officially begun yet - if ( !config.started ) { - - // Record the time of the test run's beginning - config.started = now(); - - verifyLoggingCallbacks(); - - // Delete the loose unnamed module if unused. - if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) { - config.modules.shift(); - } - - // Avoid unnecessary information by not logging modules' test environments - for ( i = 0, l = config.modules.length; i < l; i++ ) { - modulesLog.push({ - name: config.modules[ i ].name, - tests: config.modules[ i ].tests - }); - } +function pauseProcessing() { + config.blocking = true; - // The test run is officially beginning now - runLoggingCallbacks( "begin", { - totalTests: Test.count, - modules: modulesLog - }); + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = setTimeout( function() { + if ( config.current ) { + config.current.semaphore = 0; + QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) ); + } else { + throw new Error( "Test timed out" ); + } + resumeProcessing(); + }, config.testTimeout ); } - - config.blocking = false; - process( true ); } function resumeProcessing() { @@ -623,7 +660,7 @@ function resumeProcessing() { // A slight delay to allow this iteration of the event loop to finish (more assertions, etc.) if ( defined.setTimeout ) { - setTimeout(function() { + setTimeout( function() { if ( config.current && config.current.semaphore > 0 ) { return; } @@ -638,169 +675,74 @@ function resumeProcessing() { } } -function pauseProcessing() { - config.blocking = true; - - if ( config.testTimeout && defined.setTimeout ) { - clearTimeout( config.timeout ); - config.timeout = setTimeout(function() { - if ( config.current ) { - config.current.semaphore = 0; - QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) ); - } else { - throw new Error( "Test timed out" ); - } - resumeProcessing(); - }, config.testTimeout ); - } -} +function done() { + var runtime, passed; -function saveGlobal() { - config.pollution = []; + config.autorun = true; - if ( config.noglobals ) { - for ( var key in window ) { - if ( hasOwn.call( window, key ) ) { - // in Opera sometimes DOM element ids show up here, ignore them - if ( /^qunit-test-output/.test( key ) ) { - continue; - } - config.pollution.push( key ); - } - } + // Log the last module results + if ( config.previousModule ) { + runLoggingCallbacks( "moduleDone", { + name: config.previousModule.name, + tests: config.previousModule.tests, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all, + runtime: now() - config.moduleStats.started + } ); } -} + delete config.previousModule; -function checkPollution() { - var newGlobals, - deletedGlobals, - old = config.pollution; + runtime = now() - config.started; + passed = config.stats.all - config.stats.bad; - saveGlobal(); + runLoggingCallbacks( "done", { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + } ); +} - newGlobals = diff( config.pollution, old ); - if ( newGlobals.length > 0 ) { - QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) ); +function setHook( module, hookName ) { + if ( module.testEnvironment === undefined ) { + module.testEnvironment = {}; } - deletedGlobals = diff( old, config.pollution ); - if ( deletedGlobals.length > 0 ) { - QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) ); - } + return function( callback ) { + module.testEnvironment[ hookName ] = callback; + }; } -// returns a new Array with the elements that are in a but not in b -function diff( a, b ) { - var i, j, - result = a.slice(); +var focused = false; +var priorityCount = 0; +var unitSampler; - for ( i = 0; i < result.length; i++ ) { - for ( j = 0; j < b.length; j++ ) { - if ( result[ i ] === b[ j ] ) { - result.splice( i, 1 ); - i--; - break; - } - } - } - return result; -} - -function extend( a, b, undefOnly ) { - for ( var prop in b ) { - if ( hasOwn.call( b, prop ) ) { - - // Avoid "Member not found" error in IE8 caused by messing with window.constructor - if ( !( prop === "constructor" && a === window ) ) { - if ( b[ prop ] === undefined ) { - delete a[ prop ]; - } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) { - a[ prop ] = b[ prop ]; - } - } - } - } - - return a; -} - -function runLoggingCallbacks( key, args ) { - var i, l, callbacks; - - callbacks = config.callbacks[ key ]; - for ( i = 0, l = callbacks.length; i < l; i++ ) { - callbacks[ i ]( args ); - } -} - -// DEPRECATED: This will be removed on 2.0.0+ -// This function verifies if the loggingCallbacks were modified by the user -// If so, it will restore it, assign the given callback and print a console warning -function verifyLoggingCallbacks() { - var loggingCallback, userCallback; - - for ( loggingCallback in loggingCallbacks ) { - if ( QUnit[ loggingCallback ] !== loggingCallbacks[ loggingCallback ] ) { - - userCallback = QUnit[ loggingCallback ]; - - // Restore the callback function - QUnit[ loggingCallback ] = loggingCallbacks[ loggingCallback ]; - - // Assign the deprecated given callback - QUnit[ loggingCallback ]( userCallback ); - - if ( window.console && window.console.warn ) { - window.console.warn( - "QUnit." + loggingCallback + " was replaced with a new value.\n" + - "Please, check out the documentation on how to apply logging callbacks.\n" + - "Reference: http://api.qunitjs.com/category/callbacks/" - ); - } - } - } -} - -// from jquery.js -function inArray( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); - } - - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; - } - } - - return -1; -} - -function Test( settings ) { - var i, l; - - ++Test.count; - - extend( this, settings ); - this.assertions = []; - this.semaphore = 0; - this.usedAsync = false; - this.module = config.currentModule; - this.stack = sourceFromStacktrace( 3 ); - - // Register unique strings - for ( i = 0, l = this.module.tests; i < l.length; i++ ) { - if ( this.module.tests[ i ].name === this.testName ) { - this.testName += " "; +function Test( settings ) { + var i, l; + + ++Test.count; + + extend( this, settings ); + this.assertions = []; + this.semaphore = 0; + this.usedAsync = false; + this.module = config.currentModule; + this.stack = sourceFromStacktrace( 3 ); + + // Register unique strings + for ( i = 0, l = this.module.tests; i < l.length; i++ ) { + if ( this.module.tests[ i ].name === this.testName ) { + this.testName += " "; } } this.testId = generateHash( this.module.name, this.testName ); - this.module.tests.push({ + this.module.tests.push( { name: this.testName, testId: this.testId - }); + } ); if ( settings.skip ) { @@ -836,28 +778,30 @@ Test.prototype = { passed: config.moduleStats.all - config.moduleStats.bad, total: config.moduleStats.all, runtime: now() - config.moduleStats.started - }); + } ); } config.previousModule = this.module; config.moduleStats = { all: 0, bad: 0, started: now() }; runLoggingCallbacks( "moduleStart", { name: this.module.name, tests: this.module.tests - }); + } ); } config.current = this; + if ( this.module.testEnvironment ) { + delete this.module.testEnvironment.beforeEach; + delete this.module.testEnvironment.afterEach; + } this.testEnvironment = extend( {}, this.module.testEnvironment ); - delete this.testEnvironment.beforeEach; - delete this.testEnvironment.afterEach; this.started = now(); runLoggingCallbacks( "testStart", { name: this.testName, module: this.module.name, testId: this.testId - }); + } ); if ( !config.pollution ) { saveGlobal(); @@ -876,19 +820,17 @@ Test.prototype = { this.callbackStarted = now(); if ( config.notrycatch ) { - promise = this.callback.call( this.testEnvironment, this.assert ); - this.resolvePromise( promise ); + runTest( this ); return; } try { - promise = this.callback.call( this.testEnvironment, this.assert ); - this.resolvePromise( promise ); + runTest( this ); } catch ( e ) { this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) ); - // else next test will carry the responsibility + // Else next test will carry the responsibility saveGlobal(); // Restart the tests if they're blocking @@ -896,6 +838,11 @@ Test.prototype = { QUnit.start(); } } + + function runTest( test ) { + promise = test.callback.call( test.testEnvironment, test.assert ); + test.resolvePromise( promise ); + } }, after: function() { @@ -908,16 +855,19 @@ Test.prototype = { return function runHook() { config.current = test; if ( config.notrycatch ) { - promise = hook.call( test.testEnvironment, test.assert ); - test.resolvePromise( promise, hookName ); + callHook(); return; } try { - promise = hook.call( test.testEnvironment, test.assert ); - test.resolvePromise( promise, hookName ); + callHook(); } catch ( error ) { test.pushFailure( hookName + " failed on " + test.testName + ": " + - ( error.message || error ), extractStacktrace( error, 0 ) ); + ( error.message || error ), extractStacktrace( error, 0 ) ); + } + + function callHook() { + promise = hook.call( test.testEnvironment, test.assert ); + test.resolvePromise( promise, hookName ); } }; }, @@ -926,16 +876,20 @@ Test.prototype = { hooks: function( handler ) { var hooks = []; - // Hooks are ignored on skipped tests - if ( this.skip ) { - return hooks; + function processHooks( test, module ) { + if ( module.parentModule ) { + processHooks( test, module.parentModule ); + } + if ( module.testEnvironment && + QUnit.objectType( module.testEnvironment[ handler ] ) === "function" ) { + hooks.push( test.queueHook( module.testEnvironment[ handler ], handler ) ); + } } - if ( this.module.testEnvironment && - QUnit.objectType( this.module.testEnvironment[ handler ] ) === "function" ) { - hooks.push( this.queueHook( this.module.testEnvironment[ handler ], handler ) ); + // Hooks are ignored on skipped tests + if ( !this.skip ) { + processHooks( this, this.module ); } - return hooks; }, @@ -980,9 +934,12 @@ Test.prototype = { assertions: this.assertions, testId: this.testId, + // Source of Test + source: this.stack, + // DEPRECATED: this property will be removed in 2.0.0, use runtime instead duration: this.runtime - }); + } ); // QUnit.reset() is deprecated and will be replaced for a new // fixture reset function on QUnit 2.0/2.1. @@ -993,7 +950,7 @@ Test.prototype = { }, queue: function() { - var bad, + var priority, test = this; if ( !this.valid() ) { @@ -1002,14 +959,13 @@ Test.prototype = { function run() { - // each of these can by async - synchronize([ + // Each of these can by async + synchronize( [ function() { test.before(); }, test.hooks( "beforeEach" ), - function() { test.run(); }, @@ -1022,35 +978,33 @@ Test.prototype = { function() { test.finish(); } - ]); + ] ); } - // `bad` initialized at top of scope - // defer when previous test run passed, if storage is available - bad = QUnit.config.reorder && defined.sessionStorage && + // Prioritize previously failed tests, detected from sessionStorage + priority = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName ); - if ( bad ) { - run(); - } else { - synchronize( run, true ); - } + return synchronize( run, priority, config.seed ); }, - push: function( result, actual, expected, message ) { + pushResult: function( resultInfo ) { + + // Destructure of resultInfo = { result, actual, expected, message, negative } var source, details = { module: this.module.name, name: this.testName, - result: result, - message: message, - actual: actual, - expected: expected, + result: resultInfo.result, + message: resultInfo.message, + actual: resultInfo.actual, + expected: resultInfo.expected, testId: this.testId, + negative: resultInfo.negative || false, runtime: now() - this.started }; - if ( !result ) { + if ( !resultInfo.result ) { source = sourceFromStacktrace(); if ( source ) { @@ -1060,14 +1014,14 @@ Test.prototype = { runLoggingCallbacks( "log", details ); - this.assertions.push({ - result: !!result, - message: message - }); + this.assertions.push( { + result: !!resultInfo.result, + message: resultInfo.message + } ); }, pushFailure: function( message, source, actual ) { - if ( !this instanceof Test ) { + if ( !( this instanceof Test ) ) { throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace( 2 ) ); } @@ -1088,10 +1042,10 @@ Test.prototype = { runLoggingCallbacks( "log", details ); - this.assertions.push({ + this.assertions.push( { result: false, message: message - }); + } ); }, resolvePromise: function( promise, phase ) { @@ -1103,14 +1057,14 @@ Test.prototype = { QUnit.stop(); then.call( promise, - QUnit.start, + function() { QUnit.start(); }, function( error ) { message = "Promise rejected " + ( !phase ? "during" : phase.replace( /Each$/, "" ) ) + " " + test.testName + ": " + ( error.message || error ); test.pushFailure( message, extractStacktrace( error, 0 ) ); - // else next test will carry the responsibility + // Else next test will carry the responsibility saveGlobal(); // Unblock @@ -1122,21 +1076,45 @@ Test.prototype = { }, valid: function() { - var include, - filter = config.filter, - module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(), - fullName = ( this.module.name + ": " + this.testName ).toLowerCase(); + var filter = config.filter, + regexFilter = /^(!?)\/([\w\W]*)\/(i?$)/.exec( filter ), + module = config.module && config.module.toLowerCase(), + fullName = ( this.module.name + ": " + this.testName ); + + function moduleChainNameMatch( testModule ) { + var testModuleName = testModule.name ? testModule.name.toLowerCase() : null; + if ( testModuleName === module ) { + return true; + } else if ( testModule.parentModule ) { + return moduleChainNameMatch( testModule.parentModule ); + } else { + return false; + } + } + + function moduleChainIdMatch( testModule ) { + return inArray( testModule.moduleId, config.moduleId ) > -1 || + testModule.parentModule && moduleChainIdMatch( testModule.parentModule ); + } // Internally-generated tests are always valid if ( this.callback && this.callback.validTest ) { return true; } - if ( config.testId.length > 0 && inArray( this.testId, config.testId ) < 0 ) { + if ( config.moduleId && config.moduleId.length > 0 && + !moduleChainIdMatch( this.module ) ) { + + return false; + } + + if ( config.testId && config.testId.length > 0 && + inArray( this.testId, config.testId ) < 0 ) { + return false; } - if ( module && ( !this.module.name || this.module.name.toLowerCase() !== module ) ) { + if ( module && !moduleChainNameMatch( this.module ) ) { return false; } @@ -1144,9 +1122,25 @@ Test.prototype = { return true; } - include = filter.charAt( 0 ) !== "!"; + return regexFilter ? + this.regexFilter( !!regexFilter[ 1 ], regexFilter[ 2 ], regexFilter[ 3 ], fullName ) : + this.stringFilter( filter, fullName ); + }, + + regexFilter: function( exclude, pattern, flags, fullName ) { + var regex = new RegExp( pattern, flags ); + var match = regex.test( fullName ); + + return match !== exclude; + }, + + stringFilter: function( filter, fullName ) { + filter = filter.toLowerCase(); + fullName = fullName.toLowerCase(); + + var include = filter.charAt( 0 ) !== "!"; if ( !include ) { - filter = filter.toLowerCase().slice( 1 ); + filter = filter.slice( 1 ); } // If the filter matches, we need to honour include @@ -1157,7 +1151,6 @@ Test.prototype = { // Otherwise, do the opposite return !include; } - }; // Resets the test setup. Useful for tests that modify the DOM. @@ -1170,7 +1163,7 @@ QUnit.reset = function() { // Return on non-browser environments // This is necessary to not break on node tests - if ( typeof window === "undefined" ) { + if ( !defined.document ) { return; } @@ -1218,6 +1211,157 @@ function generateHash( module, testName ) { return hex.slice( -8 ); } +function synchronize( callback, priority, seed ) { + var last = !priority, + index; + + if ( QUnit.objectType( callback ) === "array" ) { + while ( callback.length ) { + synchronize( callback.shift() ); + } + return; + } + + if ( priority ) { + config.queue.splice( priorityCount++, 0, callback ); + } else if ( seed ) { + if ( !unitSampler ) { + unitSampler = unitSamplerGenerator( seed ); + } + + // Insert into a random position after all priority items + index = Math.floor( unitSampler() * ( config.queue.length - priorityCount + 1 ) ); + config.queue.splice( priorityCount + index, 0, callback ); + } else { + config.queue.push( callback ); + } + + if ( config.autorun && !config.blocking ) { + process( last ); + } +} + +function unitSamplerGenerator( seed ) { + + // 32-bit xorshift, requires only a nonzero seed + // http://excamera.com/sphinx/article-xorshift.html + var sample = parseInt( generateHash( seed ), 16 ) || -1; + return function() { + sample ^= sample << 13; + sample ^= sample >>> 17; + sample ^= sample << 5; + + // ECMAScript has no unsigned number type + if ( sample < 0 ) { + sample += 0x100000000; + } + + return sample / 0x100000000; + }; +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in global ) { + if ( hasOwn.call( global, key ) ) { + + // In Opera sometimes DOM element ids show up here, ignore them + if ( /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } + } + } +} + +function checkPollution() { + var newGlobals, + deletedGlobals, + old = config.pollution; + + saveGlobal(); + + newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) ); + } + + deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) ); + } +} + +// Will be exposed as QUnit.asyncTest +function asyncTest( testName, expected, callback ) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test( testName, expected, callback, true ); +} + +// Will be exposed as QUnit.test +function test( testName, expected, callback, async ) { + if ( focused ) { return; } + + var newTest; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + newTest = new Test( { + testName: testName, + expected: expected, + async: async, + callback: callback + } ); + + newTest.queue(); +} + +// Will be exposed as QUnit.skip +function skip( testName ) { + if ( focused ) { return; } + + var test = new Test( { + testName: testName, + skip: true + } ); + + test.queue(); +} + +// Will be exposed as QUnit.only +function only( testName, expected, callback, async ) { + var newTest; + + if ( focused ) { return; } + + QUnit.config.queue.length = 0; + focused = true; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + newTest = new Test( { + testName: testName, + expected: expected, + async: async, + callback: callback + } ); + + newTest.queue(); +} + function Assert( testContext ) { this.test = testContext; } @@ -1235,30 +1379,55 @@ QUnit.assert = Assert.prototype = { } }, - // Increment this Test's semaphore counter, then return a single-use function that + // Increment this Test's semaphore counter, then return a function that // decrements that counter a maximum of once. - async: function() { + async: function( count ) { var test = this.test, - popped = false; + popped = false, + acceptCallCount = count; + + if ( typeof acceptCallCount === "undefined" ) { + acceptCallCount = 1; + } test.semaphore += 1; test.usedAsync = true; pauseProcessing(); return function done() { - if ( !popped ) { - test.semaphore -= 1; - popped = true; - resumeProcessing(); - } else { - test.pushFailure( "Called the callback returned from `assert.async` more than once", + + if ( popped ) { + test.pushFailure( "Too many calls to the `assert.async` callback", sourceFromStacktrace( 2 ) ); + return; + } + acceptCallCount -= 1; + if ( acceptCallCount > 0 ) { + return; } + + test.semaphore -= 1; + popped = true; + resumeProcessing(); }; }, // Exports test.push() to the user API - push: function( /* result, actual, expected, message */ ) { + // Alias of pushResult. + push: function( result, actual, expected, message, negative ) { + var currentAssert = this instanceof Assert ? this : QUnit.config.current.assert; + return currentAssert.pushResult( { + result: result, + actual: actual, + expected: expected, + message: message, + negative: negative + } ); + }, + + pushResult: function( resultInfo ) { + + // Destructure of resultInfo = { result, actual, expected, message, negative } var assert = this, currentTest = ( assert instanceof Assert && assert.test ) || QUnit.config.current; @@ -1281,98 +1450,119 @@ QUnit.assert = Assert.prototype = { if ( !( assert instanceof Assert ) ) { assert = currentTest.assert; } - return assert.test.push.apply( assert.test, arguments ); + + return assert.test.pushResult( resultInfo ); }, - /** - * Asserts rough true-ish result. - * @name ok - * @function - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); - */ ok: function( result, message ) { message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " + QUnit.dump.parse( result ) ); - this.push( !!result, result, true, message ); + this.pushResult( { + result: !!result, + actual: result, + expected: true, + message: message + } ); + }, + + notOk: function( result, message ) { + message = message || ( !result ? "okay" : "failed, expected argument to be falsy, was: " + + QUnit.dump.parse( result ) ); + this.pushResult( { + result: !result, + actual: result, + expected: false, + message: message + } ); }, - /** - * Assert that the first two arguments are equal, with an optional message. - * Prints out both actual and expected values. - * @name equal - * @function - * @example equal( format( "{0} bytes.", 2), "2 bytes.", "replaces {0} with next argument" ); - */ equal: function( actual, expected, message ) { /*jshint eqeqeq:false */ - this.push( expected == actual, actual, expected, message ); + this.pushResult( { + result: expected == actual, + actual: actual, + expected: expected, + message: message + } ); }, - /** - * @name notEqual - * @function - */ notEqual: function( actual, expected, message ) { /*jshint eqeqeq:false */ - this.push( expected != actual, actual, expected, message ); + this.pushResult( { + result: expected != actual, + actual: actual, + expected: expected, + message: message, + negative: true + } ); }, - /** - * @name propEqual - * @function - */ propEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); - this.push( QUnit.equiv( actual, expected ), actual, expected, message ); + this.pushResult( { + result: QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message + } ); }, - /** - * @name notPropEqual - * @function - */ notPropEqual: function( actual, expected, message ) { actual = objectValues( actual ); expected = objectValues( expected ); - this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); + this.pushResult( { + result: !QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message, + negative: true + } ); }, - /** - * @name deepEqual - * @function - */ deepEqual: function( actual, expected, message ) { - this.push( QUnit.equiv( actual, expected ), actual, expected, message ); + this.pushResult( { + result: QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message + } ); }, - /** - * @name notDeepEqual - * @function - */ notDeepEqual: function( actual, expected, message ) { - this.push( !QUnit.equiv( actual, expected ), actual, expected, message ); + this.pushResult( { + result: !QUnit.equiv( actual, expected ), + actual: actual, + expected: expected, + message: message, + negative: true + } ); }, - /** - * @name strictEqual - * @function - */ strictEqual: function( actual, expected, message ) { - this.push( expected === actual, actual, expected, message ); + this.pushResult( { + result: expected === actual, + actual: actual, + expected: expected, + message: message + } ); }, - /** - * @name notStrictEqual - * @function - */ notStrictEqual: function( actual, expected, message ) { - this.push( expected !== actual, actual, expected, message ); + this.pushResult( { + result: expected !== actual, + actual: actual, + expected: expected, + message: message, + negative: true + } ); }, "throws": function( block, expected, message ) { var actual, expectedType, expectedOutput = expected, - ok = false; + ok = false, + currentTest = ( this instanceof Assert && this.test ) || QUnit.config.current; // 'expected' is optional unless doing string comparison if ( message == null && typeof expected === "string" ) { @@ -1380,285 +1570,351 @@ QUnit.assert = Assert.prototype = { expected = null; } - this.test.ignoreGlobalErrors = true; + currentTest.ignoreGlobalErrors = true; try { - block.call( this.test.testEnvironment ); - } catch (e) { + block.call( currentTest.testEnvironment ); + } catch ( e ) { actual = e; } - this.test.ignoreGlobalErrors = false; + currentTest.ignoreGlobalErrors = false; if ( actual ) { expectedType = QUnit.objectType( expected ); - // we don't want to validate thrown error + // We don't want to validate thrown error if ( !expected ) { ok = true; expectedOutput = null; - // expected is a regexp + // Expected is a regexp } else if ( expectedType === "regexp" ) { ok = expected.test( errorString( actual ) ); - // expected is a string + // Expected is a string } else if ( expectedType === "string" ) { ok = expected === errorString( actual ); - // expected is a constructor, maybe an Error constructor + // Expected is a constructor, maybe an Error constructor } else if ( expectedType === "function" && actual instanceof expected ) { ok = true; - // expected is an Error object + // Expected is an Error object } else if ( expectedType === "object" ) { ok = actual instanceof expected.constructor && actual.name === expected.name && actual.message === expected.message; - // expected is a validation function which returns true if validation passed + // Expected is a validation function which returns true if validation passed } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) { expectedOutput = null; ok = true; } - - this.push( ok, actual, expectedOutput, message ); - } else { - this.test.pushFailure( message, null, "No exception was thrown." ); } + + currentTest.assert.pushResult( { + result: ok, + actual: actual, + expected: expectedOutput, + message: message + } ); } }; -// Provide an alternative to assert.throws(), for enviroments that consider throws a reserved word +// Provide an alternative to assert.throws(), for environments that consider throws a reserved word // Known to us are: Closure Compiler, Narwhal -(function() { +( function() { /*jshint sub:true */ - Assert.prototype.raises = Assert.prototype[ "throws" ]; -}()); + Assert.prototype.raises = Assert.prototype [ "throws" ]; //jscs:ignore requireDotNotation +}() ); + +function errorString( error ) { + var name, message, + resultErrorString = error.toString(); + if ( resultErrorString.substring( 0, 7 ) === "[object" ) { + name = error.name ? error.name.toString() : "Error"; + message = error.message ? error.message.toString() : ""; + if ( name && message ) { + return name + ": " + message; + } else if ( name ) { + return name; + } else if ( message ) { + return message; + } else { + return "Error"; + } + } else { + return resultErrorString; + } +} // Test for equality any JavaScript type. // Author: Philippe Rathé -QUnit.equiv = (function() { - - // Call the o related callback with the given arguments. - function bindCallbacks( o, callbacks, args ) { - var prop = QUnit.objectType( o ); - if ( prop ) { - if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { - return callbacks[ prop ].apply( callbacks, args ); - } else { - return callbacks[ prop ]; // or undefined - } - } - } +QUnit.equiv = ( function() { - // the real equiv function - var innerEquiv, + // Stack to decide between skip/abort functions + var callers = []; - // stack to decide between skip/abort functions - callers = [], + // Stack to avoiding loops from circular referencing + var parents = []; + var parentsB = []; - // stack to avoiding loops from circular referencing - parents = [], - parentsB = [], + var getProto = Object.getPrototypeOf || function( obj ) { - getProto = Object.getPrototypeOf || function( obj ) { - /* jshint camelcase: false, proto: true */ - return obj.__proto__; - }, - callbacks = (function() { + /*jshint proto: true */ + return obj.__proto__; + }; - // for string, boolean, number and null - function useStrictEquality( b, a ) { + function useStrictEquality( b, a ) { - /*jshint eqeqeq:false */ - if ( b instanceof a.constructor || a instanceof b.constructor ) { + // To catch short annotation VS 'new' annotation of a declaration. e.g.: + // `var i = 1;` + // `var j = new Number(1);` + if ( typeof a === "object" ) { + a = a.valueOf(); + } + if ( typeof b === "object" ) { + b = b.valueOf(); + } - // to catch short annotation VS 'new' annotation of a - // declaration - // e.g. var i = 1; - // var j = new Number(1); - return a == b; - } else { - return a === b; - } - } + return a === b; + } - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, + function compareConstructors( a, b ) { + var protoA = getProto( a ); + var protoB = getProto( b ); - "nan": function( b ) { - return isNaN( b ); - }, + // Comparing constructors is more strict than using `instanceof` + if ( a.constructor === b.constructor ) { + return true; + } - "date": function( b, a ) { - return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); - }, + // Ref #851 + // If the obj prototype descends from a null constructor, treat it + // as a null prototype. + if ( protoA && protoA.constructor === null ) { + protoA = null; + } + if ( protoB && protoB.constructor === null ) { + protoB = null; + } + + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( ( protoA === null && protoB === Object.prototype ) || + ( protoB === null && protoA === Object.prototype ) ) { + return true; + } - "regexp": function( b, a ) { - return QUnit.objectType( b ) === "regexp" && + return false; + } - // the regex itself - a.source === b.source && + function getRegExpFlags( regexp ) { + return "flags" in regexp ? regexp.flags : regexp.toString().match( /[gimuy]*$/ )[ 0 ]; + } - // and its modifiers - a.global === b.global && + var callbacks = { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + "symbol": useStrictEquality, + "date": useStrictEquality, - // (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline && - a.sticky === b.sticky; - }, + "nan": function() { + return true; + }, - // - skip when the property is a method of an instance (OOP) - // - abort otherwise, - // initial === would have catch identical references anyway - "function": function() { - var caller = callers[ callers.length - 1 ]; - return caller !== Object && typeof caller !== "undefined"; - }, + "regexp": function( b, a ) { + return a.source === b.source && - "array": function( b, a ) { - var i, j, len, loop, aCircular, bCircular; + // Include flags in the comparison + getRegExpFlags( a ) === getRegExpFlags( b ); + }, - // b could be an object literal here - if ( QUnit.objectType( b ) !== "array" ) { - return false; - } + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function() { + var caller = callers[ callers.length - 1 ]; + return caller !== Object && typeof caller !== "undefined"; + }, - len = a.length; - if ( len !== b.length ) { - // safe and faster - return false; - } + "array": function( b, a ) { + var i, j, len, loop, aCircular, bCircular; - // track reference to avoid circular references - parents.push( a ); - parentsB.push( b ); - for ( i = 0; i < len; i++ ) { - loop = false; - for ( j = 0; j < parents.length; j++ ) { - aCircular = parents[ j ] === a[ i ]; - bCircular = parentsB[ j ] === b[ i ]; - if ( aCircular || bCircular ) { - if ( a[ i ] === b[ i ] || aCircular && bCircular ) { - loop = true; - } else { - parents.pop(); - parentsB.pop(); - return false; - } - } - } - if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { + len = a.length; + if ( len !== b.length ) { + + // Safe and faster + return false; + } + + // Track reference to avoid circular references + parents.push( a ); + parentsB.push( b ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[ j ] === a[ i ]; + bCircular = parentsB[ j ] === b[ i ]; + if ( aCircular || bCircular ) { + if ( a[ i ] === b[ i ] || aCircular && bCircular ) { + loop = true; + } else { parents.pop(); parentsB.pop(); return false; } } + } + if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { parents.pop(); parentsB.pop(); - return true; - }, + return false; + } + } + parents.pop(); + parentsB.pop(); + return true; + }, - "object": function( b, a ) { + "set": function( b, a ) { + var innerEq, + outerEq = true; - /*jshint forin:false */ - var i, j, loop, aCircular, bCircular, - // Default to true - eq = true, - aProperties = [], - bProperties = []; + if ( a.size !== b.size ) { + return false; + } - // comparing constructors is more strict than using - // instanceof - if ( a.constructor !== b.constructor ) { + a.forEach( function( aVal ) { + innerEq = false; - // Allow objects with no prototype to be equivalent to - // objects with Object as their constructor. - if ( !( ( getProto( a ) === null && getProto( b ) === Object.prototype ) || - ( getProto( b ) === null && getProto( a ) === Object.prototype ) ) ) { - return false; - } + b.forEach( function( bVal ) { + if ( innerEquiv( bVal, aVal ) ) { + innerEq = true; } + } ); - // stack constructor before traversing properties - callers.push( a.constructor ); - - // track reference to avoid circular references - parents.push( a ); - parentsB.push( b ); - - // be strict: don't ensure hasOwnProperty and go deep - for ( i in a ) { - loop = false; - for ( j = 0; j < parents.length; j++ ) { - aCircular = parents[ j ] === a[ i ]; - bCircular = parentsB[ j ] === b[ i ]; - if ( aCircular || bCircular ) { - if ( a[ i ] === b[ i ] || aCircular && bCircular ) { - loop = true; - } else { - eq = false; - break; - } - } - } - aProperties.push( i ); - if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { - eq = false; - break; - } - } + if ( !innerEq ) { + outerEq = false; + } + } ); - parents.pop(); - parentsB.pop(); - callers.pop(); // unstack, we are done + return outerEq; + }, + + "map": function( b, a ) { + var innerEq, + outerEq = true; - for ( i in b ) { - bProperties.push( i ); // collect b's properties + if ( a.size !== b.size ) { + return false; + } + + a.forEach( function( aVal, aKey ) { + innerEq = false; + + b.forEach( function( bVal, bKey ) { + if ( innerEquiv( [ bVal, bKey ], [ aVal, aKey ] ) ) { + innerEq = true; } + } ); - // Ensures identical properties name - return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + if ( !innerEq ) { + outerEq = false; } - }; - }()); + } ); - innerEquiv = function() { // can take multiple arguments - var args = [].slice.apply( arguments ); - if ( args.length < 2 ) { - return true; // end transition - } + return outerEq; + }, + + "object": function( b, a ) { + var i, j, loop, aCircular, bCircular; - return ( (function( a, b ) { - if ( a === b ) { - return true; // catch the most you can - } else if ( a === null || b === null || typeof a === "undefined" || - typeof b === "undefined" || - QUnit.objectType( a ) !== QUnit.objectType( b ) ) { + // Default to true + var eq = true; + var aProperties = []; + var bProperties = []; - // don't lose time with error prone cases + if ( compareConstructors( a, b ) === false ) { return false; - } else { - return bindCallbacks( a, callbacks, [ b, a ] ); } - // apply transition with (1..n) arguments - }( args[ 0 ], args[ 1 ] ) ) && - innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) ); + // Stack constructor before traversing properties + callers.push( a.constructor ); + + // Track reference to avoid circular references + parents.push( a ); + parentsB.push( b ); + + // Be strict: don't ensure hasOwnProperty and go deep + for ( i in a ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + aCircular = parents[ j ] === a[ i ]; + bCircular = parentsB[ j ] === b[ i ]; + if ( aCircular || bCircular ) { + if ( a[ i ] === b[ i ] || aCircular && bCircular ) { + loop = true; + } else { + eq = false; + break; + } + } + } + aProperties.push( i ); + if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) { + eq = false; + break; + } + } + + parents.pop(); + parentsB.pop(); + + // Unstack, we are done + callers.pop(); + + for ( i in b ) { + + // Collect b's properties + bProperties.push( i ); + } + + // Ensures identical properties name + return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + } }; + function typeEquiv( a, b ) { + var type = QUnit.objectType( a ); + return QUnit.objectType( b ) === type && callbacks[ type ]( b, a ); + } + + // The real equiv function + function innerEquiv( a, b ) { + + // We're done when there's nothing more to compare + if ( arguments.length < 2 ) { + return true; + } + + // Require type-specific equality + return ( a === b || typeEquiv( a, b ) ) && + + // ...across all consecutive argument pairs + ( arguments.length === 2 || innerEquiv.apply( this, [].slice.call( arguments, 1 ) ) ); + } + return innerEquiv; -}()); +}() ); // Based on jsDump by Ariel Flesler // http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html -QUnit.dump = (function() { +QUnit.dump = ( function() { function quote( str ) { - return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\""; + return "\"" + str.toString().replace( /\\/g, "\\\\" ).replace( /"/g, "\\\"" ) + "\""; } function literal( o ) { return o + ""; @@ -1694,7 +1950,7 @@ QUnit.dump = (function() { var reName = /^function (\w+)/, dump = { - // objType is used mostly internally, you can fix a (custom) type in advance + // The objType is used mostly internally, you can fix a (custom) type in advance parse: function( obj, objType, stack ) { stack = stack || []; var res, parser, parserType, @@ -1738,7 +1994,7 @@ QUnit.dump = (function() { type = "node"; } else if ( - // native arrays + // Native arrays toString.call( obj ) === "[object Array]" || // NodeList objects @@ -1754,10 +2010,12 @@ QUnit.dump = (function() { } return type; }, + separator: function() { return this.multiline ? this.HTML ? "
    " : "\n" : this.HTML ? " " : " "; }, - // extra can be a number, shortcut for increasing-calling-decreasing + + // Extra can be a number, shortcut for increasing-calling-decreasing indent: function( extra ) { if ( !this.multiline ) { return ""; @@ -1777,13 +2035,13 @@ QUnit.dump = (function() { setParser: function( name, parser ) { this.parsers[ name ] = parser; }, + // The next 3 are exposed so you can use them quote: quote, literal: literal, join: join, - // depth: 1, - maxDepth: 5, + maxDepth: QUnit.config.maxDepth, // This is the list of parsers, to modify them, use dump.setParser parsers: { @@ -1798,13 +2056,13 @@ QUnit.dump = (function() { "function": function( fn ) { var ret = "function", - // functions never have name in IE + // Functions never have name in IE name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ]; if ( name ) { ret += " " + name; } - ret += "( "; + ret += "("; ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" ); return join( ret, dump.parse( fn, "functionCode" ), "}" ); @@ -1830,7 +2088,7 @@ QUnit.dump = (function() { nonEnumerableProperties = [ "message", "name" ]; for ( i in nonEnumerableProperties ) { key = nonEnumerableProperties[ i ]; - if ( key in map && !( key in keys ) ) { + if ( key in map && inArray( key, keys ) < 0 ) { keys.push( key ); } } @@ -1875,7 +2133,7 @@ QUnit.dump = (function() { return ret + open + "/" + tag + close; }, - // function calls it internally, it's the arguments part of the function + // Function calls it internally, it's the arguments part of the function functionArgs: function( fn ) { var args, l = fn.length; @@ -1892,11 +2150,14 @@ QUnit.dump = (function() { } return " " + args.join( ", " ) + " "; }, - // object calls it internally, the key part of an item in a map + + // Object calls it internally, the key part of an item in a map key: quote, - // function calls it internally, it's the content of the function + + // Function calls it internally, it's the content of the function functionCode: "[code]", - // node calls it internally, it's an html attribute value + + // Node calls it internally, it's a html attribute value attribute: quote, string: quote, date: quote, @@ -1904,42 +2165,45 @@ QUnit.dump = (function() { number: literal, "boolean": literal }, - // if true, entities are escaped ( <, >, \t, space and \n ) + + // If true, entities are escaped ( <, >, \t, space and \n ) HTML: false, - // indentation unit + + // Indentation unit indentChar: " ", - // if true, items in a collection, are separated by a \n, else just a space. + + // If true, items in a collection, are separated by a \n, else just a space. multiline: true }; return dump; -}()); +}() ); -// back compat +// Back compat QUnit.jsDump = QUnit.dump; -// For browser, export only select globals -if ( typeof window !== "undefined" ) { +// Deprecated +// Extend assert methods to QUnit for Backwards compatibility +( function() { + var i, + assertions = Assert.prototype; - // Deprecated - // Extend assert methods to QUnit and Global scope through Backwards compatibility - (function() { - var i, - assertions = Assert.prototype; + function applyCurrent( current ) { + return function() { + var assert = new Assert( QUnit.config.current ); + current.apply( assert, arguments ); + }; + } - function applyCurrent( current ) { - return function() { - var assert = new Assert( QUnit.config.current ); - current.apply( assert, arguments ); - }; - } + for ( i in assertions ) { + QUnit[ i ] = applyCurrent( assertions[ i ] ); + } +}() ); - for ( i in assertions ) { - QUnit[ i ] = applyCurrent( assertions[ i ] ); - } - })(); +// For browser, export only select globals +if ( defined.document ) { - (function() { + ( function() { var i, l, keys = [ "test", @@ -1949,6 +2213,7 @@ if ( typeof window !== "undefined" ) { "start", "stop", "ok", + "notOk", "equal", "notEqual", "propEqual", @@ -1957,13 +2222,14 @@ if ( typeof window !== "undefined" ) { "notDeepEqual", "strictEqual", "notStrictEqual", - "throws" + "throws", + "raises" ]; for ( i = 0, l = keys.length; i < l; i++ ) { window[ keys[ i ] ] = QUnit[ keys[ i ] ]; } - })(); + }() ); window.QUnit = QUnit; } @@ -1981,168 +2247,122 @@ if ( typeof exports !== "undefined" && exports ) { exports.QUnit = QUnit; } +if ( typeof define === "function" && define.amd ) { + define( function() { + return QUnit; + } ); + QUnit.config.autostart = false; +} + // Get a reference to the global object, like window in browsers -}( (function() { +}( ( function() { return this; -})() )); - -/*istanbul ignore next */ -// jscs:disable maximumLineLength -/* - * Javascript Diff Algorithm - * By John Resig (http://ejohn.org/) - * Modified by Chu Alan "sprite" - * - * Released under the MIT license. - * - * More Info: - * http://ejohn.org/projects/javascript-diff-algorithm/ - * - * Usage: QUnit.diff(expected, actual) - * - * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" - */ -QUnit.diff = (function() { - var hasOwn = Object.prototype.hasOwnProperty; +}() ) ) ); - /*jshint eqeqeq:false, eqnull:true */ - function diff( o, n ) { - var i, - ns = {}, - os = {}; - - for ( i = 0; i < n.length; i++ ) { - if ( !hasOwn.call( ns, n[ i ] ) ) { - ns[ n[ i ] ] = { - rows: [], - o: null - }; - } - ns[ n[ i ] ].rows.push( i ); - } - - for ( i = 0; i < o.length; i++ ) { - if ( !hasOwn.call( os, o[ i ] ) ) { - os[ o[ i ] ] = { - rows: [], - n: null - }; - } - os[ o[ i ] ].rows.push( i ); - } - - for ( i in ns ) { - if ( hasOwn.call( ns, i ) ) { - if ( ns[ i ].rows.length === 1 && hasOwn.call( os, i ) && os[ i ].rows.length === 1 ) { - n[ ns[ i ].rows[ 0 ] ] = { - text: n[ ns[ i ].rows[ 0 ] ], - row: os[ i ].rows[ 0 ] - }; - o[ os[ i ].rows[ 0 ] ] = { - text: o[ os[ i ].rows[ 0 ] ], - row: ns[ i ].rows[ 0 ] - }; - } - } - } +( function() { - for ( i = 0; i < n.length - 1; i++ ) { - if ( n[ i ].text != null && n[ i + 1 ].text == null && n[ i ].row + 1 < o.length && o[ n[ i ].row + 1 ].text == null && - n[ i + 1 ] == o[ n[ i ].row + 1 ] ) { +// Only interact with URLs via window.location +var location = typeof window !== "undefined" && window.location; +if ( !location ) { + return; +} - n[ i + 1 ] = { - text: n[ i + 1 ], - row: n[ i ].row + 1 - }; - o[ n[ i ].row + 1 ] = { - text: o[ n[ i ].row + 1 ], - row: i + 1 - }; - } - } +var urlParams = getUrlParams(); - for ( i = n.length - 1; i > 0; i-- ) { - if ( n[ i ].text != null && n[ i - 1 ].text == null && n[ i ].row > 0 && o[ n[ i ].row - 1 ].text == null && - n[ i - 1 ] == o[ n[ i ].row - 1 ] ) { +QUnit.urlParams = urlParams; - n[ i - 1 ] = { - text: n[ i - 1 ], - row: n[ i ].row - 1 - }; - o[ n[ i ].row - 1 ] = { - text: o[ n[ i ].row - 1 ], - row: i - 1 - }; - } - } +// Match module/test by inclusion in an array +QUnit.config.moduleId = [].concat( urlParams.moduleId || [] ); +QUnit.config.testId = [].concat( urlParams.testId || [] ); - return { - o: o, - n: n - }; - } +// Exact case-insensitive match of the module name +QUnit.config.module = urlParams.module; - return function( o, n ) { - o = o.replace( /\s+$/, "" ); - n = n.replace( /\s+$/, "" ); +// Regular expression or case-insenstive substring match against "moduleName: testName" +QUnit.config.filter = urlParams.filter; - var i, pre, - str = "", - out = diff( o === "" ? [] : o.split( /\s+/ ), n === "" ? [] : n.split( /\s+/ ) ), - oSpace = o.match( /\s+/g ), - nSpace = n.match( /\s+/g ); +// Test order randomization +if ( urlParams.seed === true ) { - if ( oSpace == null ) { - oSpace = [ " " ]; - } else { - oSpace.push( " " ); - } + // Generate a random seed if the option is specified without a value + QUnit.config.seed = Math.random().toString( 36 ).slice( 2 ); +} else if ( urlParams.seed ) { + QUnit.config.seed = urlParams.seed; +} - if ( nSpace == null ) { - nSpace = [ " " ]; - } else { - nSpace.push( " " ); - } +// Add URL-parameter-mapped config values with UI form rendering data +QUnit.config.urlConfig.push( + { + id: "hidepassed", + label: "Hide passed tests", + tooltip: "Only show tests and assertions that fail. Stored as query-strings." + }, + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the " + + "global object (`window` in Browsers). Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " + + "exceptions in IE reasonable. Stored as query-strings." + } +); - if ( out.n.length === 0 ) { - for ( i = 0; i < out.o.length; i++ ) { - str += "" + out.o[ i ] + oSpace[ i ] + ""; - } - } else { - if ( out.n[ 0 ].text == null ) { - for ( n = 0; n < out.o.length && out.o[ n ].text == null; n++ ) { - str += "" + out.o[ n ] + oSpace[ n ] + ""; - } - } +QUnit.begin( function() { + var i, option, + urlConfig = QUnit.config.urlConfig; - for ( i = 0; i < out.n.length; i++ ) { - if ( out.n[ i ].text == null ) { - str += "" + out.n[ i ] + nSpace[ i ] + ""; - } else { + for ( i = 0; i < urlConfig.length; i++ ) { - // `pre` initialized at top of scope - pre = ""; + // Options can be either strings or objects with nonempty "id" properties + option = QUnit.config.urlConfig[ i ]; + if ( typeof option !== "string" ) { + option = option.id; + } - for ( n = out.n[ i ].row + 1; n < out.o.length && out.o[ n ].text == null; n++ ) { - pre += "" + out.o[ n ] + oSpace[ n ] + ""; - } - str += " " + out.n[ i ].text + nSpace[ i ] + pre; - } + if ( QUnit.config[ option ] === undefined ) { + QUnit.config[ option ] = urlParams[ option ]; + } + } +} ); + +function getUrlParams() { + var i, param, name, value; + var urlParams = {}; + var params = location.search.slice( 1 ).split( "&" ); + var length = params.length; + + for ( i = 0; i < length; i++ ) { + if ( params[ i ] ) { + param = params[ i ].split( "=" ); + name = decodeURIComponent( param[ 0 ] ); + + // Allow just a key to turn on a flag, e.g., test.html?noglobals + value = param.length === 1 || + decodeURIComponent( param.slice( 1 ).join( "=" ) ) ; + if ( urlParams[ name ] ) { + urlParams[ name ] = [].concat( urlParams[ name ], value ); + } else { + urlParams[ name ] = value; } } + } - return str; - }; -}()); -// jscs:enable + return urlParams; +} -(function() { +// Don't load the HTML Reporter on non-browser environments +if ( typeof window === "undefined" || !window.document ) { + return; +} // Deprecated QUnit.init - Ref #530 // Re-initialize the configuration options QUnit.init = function() { - var tests, banner, result, qunit, - config = QUnit.config; + var config = QUnit.config; config.stats = { all: 0, bad: 0 }; config.moduleStats = { all: 0, bad: 0 }; @@ -2154,57 +2374,17 @@ QUnit.init = function() { config.filter = ""; config.queue = []; - // Return on non-browser environments - // This is necessary to not break on node tests - if ( typeof window === "undefined" ) { - return; - } - - qunit = id( "qunit" ); - if ( qunit ) { - qunit.innerHTML = - "

    " + escapeText( document.title ) + "

    " + - "

    " + - "
    " + - "

    " + - "
      "; - } - - tests = id( "qunit-tests" ); - banner = id( "qunit-banner" ); - result = id( "qunit-testresult" ); - - if ( tests ) { - tests.innerHTML = ""; - } - - if ( banner ) { - banner.className = ""; - } - - if ( result ) { - result.parentNode.removeChild( result ); - } - - if ( tests ) { - result = document.createElement( "p" ); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests ); - result.innerHTML = "Running...
       "; - } + appendInterface(); }; -// Don't load the HTML Reporter on non-Browser environments -if ( typeof window === "undefined" ) { - return; -} - var config = QUnit.config, + document = window.document, + collapseNext = false, hasOwn = Object.prototype.hasOwnProperty, + unfilteredUrl = setUrl( { filter: undefined, module: undefined, + moduleId: undefined, testId: undefined } ), defined = { - document: window.document !== undefined, - sessionStorage: (function() { + sessionStorage: ( function() { var x = "qunit-test-string"; try { sessionStorage.setItem( x, x ); @@ -2213,7 +2393,7 @@ var config = QUnit.config, } catch ( e ) { return false; } - }()) + }() ) }, modulesList = []; @@ -2240,7 +2420,7 @@ function escapeText( s ) { case "&": return "&"; } - }); + } ); } /** @@ -2255,8 +2435,15 @@ function addEvent( elem, type, fn ) { elem.addEventListener( type, fn, false ); } else if ( elem.attachEvent ) { - // support: IE <9 - elem.attachEvent( "on" + type, fn ); + // Support: IE <9 + elem.attachEvent( "on" + type, function() { + var event = window.event; + if ( !event.target ) { + event.target = event.srcElement || document; + } + + fn.call( elem, event ); + } ); } } @@ -2282,11 +2469,11 @@ function addClass( elem, name ) { } } -function toggleClass( elem, name ) { - if ( hasClass( elem, name ) ) { - removeClass( elem, name ); - } else { +function toggleClass( elem, name, force ) { + if ( force || typeof force === "undefined" && !hasClass( elem, name ) ) { addClass( elem, name ); + } else { + removeClass( elem, name ); } } @@ -2298,22 +2485,24 @@ function removeClass( elem, name ) { set = set.replace( " " + name + " ", " " ); } - // trim for prettiness + // Trim for prettiness elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" ); } function id( name ) { - return defined.document && document.getElementById && document.getElementById( name ); + return document.getElementById && document.getElementById( name ); } function getUrlConfigHtml() { var i, j, val, escaped, escapedTooltip, selection = false, - len = config.urlConfig.length, + urlConfig = config.urlConfig, urlConfigHtml = ""; - for ( i = 0; i < len; i++ ) { + for ( i = 0; i < urlConfig.length; i++ ) { + + // Options can be either strings or objects with nonempty "id" properties val = config.urlConfig[ i ]; if ( typeof val === "string" ) { val = { @@ -2325,10 +2514,6 @@ function getUrlConfigHtml() { escaped = escapeText( val.id ); escapedTooltip = escapeText( val.tooltip ); - if ( config[ val.id ] === undefined ) { - config[ val.id ] = QUnit.urlParams[ val.id ]; - } - if ( !val.value || typeof val.value === "string" ) { urlConfigHtml += "