From 027d470b574e15c94cda28f5e2c7a0ed54c11fa6 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 19 Feb 2014 17:25:00 -0500 Subject: [PATCH 0001/1272] Bower: add main property, move Sizzle to devDependencies, add license property Fixes #14798 Close gh-1516 Ref gh-1338 --- bower.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bower.json b/bower.json index bff22caf8d..74defffaa6 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,8 @@ { "name": "jquery", "version": "2.1.1pre", + "main": "dist/jquery.js", + "license": "MIT", "ignore": [ "**/.*", "build", @@ -12,10 +14,8 @@ "package.json", "bower.json" ], - "dependencies": { - "sizzle": "1.10.18" - }, "devDependencies": { + "sizzle": "1.10.18", "requirejs": "2.1.10", "qunit": "1.14.0", "sinon": "1.8.1" From a35996141e3c1de92e89ed77eac1799124e747d3 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 19 Feb 2014 17:57:34 -0500 Subject: [PATCH 0002/1272] Bower: stop ignoring yourself, bower Ref #14798 Ref gh-1516 Ref gh-1338 --- bower.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bower.json b/bower.json index 74defffaa6..9e53778495 100644 --- a/bower.json +++ b/bower.json @@ -11,8 +11,7 @@ "*.md", "AUTHORS.txt", "Gruntfile.js", - "package.json", - "bower.json" + "package.json" ], "devDependencies": { "sizzle": "1.10.18", From 279913c71b63da721fa2f118cdce150effbf773e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Tue, 4 Mar 2014 23:08:35 +0100 Subject: [PATCH 0003/1272] Core: Remove native String#trim usage to save size Fixes #14794 --- src/core.js | 22 ++++++---------------- src/var/trim.js | 3 --- 2 files changed, 6 insertions(+), 19 deletions(-) delete mode 100644 src/var/trim.js diff --git a/src/core.js b/src/core.js index 11c232765a..311e360aab 100644 --- a/src/core.js +++ b/src/core.js @@ -7,9 +7,8 @@ define([ "./var/class2type", "./var/toString", "./var/hasOwn", - "./var/trim", "./var/support" -], function( arr, slice, concat, push, indexOf, class2type, toString, hasOwn, trim, support ) { +], function( arr, slice, concat, push, indexOf, class2type, toString, hasOwn, support ) { var // Use the correct document accordingly with window argument (sandbox) @@ -341,20 +340,11 @@ jQuery.extend({ }, // Support: Android<4.1 - // Use native String.trim function wherever possible - trim: trim && !trim.call("\uFEFF\xA0") ? - function( text ) { - return text == null ? - "" : - trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, // results is for internal usage only makeArray: function( arr, results ) { diff --git a/src/var/trim.js b/src/var/trim.js deleted file mode 100644 index 18f8356582..0000000000 --- a/src/var/trim.js +++ /dev/null @@ -1,3 +0,0 @@ -define(function() { - return "".trim; -}); From 10efa1f5b44046aab6bcc8423322a41923faa290 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Mon, 3 Mar 2014 22:18:50 -0500 Subject: [PATCH 0004/1272] Core: Arrays like [42] should fail .isNumeric() Fixes #14179 --- src/core.js | 2 +- test/unit/core.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core.js b/src/core.js index 311e360aab..c494d7a60f 100644 --- a/src/core.js +++ b/src/core.js @@ -216,7 +216,7 @@ jQuery.extend({ // parseFloat NaNs numeric-cast false positives (null|true|false|"") // ...but misinterprets leading-number strings, particularly hex literals ("0x...") // subtraction forces infinities to NaN - return obj - parseFloat( obj ) >= 0; + return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0; }, isPlainObject: function( obj ) { diff --git a/test/unit/core.js b/test/unit/core.js index d781d261a5..6801c7c0d2 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -457,7 +457,7 @@ test("isFunction", function() { }); test( "isNumeric", function() { - expect( 36 ); + expect( 38 ); var t = jQuery.isNumeric, Traditionalists = /** @constructor */ function(n) { @@ -505,6 +505,8 @@ test( "isNumeric", function() { equal( t(Number.NEGATIVE_INFINITY), false, "Negative Infinity"); equal( t(rong), false, "Custom .toString returning non-number"); equal( t({}), false, "Empty object"); + equal( t( [] ), false, "Empty array" ); + equal( t( [ 42 ] ), false, "Array with one number" ); equal( t(function(){} ), false, "Instance of a function"); equal( t( new Date() ), false, "Instance of a Date"); equal( t(function(){} ), false, "Instance of a function"); From 3a68c114e3a30af86dc261c9d62ce2ae4144d420 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Mon, 3 Mar 2014 21:37:56 -0500 Subject: [PATCH 0005/1272] Ajax: .load() should trim its selector Fixes #14773 --- src/ajax/load.js | 2 +- test/data/test3.html | 1 + test/unit/ajax.js | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/ajax/load.js b/src/ajax/load.js index 3c345a0278..bff25b1a40 100644 --- a/src/ajax/load.js +++ b/src/ajax/load.js @@ -25,7 +25,7 @@ jQuery.fn.load = function( url, params, callback ) { off = url.indexOf(" "); if ( off >= 0 ) { - selector = url.slice( off ); + selector = jQuery.trim( url.slice( off ) ); url = url.slice( 0, off ); } diff --git a/test/data/test3.html b/test/data/test3.html index 909d41745c..a7f862a869 100644 --- a/test/data/test3.html +++ b/test/data/test3.html @@ -1,3 +1,4 @@
This is a user
This is a user
This is a teacher
+
This is a superuser
diff --git a/test/unit/ajax.js b/test/unit/ajax.js index c7d7daba4f..a07749fc6e 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1807,6 +1807,14 @@ module( "ajax", { }); }); + // Selector should be trimmed to avoid leading spaces (#14773) + asyncTest( "jQuery.fn.load( URL_SELECTOR with spaces )", 1, function() { + jQuery("#first").load( "data/test3.html #superuser ", function() { + strictEqual( jQuery( this ).children("div").length, 1, "Verify that specific elements were injected" ); + start(); + }); + }); + asyncTest( "jQuery.fn.load( String, Function ) - simple: inject text into DOM", 2, function() { jQuery("#first").load( url("data/name.html"), function() { ok( /^ERROR/.test(jQuery("#first").text()), "Check if content was injected into the DOM" ); From 06adf7c95d93507908181995a9ea15fe2729595a Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Mon, 3 Mar 2014 22:43:51 -0500 Subject: [PATCH 0006/1272] Event: Allow triggerHandler(beforeunload) Fixes #14791 --- src/event.js | 2 +- test/data/event/triggerunload.html | 18 ++++++++++++++++++ test/unit/event.js | 5 +++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 test/data/event/triggerunload.html diff --git a/src/event.js b/src/event.js index 8d40312113..ee1f3fcadf 100644 --- a/src/event.js +++ b/src/event.js @@ -583,7 +583,7 @@ jQuery.event = { // Support: Firefox 20+ // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined ) { + if ( event.result !== undefined && event.originalEvent ) { event.originalEvent.returnValue = event.result; } } diff --git a/test/data/event/triggerunload.html b/test/data/event/triggerunload.html new file mode 100644 index 0000000000..a7879c7728 --- /dev/null +++ b/test/data/event/triggerunload.html @@ -0,0 +1,18 @@ + + + + + diff --git a/test/unit/event.js b/test/unit/event.js index 22f6dacefa..84cad50ac8 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -2434,6 +2434,11 @@ testIframeWithCallback( "Focusing iframe element", "event/focusElem.html", funct ok( isOk, "Focused an element in an iframe" ); }); +testIframeWithCallback( "triggerHandler(onbeforeunload)", "event/triggerunload.html", function( isOk ) { + expect( 1 ); + ok( isOk, "Triggered onbeforeunload without an error" ); +}); + // need PHP here to make the incepted IFRAME hang if ( hasPHP ) { testIframeWithCallback( "jQuery.ready synchronous load with long loading subresources", "event/syncReady.html", function( isOk ) { From f4b37d89820535d6c7503925aa8872645681a865 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Mon, 3 Mar 2014 20:55:30 -0500 Subject: [PATCH 0007/1272] CSS: Return values should be numbers Fixes #14792 --- src/css.js | 4 ++-- test/unit/css.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/css.js b/src/css.js index 30342a230d..4d6838a4ef 100644 --- a/src/css.js +++ b/src/css.js @@ -29,8 +29,8 @@ var cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400 + letterSpacing: "0", + fontWeight: "400" }, cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; diff --git a/test/unit/css.js b/test/unit/css.js index 67bd332a4c..09839f185d 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -813,12 +813,13 @@ testIframeWithCallback( "css('width') should work correctly before document read ); test("certain css values of 'normal' should be convertable to a number, see #8627", function() { - expect ( 2 ); + expect ( 3 ); var el = jQuery("
test
").appendTo("#qunit-fixture"); ok( jQuery.isNumeric( parseFloat( el.css("letterSpacing") ) ), "css('letterSpacing') not convertable to number, see #8627" ); ok( jQuery.isNumeric( parseFloat( el.css("fontWeight") ) ), "css('fontWeight') not convertable to number, see #8627" ); + equal( typeof el.css( "fontWeight" ), "string", ".css() returns a string" ); }); // only run this test in IE9 From 2df1aad6a1c9376c2a477eba26ee992113ed1c23 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Mon, 3 Mar 2014 22:04:23 -0500 Subject: [PATCH 0008/1272] Core: Do not run window.onready when ready Fixes #14802 --- src/core/ready.js | 5 +++-- test/data/core/onready.html | 24 ++++++++++++++++++++++++ test/unit/core.js | 7 +++++++ 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 test/data/core/onready.html diff --git a/src/core/ready.js b/src/core/ready.js index e64977cd97..122b1610d4 100644 --- a/src/core/ready.js +++ b/src/core/ready.js @@ -51,8 +51,9 @@ jQuery.extend({ readyList.resolveWith( document, [ jQuery ] ); // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); } } }); diff --git a/test/data/core/onready.html b/test/data/core/onready.html new file mode 100644 index 0000000000..1e8f127e77 --- /dev/null +++ b/test/data/core/onready.html @@ -0,0 +1,24 @@ + + + + + alias-masked DOM properties (#14074) + + + + +
+ +
+ + + \ No newline at end of file diff --git a/test/unit/core.js b/test/unit/core.js index 6801c7c0d2..d1b221ce87 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1516,3 +1516,10 @@ testIframeWithCallback( "Tolerating alias-masked DOM properties (#14074)", "core deepEqual( errors, [], "jQuery loaded" ); } ); + +testIframeWithCallback( "Don't call window.onready (#14802)", "core/onready.html", + function( error ) { + expect( 1 ); + equal( error, false, "no call to user-defined onready" ); + } +); From 984f77a930aa322bcc277762303370d7a2a4667a Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Fri, 7 Mar 2014 09:55:26 -0500 Subject: [PATCH 0009/1272] Build: Fix AMD option for custom builds Fixes #14859 --- build/tasks/build.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/build/tasks/build.js b/build/tasks/build.js index e5794fe934..fa164cf926 100644 --- a/build/tasks/build.js +++ b/build/tasks/build.js @@ -55,12 +55,6 @@ module.exports = function( grunt ) { // Remove EXPOSE lines from Sizzle .replace( /\/\/\s*EXPOSE[\w\W]*\/\/\s*EXPOSE/, "return Sizzle;" ); - // AMD Name - } else if ( (amdName = grunt.option( "amd" )) != null && /^exports\/amd$/.test( name ) ) { - // Remove the comma for anonymous defines - contents = contents - .replace( /(\s*)"jquery"(\,\s*)/, amdName ? "$1\"" + amdName + "\"$2" : "" ); - } else { // Ignore jQuery's exports (the only necessary one) @@ -87,6 +81,18 @@ module.exports = function( grunt ) { contents = contents .replace( /define\(\[[^\]]+\]\)[\W\n]+$/, "" ); } + // AMD Name + if ( (amdName = grunt.option( "amd" )) != null && /^exports\/amd$/.test( name ) ) { + if (amdName) { + grunt.log.writeln( "Naming jQuery with AMD name: " + amdName ); + } else { + grunt.log.writeln( "AMD name now anonymous" ); + } + // Remove the comma for anonymous defines + contents = contents + .replace( /(\s*)"jquery"(\,\s*)/, amdName ? "$1\"" + amdName + "\"$2" : "" ); + + } return contents; } From a96d5bed58f2b30f97d6dd2f5691cd890f62b75f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Sun, 9 Mar 2014 23:31:59 +0100 Subject: [PATCH 0010/1272] Manipulation: don't use Object.keys for consistency Fixes #14659 --- src/manipulation.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/manipulation.js b/src/manipulation.js index ff7a0d51a4..31d0c4edc4 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -276,7 +276,7 @@ jQuery.extend({ }, cleanData: function( elems ) { - var data, elem, events, type, key, j, + var data, elem, type, key, special = jQuery.event.special, i = 0; @@ -285,9 +285,8 @@ jQuery.extend({ key = elem[ data_priv.expando ]; if ( key && (data = data_priv.cache[ key ]) ) { - events = Object.keys( data.events || {} ); - if ( events.length ) { - for ( j = 0; (type = events[j]) !== undefined; j++ ) { + if ( data.events ) { + for ( type in data.events ) { if ( special[ type ] ) { jQuery.event.remove( elem, type ); From b19d4d3450c385b7074035b17f3ba8d0b86cf0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Mon, 10 Mar 2014 14:56:42 +0100 Subject: [PATCH 0011/1272] Ajax, Effects: Disable Chrome 31 workarounds --- test/unit/ajax.js | 15 ++++----------- test/unit/effects.js | 19 +++---------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/test/unit/ajax.js b/test/unit/ajax.js index a07749fc6e..c099e12b1c 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1532,17 +1532,10 @@ module( "ajax", { } } ); - // Support: Chrome 31. - // Chrome 31 doesn't fire Ajax requests in beforeunload event handler. - // There is no way for us to workaround it and it's been fixed in Chrome 32 - // so let's just blacklist Chrome 31 as long as it's in TestSwarm. - // See https://code.google.com/p/chromium/issues/detail?id=321241 - if ( navigator.userAgent.indexOf( " Chrome/31." ) === -1 ) { - testIframeWithCallback( "#14379 - jQuery.ajax() on unload", "ajax/onunload.html", function( status ) { - expect( 1 ); - strictEqual( status, "success", "Request completed" ); - }); - } + testIframeWithCallback( "#14379 - jQuery.ajax() on unload", "ajax/onunload.html", function( status ) { + expect( 1 ); + strictEqual( status, "success", "Request completed" ); + }); ajaxTest( "#14683 - jQuery.ajax() - Exceptions thrown synchronously by xhr.send should be caught", 4, [ { diff --git a/test/unit/effects.js b/test/unit/effects.js index 0762361cbe..3016bdbf3d 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -362,29 +362,16 @@ test("animate table-row width/height", function() { }); test("animate table-cell width/height", function() { - // Support: Chrome 31. - // Chrome 31 reports incorrect offsetWidth on a table cell with fixed width. - // This is fixed in Chrome 32 so let's just skip the failing test in Chrome 31. - // See https://code.google.com/p/chromium/issues/detail?id=290399 - var td, - chrome31 = navigator.userAgent.indexOf( " Chrome/31." ) !== -1; - - if (chrome31) { - expect(2); - } else { - expect(3); - } + expect(3); - td = jQuery( "#table" ) + var td = jQuery( "#table" ) .attr({ "cellspacing": 0, "cellpadding": 0, "border": 0 }) .html( "
" ) .find( "td" ); td.animate({ width: 10, height: 10 }, 100, function() { equal( jQuery( this ).css( "display" ), "table-cell", "display mode is correct" ); - if (!chrome31) { - equal( this.offsetWidth, 20, "width animated to shrink wrap point" ); - } + equal( this.offsetWidth, 20, "width animated to shrink wrap point" ); equal( this.offsetHeight, 20, "height animated to shrink wrap point" ); }); this.clock.tick( 100 ); From 2c180ef938201f1213b5c43c8212856d0282e1f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Mon, 10 Mar 2014 00:59:14 +0100 Subject: [PATCH 0012/1272] Css: Revert 24e587929f62428e1959b10aace6dc4fd65ab397 The workaround to be able to change !important styles broke the browser keeping the old CSS value if the new one was rejected. Patching it would involve a significant perf hit (~33%) so the initial patch needs to be reverted instead. Tests by m_gol & gibson042. Fixes #14836 Closes gh-1532 --- src/css.js | 3 --- test/unit/css.js | 27 ++++++++++++++++++++------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/css.js b/src/css.js index 4d6838a4ef..5e22dae00f 100644 --- a/src/css.js +++ b/src/css.js @@ -286,9 +286,6 @@ jQuery.extend({ // If a hook was provided, use that value, otherwise just set the specified value if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - // Support: Chrome, Safari - // Setting style to blank string required to delete "style: x !important;" - style[ name ] = ""; style[ name ] = value; } diff --git a/test/unit/css.js b/test/unit/css.js index 09839f185d..a65bf1dbec 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -204,7 +204,7 @@ test( "css() explicit and relative values", 29, function() { }); test("css(String, Object)", function() { - expect( 19 ); + expect( 20 ); var j, div, display, ret, success; jQuery("#nothiddendiv").css("top", "-1em"); @@ -239,15 +239,18 @@ test("css(String, Object)", function() { equal( ret, div, "Make sure setting undefined returns the original set." ); equal( div.css("display"), display, "Make sure that the display wasn't changed." ); - // Test for Bug #5509 success = true; try { - jQuery("#foo").css("backgroundColor", "rgba(0, 0, 0, 0.1)"); + jQuery( "#foo" ).css( "backgroundColor", "rgba(0, 0, 0, 0.1)" ); } catch (e) { success = false; } - ok( success, "Setting RGBA values does not throw Error" ); + ok( success, "Setting RGBA values does not throw Error (#5509)" ); + + jQuery( "#foo" ).css( "font", "7px/21px sans-serif" ); + strictEqual( jQuery( "#foo" ).css( "line-height" ), "21px", + "Set font shorthand property (#14759)" ); }); test( "css(Array)", function() { @@ -923,10 +926,20 @@ test( ":visible/:hidden selectors", function() { t( "Is Hidden", "#form input:hidden", ["hidden1","hidden2"] ); }); -test( "Override !important when changing styles (#14394)", function() { +test( "Keep the last style if the new one isn't recognized by the browser (#14836)", function() { + expect( 2 ); + + var el; + el = jQuery( "
" ).css( "color", "black" ).css( "color", "fake value" ); + equal( el.css( "color" ), "black", "The old style is kept when setting an unrecognized value" ); + el = jQuery( "
" ).css( "color", "black" ).css( "color", " " ); + equal( el.css( "color" ), "black", "The old style is kept when setting to a space" ); +}); + +test( "Reset the style if set to an empty string", function() { expect( 1 ); - var el = jQuery( "
" ).css( "display", "none" ); - equal( el.css( "display" ), "none", "New style replaced !important" ); + var el = jQuery( "
" ).css( "color", "black" ).css( "color", "" ); + equal( el.css( "color" ), "", "The style can be reset by setting to an empty string" ); }); asyncTest( "Clearing a Cloned Element's Style Shouldn't Clear the Original Element's Style (#8908)", 24, function() { From 0c12cb3910c446960a274fb0eab11b8830bed71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Mon, 10 Mar 2014 19:53:50 +0100 Subject: [PATCH 0013/1272] Css: Fix tests It's not easy to find a CSS property that is implemented even in ancient browsers and that returns a consistent result among browsers when passed through .css(). color didn't work since Firefox normalizes it an empty value to rgb(0, 0, 0). --- test/unit/css.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/test/unit/css.js b/test/unit/css.js index a65bf1dbec..4ac5452444 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -930,16 +930,19 @@ test( "Keep the last style if the new one isn't recognized by the browser (#1483 expect( 2 ); var el; - el = jQuery( "
" ).css( "color", "black" ).css( "color", "fake value" ); - equal( el.css( "color" ), "black", "The old style is kept when setting an unrecognized value" ); - el = jQuery( "
" ).css( "color", "black" ).css( "color", " " ); - equal( el.css( "color" ), "black", "The old style is kept when setting to a space" ); + el = jQuery( "
" ).css( "position", "absolute" ).css( "position", "fake value" ); + equal( el.css( "position" ), "absolute", "The old style is kept when setting an unrecognized value" ); + el = jQuery( "
" ).css( "position", "absolute" ).css( "position", " " ); + equal( el.css( "position" ), "absolute", "The old style is kept when setting to a space" ); }); test( "Reset the style if set to an empty string", function() { expect( 1 ); - var el = jQuery( "
" ).css( "color", "black" ).css( "color", "" ); - equal( el.css( "color" ), "", "The style can be reset by setting to an empty string" ); + var el = jQuery( "
" ).css( "position", "absolute" ).css( "position", "" ); + // Some browsers return an empty string; others "static". Both those cases mean the style + // was reset successfully so accept them both. + equal( el.css( "position" ) || "static", "static", + "The style can be reset by setting to an empty string" ); }); asyncTest( "Clearing a Cloned Element's Style Shouldn't Clear the Original Element's Style (#8908)", 24, function() { From 14872941f9de78e7436e58ac1f03a4b2d5aa34e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Mon, 10 Mar 2014 20:37:11 +0100 Subject: [PATCH 0014/1272] Build: Make it possible to change browserSets in the testswarm task --- build/tasks/testswarm.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index 7907d0f12b..9a69b2253d 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -2,7 +2,7 @@ module.exports = function( grunt ) { "use strict"; - grunt.registerTask( "testswarm", function( commit, configFile ) { + grunt.registerTask( "testswarm", function( commit, configFile, browserSets ) { var jobName, testswarm = require( "testswarm" ), runs = {}, @@ -11,6 +11,10 @@ module.exports = function( grunt ) { config = grunt.file.readJSON( configFile ).jquery, tests = grunt.config([ this.name, "tests" ]); + if ( !browserSets ) { + browserSets = [ "popular-no-old-ie", "ios" ]; + } + if ( pull ) { jobName = "Pull #" + pull[ 1 ] + ""; @@ -38,7 +42,7 @@ module.exports = function( grunt ) { name: jobName, runs: runs, runMax: config.runMax, - browserSets: [ "popular-no-old-ie", "ios" ] + browserSets: browserSets }, function( err, passed ) { if ( err ) { grunt.log.error( err ); From a81dbc4ed82bc38b1ac5f6a8242e044232ea1594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Tue, 11 Mar 2014 21:12:39 +0100 Subject: [PATCH 0015/1272] Build: Allow to specify timeout in the testswarm task --- build/tasks/testswarm.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index 9a69b2253d..135a3cc7ef 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -2,7 +2,7 @@ module.exports = function( grunt ) { "use strict"; - grunt.registerTask( "testswarm", function( commit, configFile, browserSets ) { + grunt.registerTask( "testswarm", function( commit, configFile, browserSets, timeout ) { var jobName, testswarm = require( "testswarm" ), runs = {}, @@ -11,10 +11,6 @@ module.exports = function( grunt ) { config = grunt.file.readJSON( configFile ).jquery, tests = grunt.config([ this.name, "tests" ]); - if ( !browserSets ) { - browserSets = [ "popular-no-old-ie", "ios" ]; - } - if ( pull ) { jobName = "Pull #" + pull[ 1 ] + ""; @@ -30,7 +26,7 @@ module.exports = function( grunt ) { testswarm.createClient( { url: config.swarmUrl, pollInterval: 10000, - timeout: 1000 * 60 * 30 + timeout: timeout || 1000 * 60 * 30 } ) .addReporter( testswarm.reporters.cli ) .auth( { @@ -42,7 +38,7 @@ module.exports = function( grunt ) { name: jobName, runs: runs, runMax: config.runMax, - browserSets: browserSets + browserSets: browserSets || [ "popular-no-old-ie", "ios" ] }, function( err, passed ) { if ( err ) { grunt.log.error( err ); From 22c515c6717efe46685b43215208aa4e5648fbc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=CC=88rn=20Zaefferer?= Date: Wed, 12 Mar 2014 11:08:16 +0100 Subject: [PATCH 0016/1272] Build: Fix testswarm task, use API correctly --- build/tasks/testswarm.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index 135a3cc7ef..3de7a089b5 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -23,10 +23,8 @@ module.exports = function( grunt ) { runs[ test ] = config.testUrl + commit + "/test/index.html?module=" + test; }); - testswarm.createClient( { - url: config.swarmUrl, - pollInterval: 10000, - timeout: timeout || 1000 * 60 * 30 + testswarm.createClient({ + url: config.swarmUrl } ) .addReporter( testswarm.reporters.cli ) .auth( { @@ -38,7 +36,8 @@ module.exports = function( grunt ) { name: jobName, runs: runs, runMax: config.runMax, - browserSets: browserSets || [ "popular-no-old-ie", "ios" ] + browserSets: browserSets || [ "popular-no-old-ie", "ios" ], + timeout: timeout || 1000 * 60 * 30 }, function( err, passed ) { if ( err ) { grunt.log.error( err ); From 26ce21786252981563e49e91a85b3e0bfa16c3e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Thu, 13 Mar 2014 01:46:18 +0100 Subject: [PATCH 0017/1272] Support: Make the support matrix for iOS 6 match iOS 7 as well --- 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 feea7dd350..867ba1d749 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -195,7 +195,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec "radioValue": true, "reliableMarginRight": true }; - } else if ( /iphone os 6_0/i.test( userAgent ) ) { + } else if ( /iphone os (?:6|7)_/i.test( userAgent ) ) { expected = { "ajax": true, "boxSizingReliable": true, From 6a89db86ed817f6a7498076e2a06b90f9fce0831 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Wed, 5 Mar 2014 22:46:23 -0500 Subject: [PATCH 0018/1272] Event: Call underlying stopImmediatePropagation when present Fixes #13997 --- src/event.js | 7 +++++++ test/unit/event.js | 15 +++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/event.js b/src/event.js index ee1f3fcadf..35c1c66b7f 100644 --- a/src/event.js +++ b/src/event.js @@ -683,7 +683,14 @@ jQuery.Event.prototype = { } }, stopImmediatePropagation: function() { + var e = this.originalEvent; + this.isImmediatePropagationStopped = returnTrue; + + if ( e && e.stopImmediatePropagation ) { + e.stopImmediatePropagation(); + } + this.stopPropagation(); } }; diff --git a/test/unit/event.js b/test/unit/event.js index 84cad50ac8..d93e8f778f 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -386,10 +386,13 @@ test("on immediate propagation", function() { $p.off( "click", "**" ); }); -test("on bubbling, isDefaultPrevented", function() { - expect(2); +test("on bubbling, isDefaultPrevented, stopImmediatePropagation", function() { + expect( 3 ); var $anchor2 = jQuery( "#anchor2" ), $main = jQuery( "#qunit-fixture" ), + neverCallMe = function() { + ok( false, "immediate propagation should have been stopped" ); + }, fakeClick = function($jq) { // Use a native click so we don't get jQuery simulated bubbling var e = document.createEvent( "MouseEvents" ); @@ -414,6 +417,14 @@ test("on bubbling, isDefaultPrevented", function() { fakeClick( $anchor2 ); $anchor2.off( "click" ); $main.off( "click", "**" ); + + $anchor2.on( "click", function( e ) { + e.stopImmediatePropagation(); + ok( true, "anchor was clicked and prop stopped" ); + }); + $anchor2[0].addEventListener( "click", neverCallMe, false ); + fakeClick( $anchor2 ); + $anchor2[0].removeEventListener( "click", neverCallMe ); }); test("on(), iframes", function() { From 854d242db457e3191e3ca1f2a366f6c981a12fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Thu, 13 Mar 2014 03:26:27 +0100 Subject: [PATCH 0019/1272] Core: Bump timeouts to stabilize doc ready test The "document ready when jQuery loaded asynchronously" test fails all the time in iOS7 and sometimes in other browsers. Bumping the timeouts *might* help these other browsers to be less flakey here. --- test/data/core/dont_return.php | 2 +- test/data/core/dynamic_ready.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/data/core/dont_return.php b/test/data/core/dont_return.php index 3ac56e1efd..4168cb3f71 100644 --- a/test/data/core/dont_return.php +++ b/test/data/core/dont_return.php @@ -1,3 +1,3 @@ diff --git a/test/data/core/dynamic_ready.html b/test/data/core/dynamic_ready.html index 799145b981..3b29c11048 100644 --- a/test/data/core/dynamic_ready.html +++ b/test/data/core/dynamic_ready.html @@ -28,7 +28,7 @@ timeoutId = setTimeout(function () { timeoutFired = true; window.parent.iframeCallback( false ); - }, 3000); + }, 10000); }); From 2585ee58809c22a3c97f87b1b4aa68dbd41f386c Mon Sep 17 00:00:00 2001 From: "S. Andrew Sheppard" Date: Thu, 9 Jan 2014 15:27:18 -0600 Subject: [PATCH 0020/1272] AMD: Note on AMD best practices Fixes #14687 Closes gh-1478 --- AUTHORS.txt | 1 + src/exports/amd.js | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index f5c06a6d24..b30e719a98 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -215,3 +215,4 @@ John Paul Jakob Stoeck Christopher Jones Forbes Lindesay +S. Andrew Sheppard diff --git a/src/exports/amd.js b/src/exports/amd.js index 815b5d88af..9a9846f9f6 100644 --- a/src/exports/amd.js +++ b/src/exports/amd.js @@ -9,6 +9,12 @@ define([ // derived from file names, and jQuery is normally delivered in a lowercase // file name. Do this after creating the global so that if an AMD module wants // to call noConflict to hide this version of jQuery, it will work. + +// Note that for maximum portability, libraries that are not jQuery should +// declare themselves as anonymous modules, and avoid setting a global if an +// AMD loader is present. jQuery is a special case. For more information, see +// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon + if ( typeof define === "function" && define.amd ) { define( "jquery", [], function() { return jQuery; From 594687abdcd8427df1face9466ebff7f04b36fc6 Mon Sep 17 00:00:00 2001 From: Leonardo Balter Date: Wed, 22 Jan 2014 01:47:54 -0200 Subject: [PATCH 0021/1272] Readme: updating QUnit information updates QUnit reference site and method naming. Closes gh-1493 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48880de716..9f75b74bb5 100644 --- a/README.md +++ b/README.md @@ -246,7 +246,7 @@ Following are some commands that can be used there: * `Ctrl + S` - save * `Ctrl + Q` - quit -[QUnit](http://docs.jquery.com/QUnit) Reference +[QUnit](http://api.qunitjs.com) Reference ----------------- ### Test methods ### From c29e9c4db18738f7bfeb6b4a8019121a9079beb6 Mon Sep 17 00:00:00 2001 From: Roman Rei_ Date: Mon, 10 Mar 2014 19:30:22 +0100 Subject: [PATCH 0022/1272] CSS: Add flex-grow and flex-shrink to cssNumber Fixes #14888 Closes gh-1536 --- .mailmap | 1 + AUTHORS.txt | 1 + src/css.js | 2 ++ 3 files changed, 4 insertions(+) diff --git a/.mailmap b/.mailmap index c28005fe06..53c5fdab26 100644 --- a/.mailmap +++ b/.mailmap @@ -77,6 +77,7 @@ Richard D. Worth Rick Waldron Rick Waldron Robert Katić +Roman Reiß Ron Otten Sai Lung Wong Scott González diff --git a/AUTHORS.txt b/AUTHORS.txt index b30e719a98..0aff9194c0 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -216,3 +216,4 @@ Jakob Stoeck Christopher Jones Forbes Lindesay S. Andrew Sheppard +Roman Reiß diff --git a/src/css.js b/src/css.js index 5e22dae00f..2a3a84d00b 100644 --- a/src/css.js +++ b/src/css.js @@ -222,6 +222,8 @@ jQuery.extend({ cssNumber: { "columnCount": true, "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, "fontWeight": true, "lineHeight": true, "opacity": true, From aa951a3184fc02551bfcb8381cdac28298432419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Sun, 16 Mar 2014 04:09:12 +0100 Subject: [PATCH 0023/1272] Build: Refactor testswarm Grunt task options Add a possibility to specify the project name. Infer browserSets & timeout out of it instead of defining it in the Jenkins configuration. --- build/tasks/testswarm.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index 3de7a089b5..c4839ae603 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -2,14 +2,16 @@ module.exports = function( grunt ) { "use strict"; - grunt.registerTask( "testswarm", function( commit, configFile, browserSets, timeout ) { - var jobName, + grunt.registerTask( "testswarm", function( commit, configFile, projectName ) { + var jobName, config, tests, testswarm = require( "testswarm" ), runs = {}, done = this.async(), - pull = /PR-(\d+)/.exec( commit ), - config = grunt.file.readJSON( configFile ).jquery, - tests = grunt.config([ this.name, "tests" ]); + pull = /PR-(\d+)/.exec( commit ); + + projectName = projectName || "jquery"; + config = grunt.file.readJSON( configFile )[ projectName ]; + tests = grunt.config([ this.name, "tests" ]); if ( pull ) { jobName = "Pull Date: Thu, 30 Jan 2014 16:07:06 +0100 Subject: [PATCH 0025/1272] Event: Treat Pointer events like mouse events, #14741 Ref #14741 Ref gh-1503 --- src/event.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/event.js b/src/event.js index 35c1c66b7f..b08fde6a78 100644 --- a/src/event.js +++ b/src/event.js @@ -14,7 +14,7 @@ define([ var rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, + rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/, rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; @@ -699,7 +699,9 @@ jQuery.Event.prototype = { // Support: Chrome 15+ jQuery.each({ mouseenter: "mouseover", - mouseleave: "mouseout" + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { delegateType: fix, From 472f70a9df75c289393d6618c36257a04f9cb902 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Sun, 16 Mar 2014 10:46:57 -0400 Subject: [PATCH 0026/1272] Event: Unit test for #14741 fix Fixes #14741 Closes gh-1503 --- test/unit/event.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/unit/event.js b/test/unit/event.js index d93e8f778f..e8cfd715cc 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -840,6 +840,20 @@ test("mouseover triggers mouseenter", function() { elem.remove(); }); +test("pointerover triggers pointerenter", function() { + expect(1); + + var count = 0, + elem = jQuery(""); + elem.on( "pointerenter", function () { + count++; + }); + elem.trigger("pointerover"); + equal(count, 1, "make sure pointerover triggers a pointerenter" ); + + elem.remove(); +}); + test("withinElement implemented with jQuery.contains()", function() { expect(1); From 551578eb3676f67cccd8a91a582c2225bc970cac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Mon, 17 Mar 2014 18:13:00 +0100 Subject: [PATCH 0027/1272] Core: Blacklist the ready test on async-loaded jQuery in iOS7 Fixes #14882 --- test/unit/core.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/unit/core.js b/test/unit/core.js index d1b221ce87..681fef5dc7 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1505,10 +1505,15 @@ testIframeWithCallback( "Conditional compilation compatibility (#13274)", "core/ ok( $(), "jQuery executes" ); }); -testIframeWithCallback( "document ready when jQuery loaded asynchronously (#13655)", "core/dynamic_ready.html", function( ready ) { - expect( 1 ); - equal( true, ready, "document ready correctly fired when jQuery is loaded after DOMContentLoaded" ); -}); +// iOS7 doesn't fire the load event if the long-loading iframe gets its source reset to about:blank. +// This makes this test fail but it doesn't seem to cause any real-life problems so blacklisting +// this test there is preferred to complicating the hard-to-test core/ready code further. +if ( !/iphone os 7_/i.test( navigator.userAgent ) ) { + testIframeWithCallback( "document ready when jQuery loaded asynchronously (#13655)", "core/dynamic_ready.html", function( ready ) { + expect( 1 ); + equal( true, ready, "document ready correctly fired when jQuery is loaded after DOMContentLoaded" ); + }); +} testIframeWithCallback( "Tolerating alias-masked DOM properties (#14074)", "core/aliased.html", function( errors ) { From c1e9bb9e61a79a1d0c4300cc31eac7ff61107085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Tue, 18 Mar 2014 11:55:06 +0100 Subject: [PATCH 0028/1272] Build: Change the timeout for the weekly job from 4h to 1h --- build/tasks/testswarm.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index c4839ae603..1e4e045317 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -38,10 +38,10 @@ module.exports = function( grunt ) { name: jobName, runs: runs, runMax: config.runMax, - browserSets: projectName === "jquery" ? - [ "popular-no-old-ie", "ios" ] : - "weekly-no-old-ie", - timeout: projectName === "jquery" ? 1000 * 60 * 30 : 1000 * 60 * 60 * 4 + browserSets: projectName === "jqueryweekly" ? + "weekly-no-old-ie" : + [ "popular-no-old-ie", "ios" ], + timeout: projectName === "jqueryweekly" ? 1000 * 60 * 60 : 1000 * 60 * 30 }, function( err, passed ) { if ( err ) { grunt.log.error( err ); From b5074944b0b27f50ffe2ca9f96348b8d0cd5c82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Tue, 18 Mar 2014 16:50:04 +0100 Subject: [PATCH 0029/1272] Core: Change the sleep time in dont_return.php to a sane value PHP sleep function accepts time in seconds, not milliseconds; the previous value was starving the PHP FPM process pool. --- test/data/core/dont_return.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data/core/dont_return.php b/test/data/core/dont_return.php index 4168cb3f71..45565b6e72 100644 --- a/test/data/core/dont_return.php +++ b/test/data/core/dont_return.php @@ -1,3 +1,3 @@ From 14e0a632a04e114dbf6cc044e74c3260c7f28a7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Tue, 18 Mar 2014 20:55:50 +0100 Subject: [PATCH 0030/1272] Event: Don't test stopImmediatePropagation in Android 2.3 Android 2.3 doesn't support stopImmediatePropagation; jQuery fallbacks to stopPropagation in such a case. --- test/unit/event.js | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/test/unit/event.js b/test/unit/event.js index e8cfd715cc..6e5a2d09ec 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -387,7 +387,13 @@ test("on immediate propagation", function() { }); test("on bubbling, isDefaultPrevented, stopImmediatePropagation", function() { - expect( 3 ); + // Support: Android 2.3 + if ( /android 2\.3/i.test( navigator.userAgent ) ) { + expect( 2 ); + } else { + expect( 3 ); + } + var $anchor2 = jQuery( "#anchor2" ), $main = jQuery( "#qunit-fixture" ), neverCallMe = function() { @@ -418,13 +424,18 @@ test("on bubbling, isDefaultPrevented, stopImmediatePropagation", function() { $anchor2.off( "click" ); $main.off( "click", "**" ); - $anchor2.on( "click", function( e ) { - e.stopImmediatePropagation(); - ok( true, "anchor was clicked and prop stopped" ); - }); - $anchor2[0].addEventListener( "click", neverCallMe, false ); - fakeClick( $anchor2 ); - $anchor2[0].removeEventListener( "click", neverCallMe ); + // Android 2.3 doesn't support stopImmediatePropagation; jQuery fallbacks to stopPropagation + // in such a case. + // Support: Android 2.3 + if ( !/android 2\.3/i.test( navigator.userAgent ) ) { + $anchor2.on( "click", function( e ) { + e.stopImmediatePropagation(); + ok( true, "anchor was clicked and prop stopped" ); + }); + $anchor2[0].addEventListener( "click", neverCallMe, false ); + fakeClick( $anchor2 ); + $anchor2[0].removeEventListener( "click", neverCallMe ); + } }); test("on(), iframes", function() { From 55c196e8377221f1b417eda5cda74a56c5cae96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Tue, 18 Mar 2014 20:59:33 +0100 Subject: [PATCH 0031/1272] Event: Simplify the logic behind blacklisting Android 2.3 on one test --- test/unit/event.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/test/unit/event.js b/test/unit/event.js index 6e5a2d09ec..67fe9115b7 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -387,12 +387,7 @@ test("on immediate propagation", function() { }); test("on bubbling, isDefaultPrevented, stopImmediatePropagation", function() { - // Support: Android 2.3 - if ( /android 2\.3/i.test( navigator.userAgent ) ) { - expect( 2 ); - } else { - expect( 3 ); - } + expect( 3 ); var $anchor2 = jQuery( "#anchor2" ), $main = jQuery( "#qunit-fixture" ), @@ -427,7 +422,9 @@ test("on bubbling, isDefaultPrevented, stopImmediatePropagation", function() { // Android 2.3 doesn't support stopImmediatePropagation; jQuery fallbacks to stopPropagation // in such a case. // Support: Android 2.3 - if ( !/android 2\.3/i.test( navigator.userAgent ) ) { + if ( /android 2\.3/i.test( navigator.userAgent ) ) { + ok( true, "Android 2.3, skipping native stopImmediatePropagation check" ); + } else { $anchor2.on( "click", function( e ) { e.stopImmediatePropagation(); ok( true, "anchor was clicked and prop stopped" ); From a10aa3aac5223c250327d00c500ceb9c7a18b7f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Wed, 19 Mar 2014 02:29:04 +0100 Subject: [PATCH 0032/1272] Core: Change the sleep time in dont_return.php from 100s to 30s Half a minute is more than enough for the test to finish even in the slowest browsers and in case of starving the PHP FPM process pool, one has to wait for only half a minute to try again. --- test/data/core/dont_return.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data/core/dont_return.php b/test/data/core/dont_return.php index 45565b6e72..1eef336926 100644 --- a/test/data/core/dont_return.php +++ b/test/data/core/dont_return.php @@ -1,3 +1,3 @@ From 3ffd95bdb13ade8a40a7dd975e6aca401b7a3d11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=CC=88rn=20Zaefferer?= Date: Fri, 21 Feb 2014 12:53:00 +0100 Subject: [PATCH 0033/1272] Package: Sort devDependencies --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index da9cfbfedd..06ae1f13b7 100644 --- a/package.json +++ b/package.json @@ -30,21 +30,21 @@ "dependencies": {}, "devDependencies": { "archiver": "0.5.2", - "gzip-js": "0.3.2", - "testswarm": "1.1.0", - "load-grunt-tasks": "0.3.0", - "requirejs": "2.1.10", - "shelljs": "0.2.6", "grunt": "0.4.2", + "grunt-bowercopy": "0.7.1", "grunt-cli": "0.1.13", + "grunt-compare-size": "0.4.0", "grunt-contrib-jshint": "0.8.0", "grunt-contrib-uglify": "0.3.2", "grunt-contrib-watch": "0.5.3", - "grunt-bowercopy": "0.7.1", - "grunt-compare-size": "0.4.0", "grunt-git-authors": "1.2.0", "grunt-jscs-checker": "0.3.2", - "grunt-jsonlint": "1.0.4" + "grunt-jsonlint": "1.0.4", + "gzip-js": "0.3.2", + "load-grunt-tasks": "0.3.0", + "requirejs": "2.1.10", + "shelljs": "0.2.6", + "testswarm": "1.1.0" }, "scripts": { "build": "npm install && grunt", From d3c1ce9c243e04f80e2093e20ffe16bbade93985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=CC=88rn=20Zaefferer?= Date: Fri, 21 Feb 2014 12:53:36 +0100 Subject: [PATCH 0034/1272] Build: Add commitplease for commit msg checking Closes gh-1523 --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 06ae1f13b7..874e1b7c3a 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "dependencies": {}, "devDependencies": { "archiver": "0.5.2", + "commitplease": "1.7.0", "grunt": "0.4.2", "grunt-bowercopy": "0.7.1", "grunt-cli": "0.1.13", From 9ad6e7e93e62a27e6ef803fbf46623bca732750f Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Thu, 20 Mar 2014 09:00:22 -0400 Subject: [PATCH 0035/1272] Tests: Remove obsolete speed directory Closes gh-1551 --- speed/benchmark.js | 15 - speed/benchmarker.css | 65 - speed/benchmarker.js | 181 -- speed/closest.html | 39 - speed/css.html | 82 - speed/event.html | 58 - speed/filter.html | 183 -- speed/find.html | 179 -- speed/index.html | 72 - speed/jquery-basis.js | 6238 ------------------------------------ speed/slice.vs.concat.html | 47 - 11 files changed, 7159 deletions(-) delete mode 100644 speed/benchmark.js delete mode 100644 speed/benchmarker.css delete mode 100644 speed/benchmarker.js delete mode 100644 speed/closest.html delete mode 100644 speed/css.html delete mode 100644 speed/event.html delete mode 100644 speed/filter.html delete mode 100644 speed/find.html delete mode 100644 speed/index.html delete mode 100644 speed/jquery-basis.js delete mode 100644 speed/slice.vs.concat.html diff --git a/speed/benchmark.js b/speed/benchmark.js deleted file mode 100644 index 334abf15d1..0000000000 --- a/speed/benchmark.js +++ /dev/null @@ -1,15 +0,0 @@ -// Runs a function many times without the function call overhead -function benchmark(fn, times, name){ - fn = fn.toString(); - var s = fn.indexOf('{')+1, - e = fn.lastIndexOf('}'); - fn = fn.substring(s,e); - - return benchmarkString(fn, times, name); -} - -function benchmarkString(fn, times, name) { - var fn = new Function("i", "var t=new Date; while(i--) {" + fn + "}; return new Date - t")(times) - fn.displayName = name || "benchmarked"; - return fn; -} diff --git a/speed/benchmarker.css b/speed/benchmarker.css deleted file mode 100644 index 6c5b4c35b6..0000000000 --- a/speed/benchmarker.css +++ /dev/null @@ -1,65 +0,0 @@ - - .dialog { - margin-bottom: 1em; - } - a.expand { - background: #e3e3e3; - } - - div#time-test { - font-family: Arial, Helvetica, sans-serif; - font-size: 62.5%; - } - - td.test button { - float: right; - } - - table { - border: 1px solid #000; - } - - table td, table th { - border: 1px solid #000; - padding: 10px; - } - - td.winner { - background-color: #cfc; - } - - td.tie { - background-color: #ffc; - } - - td.fail { - background-color: #f99; - font-weight: bold; - text-align: center; - } - - tfoot td { - text-align: center; - } - - #time-test { - margin: 1em 0; - padding: .5em; - background: #e3e3e3; - } - #time-taken { - font-weight: bold; - } - - span.wins { - color: #330; - } - - span.fails { - color: #900; - } - - div.buttons { - margin-top: 10px; - margin-bottom: 10px; - } diff --git a/speed/benchmarker.js b/speed/benchmarker.js deleted file mode 100644 index 602f5ac318..0000000000 --- a/speed/benchmarker.js +++ /dev/null @@ -1,181 +0,0 @@ - jQuery.benchmarker.tests = [ - // Selectors from: - // http://ejohn.org/blog/selectors-that-people-actually-use/ - /* - // For Amazon.com - "#navAmazonLogo", "#navSwmSkedPop", - ".navbar", ".navGreeting", - "div", "table", - "img.navCrossshopTabCap", "span.navGreeting", - "#navbar table", "#navidWelcomeMsg span", - "div#navbar", "ul#navAmazonLogo", - "#navAmazonLogo .navAmazonLogoGatewayPanel", "#navidWelcomeMsg .navGreeting", - ".navbar .navAmazonLogoGatewayPanel", ".navbar .navGreeting", - "*", - "#navAmazonLogo li.navAmazonLogoGatewayPanel", "#navidWelcomeMsg span.navGreeting", - "a[name=top]", "form[name=site-search]", - ".navbar li", ".navbar span", - "[name=top]", "[name=site-search]", - "ul li", "a img", - "#navbar #navidWelcomeMsg", "#navbar #navSwmDWPop", - "#navbar ul li", "#navbar a img" - */ - // For Yahoo.com - "#page", "#masthead", "#mastheadhd", - ".mastheadbd", ".first", ".on", - "div", "li", "a", - "div.mastheadbd", "li.first", "li.on", - "#page div", "#dtba span", - "div#page", "div#masthead", - "#page .mastheadbd", "#page .first", - ".outer_search_container .search_container", ".searchbox_container .inputtext", - "*", - "#page div.mastheadbd", "#page li.first", - "input[name=p]", "a[name=marketplace]", - ".outer_search_container div", ".searchbox_container span", - "[name=p]", "[name=marketplace]", - "ul li", "form input", - "#page #e2econtent", "#page #e2e" - ]; - - jQuery.fn.benchmark = function() { - this.each(function() { - try { - jQuery(this).parent().children("*:gt(1)").remove(); - } catch(e) { } - }) - // set # times to run the test in index.html - var times = parseInt(jQuery("#times").val()); - jQuery.benchmarker.startingList = this.get(); - benchmark(this.get(), times, jQuery.benchmarker.libraries); - } - - jQuery(function() { - for(i = 0; i < jQuery.benchmarker.tests.length; i++) { - jQuery("tbody").append("" + jQuery.benchmarker.tests[i] + ""); - } - jQuery("tbody tr:first-child").remove(); - jQuery("td.test").before(""); - jQuery("button.runTests").bind("click", function() { - jQuery('td:has(input:checked) + td.test').benchmark(); - }); - - jQuery("button.retryTies").bind("click", function() { jQuery("tr:has(td.tie) td.test").benchmark() }) - - jQuery("button.selectAll").bind("click", function() { jQuery("input[type=checkbox]").each(function() { this.checked = true }) }) - jQuery("button.deselectAll").bind("click", function() { jQuery("input[type=checkbox]").each(function() { this.checked = false }) }) - - jQuery("#addTest").bind("click", function() { - jQuery("table").append(""); - jQuery("div#time-test > button").each(function() { this.disabled = true; }) - jQuery("tbody tr:last button").bind("click", function() { - var td = jQuery(this).parent(); - td.html("" + jQuery(this).prev().val()).addClass("test"); - jQuery("div#time-test > button").each(function() { this.disabled = false; }) - jQuery("button", td).bind("click", function() { jQuery(this).parents("tr").remove(); }) - }) - }) - - var headers = jQuery.map(jQuery.benchmarker.libraries, function(i,n) { - var extra = n == 0 ? "basis - " : ""; - return "" + extra + i + "" - }).join(""); - - jQuery("thead tr").append(headers); - - var footers = ""; - for(i = 0; i < jQuery.benchmarker.libraries.length; i++) - footers += "" - - var wlfooters = ""; - for(i = 0; i < jQuery.benchmarker.libraries.length; i++) - wlfooters += "W / F" - - jQuery("tfoot tr:first").append(footers); - jQuery("tfoot tr:last").append(wlfooters); - - }); - - benchmark = function(list, times, libraries) { - if(list[0]) { - var times = times || 50; - var el = list[0]; - var code = jQuery(el).text().replace(/^-/, ""); - var timeArr = [] - for(i = 0; i < times + 2; i++) { - var time = new Date() - try { - window[libraries[0]](code); - } catch(e) { } - timeArr.push(new Date() - time); - } - var diff = Math.sum(timeArr) - Math.max.apply( Math, timeArr ) - - Math.min.apply( Math, timeArr ); - try { - var libRes = window[libraries[0]](code); - var jqRes = jQuery(code); - if(((jqRes.length == 0) && (libRes.length != 0)) || - (libRes.length > 0 && (jqRes.length == libRes.length)) || - ((libraries[0] == "cssQuery" || libraries[0] == "jQuery") && code.match(/nth\-child/) && (libRes.length > 0)) || - ((libraries[0] == "jQold") && jqRes.length > 0)) { - jQuery(el).parent().append("" + Math.round(diff / times * 100) / 100 + "ms"); - } else { - jQuery(el).parent().append("FAIL"); - } - } catch(e) { - jQuery(el).parent().append("FAIL"); - } - setTimeout(benchmarkList(list, times, libraries), 100); - } else if(libraries[1]) { - benchmark(jQuery.benchmarker.startingList, times, libraries.slice(1)); - } else { - jQuery("tbody tr").each(function() { - var winners = jQuery("td:gt(1)", this).min(2); - if(winners.length == 1) winners.addClass("winner"); - else winners.addClass("tie"); - }); - setTimeout(count, 100); - } - } - - function benchmarkList(list, times, libraries) { - return function() { - benchmark(list.slice(1), times, libraries); - } - } - - function count() { - for(i = 3; i <= jQuery.benchmarker.libraries.length + 2 ; i++) { - var fails = jQuery("td:nth-child(" + i + ").fail").length; - var wins = jQuery("td:nth-child(" + i + ").winner").length; - jQuery("tfoot tr:first th:eq(" + (i - 1) + ")") - .html("" + wins + " / " + fails + ""); - } - } - - - jQuery.fn.maxmin = function(tolerance, maxmin, percentage) { - tolerance = tolerance || 0; - var target = Math[maxmin].apply(Math, jQuery.map(this, function(i) { - var parsedNum = parseFloat(i.innerHTML.replace(/[^\.\d]/g, "")); - if(parsedNum || (parsedNum == 0)) return parsedNum; - })); - return this.filter(function() { - if( withinTolerance(parseFloat(this.innerHTML.replace(/[^\.\d]/g, "")), target, tolerance, percentage) ) return true; - }) - } - - jQuery.fn.max = function(tolerance, percentage) { return this.maxmin(tolerance, "max", percentage) } - jQuery.fn.min = function(tolerance, percentage) { return this.maxmin(tolerance, "min", percentage) } - - function withinTolerance(number, target, tolerance, percentage) { - if(percentage) { var high = target + ((tolerance / 100) * target); var low = target - ((tolerance / 100) * target); } - else { var high = target + tolerance; var low = target - tolerance; } - if(number >= low && number <= high) return true; - } - - Math.sum = function(arr) { - var sum = 0; - for(i = 0; i < arr.length; i++) sum += arr[i]; - return sum; - } diff --git a/speed/closest.html b/speed/closest.html deleted file mode 100644 index 12469f7db0..0000000000 --- a/speed/closest.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - Test .closest() Performance - - - - - - - -
-

Hello

-
-
-

lorem ipsum

-

dolor sit amet

-
-
-
-
    - - - diff --git a/speed/css.html b/speed/css.html deleted file mode 100644 index 4d6700cf48..0000000000 --- a/speed/css.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - Test Event Handling Performance - - - - - - - - -

    Getting Values: Loading...

    -

    Setting Values: Loading...

    - - diff --git a/speed/event.html b/speed/event.html deleted file mode 100644 index eb4dfc7cea..0000000000 --- a/speed/event.html +++ /dev/null @@ -1,58 +0,0 @@ - - - - Test Event Handling Performance - - - - - - - -

    Move the mouse, please!

    -

    - - diff --git a/speed/filter.html b/speed/filter.html deleted file mode 100644 index e19e82c61a..0000000000 --- a/speed/filter.html +++ /dev/null @@ -1,183 +0,0 @@ - - - - Test .filter() Performance - - - - - - - -
    -

    Hello

    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
      - - - diff --git a/speed/find.html b/speed/find.html deleted file mode 100644 index 01ed1d3a1d..0000000000 --- a/speed/find.html +++ /dev/null @@ -1,179 +0,0 @@ - - - - Test .find() Performance - - - - - - - -
      -

      Hello

      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      -
        - - - diff --git a/speed/index.html b/speed/index.html deleted file mode 100644 index 74c67bc39f..0000000000 --- a/speed/index.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - Speed Test - - - - - - - - -

        Speed Test

        -
        -
        -

        Using the following selector expressions ( times each):

        -

        NOTE: Number shown is an average.

        -
        - - - - - -
        - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Run?Test
        - -
        - - - - - - -
        -
        -
        - - - - - diff --git a/speed/jquery-basis.js b/speed/jquery-basis.js deleted file mode 100644 index 9335cc0bb3..0000000000 --- a/speed/jquery-basis.js +++ /dev/null @@ -1,6238 +0,0 @@ -/*! - * jQuery JavaScript Library v1.4.2 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Sat Feb 13 22:33:48 2010 -0500 - */ -(function( window, undefined ) { - -// Define a local copy of jQuery -var jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context ); - }, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - - // A central reference to the root jQuery(document) - rootjQuery, - - // A simple way to check for HTML strings or ID strings - // (both of which we optimize for) - quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/, - - // Is it a simple selector - isSimple = /^.[^:#\[\.,]*$/, - - // Check if a string has a non-whitespace character in it - rnotwhite = /\S/, - - // Used for trimming whitespace - rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, - - // Keep a UserAgent string for use with jQuery.browser - userAgent = navigator.userAgent, - - // For matching the engine and version of the browser - browserMatch, - - // Has the ready events already been bound? - readyBound = false, - - // The functions to execute on DOM ready - readyList = [], - - // The ready event handler - DOMContentLoaded, - - // Save a reference to some core methods - toString = Object.prototype.toString, - hasOwnProperty = Object.prototype.hasOwnProperty, - push = Array.prototype.push, - slice = Array.prototype.slice, - indexOf = Array.prototype.indexOf; - -jQuery.fn = jQuery.prototype = { - init: function( selector, context ) { - var match, elem, ret, doc; - - // Handle $(""), $(null), or $(undefined) - if ( !selector ) { - return this; - } - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - } - - // The body element only exists once, optimize finding it - if ( selector === "body" && !context ) { - this.context = document; - this[0] = document.body; - this.selector = "body"; - this.length = 1; - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - // Are we dealing with HTML string or an ID? - match = quickExpr.exec( selector ); - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - doc = (context ? context.ownerDocument || context : document); - - // If a single string is passed in and it's a single tag - // just do a createElement and skip the rest - ret = rsingleTag.exec( selector ); - - if ( ret ) { - if ( jQuery.isPlainObject( context ) ) { - selector = [ document.createElement( ret[1] ) ]; - jQuery.fn.attr.call( selector, context, true ); - - } else { - selector = [ doc.createElement( ret[1] ) ]; - } - - } else { - ret = buildFragment( [ match[1] ], [ doc ] ); - selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; - } - - return jQuery.merge( this, selector ); - - // HANDLE: $("#id") - } else { - elem = document.getElementById( match[2] ); - - if ( elem ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $("TAG") - } else if ( !context && /^\w+$/.test( selector ) ) { - this.selector = selector; - this.context = document; - selector = document.getElementsByTagName( selector ); - return jQuery.merge( this, selector ); - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return (context || rootjQuery).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return jQuery( context ).find( selector ); - } - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if (selector.selector !== undefined) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The current version of jQuery being used - jquery: "1.4.2", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return slice.call( this, 0 ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems, name, selector ) { - // Build a new jQuery matched element set - var ret = jQuery(); - - if ( jQuery.isArray( elems ) ) { - push.apply( ret, elems ); - - } else { - jQuery.merge( ret, elems ); - } - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - ret.context = this.context; - - if ( name === "find" ) { - ret.selector = this.selector + (this.selector ? " " : "") + selector; - } else if ( name ) { - ret.selector = this.selector + "." + name + "(" + selector + ")"; - } - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Attach the listeners - jQuery.bindReady(); - - // If the DOM is already ready - if ( jQuery.isReady ) { - // Execute the function immediately - fn.call( document, jQuery ); - - // Otherwise, remember the function for later - } else if ( readyList ) { - // Add the function to the wait list - readyList.push( fn ); - } - - return this; - }, - - eq: function( i ) { - return i === -1 ? - this.slice( i ) : - this.slice( i, +i + 1 ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ), - "slice", slice.call(arguments).join(",") ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || jQuery(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - // copy reference to target object - var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging object literal values or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) { - var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src - : jQuery.isArray(copy) ? [] : {}; - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - window.$ = _$; - - if ( deep ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // Handle when the DOM is ready - ready: function() { - // Make sure that the DOM is not already loaded - if ( !jQuery.isReady ) { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready, 13 ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If there are functions bound, to execute - if ( readyList ) { - // Execute all of them - var fn, i = 0; - while ( (fn = readyList[ i++ ]) ) { - fn.call( document, jQuery ); - } - - // Reset the list of functions - readyList = null; - } - - // Trigger any bound ready events - if ( jQuery.fn.triggerHandler ) { - jQuery( document ).triggerHandler( "ready" ); - } - } - }, - - bindReady: function() { - if ( readyBound ) { - return; - } - - readyBound = true; - - // Catch cases where $(document).ready() is called after the - // browser event has already occurred. - if ( document.readyState === "complete" ) { - return jQuery.ready(); - } - - // Mozilla, Opera and webkit nightlies currently support this event - if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", jQuery.ready, false ); - - // If IE event model is used - } else if ( document.attachEvent ) { - // ensure firing before onload, - // maybe late but safe also for iframes - document.attachEvent("onreadystatechange", DOMContentLoaded); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", jQuery.ready ); - - // If IE and not a frame - // continually check to see if the document is ready - var toplevel = false; - - try { - toplevel = window.frameElement == null; - } catch(e) {} - - if ( document.documentElement.doScroll && toplevel ) { - doScrollCheck(); - } - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return toString.call(obj) === "[object Function]"; - }, - - isArray: function( obj ) { - return toString.call(obj) === "[object Array]"; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { - return false; - } - - // Not own constructor property must be Object - if ( obj.constructor - && !hasOwnProperty.call(obj, "constructor") - && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || hasOwnProperty.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - for ( var name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw msg; - }, - - parseJSON: function( data ) { - if ( typeof data !== "string" || !data ) { - return null; - } - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") - .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") - .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) { - - // Try to use the native JSON parser first - return window.JSON && window.JSON.parse ? - window.JSON.parse( data ) : - (new Function("return " + data))(); - - } else { - jQuery.error( "Invalid JSON: " + data ); - } - }, - - noop: function() {}, - - // Evaluates a script in a global context - globalEval: function( data ) { - if ( data && rnotwhite.test(data) ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.head || document.getElementsByTagName("head")[0] || document.documentElement, - script = document.createElement("script"); - - if ( jQuery.support.scriptEval ) { - script.appendChild( document.createTextNode( data ) ); - } else { - script.text = data; - } - - // Use insertBefore instead of appendChild to circumvent an IE6 bug. - // This arises when a base node is used (#2709). - head.insertBefore( script, head.firstChild ); - head.removeChild( script ); - } - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); - }, - - // args is for internal usage only - each: function( object, callback, args ) { - var name, i = 0, - length = object.length, - isObj = length === undefined || jQuery.isFunction(object); - - if ( args ) { - if ( isObj ) { - for ( name in object ) { - if ( callback.apply( object[ name ], args ) === false ) { - break; - } - } - } else { - for ( ; i < length; ) { - if ( callback.apply( object[ i++ ], args ) === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isObj ) { - for ( name in object ) { - if ( callback.call( object[ name ], name, object[ name ] ) === false ) { - break; - } - } - } else { - for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} - } - } - - return object; - }, - - trim: function( text ) { - return (text || "").replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( array, results ) { - var ret = results || []; - - if ( array != null ) { - // The window, strings (and functions) also have 'length' - // The extra typeof function check is to prevent crashes - // in Safari 2 (See: #3039) - if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) { - push.call( ret, array ); - } else { - jQuery.merge( ret, array ); - } - } - - return ret; - }, - - inArray: function( 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; - }, - - merge: function( first, second ) { - var i = first.length, j = 0; - - if ( typeof second.length === "number" ) { - for ( var l = second.length; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var ret = []; - - // Go through the array, only saving the items - // that pass the validator function - for ( var i = 0, length = elems.length; i < length; i++ ) { - if ( !inv !== !callback( elems[ i ], i ) ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var ret = [], value; - - // Go through the array, translating each of the items to their - // new value (or values). - for ( var i = 0, length = elems.length; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - return ret.concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - proxy: function( fn, proxy, thisObject ) { - if ( arguments.length === 2 ) { - if ( typeof proxy === "string" ) { - thisObject = fn; - fn = thisObject[ proxy ]; - proxy = undefined; - - } else if ( proxy && !jQuery.isFunction( proxy ) ) { - thisObject = proxy; - proxy = undefined; - } - } - - if ( !proxy && fn ) { - proxy = function() { - return fn.apply( thisObject || this, arguments ); - }; - } - - // Set the guid of unique handler to the same of original handler, so it can be removed - if ( fn ) { - proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - } - - // So proxy can be declared as an argument - return proxy; - }, - - // Use of jQuery.browser is frowned upon. - // More details: http://docs.jquery.com/Utilities/jQuery.browser - uaMatch: function( ua ) { - ua = ua.toLowerCase(); - - var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) || - /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) || - /(msie) ([\w.]+)/.exec( ua ) || - !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) || - []; - - return { browser: match[1] || "", version: match[2] || "0" }; - }, - - browser: {} -}); - -browserMatch = jQuery.uaMatch( userAgent ); -if ( browserMatch.browser ) { - jQuery.browser[ browserMatch.browser ] = true; - jQuery.browser.version = browserMatch.version; -} - -// Deprecated, use jQuery.browser.webkit instead -if ( jQuery.browser.webkit ) { - jQuery.browser.safari = true; -} - -if ( indexOf ) { - jQuery.inArray = function( elem, array ) { - return indexOf.call( array, elem ); - }; -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); - -// Cleanup functions for the document ready method -if ( document.addEventListener ) { - DOMContentLoaded = function() { - document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); - jQuery.ready(); - }; - -} else if ( document.attachEvent ) { - DOMContentLoaded = function() { - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( document.readyState === "complete" ) { - document.detachEvent( "onreadystatechange", DOMContentLoaded ); - jQuery.ready(); - } - }; -} - -// The DOM ready check for Internet Explorer -function doScrollCheck() { - if ( jQuery.isReady ) { - return; - } - - try { - // If IE is used, use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - document.documentElement.doScroll("left"); - } catch( error ) { - setTimeout( doScrollCheck, 1 ); - return; - } - - // and execute any waiting functions - jQuery.ready(); -} - -function evalScript( i, elem ) { - if ( elem.src ) { - jQuery.ajax({ - url: elem.src, - async: false, - dataType: "script" - }); - } else { - jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); - } - - if ( elem.parentNode ) { - elem.parentNode.removeChild( elem ); - } -} - -// Multifunctional method to get and set values to a collection -// The value/s can be optionally by executed if its a function -function access( elems, key, value, exec, fn, pass ) { - var length = elems.length; - - // Setting many attributes - if ( typeof key === "object" ) { - for ( var k in key ) { - access( elems, k, key[k], exec, fn, value ); - } - return elems; - } - - // Setting one attribute - if ( value !== undefined ) { - // Optionally, function values get executed if exec is true - exec = !pass && exec && jQuery.isFunction(value); - - for ( var i = 0; i < length; i++ ) { - fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); - } - - return elems; - } - - // Getting an attribute - return length ? fn( elems[0], key ) : undefined; -} - -function now() { - return (new Date).getTime(); -} -(function() { - - jQuery.support = {}; - - var root = document.documentElement, - script = document.createElement("script"), - div = document.createElement("div"), - id = "script" + now(); - - div.style.display = "none"; - div.innerHTML = "
        a"; - - var all = div.getElementsByTagName("*"), - a = div.getElementsByTagName("a")[0]; - - // Can't get basic test support - if ( !all || !all.length || !a ) { - return; - } - - jQuery.support = { - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: div.firstChild.nodeType === 3, - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText insted) - style: /red/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: a.getAttribute("href") === "/a", - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.55$/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Make sure that if no value is specified for a checkbox - // that it defaults to "on". - // (WebKit defaults to "" instead) - checkOn: div.getElementsByTagName("input")[0].value === "on", - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected, - - parentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null, - - // Will be defined later - deleteExpando: true, - checkClone: false, - scriptEval: false, - noCloneEvent: true, - boxModel: null - }; - - script.type = "text/javascript"; - try { - script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); - } catch(e) {} - - root.insertBefore( script, root.firstChild ); - - // Make sure that the execution of code works by injecting a script - // tag with appendChild/createTextNode - // (IE doesn't support this, fails, and uses .text instead) - if ( window[ id ] ) { - jQuery.support.scriptEval = true; - delete window[ id ]; - } - - // Test to see if it's possible to delete an expando from an element - // Fails in Internet Explorer - try { - delete script.test; - - } catch(e) { - jQuery.support.deleteExpando = false; - } - - root.removeChild( script ); - - if ( div.attachEvent && div.fireEvent ) { - div.attachEvent("onclick", function click() { - // Cloning a node shouldn't copy over any - // bound event handlers (IE does this) - jQuery.support.noCloneEvent = false; - div.detachEvent("onclick", click); - }); - div.cloneNode(true).fireEvent("onclick"); - } - - div = document.createElement("div"); - div.innerHTML = ""; - - var fragment = document.createDocumentFragment(); - fragment.appendChild( div.firstChild ); - - // WebKit doesn't clone checked state correctly in fragments - jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; - - // Figure out if the W3C box model works as expected - // document.body must exist before we can do this - jQuery(function() { - var div = document.createElement("div"); - div.style.width = div.style.paddingLeft = "1px"; - - document.body.appendChild( div ); - jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; - document.body.removeChild( div ).style.display = 'none'; - - div = null; - }); - - // Technique from Juriy Zaytsev - // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ - var eventSupported = function( eventName ) { - var el = document.createElement("div"); - eventName = "on" + eventName; - - var isSupported = (eventName in el); - if ( !isSupported ) { - el.setAttribute(eventName, "return;"); - isSupported = typeof el[eventName] === "function"; - } - el = null; - - return isSupported; - }; - - jQuery.support.submitBubbles = eventSupported("submit"); - jQuery.support.changeBubbles = eventSupported("change"); - - // release memory in IE - root = script = div = all = a = null; -})(); - -jQuery.props = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" -}; -var expando = "jQuery" + now(), uuid = 0, windowData = {}; - -jQuery.extend({ - cache: {}, - - expando:expando, - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - "object": true, - "applet": true - }, - - data: function( elem, name, data ) { - if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { - return; - } - - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ], cache = jQuery.cache, thisCache; - - if ( !id && typeof name === "string" && data === undefined ) { - return null; - } - - // Compute a unique ID for the element - if ( !id ) { - id = ++uuid; - } - - // Avoid generating a new cache unless none exists and we - // want to manipulate it. - if ( typeof name === "object" ) { - elem[ expando ] = id; - thisCache = cache[ id ] = jQuery.extend(true, {}, name); - - } else if ( !cache[ id ] ) { - elem[ expando ] = id; - cache[ id ] = {}; - } - - thisCache = cache[ id ]; - - // Prevent overriding the named cache with undefined values - if ( data !== undefined ) { - thisCache[ name ] = data; - } - - return typeof name === "string" ? thisCache[ name ] : thisCache; - }, - - removeData: function( elem, name ) { - if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { - return; - } - - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ]; - - // If we want to remove a specific section of the element's data - if ( name ) { - if ( thisCache ) { - // Remove the section of cache data - delete thisCache[ name ]; - - // If we've removed all the data, remove the element's cache - if ( jQuery.isEmptyObject(thisCache) ) { - jQuery.removeData( elem ); - } - } - - // Otherwise, we want to remove all of the element's data - } else { - if ( jQuery.support.deleteExpando ) { - delete elem[ jQuery.expando ]; - - } else if ( elem.removeAttribute ) { - elem.removeAttribute( jQuery.expando ); - } - - // Completely remove the data cache - delete cache[ id ]; - } - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - if ( typeof key === "undefined" && this.length ) { - return jQuery.data( this[0] ); - - } else if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - var parts = key.split("."); - parts[1] = parts[1] ? "." + parts[1] : ""; - - if ( value === undefined ) { - var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); - - if ( data === undefined && this.length ) { - data = jQuery.data( this[0], key ); - } - return data === undefined && parts[1] ? - this.data( parts[0] ) : - data; - } else { - return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() { - jQuery.data( this, key, value ); - }); - } - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); -jQuery.extend({ - queue: function( elem, type, data ) { - if ( !elem ) { - return; - } - - type = (type || "fx") + "queue"; - var q = jQuery.data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( !data ) { - return q || []; - } - - if ( !q || jQuery.isArray(data) ) { - q = jQuery.data( elem, type, jQuery.makeArray(data) ); - - } else { - q.push( data ); - } - - return q; - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), fn = queue.shift(); - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - } - - if ( fn ) { - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift("inprogress"); - } - - fn.call(elem, function() { - jQuery.dequeue(elem, type); - }); - } - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - } - - if ( data === undefined ) { - return jQuery.queue( this[0], type ); - } - return this.each(function( i, elem ) { - var queue = jQuery.queue( this, type, data ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; - type = type || "fx"; - - return this.queue( type, function() { - var elem = this; - setTimeout(function() { - jQuery.dequeue( elem, type ); - }, time ); - }); - }, - - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - } -}); -var rclass = /[\n\t]/g, - rspace = /\s+/, - rreturn = /\r/g, - rspecialurl = /href|src|style/, - rtype = /(button|input)/i, - rfocusable = /(button|input|object|select|textarea)/i, - rclickable = /^(a|area)$/i, - rradiocheck = /radio|checkbox/; - -jQuery.fn.extend({ - attr: function( name, value ) { - return access( this, name, value, true, jQuery.attr ); - }, - - removeAttr: function( name, fn ) { - return this.each(function(){ - jQuery.attr( this, name, "" ); - if ( this.nodeType === 1 ) { - this.removeAttribute( name ); - } - }); - }, - - addClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.addClass( value.call(this, i, self.attr("class")) ); - }); - } - - if ( value && typeof value === "string" ) { - var classNames = (value || "").split( rspace ); - - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; - - if ( elem.nodeType === 1 ) { - if ( !elem.className ) { - elem.className = value; - - } else { - var className = " " + elem.className + " ", setClass = elem.className; - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { - setClass += " " + classNames[c]; - } - } - elem.className = jQuery.trim( setClass ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - if ( jQuery.isFunction(value) ) { - return this.each(function(i) { - var self = jQuery(this); - self.removeClass( value.call(this, i, self.attr("class")) ); - }); - } - - if ( (value && typeof value === "string") || value === undefined ) { - var classNames = (value || "").split(rspace); - - for ( var i = 0, l = this.length; i < l; i++ ) { - var elem = this[i]; - - if ( elem.nodeType === 1 && elem.className ) { - if ( value ) { - var className = (" " + elem.className + " ").replace(rclass, " "); - for ( var c = 0, cl = classNames.length; c < cl; c++ ) { - className = className.replace(" " + classNames[c] + " ", " "); - } - elem.className = jQuery.trim( className ); - - } else { - elem.className = ""; - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function(i) { - var self = jQuery(this); - self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, i = 0, self = jQuery(this), - state = stateVal, - classNames = value.split( rspace ); - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - } else if ( type === "undefined" || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery.data( this, "__className__", this.className ); - } - - // toggle whole className - this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " "; - for ( var i = 0, l = this.length; i < l; i++ ) { - if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - if ( value === undefined ) { - var elem = this[0]; - - if ( elem ) { - if ( jQuery.nodeName( elem, "option" ) ) { - return (elem.attributes.value || {}).specified ? elem.value : elem.text; - } - - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type === "select-one"; - - // Nothing was selected - if ( index < 0 ) { - return null; - } - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - if ( option.selected ) { - // Get the specific value for the option - value = jQuery(option).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - } - - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { - return elem.getAttribute("value") === null ? "on" : elem.value; - } - - - // Everything else, we just grab the value - return (elem.value || "").replace(rreturn, ""); - - } - - return undefined; - } - - var isFunction = jQuery.isFunction(value); - - return this.each(function(i) { - var self = jQuery(this), val = value; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call(this, i, self.val()); - } - - // Typecast each time if the value is a Function and the appended - // value is therefore different each time. - if ( typeof val === "number" ) { - val += ""; - } - - if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { - this.checked = jQuery.inArray( self.val(), val ) >= 0; - - } else if ( jQuery.nodeName( this, "select" ) ) { - var values = jQuery.makeArray(val); - - jQuery( "option", this ).each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - this.selectedIndex = -1; - } - - } else { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - attrFn: { - val: true, - css: true, - html: true, - text: true, - data: true, - width: true, - height: true, - offset: true - }, - - attr: function( elem, name, value, pass ) { - // don't set attributes on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; - } - - if ( pass && name in jQuery.attrFn ) { - return jQuery(elem)[name](value); - } - - var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), - // Whether we are setting (or getting) - set = value !== undefined; - - // Try to normalize/fix the name - name = notxml && jQuery.props[ name ] || name; - - // Only do all the following if this is a node (faster for style) - if ( elem.nodeType === 1 ) { - // These attributes require special treatment - var special = rspecialurl.test( name ); - - // Safari mis-reports the default selected property of an option - // Accessing the parent's selectedIndex property fixes it - if ( name === "selected" && !jQuery.support.optSelected ) { - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - - // If applicable, access the attribute via the DOM 0 way - if ( name in elem && notxml && !special ) { - if ( set ) { - // We can't allow the type property to be changed (since it causes problems in IE) - if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { - jQuery.error( "type property can't be changed" ); - } - - elem[ name ] = value; - } - - // browsers index elements by id/name on forms, give priority to attributes. - if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { - return elem.getAttributeNode( name ).nodeValue; - } - - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - if ( name === "tabIndex" ) { - var attributeNode = elem.getAttributeNode( "tabIndex" ); - - return attributeNode && attributeNode.specified ? - attributeNode.value : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - - return elem[ name ]; - } - - if ( !jQuery.support.style && notxml && name === "style" ) { - if ( set ) { - elem.style.cssText = "" + value; - } - - return elem.style.cssText; - } - - if ( set ) { - // convert the value to a string (all browsers do this but IE) see #1070 - elem.setAttribute( name, "" + value ); - } - - var attr = !jQuery.support.hrefNormalized && notxml && special ? - // Some attributes require a special call on IE - elem.getAttribute( name, 2 ) : - elem.getAttribute( name ); - - // Non-existent attributes return null, we normalize to undefined - return attr === null ? undefined : attr; - } - - // elem is actually elem.style ... set the style - // Using attr for specific style information is now deprecated. Use style instead. - return jQuery.style( elem, name, value ); - } -}); -var rnamespaces = /\.(.*)$/, - fcleanup = function( nm ) { - return nm.replace(/[^\w\s\.\|`]/g, function( ch ) { - return "\\" + ch; - }); - }; - -/* - * A number of helper functions used for managing events. - * Many of the ideas behind this code originated from - * Dean Edwards' addEvent library. - */ -jQuery.event = { - - // Bind an event to an element - // Original by Dean Edwards - add: function( elem, types, handler, data ) { - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // For whatever reason, IE has trouble passing the window object - // around, causing it to be cloned in the process - if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) { - elem = window; - } - - var handleObjIn, handleObj; - - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - } - - // Make sure that the function being executed has a unique ID - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure - var elemData = jQuery.data( elem ); - - // If no elemData is found then we must be trying to bind to one of the - // banned noData elements - if ( !elemData ) { - return; - } - - var events = elemData.events = elemData.events || {}, - eventHandle = elemData.handle, eventHandle; - - if ( !eventHandle ) { - elemData.handle = eventHandle = function() { - // Handle the second event of a trigger and when - // an event is called after a page has unloaded - return typeof jQuery !== "undefined" && !jQuery.event.triggered ? - jQuery.event.handle.apply( eventHandle.elem, arguments ) : - undefined; - }; - } - - // Add elem as a property of the handle function - // This is to prevent a memory leak with non-native events in IE. - eventHandle.elem = elem; - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = types.split(" "); - - var type, i = 0, namespaces; - - while ( (type = types[ i++ ]) ) { - handleObj = handleObjIn ? - jQuery.extend({}, handleObjIn) : - { handler: handler, data: data }; - - // Namespaced event handlers - if ( type.indexOf(".") > -1 ) { - namespaces = type.split("."); - type = namespaces.shift(); - handleObj.namespace = namespaces.slice(0).sort().join("."); - - } else { - namespaces = []; - handleObj.namespace = ""; - } - - handleObj.type = type; - handleObj.guid = handler.guid; - - // Get the current list of functions bound to this event - var handlers = events[ type ], - special = jQuery.event.special[ type ] || {}; - - // Init the event handler queue - if ( !handlers ) { - handlers = events[ type ] = []; - - // Check for a special event handler - // Only use addEventListener/attachEvent if the special - // events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add the function to the element's handler list - handlers.push( handleObj ); - - // Keep track of which events have been used, for global triggering - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - global: {}, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, pos ) { - // don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, - elemData = jQuery.data( elem ), - events = elemData && elemData.events; - - if ( !elemData || !events ) { - return; - } - - // types is actually an event object here - if ( types && types.type ) { - handler = types.handler; - types = types.type; - } - - // Unbind all events for the element - if ( !types || typeof types === "string" && types.charAt(0) === "." ) { - types = types || ""; - - for ( type in events ) { - jQuery.event.remove( elem, type + types ); - } - - return; - } - - // Handle multiple events separated by a space - // jQuery(...).unbind("mouseover mouseout", fn); - types = types.split(" "); - - while ( (type = types[ i++ ]) ) { - origType = type; - handleObj = null; - all = type.indexOf(".") < 0; - namespaces = []; - - if ( !all ) { - // Namespaced event handlers - namespaces = type.split("."); - type = namespaces.shift(); - - namespace = new RegExp("(^|\\.)" + - jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)") - } - - eventType = events[ type ]; - - if ( !eventType ) { - continue; - } - - if ( !handler ) { - for ( var j = 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( all || namespace.test( handleObj.namespace ) ) { - jQuery.event.remove( elem, origType, handleObj.handler, j ); - eventType.splice( j--, 1 ); - } - } - - continue; - } - - special = jQuery.event.special[ type ] || {}; - - for ( var j = pos || 0; j < eventType.length; j++ ) { - handleObj = eventType[ j ]; - - if ( handler.guid === handleObj.guid ) { - // remove the given handler for the given type - if ( all || namespace.test( handleObj.namespace ) ) { - if ( pos == null ) { - eventType.splice( j--, 1 ); - } - - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - - if ( pos != null ) { - break; - } - } - } - - // remove generic event handler if no more handlers exist - if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { - if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { - removeEvent( elem, type, elemData.handle ); - } - - ret = null; - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - var handle = elemData.handle; - if ( handle ) { - handle.elem = null; - } - - delete elemData.events; - delete elemData.handle; - - if ( jQuery.isEmptyObject( elemData ) ) { - jQuery.removeData( elem ); - } - } - }, - - // bubbling is internal - trigger: function( event, data, elem /*, bubbling */ ) { - // Event object or event type - var type = event.type || event, - bubbling = arguments[3]; - - if ( !bubbling ) { - event = typeof event === "object" ? - // jQuery.Event object - event[expando] ? event : - // Object literal - jQuery.extend( jQuery.Event(type), event ) : - // Just the event type (string) - jQuery.Event(type); - - if ( type.indexOf("!") >= 0 ) { - event.type = type = type.slice(0, -1); - event.exclusive = true; - } - - // Handle a global trigger - if ( !elem ) { - // Don't bubble custom events when global (to avoid too much overhead) - event.stopPropagation(); - - // Only trigger if we've ever bound an event for it - if ( jQuery.event.global[ type ] ) { - jQuery.each( jQuery.cache, function() { - if ( this.events && this.events[type] ) { - jQuery.event.trigger( event, data, this.handle.elem ); - } - }); - } - } - - // Handle triggering a single element - - // don't do events on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; - } - - // Clean up in case it is reused - event.result = undefined; - event.target = elem; - - // Clone the incoming data, if any - data = jQuery.makeArray( data ); - data.unshift( event ); - } - - event.currentTarget = elem; - - // Trigger the event, it is assumed that "handle" is a function - var handle = jQuery.data( elem, "handle" ); - if ( handle ) { - handle.apply( elem, data ); - } - - var parent = elem.parentNode || elem.ownerDocument; - - // Trigger an inline bound script - try { - if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { - if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { - event.result = false; - } - } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (e) {} - - if ( !event.isPropagationStopped() && parent ) { - jQuery.event.trigger( event, data, parent, true ); - - } else if ( !event.isDefaultPrevented() ) { - var target = event.target, old, - isClick = jQuery.nodeName(target, "a") && type === "click", - special = jQuery.event.special[ type ] || {}; - - if ( (!special._default || special._default.call( elem, event ) === false) && - !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { - - try { - if ( target[ type ] ) { - // Make sure that we don't accidentally re-trigger the onFOO events - old = target[ "on" + type ]; - - if ( old ) { - target[ "on" + type ] = null; - } - - jQuery.event.triggered = true; - target[ type ](); - } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (e) {} - - if ( old ) { - target[ "on" + type ] = old; - } - - jQuery.event.triggered = false; - } - } - }, - - handle: function( event ) { - var all, handlers, namespaces, namespace, events; - - event = arguments[0] = jQuery.event.fix( event || window.event ); - event.currentTarget = this; - - // Namespaced event handlers - all = event.type.indexOf(".") < 0 && !event.exclusive; - - if ( !all ) { - namespaces = event.type.split("."); - event.type = namespaces.shift(); - namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - var events = jQuery.data(this, "events"), handlers = events[ event.type ]; - - if ( events && handlers ) { - // Clone the handlers to prevent manipulation - handlers = handlers.slice(0); - - for ( var j = 0, l = handlers.length; j < l; j++ ) { - var handleObj = handlers[ j ]; - - // Filter the functions by class - if ( all || namespace.test( handleObj.namespace ) ) { - // Pass in a reference to the handler function itself - // So that we can later remove it - event.handler = handleObj.handler; - event.data = handleObj.data; - event.handleObj = handleObj; - - var ret = handleObj.handler.apply( this, arguments ); - - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - - if ( event.isImmediatePropagationStopped() ) { - break; - } - } - } - } - - return event.result; - }, - - props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), - - fix: function( event ) { - if ( event[ expando ] ) { - return event; - } - - // store a copy of the original event object - // and "clone" to set read-only properties - var originalEvent = event; - event = jQuery.Event( originalEvent ); - - for ( var i = this.props.length, prop; i; ) { - prop = this.props[ --i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Fix target property, if necessary - if ( !event.target ) { - event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either - } - - // check if target is a textnode (safari) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && event.fromElement ) { - event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; - } - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && event.clientX != null ) { - var doc = document.documentElement, body = document.body; - event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); - event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); - } - - // Add which for key events - if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) { - event.which = event.charCode || event.keyCode; - } - - // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) - if ( !event.metaKey && event.ctrlKey ) { - event.metaKey = event.ctrlKey; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && event.button !== undefined ) { - event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); - } - - return event; - }, - - // Deprecated, use jQuery.guid instead - guid: 1E8, - - // Deprecated, use jQuery.proxy instead - proxy: jQuery.proxy, - - special: { - ready: { - // Make sure the ready event is setup - setup: jQuery.bindReady, - teardown: jQuery.noop - }, - - live: { - add: function( handleObj ) { - jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); - }, - - remove: function( handleObj ) { - var remove = true, - type = handleObj.origType.replace(rnamespaces, ""); - - jQuery.each( jQuery.data(this, "events").live || [], function() { - if ( type === this.origType.replace(rnamespaces, "") ) { - remove = false; - return false; - } - }); - - if ( remove ) { - jQuery.event.remove( this, handleObj.origType, liveHandler ); - } - } - - }, - - beforeunload: { - setup: function( data, namespaces, eventHandle ) { - // We only want to do this special case on windows - if ( this.setInterval ) { - this.onbeforeunload = eventHandle; - } - - return false; - }, - teardown: function( namespaces, eventHandle ) { - if ( this.onbeforeunload === eventHandle ) { - this.onbeforeunload = null; - } - } - } - } -}; - -var removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - elem.removeEventListener( type, handle, false ); - } : - function( elem, type, handle ) { - elem.detachEvent( "on" + type, handle ); - }; - -jQuery.Event = function( src ) { - // Allow instantiation without the 'new' keyword - if ( !this.preventDefault ) { - return new jQuery.Event( src ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - // Event type - } else { - this.type = src; - } - - // timeStamp is buggy for some events on Firefox(#3843) - // So we won't rely on the native value - this.timeStamp = now(); - - // Mark it as fixed - this[ expando ] = true; -}; - -function returnFalse() { - return false; -} -function returnTrue() { - return true; -} - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - preventDefault: function() { - this.isDefaultPrevented = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - - // if preventDefault exists run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - } - // otherwise set the returnValue property of the original event to false (IE) - e.returnValue = false; - }, - stopPropagation: function() { - this.isPropagationStopped = returnTrue; - - var e = this.originalEvent; - if ( !e ) { - return; - } - // if stopPropagation exists run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - // otherwise set the cancelBubble property of the original event to true (IE) - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - }, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse -}; - -// Checks if an event happened on an element within another element -// Used in jQuery.event.special.mouseenter and mouseleave handlers -var withinElement = function( event ) { - // Check if mouse(over|out) are still within the same parent element - var parent = event.relatedTarget; - - // Firefox sometimes assigns relatedTarget a XUL element - // which we cannot access the parentNode property of - try { - // Traverse up the tree - while ( parent && parent !== this ) { - parent = parent.parentNode; - } - - if ( parent !== this ) { - // set the correct event type - event.type = event.data; - - // handle event if we actually just moused on to a non sub-element - jQuery.event.handle.apply( this, arguments ); - } - - // assuming we've left the element since we most likely mousedover a xul element - } catch(e) { } -}, - -// In case of event delegation, we only need to rename the event.type, -// liveHandler will take care of the rest. -delegate = function( event ) { - event.type = event.data; - jQuery.event.handle.apply( this, arguments ); -}; - -// Create mouseenter and mouseleave events -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - setup: function( data ) { - jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); - }, - teardown: function( data ) { - jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); - } - }; -}); - -// submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function( data, namespaces ) { - if ( this.nodeName.toLowerCase() !== "form" ) { - jQuery.event.add(this, "click.specialSubmit", function( e ) { - var elem = e.target, type = elem.type; - - if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { - return trigger( "submit", this, arguments ); - } - }); - - jQuery.event.add(this, "keypress.specialSubmit", function( e ) { - var elem = e.target, type = elem.type; - - if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { - return trigger( "submit", this, arguments ); - } - }); - - } else { - return false; - } - }, - - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialSubmit" ); - } - }; - -} - -// change delegation, happens here so we have bind. -if ( !jQuery.support.changeBubbles ) { - - var formElems = /textarea|input|select/i, - - changeFilters, - - getVal = function( elem ) { - var type = elem.type, val = elem.value; - - if ( type === "radio" || type === "checkbox" ) { - val = elem.checked; - - } else if ( type === "select-multiple" ) { - val = elem.selectedIndex > -1 ? - jQuery.map( elem.options, function( elem ) { - return elem.selected; - }).join("-") : - ""; - - } else if ( elem.nodeName.toLowerCase() === "select" ) { - val = elem.selectedIndex; - } - - return val; - }, - - testChange = function testChange( e ) { - var elem = e.target, data, val; - - if ( !formElems.test( elem.nodeName ) || elem.readOnly ) { - return; - } - - data = jQuery.data( elem, "_change_data" ); - val = getVal(elem); - - // the current data will be also retrieved by beforeactivate - if ( e.type !== "focusout" || elem.type !== "radio" ) { - jQuery.data( elem, "_change_data", val ); - } - - if ( data === undefined || val === data ) { - return; - } - - if ( data != null || val ) { - e.type = "change"; - return jQuery.event.trigger( e, arguments[1], elem ); - } - }; - - jQuery.event.special.change = { - filters: { - focusout: testChange, - - click: function( e ) { - var elem = e.target, type = elem.type; - - if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { - return testChange.call( this, e ); - } - }, - - // Change has to be called before submit - // Keydown will be called before keypress, which is used in submit-event delegation - keydown: function( e ) { - var elem = e.target, type = elem.type; - - if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || - (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || - type === "select-multiple" ) { - return testChange.call( this, e ); - } - }, - - // Beforeactivate happens also before the previous element is blurred - // with this event you can't trigger a change event, but you can store - // information/focus[in] is not needed anymore - beforeactivate: function( e ) { - var elem = e.target; - jQuery.data( elem, "_change_data", getVal(elem) ); - } - }, - - setup: function( data, namespaces ) { - if ( this.type === "file" ) { - return false; - } - - for ( var type in changeFilters ) { - jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); - } - - return formElems.test( this.nodeName ); - }, - - teardown: function( namespaces ) { - jQuery.event.remove( this, ".specialChange" ); - - return formElems.test( this.nodeName ); - } - }; - - changeFilters = jQuery.event.special.change.filters; -} - -function trigger( type, elem, args ) { - args[0].type = type; - return jQuery.event.handle.apply( elem, args ); -} - -// Create "bubbling" focus and blur events -if ( document.addEventListener ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - jQuery.event.special[ fix ] = { - setup: function() { - this.addEventListener( orig, handler, true ); - }, - teardown: function() { - this.removeEventListener( orig, handler, true ); - } - }; - - function handler( e ) { - e = jQuery.event.fix( e ); - e.type = fix; - return jQuery.event.handle.call( this, e ); - } - }); -} - -jQuery.each(["bind", "one"], function( i, name ) { - jQuery.fn[ name ] = function( type, data, fn ) { - // Handle object literals - if ( typeof type === "object" ) { - for ( var key in type ) { - this[ name ](key, data, type[key], fn); - } - return this; - } - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - var handler = name === "one" ? jQuery.proxy( fn, function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }) : fn; - - if ( type === "unload" && name !== "one" ) { - this.one( type, data, fn ); - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.add( this[i], type, handler, data ); - } - } - - return this; - }; -}); - -jQuery.fn.extend({ - unbind: function( type, fn ) { - // Handle object literals - if ( typeof type === "object" && !type.preventDefault ) { - for ( var key in type ) { - this.unbind(key, type[key]); - } - - } else { - for ( var i = 0, l = this.length; i < l; i++ ) { - jQuery.event.remove( this[i], type, fn ); - } - } - - return this; - }, - - delegate: function( selector, types, data, fn ) { - return this.live( types, data, fn, selector ); - }, - - undelegate: function( selector, types, fn ) { - if ( arguments.length === 0 ) { - return this.unbind( "live" ); - - } else { - return this.die( types, null, fn, selector ); - } - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - - triggerHandler: function( type, data ) { - if ( this[0] ) { - var event = jQuery.Event( type ); - event.preventDefault(); - event.stopPropagation(); - jQuery.event.trigger( event, data, this[0] ); - return event.result; - } - }, - - toggle: function( fn ) { - // Save reference to arguments for access in closure - var args = arguments, i = 1; - - // link all the functions, so any of them can unbind this click handler - while ( i < args.length ) { - jQuery.proxy( fn, args[ i++ ] ); - } - - return this.click( jQuery.proxy( fn, function( event ) { - // Figure out which function to execute - var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; - jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); - - // Make sure that clicks stop - event.preventDefault(); - - // and execute the function - return args[ lastToggle ].apply( this, arguments ) || false; - })); - }, - - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -}); - -var liveMap = { - focus: "focusin", - blur: "focusout", - mouseenter: "mouseover", - mouseleave: "mouseout" -}; - -jQuery.each(["live", "die"], function( i, name ) { - jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { - var type, i = 0, match, namespaces, preType, - selector = origSelector || this.selector, - context = origSelector ? this : jQuery( this.context ); - - if ( jQuery.isFunction( data ) ) { - fn = data; - data = undefined; - } - - types = (types || "").split(" "); - - while ( (type = types[ i++ ]) != null ) { - match = rnamespaces.exec( type ); - namespaces = ""; - - if ( match ) { - namespaces = match[0]; - type = type.replace( rnamespaces, "" ); - } - - if ( type === "hover" ) { - types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); - continue; - } - - preType = type; - - if ( type === "focus" || type === "blur" ) { - types.push( liveMap[ type ] + namespaces ); - type = type + namespaces; - - } else { - type = (liveMap[ type ] || type) + namespaces; - } - - if ( name === "live" ) { - // bind live handler - context.each(function(){ - jQuery.event.add( this, liveConvert( type, selector ), - { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); - }); - - } else { - // unbind live handler - context.unbind( liveConvert( type, selector ), fn ); - } - } - - return this; - } -}); - -function liveHandler( event ) { - var stop, elems = [], selectors = [], args = arguments, - related, match, handleObj, elem, j, i, l, data, - events = jQuery.data( this, "events" ); - - // Make sure we avoid non-left-click bubbling in Firefox (#3861) - if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) { - return; - } - - event.liveFired = this; - - var live = events.live.slice(0); - - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { - selectors.push( handleObj.selector ); - - } else { - live.splice( j--, 1 ); - } - } - - match = jQuery( event.target ).closest( selectors, event.currentTarget ); - - for ( i = 0, l = match.length; i < l; i++ ) { - for ( j = 0; j < live.length; j++ ) { - handleObj = live[j]; - - if ( match[i].selector === handleObj.selector ) { - elem = match[i].elem; - related = null; - - // Those two events require additional checking - if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { - related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; - } - - if ( !related || related !== elem ) { - elems.push({ elem: elem, handleObj: handleObj }); - } - } - } - } - - for ( i = 0, l = elems.length; i < l; i++ ) { - match = elems[i]; - event.currentTarget = match.elem; - event.data = match.handleObj.data; - event.handleObj = match.handleObj; - - if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) { - stop = false; - break; - } - } - - return stop; -} - -function liveConvert( type, selector ) { - return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&"); -} - -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 error").split(" "), function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( fn ) { - return fn ? this.bind( name, fn ) : this.trigger( name ); - }; - - if ( jQuery.attrFn ) { - jQuery.attrFn[ name ] = true; - } -}); - -// Prevent memory leaks in IE -// Window isn't included so as not to unbind existing unload events -// More info: -// - http://isaacschlueter.com/2006/10/msie-memory-leaks/ -if ( window.attachEvent && !window.addEventListener ) { - window.attachEvent("onunload", function() { - for ( var id in jQuery.cache ) { - if ( jQuery.cache[ id ].handle ) { - // Try/Catch is to handle iframes being unloaded, see #4280 - try { - jQuery.event.remove( jQuery.cache[ id ].handle.elem ); - } catch(e) {} - } - } - }); -} -/*! - * Sizzle CSS Selector Engine - v1.0 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){ - -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true; - -// Here we check if the JavaScript engine is using some sort of -// optimization where it does not always call our comparison -// function. If that is the case, discard the hasDuplicate value. -// Thus far that includes Google Chrome. -[0, 0].sort(function(){ - baseHasDuplicate = false; - return 0; -}); - -var Sizzle = function(selector, context, results, seed) { - results = results || []; - var origContext = context = context || document; - - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context), - soFar = selector; - - // Reset the position of the chunker regexp (start from head) - while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { - soFar = m[3]; - - parts.push( m[1] ); - - if ( m[2] ) { - extra = m[3]; - break; - } - } - - if ( parts.length > 1 && origPOS.exec( selector ) ) { - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context ); - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); - - while ( parts.length ) { - selector = parts.shift(); - - if ( Expr.relative[ selector ] ) { - selector += parts.shift(); - } - - set = posProcess( selector, set ); - } - } - } else { - // Take a shortcut and set the context if the root selector is an ID - // (but not if it'll be faster if the inner selector is an ID) - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - var ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; - } - - if ( context ) { - var ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; - - if ( parts.length > 0 ) { - checkSet = makeArray(set); - } else { - prune = false; - } - - while ( parts.length ) { - var cur = parts.pop(), pop = cur; - - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } - - if ( pop == null ) { - pop = context; - } - - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - } else { - checkSet = parts = []; - } - } - - if ( !checkSet ) { - checkSet = set; - } - - if ( !checkSet ) { - Sizzle.error( cur || selector ); - } - - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - } else if ( context && context.nodeType === 1 ) { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - } else { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - } else { - makeArray( checkSet, results ); - } - - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } - - return results; -}; - -Sizzle.uniqueSort = function(results){ - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort(sortOrder); - - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[i-1] ) { - results.splice(i--, 1); - } - } - } - } - - return results; -}; - -Sizzle.matches = function(expr, set){ - return Sizzle(expr, null, null, set); -}; - -Sizzle.find = function(expr, context, isXML){ - var set, match; - - if ( !expr ) { - return []; - } - - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var type = Expr.order[i], match; - - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; - match.splice(1,1); - - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace(/\\/g, ""); - set = Expr.find[ type ]( match, context, isXML ); - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } - - if ( !set ) { - set = context.getElementsByTagName("*"); - } - - return {set: set, expr: expr}; -}; - -Sizzle.filter = function(expr, set, inplace, not){ - var old = expr, result = [], curLoop = set, match, anyFound, - isXMLFilter = set && set[0] && isXML(set[0]); - - while ( expr && set.length ) { - for ( var type in Expr.filter ) { - if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { - var filter = Expr.filter[ type ], found, item, left = match[1]; - anyFound = false; - - match.splice(1,1); - - if ( left.substr( left.length - 1 ) === "\\" ) { - continue; - } - - if ( curLoop === result ) { - result = []; - } - - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - - if ( !match ) { - anyFound = found = true; - } else if ( match === true ) { - continue; - } - } - - if ( match ) { - for ( var i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - var pass = not ^ !!found; - - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - } else { - curLoop[i] = false; - } - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } - - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } - - expr = expr.replace( Expr.match[ type ], "" ); - - if ( !anyFound ) { - return []; - } - - break; - } - } - } - - // Improper expression - if ( expr === old ) { - if ( anyFound == null ) { - Sizzle.error( expr ); - } else { - break; - } - } - - old = expr; - } - - return curLoop; -}; - -Sizzle.error = function( msg ) { - throw "Syntax error, unrecognized expression: " + msg; -}; - -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - match: { - ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ - }, - leftMatch: {}, - attrMap: { - "class": "className", - "for": "htmlFor" - }, - attrHandle: { - href: function(elem){ - return elem.getAttribute("href"); - } - }, - relative: { - "+": function(checkSet, part){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !/\W/.test(part), - isPartStrNotTag = isPartStr && !isTag; - - if ( isTag ) { - part = part.toLowerCase(); - } - - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - - checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? - elem || false : - elem === part; - } - } - - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - ">": function(checkSet, part){ - var isPartStr = typeof part === "string"; - - if ( isPartStr && !/\W/.test(part) ) { - part = part.toLowerCase(); - - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; - } - } - } else { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } - - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - "": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; - - if ( typeof part === "string" && !/\W/.test(part) ) { - var nodeCheck = part = part.toLowerCase(); - checkFn = dirNodeCheck; - } - - checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); - }, - "~": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; - - if ( typeof part === "string" && !/\W/.test(part) ) { - var nodeCheck = part = part.toLowerCase(); - checkFn = dirNodeCheck; - } - - checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); - } - }, - find: { - ID: function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? [m] : []; - } - }, - NAME: function(match, context){ - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], results = context.getElementsByName(match[1]); - - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } - - return ret.length === 0 ? null : ret; - } - }, - TAG: function(match, context){ - return context.getElementsByTagName(match[1]); - } - }, - preFilter: { - CLASS: function(match, curLoop, inplace, result, not, isXML){ - match = " " + match[1].replace(/\\/g, "") + " "; - - if ( isXML ) { - return match; - } - - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { - if ( !inplace ) { - result.push( elem ); - } - } else if ( inplace ) { - curLoop[i] = false; - } - } - } - - return false; - }, - ID: function(match){ - return match[1].replace(/\\/g, ""); - }, - TAG: function(match, curLoop){ - return match[1].toLowerCase(); - }, - CHILD: function(match){ - if ( match[1] === "nth" ) { - // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' - var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( - match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); - - // calculate the numbers (first)n+(last) including if they are negative - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } - - // TODO: Move to normal caching system - match[0] = done++; - - return match; - }, - ATTR: function(match, curLoop, inplace, result, not, isXML){ - var name = match[1].replace(/\\/g, ""); - - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } - - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } - - return match; - }, - PSEUDO: function(match, curLoop, inplace, result, not){ - if ( match[1] === "not" ) { - // If we're dealing with a complex expression, or a simple one - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - if ( !inplace ) { - result.push.apply( result, ret ); - } - return false; - } - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } - - return match; - }, - POS: function(match){ - match.unshift( true ); - return match; - } - }, - filters: { - enabled: function(elem){ - return elem.disabled === false && elem.type !== "hidden"; - }, - disabled: function(elem){ - return elem.disabled === true; - }, - checked: function(elem){ - return elem.checked === true; - }, - selected: function(elem){ - // Accessing this property makes selected-by-default - // options in Safari work properly - elem.parentNode.selectedIndex; - return elem.selected === true; - }, - parent: function(elem){ - return !!elem.firstChild; - }, - empty: function(elem){ - return !elem.firstChild; - }, - has: function(elem, i, match){ - return !!Sizzle( match[3], elem ).length; - }, - header: function(elem){ - return /h\d/i.test( elem.nodeName ); - }, - text: function(elem){ - return "text" === elem.type; - }, - radio: function(elem){ - return "radio" === elem.type; - }, - checkbox: function(elem){ - return "checkbox" === elem.type; - }, - file: function(elem){ - return "file" === elem.type; - }, - password: function(elem){ - return "password" === elem.type; - }, - submit: function(elem){ - return "submit" === elem.type; - }, - image: function(elem){ - return "image" === elem.type; - }, - reset: function(elem){ - return "reset" === elem.type; - }, - button: function(elem){ - return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; - }, - input: function(elem){ - return /input|select|textarea|button/i.test(elem.nodeName); - } - }, - setFilters: { - first: function(elem, i){ - return i === 0; - }, - last: function(elem, i, match, array){ - return i === array.length - 1; - }, - even: function(elem, i){ - return i % 2 === 0; - }, - odd: function(elem, i){ - return i % 2 === 1; - }, - lt: function(elem, i, match){ - return i < match[3] - 0; - }, - gt: function(elem, i, match){ - return i > match[3] - 0; - }, - nth: function(elem, i, match){ - return match[3] - 0 === i; - }, - eq: function(elem, i, match){ - return match[3] - 0 === i; - } - }, - filter: { - PSEUDO: function(elem, match, i, array){ - var name = match[1], filter = Expr.filters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; - } else if ( name === "not" ) { - var not = match[3]; - - for ( var i = 0, l = not.length; i < l; i++ ) { - if ( not[i] === elem ) { - return false; - } - } - - return true; - } else { - Sizzle.error( "Syntax error, unrecognized expression: " + name ); - } - }, - CHILD: function(elem, match){ - var type = match[1], node = elem; - switch (type) { - case 'only': - case 'first': - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - if ( type === "first" ) { - return true; - } - node = elem; - case 'last': - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) { - return false; - } - } - return true; - case 'nth': - var first = match[2], last = match[3]; - - if ( first === 1 && last === 0 ) { - return true; - } - - var doneName = match[0], - parent = elem.parentNode; - - if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { - var count = 0; - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - parent.sizcache = doneName; - } - - var diff = elem.nodeIndex - last; - if ( first === 0 ) { - return diff === 0; - } else { - return ( diff % first === 0 && diff / first >= 0 ); - } - } - }, - ID: function(elem, match){ - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - TAG: function(elem, match){ - return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; - }, - CLASS: function(elem, match){ - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - ATTR: function(elem, match){ - var name = match[1], - result = Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; - - return result == null ? - type === "!=" : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value !== check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - POS: function(elem, match, i, array){ - var name = match[2], filter = Expr.setFilters[ name ]; - - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; - -var origPOS = Expr.match.POS; - -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){ - return "\\" + (num - 0 + 1); - })); -} - -var makeArray = function(array, results) { - array = Array.prototype.slice.call( array, 0 ); - - if ( results ) { - results.push.apply( results, array ); - return results; - } - - return array; -}; - -// Perform a simple check to determine if the browser is capable of -// converting a NodeList to an array using builtin methods. -// Also verifies that the returned array holds DOM nodes -// (which is not the case in the Blackberry browser) -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; - -// Provide a fallback method if it does not work -} catch(e){ - makeArray = function(array, results) { - var ret = results || []; - - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - } else { - if ( typeof array.length === "number" ) { - for ( var i = 0, l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - } else { - for ( var i = 0; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } - - return ret; - }; -} - -var sortOrder; - -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - if ( a == b ) { - hasDuplicate = true; - } - return a.compareDocumentPosition ? -1 : 1; - } - - var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( "sourceIndex" in document.documentElement ) { - sortOrder = function( a, b ) { - if ( !a.sourceIndex || !b.sourceIndex ) { - if ( a == b ) { - hasDuplicate = true; - } - return a.sourceIndex ? -1 : 1; - } - - var ret = a.sourceIndex - b.sourceIndex; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( document.createRange ) { - sortOrder = function( a, b ) { - if ( !a.ownerDocument || !b.ownerDocument ) { - if ( a == b ) { - hasDuplicate = true; - } - return a.ownerDocument ? -1 : 1; - } - - var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); - aRange.setStart(a, 0); - aRange.setEnd(a, 0); - bRange.setStart(b, 0); - bRange.setEnd(b, 0); - var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} - -// Utility function for retrieving the text value of an array of DOM nodes -function getText( elems ) { - var ret = "", elem; - - for ( var i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += getText( elem.childNodes ); - } - } - - return ret; -} - -// Check to see if the browser returns elements by name when -// querying by getElementById (and provide a workaround) -(function(){ - // We're going to inject a fake input element with a specified name - var form = document.createElement("div"), - id = "script" + (new Date).getTime(); - form.innerHTML = ""; - - // Inject it into the root element, check its status, and remove it quickly - var root = document.documentElement; - root.insertBefore( form, root.firstChild ); - - // The workaround has to do additional checks after a getElementById - // Which slows things down for other browsers (hence the branching) - if ( document.getElementById( id ) ) { - Expr.find.ID = function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; - } - }; - - Expr.filter.ID = function(elem, match){ - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - } - - root.removeChild( form ); - root = form = null; // release memory in IE -})(); - -(function(){ - // Check to see if the browser returns only elements - // when doing getElementsByTagName("*") - - // Create a fake element - var div = document.createElement("div"); - div.appendChild( document.createComment("") ); - - // Make sure no comments are found - if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function(match, context){ - var results = context.getElementsByTagName(match[1]); - - // Filter out possible comments - if ( match[1] === "*" ) { - var tmp = []; - - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - - results = tmp; - } - - return results; - }; - } - - // Check to see if an attribute returns normalized href attributes - div.innerHTML = ""; - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - Expr.attrHandle.href = function(elem){ - return elem.getAttribute("href", 2); - }; - } - - div = null; // release memory in IE -})(); - -if ( document.querySelectorAll ) { - (function(){ - var oldSizzle = Sizzle, div = document.createElement("div"); - div.innerHTML = "

        "; - - // Safari can't handle uppercase or unicode characters when - // in quirks mode. - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } - - Sizzle = function(query, context, extra, seed){ - context = context || document; - - // Only use querySelectorAll on non-XML documents - // (ID selectors don't work in non-HTML documents) - if ( !seed && context.nodeType === 9 && !isXML(context) ) { - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(e){} - } - - return oldSizzle(query, context, extra, seed); - }; - - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } - - div = null; // release memory in IE - })(); -} - -(function(){ - var div = document.createElement("div"); - - div.innerHTML = "
        "; - - // Opera can't find a second classname (in 9.6) - // Also, make sure that getElementsByClassName actually exists - if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { - return; - } - - // Safari caches class attributes, doesn't catch changes (in 3.2) - div.lastChild.className = "e"; - - if ( div.getElementsByClassName("e").length === 1 ) { - return; - } - - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function(match, context, isXML) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; - - div = null; // release memory in IE -})(); - -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - elem = elem[dir]; - var match = false; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; - elem.sizset = i; - } - - if ( elem.nodeName.toLowerCase() === cur ) { - match = elem; - break; - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - elem = elem[dir]; - var match = false; - - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } - - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem.sizcache = doneName; - elem.sizset = i; - } - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } - - checkSet[i] = match; - } - } -} - -var contains = document.compareDocumentPosition ? function(a, b){ - return !!(a.compareDocumentPosition(b) & 16); -} : function(a, b){ - return a !== b && (a.contains ? a.contains(b) : true); -}; - -var isXML = function(elem){ - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -var posProcess = function(selector, context){ - var tmpSet = [], later = "", match, - root = context.nodeType ? [context] : context; - - // Position selectors must be done after the filter - // And so must :not(positional) so we move all PSEUDOs to the end - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); - } - - return Sizzle.filter( later, tmpSet ); -}; - -// EXPOSE -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.filters; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = getText; -jQuery.isXMLDoc = isXML; -jQuery.contains = contains; - -return; - -window.Sizzle = Sizzle; - -})(); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prevUntil|prevAll)/, - // Note: This RegExp should be improved, or likely pulled from Sizzle - rmultiselector = /,/, - slice = Array.prototype.slice; - -// Implement the identical functionality for filter and not -var winnow = function( elements, qualifier, keep ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem, i ) { - return (elem === qualifier) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem, i ) { - return (jQuery.inArray( elem, qualifier ) >= 0) === keep; - }); -}; - -jQuery.fn.extend({ - find: function( selector ) { - var ret = this.pushStack( "", "find", selector ), length = 0; - - for ( var i = 0, l = this.length; i < l; i++ ) { - length = ret.length; - jQuery.find( selector, this[i], ret ); - - if ( i > 0 ) { - // Make sure that the results are unique - for ( var n = length; n < ret.length; n++ ) { - for ( var r = 0; r < length; r++ ) { - if ( ret[r] === ret[n] ) { - ret.splice(n--, 1); - break; - } - } - } - } - } - - return ret; - }, - - has: function( target ) { - var targets = jQuery( target ); - return this.filter(function() { - for ( var i = 0, l = targets.length; i < l; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false), "not", selector); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true), "filter", selector ); - }, - - is: function( selector ) { - return !!selector && jQuery.filter( selector, this ).length > 0; - }, - - closest: function( selectors, context ) { - if ( jQuery.isArray( selectors ) ) { - var ret = [], cur = this[0], match, matches = {}, selector; - - if ( cur && selectors.length ) { - for ( var i = 0, l = selectors.length; i < l; i++ ) { - selector = selectors[i]; - - if ( !matches[selector] ) { - matches[selector] = jQuery.expr.match.POS.test( selector ) ? - jQuery( selector, context || this.context ) : - selector; - } - } - - while ( cur && cur.ownerDocument && cur !== context ) { - for ( selector in matches ) { - match = matches[selector]; - - if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { - ret.push({ selector: selector, elem: cur }); - delete matches[selector]; - } - } - cur = cur.parentNode; - } - } - - return ret; - } - - var pos = jQuery.expr.match.POS.test( selectors ) ? - jQuery( selectors, context || this.context ) : null; - - return this.map(function( i, cur ) { - while ( cur && cur.ownerDocument && cur !== context ) { - if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) { - return cur; - } - cur = cur.parentNode; - } - return null; - }); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - if ( !elem || typeof elem === "string" ) { - return jQuery.inArray( this[0], - // If it receives a string, the selector is used - // If it receives nothing, the siblings are used - elem ? jQuery( elem ) : this.parent().children() ); - } - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context || this.context ) : - jQuery.makeArray( selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? - all : - jQuery.unique( all ) ); - }, - - andSelf: function() { - return this.add( this.prevObject ); - } -}); - -// A painfully simple check to see if an element is disconnected -// from a document (should be improved, where feasible). -function isDisconnected( node ) { - return !node || !node.parentNode || node.parentNode.nodeType === 11; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return jQuery.nth( elem, 2, "nextSibling" ); - }, - prev: function( elem ) { - return jQuery.nth( elem, 2, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( elem.parentNode.firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.makeArray( elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 ? jQuery.unique( ret ) : ret; - - if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret, name, slice.call(arguments).join(",") ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], cur = elem[dir]; - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - nth: function( cur, result, dir, elem ) { - result = result || 1; - var num = 0; - - for ( ; cur; cur = cur[dir] ) { - if ( cur.nodeType === 1 && ++num === result ) { - break; - } - } - - return cur; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); -var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, - rleadingWhitespace = /^\s+/, - rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g, - rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i, - rtagName = /<([\w:]+)/, - rtbody = /"; - }, - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
        ", "
        " ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - col: [ 2, "", "
        " ], - area: [ 1, "", "" ], - _default: [ 0, "", "" ] - }; - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -// IE can't serialize and From ca0086b55a158d8a4347f94254878d6dc5dd90ed Mon Sep 17 00:00:00 2001 From: Benjy Cui Date: Tue, 18 Mar 2014 17:15:58 +0800 Subject: [PATCH 0036/1272] Core: Fix comments for .get() method Closes gh-1547 --- AUTHORS.txt | 2 ++ src/core.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/AUTHORS.txt b/AUTHORS.txt index 0aff9194c0..954e97afe0 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -217,3 +217,5 @@ Christopher Jones Forbes Lindesay S. Andrew Sheppard Roman Reiß +Benjy Cui + diff --git a/src/core.js b/src/core.js index c494d7a60f..b520b59303 100644 --- a/src/core.js +++ b/src/core.js @@ -57,10 +57,10 @@ jQuery.fn = jQuery.prototype = { get: function( num ) { return num != null ? - // Return a 'clean' array + // Return just the one element from the set ( num < 0 ? this[ num + this.length ] : this[ num ] ) : - // Return just the object + // Return all the elements in a clean array slice.call( this ); }, From e547a2775fc79e4b2eb807da9d30719afc570458 Mon Sep 17 00:00:00 2001 From: Rodrigo Rosenfeld Rosas Date: Tue, 28 Jan 2014 15:19:25 -0200 Subject: [PATCH 0037/1272] CSS: window.getDefaultComputedStyle may return null Fixes #14736 Closes gh-1501 (cherry picked from commit 51910ba8a5aff4cd1a811f1fdb76a6c62a09a666) --- AUTHORS.txt | 1 + src/css/defaultDisplay.js | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AUTHORS.txt b/AUTHORS.txt index 954e97afe0..5a4b804a85 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -218,4 +218,5 @@ Forbes Lindesay S. Andrew Sheppard Roman Reiß Benjy Cui +Rodrigo Rosenfeld Rosas diff --git a/src/css/defaultDisplay.js b/src/css/defaultDisplay.js index 45af9f90f8..631b9ba8a5 100644 --- a/src/css/defaultDisplay.js +++ b/src/css/defaultDisplay.js @@ -13,14 +13,15 @@ var iframe, */ // Called only from within defaultDisplay function actualDisplay( name, doc ) { - var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + var style, + elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), // getDefaultComputedStyle might be reliably used only on attached element - display = window.getDefaultComputedStyle ? + display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ? // Use of this method is a temporary fix (more like optmization) until something better comes along, // since it was removed from specification and supported only in FF - window.getDefaultComputedStyle( elem[ 0 ] ).display : jQuery.css( elem[ 0 ], "display" ); + style.display : jQuery.css( elem[ 0 ], "display" ); // We don't have any data stored on the element, // so use "detach" method as fast way to get rid of the element From 541e7349b6533eb533c15d17e3e9e432e4a719ea Mon Sep 17 00:00:00 2001 From: John Hoven Date: Thu, 6 Mar 2014 13:56:09 -0600 Subject: [PATCH 0038/1272] Attributes: Trim whitespace from option text when returned as a value Fixes #14858 Ref #14686 Closes gh-1531 (cherry picked from commit 9ec429cf6270e455aba4eba85f4db80e633806b6) Conflicts: src/attributes/val.js --- AUTHORS.txt | 1 + src/attributes/val.js | 10 ++++++++++ test/unit/attributes.js | 13 +++++++++++++ 3 files changed, 24 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 5a4b804a85..f68f3304ac 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -219,4 +219,5 @@ S. Andrew Sheppard Roman Reiß Benjy Cui Rodrigo Rosenfeld Rosas +John Hoven diff --git a/src/attributes/val.js b/src/attributes/val.js index 6d6b8ea7ca..42ef32343c 100644 --- a/src/attributes/val.js +++ b/src/attributes/val.js @@ -71,6 +71,16 @@ jQuery.fn.extend({ jQuery.extend({ valHooks: { + option: { + get: function( elem ) { + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + // Support: IE10-11+ + // option.text throws exceptions (#14686, #14858) + jQuery.trim( jQuery.text( elem ) ); + } + }, select: { get: function( elem ) { var value, option, diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 4a9bb677e3..7839abd856 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -1459,3 +1459,16 @@ test( "should not throw at $(option).val() (#14686)", 1, function() { ok( false ); } }); + +test( "Insignificant white space returned for $(option).val() (#14858)", function() { + expect ( 3 ); + + var val = jQuery( "" ).val(); + equal( val.length, 0, "Empty option should have no value" ); + + val = jQuery( "" ).val(); + equal( val.length, 0, "insignificant white-space returned for value" ); + + val = jQuery( "" ).val(); + equal( val.length, 4, "insignificant white-space returned for value" ); +}); From 85af4e6412e49c2e6a872feef00718a46c2fa2ce Mon Sep 17 00:00:00 2001 From: Jonathan Sampson Date: Tue, 11 Mar 2014 03:44:34 -0400 Subject: [PATCH 0039/1272] Manipulation: Change support test to be WWA-friendly Setting the innerHTML property in an unsafe manner raises issues in Windows Web Applications. Strings being passed into innerHTML cannot include the name attribute. Closes gh-1537 --- src/manipulation/support.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/manipulation/support.js b/src/manipulation/support.js index e2ba066ecd..fb1e855679 100644 --- a/src/manipulation/support.js +++ b/src/manipulation/support.js @@ -4,10 +4,17 @@ define([ (function() { var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ); + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); // #11217 - WebKit loses check when the name is after the checked attribute - div.innerHTML = ""; + // Support: Windows Web Apps (WWA) + // `name` and `type` need .setAttribute for WWA + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 // old WebKit doesn't clone checked state correctly in fragments From 5a8f76933288396b915800a18240aa17d3414201 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 5 Feb 2014 09:54:15 +0400 Subject: [PATCH 0040/1272] CSS: jQuery#hide should always save display value Fixes #14750 Closes gh-1509 --- src/css.js | 9 +++------ test/unit/css.js | 10 ++++++++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/css.js b/src/css.js index 2a3a84d00b..a7f61bb1e2 100644 --- a/src/css.js +++ b/src/css.js @@ -177,13 +177,10 @@ function showHide( elements, show ) { values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) ); } } else { + hidden = isHidden( elem ); - if ( !values[ index ] ) { - hidden = isHidden( elem ); - - if ( display && display !== "none" || !hidden ) { - data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css(elem, "display") ); - } + if ( display !== "none" || !hidden ) { + data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); } } } diff --git a/test/unit/css.js b/test/unit/css.js index 4ac5452444..6a8d7ac465 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1048,6 +1048,16 @@ asyncTest( "Make sure initialized display value for disconnected nodes is correc jQuery._removeData( jQuery("#display")[ 0 ] ); }); +test( "show() after hide() should always set display to initial value (#14750)", 1, function() { + var div = jQuery( "
        " ), + fixture = jQuery( "#qunit-fixture" ); + + fixture.append( div ); + + div.css( "display", "inline" ).hide().show().css( "display", "list-item" ).hide().show(); + equal( div.css( "display" ), "list-item", "should get last set display value" ); +}); + // Support: IE < 11, Safari < 7 // We have to jump through the hoops here in order to test work with "order" CSS property, // that some browsers do not support. This test is not, strictly speaking, correct, From 890d441aa5d319e49951ba6f0ec719cd4cb96759 Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Thu, 20 Mar 2014 03:39:36 -0400 Subject: [PATCH 0041/1272] Effects: Don't overwrite display:none when .hide()ing hidden elements Fixes #14848 Closes gh-1548 --- src/effects.js | 15 ++++++++++----- test/unit/effects.js | 13 +++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/effects.js b/src/effects.js index e3ccefff61..69d1effc5d 100644 --- a/src/effects.js +++ b/src/effects.js @@ -160,11 +160,8 @@ function defaultPrefilter( elem, props, opts ) { // Set display property to inline-block for height/width // animations on inline elements that are having width/height animated display = jQuery.css( elem, "display" ); - // Get default display if display is currently "none" - if ( display === "none" ) { - display = defaultDisplay( elem.nodeName ); - } - if ( display === "inline" && + // Test default display if display is currently "none" + if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" && jQuery.css( elem, "float" ) === "none" ) { style.display = "inline-block"; @@ -196,6 +193,10 @@ function defaultPrefilter( elem, props, opts ) { } } orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + + // Any non-fx value stops us from restoring the original display value + } else { + display = undefined; } } @@ -238,6 +239,10 @@ function defaultPrefilter( elem, props, opts ) { } } } + + // If this is a noop like .hide().hide(), restore an overwritten display value + } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) { + style.display = display; } } diff --git a/test/unit/effects.js b/test/unit/effects.js index 3016bdbf3d..15e67ec1a2 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -1620,6 +1620,19 @@ test( "hide, fadeOut and slideUp called on element width height and width = 0 sh this.clock.tick( 400 ); }); +test( "hide should not leave hidden inline elements visible (#14848)", 2, function() { + var el = jQuery("#simon1"); + + el.hide( 1, function() { + equal( el.css( "display" ), "none", "hidden" ); + el.hide( 1, function() { + equal( el.css( "display" ), "none", "still hidden" ); + }); + }); + + this.clock.tick( 100 ); +}); + test( "Handle queue:false promises", 10, function() { var foo = jQuery( "#foo" ).clone().addBack(), step = 1; From ad032d3c7df04827989a4187117614c29bf3a4ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Tue, 18 Mar 2014 22:38:08 +0100 Subject: [PATCH 0042/1272] Event: Fix isDefaultPrevented for bubbled events in Android 2.3 Fixes #14897 Closes gh-1545 --- src/event.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/event.js b/src/event.js index b08fde6a78..f38d70a40d 100644 --- a/src/event.js +++ b/src/event.js @@ -634,9 +634,9 @@ jQuery.Event = function( src, props ) { // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = src.defaultPrevented || - // Support: Android < 4.0 src.defaultPrevented === undefined && - src.getPreventDefault && src.getPreventDefault() ? + // Support: Android < 4.0 + src.returnValue === false ? returnTrue : returnFalse; From 2c2c93c7cbfafdb06a27dafee88fc67b265c8e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20J=C3=A4genstedt?= Date: Sat, 22 Feb 2014 01:43:51 +0700 Subject: [PATCH 0043/1272] Selector: Use Element.matches in selector-native if available Spec: http://dom.spec.whatwg.org/#dom-element-matches Support in Chromium: https://code.google.com/p/chromium/issues/detail?id=326652 Fixes #14902 Closes gh-1524 --- AUTHORS.txt | 1 + src/selector-native.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/AUTHORS.txt b/AUTHORS.txt index f68f3304ac..45e7ee0e90 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -220,4 +220,5 @@ Roman Reiß Benjy Cui Rodrigo Rosenfeld Rosas John Hoven +Philip Jägenstedt diff --git a/src/selector-native.js b/src/selector-native.js index cec99cef24..d8163c2f9b 100644 --- a/src/selector-native.js +++ b/src/selector-native.js @@ -29,7 +29,8 @@ define([ var docElem = window.document.documentElement, selector_hasDuplicate, - matches = docElem.webkitMatchesSelector || + matches = docElem.matches || + docElem.webkitMatchesSelector || docElem.mozMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector, From 5265cdac3d84b7bb4f8013ef10adaa5a9968fb1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Scott=20Gonz=C3=A1lez?= Date: Tue, 18 Mar 2014 11:48:21 -0400 Subject: [PATCH 0044/1272] Build: Update release script for new jquery-release API Closes gh-1544 --- build/release.js | 13 ++++++------- package.json | 2 -- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/build/release.js b/build/release.js index e7da799882..529137da71 100644 --- a/build/release.js +++ b/build/release.js @@ -4,10 +4,6 @@ module.exports = function( Release ) { fs = require( "fs" ), shell = require( "shelljs" ), - // Windows needs the .cmd version but will find the non-.cmd - // On Windows, ensure the HOME environment variable is set - gruntCmd = process.platform === "win32" ? "grunt.cmd" : "grunt", - devFile = "dist/jquery.js", minFile = "dist/jquery.min.js", mapFile = "dist/jquery.min.map", @@ -127,9 +123,7 @@ module.exports = function( Release ) { * @param {Function} callback */ generateArtifacts: function( callback ) { - if ( Release.exec( gruntCmd ).code !== 0 ) { - Release.abort("Grunt command failed"); - } + Release.exec( "grunt", "Grunt command failed" ); makeReleaseCopies(); callback([ "dist/jquery.js", "dist/jquery.min.js", "dist/jquery.min.map" ]); }, @@ -170,3 +164,8 @@ module.exports = function( Release ) { } }); }; + +module.exports.dependencies = [ + "archiver@0.5.2", + "shelljs@0.2.6" +]; diff --git a/package.json b/package.json index 874e1b7c3a..bb7cfad459 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ ], "dependencies": {}, "devDependencies": { - "archiver": "0.5.2", "commitplease": "1.7.0", "grunt": "0.4.2", "grunt-bowercopy": "0.7.1", @@ -44,7 +43,6 @@ "gzip-js": "0.3.2", "load-grunt-tasks": "0.3.0", "requirejs": "2.1.10", - "shelljs": "0.2.6", "testswarm": "1.1.0" }, "scripts": { From 4f490e55adaf4c2b141f41c846e04a36eb0626ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Mon, 31 Mar 2014 23:05:49 +0200 Subject: [PATCH 0045/1272] Support: Add Android support tests results --- test/unit/support.js | 54 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/test/unit/support.js b/test/unit/support.js index 867ba1d749..97650bdffd 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -165,19 +165,19 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec }; } else if ( /5\.1(\.\d+|) safari/i.test( userAgent ) ) { expected = { - "ajax":true, + "ajax": true, "boxSizingReliable": true, - "checkClone":false, - "checkOn":false, + "checkClone": false, + "checkOn": false, "clearCloneStyle": true, - "cors":true, - "focusinBubbles":false, - "noCloneChecked":true, - "optDisabled":true, - "optSelected":true, + "cors": true, + "focusinBubbles": false, + "noCloneChecked": true, + "optDisabled": true, + "optSelected": true, "pixelPosition": false, - "radioValue":true, - "reliableMarginRight":true + "radioValue": true, + "reliableMarginRight": true }; } else if ( /firefox/i.test( userAgent ) ) { expected = { @@ -211,10 +211,42 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec "radioValue": true, "reliableMarginRight": true }; + } else if ( /android 2\.3/i.test( userAgent ) ) { + expected = { + "ajax": true, + "boxSizingReliable": true, + "checkClone": true, + "checkOn": false, + "clearCloneStyle": false, + "cors": true, + "focusinBubbles": false, + "noCloneChecked": true, + "optDisabled": false, + "optSelected": true, + "pixelPosition": false, + "radioValue": true, + "reliableMarginRight": false + }; + } else if ( /android 4\.[0-3]/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 + }; } if ( expected ) { - test("Verify that the support tests resolve as expected per browser", function() { + test( "Verify that the support tests resolve as expected per browser", function() { var i, prop, j = 0; From 99d735ab4662f45c3b65ea1200fa0d3e2b671111 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Fri, 4 Apr 2014 11:38:15 +0200 Subject: [PATCH 0046/1272] Build: change .gitattributes; use system line ends for non-JS files --- .gitattributes | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitattributes b/.gitattributes index d6dc47053c..b7ca95b5b7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,5 @@ -* eol=lf -*.jar binary +# Auto detect text files and perform LF normalization +* text=auto + +# JS files must always use LF for tools to work +*.js eol=lf From 7869891a97eae93699cc239274e73e53daedf781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Tue, 15 Apr 2014 11:34:02 +0200 Subject: [PATCH 0047/1272] Build: use browserSets from config file; allow to override --- build/tasks/testswarm.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index 1e4e045317..91abf2794f 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -2,7 +2,8 @@ module.exports = function( grunt ) { "use strict"; - grunt.registerTask( "testswarm", function( commit, configFile, projectName ) { + grunt.registerTask( "testswarm", function( commit, configFile, projectName, browserSets, + timeout ) { var jobName, config, tests, testswarm = require( "testswarm" ), runs = {}, @@ -11,6 +12,12 @@ module.exports = function( grunt ) { projectName = projectName || "jquery"; config = grunt.file.readJSON( configFile )[ projectName ]; + browserSets = browserSets || config.browserSets; + if ( browserSets[ 0 ] === "[" ) { + // We got an array, parse it + browserSets = JSON.parse( browserSets ); + } + timeout = timeout || 1000 * 60 * 30; tests = grunt.config([ this.name, "tests" ]); if ( pull ) { @@ -38,10 +45,8 @@ module.exports = function( grunt ) { name: jobName, runs: runs, runMax: config.runMax, - browserSets: projectName === "jqueryweekly" ? - "weekly-no-old-ie" : - [ "popular-no-old-ie", "ios" ], - timeout: projectName === "jqueryweekly" ? 1000 * 60 * 60 : 1000 * 60 * 30 + browserSets: browserSets, + timeout: timeout }, function( err, passed ) { if ( err ) { grunt.log.error( err ); From a0568b07d8dcd94c3b8a27c0cf5747235c6bf93c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Tue, 15 Apr 2014 11:47:52 +0200 Subject: [PATCH 0048/1272] Build: set default testswarm timeout to 15 minutes We're not testing on IE6-7 anymore. --- build/tasks/testswarm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js index 91abf2794f..473bc9e720 100644 --- a/build/tasks/testswarm.js +++ b/build/tasks/testswarm.js @@ -17,7 +17,7 @@ module.exports = function( grunt ) { // We got an array, parse it browserSets = JSON.parse( browserSets ); } - timeout = timeout || 1000 * 60 * 30; + timeout = timeout || 1000 * 60 * 15; tests = grunt.config([ this.name, "tests" ]); if ( pull ) { From b26628a2bb20abae0e0515394efdd621452267b1 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Mon, 27 Jan 2014 23:26:27 +0400 Subject: [PATCH 0049/1272] Tests: Simplify "testTimeout" option --- test/data/testrunner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data/testrunner.js b/test/data/testrunner.js index 07e2262074..72ec66129c 100644 --- a/test/data/testrunner.js +++ b/test/data/testrunner.js @@ -21,7 +21,7 @@ var oldStart = window.start, // Max time for stop() and asyncTest() until it aborts test // and start()'s the next test. -QUnit.config.testTimeout = 20 * 1000; // 20 seconds +QUnit.config.testTimeout = 2e4; // 20 seconds // Enforce an "expect" argument or expect() call in all test bodies. QUnit.config.requireExpects = true; From e0b606d2bdd6cddeace765a50f727a33201e621d Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Mon, 27 Jan 2014 23:27:32 +0400 Subject: [PATCH 0050/1272] Tests: Remove uselss "keys" helper --- test/data/testrunner.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/test/data/testrunner.js b/test/data/testrunner.js index 72ec66129c..474073845f 100644 --- a/test/data/testrunner.js +++ b/test/data/testrunner.js @@ -35,20 +35,6 @@ window.start = function() { oldStart(); }; -function keys(o) { - var ret, key; - if ( Object.keys ) { - ret = Object.keys( o ); - } else { - ret = []; - for ( key in o ) { - ret.push( key ); - } - } - ret.sort(); - return ret; -} - /** * @param {jQuery|HTMLElement|Object|Array} elems Target (or array of targets) for jQuery.data. * @param {string} key @@ -123,7 +109,7 @@ window.moduleTeardown = function() { if ( QUnit.urlParams.jqdata || this.checkJqData ) { for ( i in jQuery.cache ) { expectedKeys = expectedDataKeys[i]; - actualKeys = jQuery.cache[i] ? keys( jQuery.cache[i] ) : jQuery.cache[i]; + actualKeys = jQuery.cache[i] ? Object.keys( jQuery.cache[i] ) : jQuery.cache[i]; if ( !QUnit.equiv( expectedKeys, actualKeys ) ) { deepEqual( actualKeys, expectedKeys, "Expected keys exist in jQuery.cache" ); } From 7149726485ff41afcfd2d12cb3041fe268cc909d Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Mon, 27 Jan 2014 23:32:46 +0400 Subject: [PATCH 0051/1272] Tests: Remove QUnit start hook --- test/data/testrunner.js | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/test/data/testrunner.js b/test/data/testrunner.js index 474073845f..c493618e71 100644 --- a/test/data/testrunner.js +++ b/test/data/testrunner.js @@ -1,8 +1,7 @@ define(function() { // Allow subprojects to test against their own fixtures -var oldStart = window.start, - qunitModule = QUnit.module, +var qunitModule = QUnit.module, qunitTest = QUnit.test, // Store the old counts so that we only assert on tests that have actually leaked, // instead of asserting every time a test has leaked sometime in the past @@ -26,15 +25,6 @@ QUnit.config.testTimeout = 2e4; // 20 seconds // Enforce an "expect" argument or expect() call in all test bodies. QUnit.config.requireExpects = true; -/** - * QUnit hooks - */ - -// Sandbox start for great justice -window.start = function() { - oldStart(); -}; - /** * @param {jQuery|HTMLElement|Object|Array} elems Target (or array of targets) for jQuery.data. * @param {string} key From a7c9facc357b4d2d98844cda4c26bb2e560c0cc8 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Mon, 27 Jan 2014 23:43:27 +0400 Subject: [PATCH 0052/1272] Tests: Simplify globals cleanup --- test/data/testrunner.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/test/data/testrunner.js b/test/data/testrunner.js index c493618e71..95df0c2667 100644 --- a/test/data/testrunner.js +++ b/test/data/testrunner.js @@ -172,23 +172,22 @@ reset = function () { QUnit.testDone(reset); // Register globals for cleanup and the cleanup code itself -// Explanation at http://perfectionkills.com/understanding-delete/#ie_bugs window.Globals = (function() { var globals = {}; + return { register: function( name ) { - globals[ name ] = true; - supportjQuery.globalEval( "var " + name + " = undefined;" ); + window[ name ] = globals[ name ] = true; }, + cleanup: function() { - var name, - current = globals; - globals = {}; - for ( name in current ) { - supportjQuery.globalEval( "try { " + - "delete " + ( supportjQuery.support.deleteExpando ? "window['" + name + "']" : name ) + - "; } catch( x ) {}" ); + var name; + + for ( name in globals ) { + delete window[ name ]; } + + globals = {}; } }; })(); From 92cff8b1a38fc45f1a6f6ddb92d089b739e7f5f5 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Tue, 18 Feb 2014 19:49:24 +0400 Subject: [PATCH 0053/1272] Tests: Remove Sizzle intergration tests Fixes #14818 --- test/data/testinit.js | 67 ++++++++------------ test/data/testrunner.js | 134 ---------------------------------------- 2 files changed, 27 insertions(+), 174 deletions(-) diff --git a/test/data/testinit.js b/test/data/testinit.js index af19dc69d9..06f33d19b2 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -131,8 +131,8 @@ fireNative = document.createEvent ? * @result "data/test.php?foo=bar&10538358345554" */ function url( value ) { - return baseURL + value + (/\?/.test(value) ? "&" : "?") + - new Date().getTime() + "" + parseInt(Math.random() * 100000, 10); + return baseURL + value + (/\?/.test( value ) ? "&" : "?") + + new Date().getTime() + "" + parseInt( Math.random() * 100000, 10 ); } // Ajax testing helper @@ -203,19 +203,17 @@ this.ajaxTest = function( title, expect, options ) { this.testIframe = function( fileName, name, fn ) { - - test(name, function() { - // pause execution for now - stop(); + asyncTest(name, function() { // load fixture in iframe var iframe = loadFixture(), win = iframe.contentWindow, - interval = setInterval( function() { + interval = setInterval(function() { if ( win && win.jQuery && win.jQuery.isReady ) { clearInterval( interval ); - // continue + start(); + // call actual tests passing the correct jQuery instance to use fn.call( this, win.jQuery, win, win.document ); document.body.removeChild( iframe ); @@ -225,9 +223,10 @@ this.testIframe = function( fileName, name, fn ) { }); function loadFixture() { - var src = url("./data/" + fileName + ".html"), - iframe = jQuery(" -
        - - -
        -
        - -
        - - - - -
        - -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        -
        -
        - -
        -
        hi there
        -
        -
        -
        -
        -
        -
        -
        - -
        -
        -
        - - -
        - - -
        - - -
        C
        -
        -
        - -
        -
          -
        1. Rice
        2. -
        3. Beans
        4. -
        5. Blinis
        6. -
        7. Tofu
        8. -
        - -
        I'm hungry. I should...
        - ...Eat lots of food... | - ...Eat a little food... | - ...Eat no food... - ...Eat a burger... - ...Eat some funyuns... - ...Eat some funyuns... -
        - -
        - - -
        - -
        - 1 - 2 - - - - - - - - -
        ​ -
        - -
        - - diff --git a/src/sizzle/test/jquery.js b/src/sizzle/test/jquery.js deleted file mode 100644 index 86a330515e..0000000000 --- a/src/sizzle/test/jquery.js +++ /dev/null @@ -1,9597 +0,0 @@ -/*! - * jQuery JavaScript Library v1.9.1 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2013-2-4 - */ -(function( window, undefined ) { - -// Can't do this because several apps including ASP.NET trace -// the stack via arguments.caller.callee and Firefox dies if -// you try to trace through "use strict" call chains. (#13335) -// Support: Firefox 18+ -//"use strict"; -var - // The deferred used on DOM ready - readyList, - - // A central reference to the root jQuery(document) - rootjQuery, - - // Support: IE<9 - // For `typeof node.method` instead of `node.method !== undefined` - core_strundefined = typeof undefined, - - // Use the correct document accordingly with window argument (sandbox) - document = window.document, - location = window.location, - - // Map over jQuery in case of overwrite - _jQuery = window.jQuery, - - // Map over the $ in case of overwrite - _$ = window.$, - - // [[Class]] -> type pairs - class2type = {}, - - // List of deleted data cache ids, so we can reuse them - core_deletedIds = [], - - core_version = "1.9.1", - - // Save a reference to some core methods - core_concat = core_deletedIds.concat, - core_push = core_deletedIds.push, - core_slice = core_deletedIds.slice, - core_indexOf = core_deletedIds.indexOf, - core_toString = class2type.toString, - core_hasOwn = class2type.hasOwnProperty, - core_trim = core_version.trim, - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.fn.init( selector, context, rootjQuery ); - }, - - // Used for matching numbers - core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, - - // Used for splitting on whitespace - core_rnotwhite = /\S+/g, - - // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // 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 <) - rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, - - // Match a standalone tag - rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - - // JSON RegExp - rvalidchars = /^[\],:{}\s]*$/, - rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, - rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, - rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }, - - // The ready event handler - completed = function( event ) { - - // readyState === "complete" is good enough for us to call the dom ready in oldIE - if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { - detach(); - jQuery.ready(); - } - }, - // Clean-up method for dom ready events - detach = function() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", completed, false ); - window.removeEventListener( "load", completed, false ); - - } else { - document.detachEvent( "onreadystatechange", completed ); - window.detachEvent( "onload", completed ); - } - }; - -jQuery.fn = jQuery.prototype = { - // The current version of jQuery being used - jquery: core_version, - - constructor: jQuery, - init: function( selector, context, rootjQuery ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) { - context = context instanceof jQuery ? context[0] : context; - - // scripts is true for back-compat - jQuery.merge( this, jQuery.parseHTML( - match[1], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[2] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[2] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[0] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || rootjQuery ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this.context = this[0] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return rootjQuery.ready( selector ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }, - - // Start with an empty selector - selector: "", - - // The default length of a jQuery object is 0 - length: 0, - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - toArray: function() { - return core_slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == null ? - - // Return a 'clean' array - this.toArray() : - - // Return just the object - ( num < 0 ? this[ this.length + num ] : this[ num ] ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // 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; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - ready: function( fn ) { - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; - }, - - slice: function() { - return this.pushStack( core_slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function( elem, i ) { - return callback.call( elem, i, elem ); - })); - }, - - end: function() { - return this.prevObject || this.constructor(null); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: core_push, - sort: [].sort, - splice: [].splice -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.fn.init.prototype = jQuery.fn; - -jQuery.extend = jQuery.fn.extend = function() { - var src, copyIsArray, copy, name, options, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction(target) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( length === i ) { - target = this; - --i; - } - - for ( ; i < length; i++ ) { - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) { - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray(src) ? src : []; - - } else { - clone = src && jQuery.isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend({ - noConflict: function( deep ) { - if ( window.$ === jQuery ) { - window.$ = _$; - } - - if ( deep && window.jQuery === jQuery ) { - window.jQuery = _jQuery; - } - - return jQuery; - }, - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). - if ( !document.body ) { - return setTimeout( jQuery.ready ); - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.trigger ) { - jQuery( document ).trigger("ready").off("ready"); - } - }, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type(obj) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type(obj) === "array"; - }, - - isWindow: function( obj ) { - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - return !isNaN( parseFloat(obj) ) && isFinite( obj ); - }, - - type: function( obj ) { - if ( obj == null ) { - return String( obj ); - } - return typeof obj === "object" || typeof obj === "function" ? - class2type[ core_toString.call(obj) ] || "object" : - typeof obj; - }, - - isPlainObject: function( obj ) { - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - // Not own constructor property must be Object - if ( obj.constructor && - !core_hasOwn.call(obj, "constructor") && - !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { - return false; - } - } catch ( e ) { - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - - var key; - for ( key in obj ) {} - - return key === undefined || core_hasOwn.call( obj, key ); - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - error: function( msg ) { - throw new Error( msg ); - }, - - // data: string of html - // context (optional): If specified, the fragment will be created in this context, defaults to document - // keepScripts (optional): If true, will include scripts passed in the html string - parseHTML: function( data, context, keepScripts ) { - if ( !data || typeof data !== "string" ) { - return null; - } - if ( typeof context === "boolean" ) { - keepScripts = context; - context = false; - } - context = context || document; - - var parsed = rsingleTag.exec( data ), - scripts = !keepScripts && []; - - // Single tag - if ( parsed ) { - return [ context.createElement( parsed[1] ) ]; - } - - parsed = jQuery.buildFragment( [ data ], context, scripts ); - if ( scripts ) { - jQuery( scripts ).remove(); - } - return jQuery.merge( [], parsed.childNodes ); - }, - - parseJSON: function( data ) { - // Attempt to parse using the native JSON parser first - if ( window.JSON && window.JSON.parse ) { - return window.JSON.parse( data ); - } - - if ( data === null ) { - return data; - } - - if ( typeof data === "string" ) { - - // Make sure leading/trailing whitespace is removed (IE can't handle it) - data = jQuery.trim( data ); - - if ( data ) { - // Make sure the incoming data is actual JSON - // Logic borrowed from http://json.org/json2.js - if ( rvalidchars.test( data.replace( rvalidescape, "@" ) - .replace( rvalidtokens, "]" ) - .replace( rvalidbraces, "")) ) { - - return ( new Function( "return " + data ) )(); - } - } - } - - jQuery.error( "Invalid JSON: " + data ); - }, - - // Cross-browser xml parsing - parseXML: function( data ) { - var xml, tmp; - if ( !data || typeof data !== "string" ) { - return null; - } - try { - if ( window.DOMParser ) { // Standard - tmp = new DOMParser(); - xml = tmp.parseFromString( data , "text/xml" ); - } else { // IE - xml = new ActiveXObject( "Microsoft.XMLDOM" ); - xml.async = "false"; - xml.loadXML( data ); - } - } catch( e ) { - xml = undefined; - } - if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; - }, - - noop: function() {}, - - // Evaluates a script in a global context - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && jQuery.trim( data ) ) { - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - }, - - // args is for internal usage only - each: function( obj, callback, args ) { - var value, - i = 0, - length = obj.length, - isArray = isArraylike( obj ); - - if ( args ) { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.apply( obj[ i ], args ); - - if ( value === false ) { - break; - } - } - } - - // A special, fast, case for the most common use of each - } else { - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } else { - for ( i in obj ) { - value = callback.call( obj[ i ], i, obj[ i ] ); - - if ( value === false ) { - break; - } - } - } - } - - return obj; - }, - - // Use native String.trim function wherever possible - trim: core_trim && !core_trim.call("\uFEFF\xA0") ? - function( text ) { - return text == null ? - "" : - core_trim.call( text ); - } : - - // Otherwise use our own trimming functionality - function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArraylike( Object(arr) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - core_push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( core_indexOf ) { - return core_indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var l = second.length, - i = first.length, - j = 0; - - if ( typeof l === "number" ) { - for ( ; j < l; j++ ) { - first[ i++ ] = second[ j ]; - } - } else { - while ( second[j] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, inv ) { - var retVal, - ret = [], - i = 0, - length = elems.length; - inv = !!inv; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - retVal = !!callback( elems[ i ], i ); - if ( inv !== retVal ) { - ret.push( elems[ i ] ); - } - } - - return ret; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var value, - i = 0, - length = elems.length, - isArray = isArraylike( elems ), - ret = []; - - // Go through the array, translating each of the items to their - if ( isArray ) { - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret[ ret.length ] = value; - } - } - } - - // Flatten any nested arrays - return core_concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var args, proxy, tmp; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = core_slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - // Multifunctional method to get and set values of a collection - // The value/s can optionally be executed if it's a function - access: function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - length = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < length; i++ ) { - fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); - } - } - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[0], key ) : emptyGet; - }, - - now: function() { - return ( new Date() ).getTime(); - } -}); - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called after the browser event has already occurred. - // we once tried to use readyState "interactive" here, but it caused issues like the one - // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 - if ( document.readyState === "complete" ) { - // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed, false ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed, false ); - - // If IE event model is used - } else { - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", completed ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", completed ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch(e) {} - - if ( top && top.doScroll ) { - (function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll("left"); - } catch(e) { - return setTimeout( doScrollCheck, 50 ); - } - - // detach all dom ready events - detach(); - - // and execute any waiting functions - jQuery.ready(); - } - })(); - } - } - } - return readyList.promise( obj ); -}; - -// Populate the class2type map -jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -}); - -function isArraylike( obj ) { - var length = obj.length, - type = jQuery.type( obj ); - - if ( jQuery.isWindow( obj ) ) { - return false; - } - - if ( obj.nodeType === 1 && length ) { - return true; - } - - return type === "array" || type !== "function" && - ( length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj ); -} - -// All jQuery objects should point back to these -rootjQuery = jQuery(document); -// 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 = optionsCache[ options ] = {}; - jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { - object[ flag ] = true; - }); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -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 ) ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - // Last fire value (for non-forgettable lists) - memory, - // Flag to know if list was already fired - fired, - // 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 && [], - // Fire callbacks - fire = function( data ) { - 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; - } - } - firing = false; - if ( list ) { - if ( stack ) { - if ( stack.length ) { - fire( stack.shift() ); - } - } else if ( memory ) { - list = []; - } else { - self.disable(); - } - } - }, - // Actual Callbacks object - self = { - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - // First, we save the current length - var start = list.length; - (function add( args ) { - jQuery.each( args, function( _, arg ) { - var type = jQuery.type( arg ); - if ( type === "function" ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && type !== "string" ) { - // Inspect recursively - add( arg ); - } - }); - })( 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 ); - } - } - return this; - }, - // 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--; - } - } - } - }); - } - 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 ); - }, - // Remove all callbacks from the list - empty: function() { - list = []; - return this; - }, - // Have the list do nothing anymore - disable: function() { - list = stack = memory = undefined; - return this; - }, - // Is it disabled? - disabled: function() { - return !list; - }, - // Lock the list in its current state - lock: function() { - stack = undefined; - if ( !memory ) { - self.disable(); - } - return this; - }, - // Is it locked? - locked: function() { - return !stack; - }, - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - if ( list && ( !fired || stack ) ) { - if ( firing ) { - stack.push( args ); - } else { - fire( args ); - } - } - return this; - }, - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; -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") ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred(function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var action = tuple[ 0 ], - fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[1] ](function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .done( newDefer.resolve ) - .fail( newDefer.reject ) - .progress( newDefer.notify ); - } else { - newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); - } - }); - }); - fns = null; - }).promise(); - }, - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[1] ] = list.add; - - // Handle state - if ( stateString ) { - list.add(function() { - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] - deferred[ tuple[0] ] = function() { - deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); - return this; - }; - deferred[ tuple[0] + "With" ] = list.fireWith; - }); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = core_slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; - if( values === progressValues ) { - deferred.notifyWith( contexts, values ); - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ) - .progress( updateFunc( i, progressContexts, progressValues ) ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -}); -jQuery.support = (function() { - - var support, all, a, - input, select, fragment, - opt, eventName, isSupported, i, - div = document.createElement("div"); - - // Setup - div.setAttribute( "className", "t" ); - div.innerHTML = "
        a"; - - // Support tests won't run in some limited or non-browser environments - all = div.getElementsByTagName("*"); - a = div.getElementsByTagName("a")[ 0 ]; - if ( !all || !a || !all.length ) { - return {}; - } - - // First batch of tests - select = document.createElement("select"); - opt = select.appendChild( document.createElement("option") ); - input = div.getElementsByTagName("input")[ 0 ]; - - a.style.cssText = "top:1px;float:left;opacity:.5"; - support = { - // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) - getSetAttribute: div.className !== "t", - - // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: div.firstChild.nodeType === 3, - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - tbody: !div.getElementsByTagName("tbody").length, - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - htmlSerialize: !!div.getElementsByTagName("link").length, - - // Get the style information from getAttribute - // (IE uses .cssText instead) - style: /top/.test( a.getAttribute("style") ), - - // Make sure that URLs aren't manipulated - // (IE normalizes it by default) - hrefNormalized: a.getAttribute("href") === "/a", - - // Make sure that element opacity exists - // (IE uses filter instead) - // Use a regex to work around a WebKit issue. See #5145 - opacity: /^0.5/.test( a.style.opacity ), - - // Verify style float existence - // (IE uses styleFloat instead of cssFloat) - cssFloat: !!a.style.cssFloat, - - // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) - checkOn: !!input.value, - - // Make sure that a selected-by-default option has a working selected property. - // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) - optSelected: opt.selected, - - // Tests for enctype support on a form (#6743) - enctype: !!document.createElement("form").enctype, - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav>", - - // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode - boxModel: document.compatMode === "CSS1Compat", - - // Will be defined later - deleteExpando: true, - noCloneEvent: true, - inlineBlockNeedsLayout: false, - shrinkWrapBlocks: false, - reliableMarginRight: true, - boxSizingReliable: true, - pixelPosition: false - }; - - // Make sure checked status is properly cloned - input.checked = true; - support.noCloneChecked = input.cloneNode( true ).checked; - - // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as disabled) - select.disabled = true; - support.optDisabled = !opt.disabled; - - // Support: IE<9 - try { - delete div.test; - } catch( e ) { - support.deleteExpando = false; - } - - // Check if we can trust getAttribute("value") - input = document.createElement("input"); - input.setAttribute( "value", "" ); - support.input = input.getAttribute( "value" ) === ""; - - // Check if an input maintains its value after becoming a radio - input.value = "t"; - input.setAttribute( "type", "radio" ); - support.radioValue = input.value === "t"; - - // #11217 - WebKit loses check when the name is after the checked attribute - input.setAttribute( "checked", "t" ); - input.setAttribute( "name", "t" ); - - fragment = document.createDocumentFragment(); - fragment.appendChild( input ); - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - support.appendChecked = input.checked; - - // WebKit doesn't clone checked state correctly in fragments - support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE<9 - // Opera does not clone events (and typeof div.attachEvent === undefined). - // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() - if ( div.attachEvent ) { - div.attachEvent( "onclick", function() { - support.noCloneEvent = false; - }); - - div.cloneNode( true ).click(); - } - - // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) - // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php - for ( i in { submit: true, change: true, focusin: true }) { - div.setAttribute( eventName = "on" + i, "t" ); - - support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; - } - - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - // Run tests that need a body at doc ready - jQuery(function() { - var container, marginDiv, tds, - divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", - body = document.getElementsByTagName("body")[0]; - - if ( !body ) { - // Return for frameset docs that don't have a body - return; - } - - container = document.createElement("div"); - container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; - - body.appendChild( container ).appendChild( div ); - - // Support: IE8 - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - div.innerHTML = "
        t
        "; - tds = div.getElementsByTagName("td"); - tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; - isSupported = ( tds[ 0 ].offsetHeight === 0 ); - - tds[ 0 ].style.display = ""; - tds[ 1 ].style.display = "none"; - - // Support: IE8 - // Check if empty table cells still have offsetWidth/Height - support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); - - // Check box-sizing and margin behavior - div.innerHTML = ""; - div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; - support.boxSizing = ( div.offsetWidth === 4 ); - support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); - - // Use window.getComputedStyle because jsdom on node.js will break without it. - if ( window.getComputedStyle ) { - support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; - support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; - - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. (#3333) - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - marginDiv = div.appendChild( document.createElement("div") ); - marginDiv.style.cssText = div.style.cssText = divReset; - marginDiv.style.marginRight = marginDiv.style.width = "0"; - div.style.width = "1px"; - - support.reliableMarginRight = - !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); - } - - if ( typeof div.style.zoom !== core_strundefined ) { - // Support: IE<8 - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - div.innerHTML = ""; - div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; - support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); - - // Support: IE6 - // Check if elements with layout shrink-wrap their children - div.style.display = "block"; - div.innerHTML = "
        "; - div.firstChild.style.width = "5px"; - support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); - - if ( support.inlineBlockNeedsLayout ) { - // Prevent IE 6 from affecting layout for positioned elements #11048 - // Prevent IE from shrinking the body in IE 7 mode #12869 - // Support: IE<8 - body.style.zoom = 1; - } - } - - body.removeChild( container ); - - // Null elements to avoid leaks in IE - container = div = tds = marginDiv = null; - }); - - // Null elements to avoid leaks in IE - all = select = fragment = opt = a = input = null; - - return support; -})(); - -var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, - rmultiDash = /([A-Z])/g; - -function internalData( elem, name, data, pvt /* Internal Use Only */ ){ - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var thisCache, ret, - internalKey = jQuery.expando, - getByName = typeof name === "string", - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { - return; - } - - if ( !id ) { - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - cache[ id ] = {}; - - // Avoids exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - if ( !isNode ) { - cache[ id ].toJSON = jQuery.noop; - } - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( getByName ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; -} - -function internalRemoveData( elem, name, pvt ) { - if ( !jQuery.acceptData( elem ) ) { - return; - } - - var i, l, thisCache, - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split(" "); - } - } - } else { - // If "name" is an array of keys... - // When data is initially created, via ("key", "val") signature, - // keys will be converted to camelCase. - // Since there is no way to tell _how_ a key was added, remove - // both plain key and camelCase key. #12786 - // This will only penalize the array argument path. - name = name.concat( jQuery.map( name, jQuery.camelCase ) ); - } - - for ( i = 0, l = name.length; i < l; i++ ) { - delete thisCache[ name[i] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - } else if ( jQuery.support.deleteExpando || cache != cache.window ) { - delete cache[ id ]; - - // When all else fails, null - } else { - cache[ id ] = null; - } -} - -jQuery.extend({ - cache: {}, - - // Unique for each copy of jQuery on the page - // Non-digits removed to match rinlinejQuery - expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), - - // The following elements throw uncatchable exceptions if you - // attempt to add expando properties to them. - noData: { - "embed": true, - // Ban all objects except for Flash (which handle expandos) - "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", - "applet": true - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data ) { - return internalData( elem, name, data ); - }, - - removeData: function( elem, name ) { - return internalRemoveData( elem, name ); - }, - - // For internal use only. - _data: function( elem, name, data ) { - return internalData( elem, name, data, true ); - }, - - _removeData: function( elem, name ) { - return internalRemoveData( elem, name, true ); - }, - - // A method for determining if a DOM node can handle the data expando - acceptData: function( elem ) { - // Do not set data on non-element because it will not be cleared (#8335). - if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { - return false; - } - - var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; - - // nodes accept data unless otherwise specified; rejection can be conditional - return !noData || noData !== true && elem.getAttribute("classid") === noData; - } -}); - -jQuery.fn.extend({ - data: function( key, value ) { - var attrs, name, - elem = this[0], - i = 0, - data = null; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - attrs = elem.attributes; - for ( ; i < attrs.length; i++ ) { - name = attrs[i].name; - - if ( !name.indexOf( "data-" ) ) { - name = jQuery.camelCase( name.slice(5) ); - - dataAttr( elem, name, data[ name ] ); - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each(function() { - jQuery.data( this, key ); - }); - } - - return jQuery.access( this, function( value ) { - - if ( value === undefined ) { - // Try to fetch any internally stored data first - return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; - } - - this.each(function() { - jQuery.data( this, key, value ); - }); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each(function() { - jQuery.removeData( this, key ); - }); - } -}); - -function dataAttr( elem, key, data ) { - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} -jQuery.extend({ - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray(data) ) { - queue = jQuery._data( elem, type, jQuery.makeArray(data) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - hooks.cur = fn; - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks("once memory").add(function() { - jQuery._removeData( elem, type + "queue" ); - jQuery._removeData( elem, key ); - }) - }); - } -}); - -jQuery.fn.extend({ - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[0], type ); - } - - return data === undefined ? - this : - this.each(function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[0] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - }); - }, - dequeue: function( type ) { - return this.each(function() { - jQuery.dequeue( this, type ); - }); - }, - // Based off of the plugin by Clint Helfers, with permission. - // http://blindsignals.com/index.php/2009/07/jquery-delay/ - delay: function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); - hooks.stop = function() { - clearTimeout( timeout ); - }; - }); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while( i-- ) { - tmp = jQuery._data( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -}); -var nodeHook, boolHook, - rclass = /[\t\r\n]/g, - rreturn = /\r/g, - rfocusable = /^(?:input|select|textarea|button|object)$/i, - rclickable = /^(?:a|area)$/i, - rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i, - ruseDefault = /^(?:checked|selected)$/i, - getSetAttribute = jQuery.support.getSetAttribute, - getSetInput = jQuery.support.input; - -jQuery.fn.extend({ - attr: function( name, value ) { - return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each(function() { - jQuery.removeAttr( this, name ); - }); - }, - - prop: function( name, value ) { - return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - name = jQuery.propFix[ name ] || name; - return this.each(function() { - // try/catch handles cases where IE balks (such as removing a property on window) - try { - this[ name ] = undefined; - delete this[ name ]; - } catch( e ) {} - }); - }, - - addClass: function( value ) { - var classes, elem, cur, clazz, j, - i = 0, - len = this.length, - proceed = typeof value === "string" && value; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).addClass( value.call( this, j, this.className ) ); - }); - } - - if ( proceed ) { - // The disjunction here is for better compressibility (see removeClass) - classes = ( value || "" ).match( core_rnotwhite ) || []; - - for ( ; i < len; i++ ) { - elem = this[ i ]; - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - " " - ); - - if ( cur ) { - j = 0; - while ( (clazz = classes[j++]) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - elem.className = jQuery.trim( cur ); - - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, clazz, j, - i = 0, - len = this.length, - proceed = arguments.length === 0 || typeof value === "string" && value; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( j ) { - jQuery( this ).removeClass( value.call( this, j, this.className ) ); - }); - } - if ( proceed ) { - classes = ( value || "" ).match( core_rnotwhite ) || []; - - for ( ; i < len; i++ ) { - elem = this[ i ]; - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( elem.className ? - ( " " + elem.className + " " ).replace( rclass, " " ) : - "" - ); - - if ( cur ) { - j = 0; - while ( (clazz = classes[j++]) ) { - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - elem.className = value ? jQuery.trim( cur ) : ""; - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value, - isBool = typeof stateVal === "boolean"; - - if ( jQuery.isFunction( value ) ) { - return this.each(function( i ) { - jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); - }); - } - - return this.each(function() { - if ( type === "string" ) { - // toggle individual class names - var className, - i = 0, - self = jQuery( this ), - state = stateVal, - classNames = value.match( core_rnotwhite ) || []; - - while ( (className = classNames[ i++ ]) ) { - // check each className given, space separated list - state = isBool ? state : !self.hasClass( className ); - self[ state ? "addClass" : "removeClass" ]( className ); - } - - // Toggle whole class name - } else if ( type === core_strundefined || type === "boolean" ) { - if ( this.className ) { - // store className if set - jQuery._data( this, "__className__", this.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. - this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; - } - }); - }, - - hasClass: function( selector ) { - var className = " " + selector + " ", - i = 0, - l = this.length; - for ( ; i < l; i++ ) { - if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { - return true; - } - } - - return false; - }, - - val: function( value ) { - var ret, hooks, isFunction, - elem = this[0]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { - return ret; - } - - ret = elem.value; - - return typeof ret === "string" ? - // handle most common string cases - ret.replace(rreturn, "") : - // handle cases where value is null/undef or number - ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each(function( i ) { - var val, - self = jQuery(this); - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, self.val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - } else if ( typeof val === "number" ) { - val += ""; - } else if ( jQuery.isArray( val ) ) { - val = jQuery.map(val, function ( value ) { - return value == null ? "" : value + ""; - }); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - }); - } -}); - -jQuery.extend({ - valHooks: { - option: { - get: function( elem ) { - // attributes.value is undefined in Blackberry 4.7 but - // uses .value. See #6932 - var val = elem.attributes.value; - return !val || val.specified ? elem.value : elem.text; - } - }, - select: { - get: function( elem ) { - var value, option, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one" || index < 0, - values = one ? null : [], - max = one ? index + 1 : options.length, - i = index < 0 ? - max : - one ? index : 0; - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // oldIE doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - // Don't return options that are disabled or in a disabled optgroup - ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && - ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var values = jQuery.makeArray( value ); - - jQuery(elem).find("option").each(function() { - this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; - }); - - if ( !values.length ) { - elem.selectedIndex = -1; - } - return values; - } - } - }, - - attr: function( elem, name, value ) { - var hooks, notxml, ret, - nType = elem.nodeType; - - // don't get/set attributes on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === core_strundefined ) { - return jQuery.prop( elem, name, value ); - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - // All attributes are lowercase - // Grab necessary hook if one is defined - if ( notxml ) { - name = name.toLowerCase(); - hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); - } - - if ( value !== undefined ) { - - if ( value === null ) { - jQuery.removeAttr( elem, name ); - - } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - elem.setAttribute( name, value + "" ); - return value; - } - - } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - - // In IE9+, Flash objects don't have .getAttribute (#12945) - // Support: IE9+ - if ( typeof elem.getAttribute !== core_strundefined ) { - ret = elem.getAttribute( name ); - } - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? - undefined : - ret; - } - }, - - removeAttr: function( elem, value ) { - var name, propName, - i = 0, - attrNames = value && value.match( core_rnotwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( (name = attrNames[i++]) ) { - propName = jQuery.propFix[ name ] || name; - - // Boolean attributes get special treatment (#10870) - if ( rboolean.test( name ) ) { - // Set corresponding property to false for boolean attributes - // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8 - if ( !getSetAttribute && ruseDefault.test( name ) ) { - elem[ jQuery.camelCase( "default-" + name ) ] = - elem[ propName ] = false; - } else { - elem[ propName ] = false; - } - - // See #9699 for explanation of this approach (setting first, then removal) - } else { - jQuery.attr( elem, name, "" ); - } - - elem.removeAttribute( getSetAttribute ? name : propName ); - } - } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { - // Setting the type on a radio button after the value resets the value in IE6-9 - // Reset value to default in case type is set after value during creation - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - propFix: { - tabindex: "tabIndex", - readonly: "readOnly", - "for": "htmlFor", - "class": "className", - maxlength: "maxLength", - cellspacing: "cellSpacing", - cellpadding: "cellPadding", - rowspan: "rowSpan", - colspan: "colSpan", - usemap: "useMap", - frameborder: "frameBorder", - contenteditable: "contentEditable" - }, - - prop: function( elem, name, value ) { - var ret, hooks, notxml, - nType = elem.nodeType; - - // don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); - - if ( notxml ) { - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { - return ret; - - } else { - return ( elem[ name ] = value ); - } - - } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { - return ret; - - } else { - return elem[ name ]; - } - } - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set - // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - var attributeNode = elem.getAttributeNode("tabindex"); - - return attributeNode && attributeNode.specified ? - parseInt( attributeNode.value, 10 ) : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } - } - } -}); - -// Hook for boolean attributes -boolHook = { - get: function( elem, name ) { - var - // Use .prop to determine if this attribute is understood as boolean - prop = jQuery.prop( elem, name ), - - // Fetch it accordingly - attr = typeof prop === "boolean" && elem.getAttribute( name ), - detail = typeof prop === "boolean" ? - - getSetInput && getSetAttribute ? - attr != null : - // oldIE fabricates an empty string for missing boolean attributes - // and conflates checked/selected into attroperties - ruseDefault.test( name ) ? - elem[ jQuery.camelCase( "default-" + name ) ] : - !!attr : - - // fetch an attribute node for properties not recognized as boolean - elem.getAttributeNode( name ); - - return detail && detail.value !== false ? - name.toLowerCase() : - undefined; - }, - set: function( elem, value, name ) { - if ( value === false ) { - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { - // IE<8 needs the *property* name - elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); - - // Use defaultChecked and defaultSelected for oldIE - } else { - elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; - } - - return name; - } -}; - -// fix oldIE value attroperty -if ( !getSetInput || !getSetAttribute ) { - jQuery.attrHooks.value = { - get: function( elem, name ) { - var ret = elem.getAttributeNode( name ); - return jQuery.nodeName( elem, "input" ) ? - - // Ignore the value *property* by using defaultValue - elem.defaultValue : - - ret && ret.specified ? ret.value : undefined; - }, - set: function( elem, value, name ) { - if ( jQuery.nodeName( elem, "input" ) ) { - // Does not return so that setAttribute is also used - elem.defaultValue = value; - } else { - // Use nodeHook if defined (#1954); otherwise setAttribute is fine - return nodeHook && nodeHook.set( elem, value, name ); - } - } - }; -} - -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( !getSetAttribute ) { - - // Use this for any attribute in IE6/7 - // This fixes almost every IE6/7 issue - nodeHook = jQuery.valHooks.button = { - get: function( elem, name ) { - var ret = elem.getAttributeNode( name ); - return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ? - ret.value : - undefined; - }, - set: function( elem, value, name ) { - // Set the existing or create a new attribute node - var ret = elem.getAttributeNode( name ); - if ( !ret ) { - elem.setAttributeNode( - (ret = elem.ownerDocument.createAttribute( name )) - ); - } - - ret.value = value += ""; - - // Break association with cloned elements by also using setAttribute (#9646) - return name === "value" || value === elem.getAttribute( name ) ? - value : - undefined; - } - }; - - // Set contenteditable to false on removals(#10429) - // Setting to empty string throws an error as an invalid value - jQuery.attrHooks.contenteditable = { - get: nodeHook.get, - set: function( elem, value, name ) { - nodeHook.set( elem, value === "" ? false : value, name ); - } - }; - - // Set width and height to auto instead of 0 on empty string( Bug #8150 ) - // This is for removals - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - set: function( elem, value ) { - if ( value === "" ) { - elem.setAttribute( name, "auto" ); - return value; - } - } - }); - }); -} - - -// Some attributes require a special call on IE -// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret = elem.getAttribute( name, 2 ); - return ret == null ? undefined : ret; - } - }); - }); - - // href/src property should get the full normalized URL (#10299/#12915) - jQuery.each([ "href", "src" ], function( i, name ) { - jQuery.propHooks[ name ] = { - get: function( elem ) { - return elem.getAttribute( name, 4 ); - } - }; - }); -} - -if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { - get: function( elem ) { - // Return undefined in the case of empty string - // Note: IE uppercases css property names, but if we were to .toLowerCase() - // .cssText, that would destroy case senstitivity in URL's, like in "background" - return elem.style.cssText || undefined; - }, - set: function( elem, value ) { - return ( elem.style.cssText = value + "" ); - } - }; -} - -// Safari mis-reports the default selected property of an option -// Accessing the parent's selectedIndex property fixes it -if ( !jQuery.support.optSelected ) { - jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { - get: function( elem ) { - var parent = elem.parentNode; - - if ( parent ) { - parent.selectedIndex; - - // Make sure that it also works with optgroups, see #5701 - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - return null; - } - }); -} - -// IE6/7 call enctype encoding -if ( !jQuery.support.enctype ) { - jQuery.propFix.enctype = "encoding"; -} - -// Radios and checkboxes getter/setter -if ( !jQuery.support.checkOn ) { - jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - get: function( elem ) { - // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified - return elem.getAttribute("value") === null ? "on" : elem.value; - } - }; - }); -} -jQuery.each([ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { - set: function( elem, value ) { - if ( jQuery.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); - } - } - }); -}); -var rformElems = /^(?:input|select|textarea)$/i, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|contextmenu)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - var tmp, events, t, handleObjIn, - special, eventHandle, handleObj, - handlers, type, namespaces, origType, - elemData = jQuery._data( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !(events = elemData.events) ) { - events = elemData.events = {}; - } - if ( !(eventHandle = elemData.handle) ) { - eventHandle = elemData.handle = function( e ) { - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - // jQuery(...).bind("mouseover mouseout", fn); - types = ( types || "" ).match( core_rnotwhite ) || [""]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend({ - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join(".") - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !(handlers = events[ type ]) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - var j, handleObj, tmp, - origCount, t, events, - special, handlers, type, - namespaces, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !(events = elemData.events) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( core_rnotwhite ) || [""]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[t] ) || []; - type = origType = tmp[1]; - namespaces = ( tmp[2] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery._removeData( elem, "events" ); - } - }, - - trigger: function( event, data, elem, onlyHandlers ) { - var handle, ontype, cur, - bubbleType, special, tmp, i, - eventPath = [ elem || document ], - type = core_hasOwn.call( event, "type" ) ? event.type : event, - namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf(".") >= 0 ) { - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split("."); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf(":") < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - event.isTrigger = true; - event.namespace = namespaces.join("."); - event.namespace_re = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === (elem.ownerDocument || document) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { - event.preventDefault(); - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && - !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - try { - elem[ type ](); - } catch ( e ) { - // IE<9 dies on focus/blur to hidden element (#1486,#12518) - // only reproducible on winXP IE8 native, not IE9 in IE8 mode - } - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event ); - - var i, ret, handleObj, matched, j, - handlerQueue = [], - args = core_slice.call( arguments ), - handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[0] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or - // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). - if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ) - .apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( (event.result = ret) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var sel, handleObj, matches, i, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - // Black-hole SVG instance trees (#13180) - // Avoid non-left-click bubbling in Firefox (#3861) - if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { - - for ( ; cur != this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { - matches = []; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matches[ sel ] === undefined ) { - matches[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) >= 0 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matches[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push({ elem: cur, handlers: matches }); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( delegateCount < handlers.length ) { - handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); - } - - return handlerQueue; - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, copy, - type = event.type, - originalEvent = event, - fixHook = this.fixHooks[ type ]; - - if ( !fixHook ) { - this.fixHooks[ type ] = fixHook = - rmouseEvent.test( type ) ? this.mouseHooks : - rkeyEvent.test( type ) ? this.keyHooks : - {}; - } - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = new jQuery.Event( originalEvent ); - - i = copy.length; - while ( i-- ) { - prop = copy[ i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Support: IE<9 - // Fix target property (#1925) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Support: Chrome 23+, Safari? - // Target should not be a text node (#504, #13143) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Support: IE<9 - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) - event.metaKey = !!event.metaKey; - - return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split(" "), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), - filter: function( event, original ) { - var body, eventDoc, doc, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - special: { - load: { - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - click: { - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { - this.click(); - return false; - } - } - }, - focus: { - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== document.activeElement && this.focus ) { - try { - this.focus(); - return false; - } catch ( e ) { - // Support: IE<9 - // If we error on focus to hidden element (#1486, #12518), - // let .trigger() run the handlers - } - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === document.activeElement && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - - beforeunload: { - postDispatch: function( event ) { - - // Even when returnValue equals to undefined Firefox will still show alert - if ( event.result !== undefined ) { - event.originalEvent.returnValue = event.result; - } - } - } - }, - - simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. - var e = jQuery.extend( - new jQuery.Event(), - event, - { type: type, - isSimulated: true, - originalEvent: {} - } - ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle, false ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 - // detachEvent needed property on element, by name of that event, to properly expose it to GC - if ( typeof elem[ name ] === core_strundefined ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - // Allow instantiation without the 'new' keyword - if ( !(this instanceof jQuery.Event) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || - src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - if ( !e ) { - return; - } - - // If preventDefault exists, run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // Support: IE - // Otherwise set the returnValue property of the original event to false - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - if ( !e ) { - return; - } - // If stopPropagation exists, run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - - // Support: IE - // Set the cancelBubble property of the original event to true - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - this.isImmediatePropagationStopped = returnTrue; - this.stopPropagation(); - } -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -jQuery.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mousenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || (related !== target && !jQuery.contains( target, related )) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -}); - -// IE submit delegation -if ( !jQuery.support.submitBubbles ) { - - jQuery.event.special.submit = { - setup: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; - if ( form && !jQuery._data( form, "submitBubbles" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submit_bubble = true; - }); - jQuery._data( form, "submitBubbles", true ); - } - }); - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - // If form was submitted by the user, bubble the event up the tree - if ( event._submit_bubble ) { - delete event._submit_bubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event, true ); - } - } - }, - - teardown: function() { - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !jQuery.support.changeBubbles ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._just_changed = true; - } - }); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._just_changed && !event.isTrigger ) { - this._just_changed = false; - } - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event, true ); - }); - } - return false; - } - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event, true ); - } - }); - jQuery._data( elem, "changeBubbles", true ); - } - }); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return !rformElems.test( this.nodeName ); - } - }; -} - -// Create "bubbling" focus and blur events -if ( !jQuery.support.focusinBubbles ) { - jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler while someone wants focusin/focusout - var attaches = 0, - handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - if ( attaches++ === 0 ) { - document.addEventListener( orig, handler, true ); - } - }, - teardown: function() { - if ( --attaches === 0 ) { - document.removeEventListener( orig, handler, true ); - } - } - }; - }); -} - -jQuery.fn.extend({ - - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var type, origFn; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return this; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); - }, - one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each(function() { - jQuery.event.remove( this, types, fn, selector ); - }); - }, - - bind: function( types, data, fn ) { - return this.on( types, null, data, fn ); - }, - unbind: function( types, fn ) { - return this.off( types, null, fn ); - }, - - delegate: function( selector, types, data, fn ) { - return this.on( types, selector, data, fn ); - }, - undelegate: function( selector, types, fn ) { - // ( namespace ) or ( selector, types [, fn] ) - return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); - }, - - trigger: function( type, data ) { - return this.each(function() { - jQuery.event.trigger( type, data, this ); - }); - }, - triggerHandler: function( type, data ) { - var elem = this[0]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -}); -/*! - * Sizzle CSS Selector Engine - * Copyright 2012 jQuery Foundation and other contributors - * Released under the MIT license - * http://sizzlejs.com/ - */ -(function( window, undefined ) { - -var i, - cachedruns, - Expr, - getText, - isXML, - compile, - hasDuplicate, - outermostContext, - - // Local document vars - setDocument, - document, - docElem, - documentIsXML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - sortOrder, - - // Instance-specific data - expando = "sizzle" + -(new Date()), - preferredDoc = window.document, - support = {}, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - - // General-purpose constants - strundefined = typeof undefined, - MAX_NEGATIVE = 1 << 31, - - // Array methods - arr = [], - pop = arr.pop, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf if we can't use a native one - indexOf = arr.indexOf || function( elem ) { - var i = 0, - len = this.length; - for ( ; i < len; i++ ) { - if ( this[i] === elem ) { - return i; - } - } - return -1; - }, - - - // Regular expressions - - // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - // http://www.w3.org/TR/css3-syntax/#characters - characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", - - // Loosely modeled on CSS identifier characters - // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors - // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = characterEncoding.replace( "w", "w#" ), - - // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors - operators = "([*^$|!~]?=)", - attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + - "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", - - // Prefer arguments quoted, - // then not containing pseudos/brackets, - // then attribute selectors/non-parenthetical expressions, - // then anything else - // These preferences are here to reduce the number of selectors - // needing tokenize in the PSEUDO preFilter - pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + characterEncoding + ")" ), - "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), - "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), - "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rsibling = /[\x20\t\r\n\f]*[+~]/, - - rnative = /^[^{]+\{\s*\[native code/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rescape = /'|\\/g, - rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, - - // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, - funescape = function( _, escaped ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - return high !== high ? - escaped : - // BMP codepoint - high < 0 ? - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }; - -// Use a stripped-down slice if we can't use a native one -try { - slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType; -} catch ( e ) { - slice = function( i ) { - var elem, - results = []; - while ( (elem = this[i++]) ) { - results.push( elem ); - } - return results; - }; -} - -/** - * For feature detection - * @param {Function} fn The function to test for native support - */ -function isNative( fn ) { - return rnative.test( fn + "" ); -} - -/** - * Create key-value caches of limited size - * @returns {Function(string, Object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var cache, - keys = []; - - return (cache = function( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key += " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key ] = value); - }); -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created div and expects a boolean result - */ -function assert( fn ) { - var div = document.createElement("div"); - - try { - return fn( div ); - } catch (e) { - return false; - } finally { - // release memory in IE - div = null; - } -} - -function Sizzle( selector, context, results, seed ) { - var match, elem, m, nodeType, - // QSA vars - i, groups, old, nid, newContext, newSelector; - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - - context = context || document; - results = results || []; - - if ( !selector || typeof selector !== "string" ) { - return results; - } - - if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { - return []; - } - - if ( !documentIsXML && !seed ) { - - // Shortcuts - if ( (match = rquickExpr.exec( selector )) ) { - // Speed-up: Sizzle("#ID") - if ( (m = match[1]) ) { - if ( nodeType === 9 ) { - elem = context.getElementById( m ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - // Handle the case where IE, Opera, and Webkit return items - // by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - } else { - // Context is not a document - if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && - contains( context, elem ) && elem.id === m ) { - results.push( elem ); - return results; - } - } - - // Speed-up: Sizzle("TAG") - } else if ( match[2] ) { - push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); - return results; - - // Speed-up: Sizzle(".CLASS") - } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) { - push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); - return results; - } - } - - // QSA path - if ( support.qsa && !rbuggyQSA.test(selector) ) { - old = true; - nid = expando; - newContext = context; - newSelector = nodeType === 9 && selector; - - // qSA works strangely on Element-rooted queries - // We can work around this by specifying an extra ID on the root - // and working up from there (Thanks to Andrew Dupont for the technique) - // IE 8 doesn't work on object elements - if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { - groups = tokenize( selector ); - - if ( (old = context.getAttribute("id")) ) { - nid = old.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", nid ); - } - nid = "[id='" + nid + "'] "; - - i = groups.length; - while ( i-- ) { - groups[i] = nid + toSelector( groups[i] ); - } - newContext = rsibling.test( selector ) && context.parentNode || context; - newSelector = groups.join(","); - } - - if ( newSelector ) { - try { - push.apply( results, slice.call( newContext.querySelectorAll( - newSelector - ), 0 ) ); - return results; - } catch(qsaError) { - } finally { - if ( !old ) { - context.removeAttribute("id"); - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Detect xml - * @param {Element|Object} elem An element or a document - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var doc = node ? node.ownerDocument || node : preferredDoc; - - // If no document and documentElement is available, return - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Set our document - document = doc; - docElem = doc.documentElement; - - // Support tests - documentIsXML = isXML( doc ); - - // Check if getElementsByTagName("*") returns only elements - support.tagNameNoComments = assert(function( div ) { - div.appendChild( doc.createComment("") ); - return !div.getElementsByTagName("*").length; - }); - - // Check if attributes should be retrieved by attribute nodes - support.attributes = assert(function( div ) { - div.innerHTML = ""; - var type = typeof div.lastChild.getAttribute("multiple"); - // IE8 returns a string for some attributes even when not present - return type !== "boolean" && type !== "string"; - }); - - // Check if getElementsByClassName can be trusted - support.getByClassName = assert(function( div ) { - // Opera can't find a second classname (in 9.6) - div.innerHTML = ""; - if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { - return false; - } - - // Safari 3.2 caches class attributes and doesn't catch changes - div.lastChild.className = "e"; - return div.getElementsByClassName("e").length === 2; - }); - - // Check if getElementById returns elements by name - // Check if getElementsByName privileges form controls or returns elements by ID - support.getByName = assert(function( div ) { - // Inject content - div.id = expando + 0; - div.innerHTML = "
        "; - docElem.insertBefore( div, docElem.firstChild ); - - // Test - var pass = doc.getElementsByName && - // buggy browsers will return fewer than the correct 2 - doc.getElementsByName( expando ).length === 2 + - // buggy browsers will return more than the correct 0 - doc.getElementsByName( expando + 0 ).length; - support.getIdNotName = !doc.getElementById( expando ); - - // Cleanup - docElem.removeChild( div ); - - return pass; - }); - - // IE6/7 return modified attributes - Expr.attrHandle = assert(function( div ) { - div.innerHTML = ""; - return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && - div.firstChild.getAttribute("href") === "#"; - }) ? - {} : - { - "href": function( elem ) { - return elem.getAttribute( "href", 2 ); - }, - "type": function( elem ) { - return elem.getAttribute("type"); - } - }; - - // ID find and filter - if ( support.getIdNotName ) { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== strundefined && !documentIsXML ) { - var m = context.getElementById( id ); - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - return m && m.parentNode ? [m] : []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - } else { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== strundefined && !documentIsXML ) { - var m = context.getElementById( id ); - - return m ? - m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? - [m] : - undefined : - []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - } - - // Tag - Expr.find["TAG"] = support.tagNameNoComments ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== strundefined ) { - return context.getElementsByTagName( tag ); - } - } : - function( tag, context ) { - var elem, - tmp = [], - i = 0, - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Name - Expr.find["NAME"] = support.getByName && function( tag, context ) { - if ( typeof context.getElementsByName !== strundefined ) { - return context.getElementsByName( name ); - } - }; - - // Class - Expr.find["CLASS"] = support.getByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) { - return context.getElementsByClassName( className ); - } - }; - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21), - // no need to also add to buggyMatches since matches checks buggyQSA - // A support test would require too much code (would include document ready) - rbuggyQSA = [ ":focus" ]; - - if ( (support.qsa = isNative(doc.querySelectorAll)) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explictly - // setting a boolean content attribute, - // since its presence should be enough - // http://bugs.jquery.com/ticket/12359 - div.innerHTML = ""; - - // IE8 - Some boolean attributes are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - }); - - assert(function( div ) { - - // Opera 10-12/IE8 - ^= $= *= and empty values - // Should not select anything - div.innerHTML = ""; - if ( div.querySelectorAll("[i^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - div.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector || - docElem.mozMatchesSelector || - docElem.webkitMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( div, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = new RegExp( rbuggyMatches.join("|") ); - - // Element contains another - // Purposefully does not implement inclusive descendent - // As in, an element does not contain itself - contains = isNative(docElem.contains) || docElem.compareDocumentPosition ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - // Document order sorting - sortOrder = docElem.compareDocumentPosition ? - function( a, b ) { - var compare; - - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) { - if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) { - if ( a === doc || contains( preferredDoc, a ) ) { - return -1; - } - if ( b === doc || contains( preferredDoc, b ) ) { - return 1; - } - return 0; - } - return compare & 4 ? -1 : 1; - } - - return a.compareDocumentPosition ? -1 : 1; - } : - function( a, b ) { - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - - // Parentless nodes are either documents or disconnected - } else if ( !aup || !bup ) { - return a === doc ? -1 : - b === doc ? 1 : - aup ? -1 : - bup ? 1 : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - // Always assume the presence of duplicates if sort doesn't - // pass them to our comparison function (as in Google Chrome). - hasDuplicate = false; - [0, 0].sort( sortOrder ); - support.detectDuplicates = hasDuplicate; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - // rbuggyQSA always contains :focus, so no need for an existence check - if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) { - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch(e) {} - } - - return Sizzle( expr, document, null, [elem] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - var val; - - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - if ( !documentIsXML ) { - name = name.toLowerCase(); - } - if ( (val = Expr.attrHandle[ name ]) ) { - return val( elem ); - } - if ( documentIsXML || support.attributes ) { - return elem.getAttribute( name ); - } - return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ? - name : - val && val.specified ? val.value : null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -// Document sorting and removing duplicates -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - i = 1, - j = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - for ( ; (elem = results[i]); i++ ) { - if ( elem === results[ i - 1 ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - return results; -}; - -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -// Returns a function to use in pseudos for input types -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -// Returns a function to use in pseudos for buttons -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -// Returns a function to use in pseudos for positionals -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - for ( ; (node = elem[i]); i++ ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (see #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[5] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[4] ) { - match[2] = match[4]; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeName ) { - if ( nodeName === "*" ) { - return function() { return true; }; - } - - nodeName = nodeName.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, outerCache, node, diff, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - // Seek `elem` from a previously-cached index - outerCache = parent[ expando ] || (parent[ expando ] = {}); - cache = outerCache[ type ] || []; - nodeIndex = cache[0] === dirruns && cache[1]; - diff = cache[0] === dirruns && cache[2]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - outerCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - // Use previously-cached element index if available - } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { - diff = cache[1]; - - // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) - } else { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { - // Cache the index of each encountered element - if ( useCache ) { - (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf.call( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifider - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsXML ? - elem.getAttribute("xml:lang") || elem.getAttribute("lang") : - elem.lang) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), - // not comment, processing instructions, or others - // Thanks to Diego Perini for the nodeName shortcut - // Greater than "@" means alpha characters (specifically not starting with "#" or "?") - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) - // use getAttribute instead to test this case - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -function tokenize( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( tokens = [] ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push( { - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - } ); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push( { - value: matched, - type: type, - matches: match - } ); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -} - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - checkNonElements = base && dir === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var data, cache, outerCache, - dirkey = dirruns + " " + doneName; - - // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { - if ( (data = cache[1]) === true || data === cachedruns ) { - return data === true; - } - } else { - cache = outerCache[ dir ] = [ dirkey ]; - cache[1] = matcher( elem, context, xml ) || cachedruns; - if ( cache[1] === true ) { - return true; - } - } - } - } - } - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf.call( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - // A counter to specify which element is currently being matched - var matcherCachedRuns = 0, - bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, expandContext ) { - var elem, j, matcher, - setMatched = [], - matchedCount = 0, - i = "0", - unmatched = seed && [], - outermost = expandContext != null, - contextBackup = outermostContext, - // We must always have either seed elements or context - elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); - - if ( outermost ) { - outermostContext = context !== document && context; - cachedruns = matcherCachedRuns; - } - - // Add elements passing elementMatchers directly to results - // Keep `i` a string if there are no elements so `matchedCount` will be "00" below - for ( ; (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context, xml ) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - cachedruns = ++matcherCachedRuns; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // Apply set filters to unmatched elements - matchedCount += i; - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !group ) { - group = tokenize( selector ); - } - i = group.length; - while ( i-- ) { - cached = matcherFromTokens( group[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - } - return cached; -}; - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function select( selector, context, results, seed ) { - var i, tokens, token, type, find, - match = tokenize( selector ); - - if ( !seed ) { - // Try to minimize operations if there is only one group - if ( match.length === 1 ) { - - // Take a shortcut and set the context if the root selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && !documentIsXML && - Expr.relative[ tokens[1].type ] ) { - - context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0]; - if ( !context ) { - return results; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && context.parentNode || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, slice.call( seed, 0 ) ); - return results; - } - - break; - } - } - } - } - } - - // Compile and execute a filtering function - // Provide `match` to avoid retokenization if we modified the selector above - compile( selector, match )( - seed, - context, - documentIsXML, - results, - rsibling.test( selector ) - ); - return results; -} - -// Deprecated -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Easy API for creating new setFilters -function setFilters() {} -Expr.filters = setFilters.prototype = Expr.pseudos; -Expr.setFilters = new setFilters(); - -// Initialize with the default document -setDocument(); - -// Override sizzle attribute retrieval -Sizzle.attr = jQuery.attr; -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[":"] = jQuery.expr.pseudos; -jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - -})( window ); -var runtil = /Until$/, - rparentsprev = /^(?:parents|prev(?:Until|All))/, - isSimple = /^.[^:#\[\.,]*$/, - rneedsContext = jQuery.expr.match.needsContext, - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend({ - find: function( selector ) { - var i, ret, self, - len = this.length; - - if ( typeof selector !== "string" ) { - self = this; - return this.pushStack( jQuery( selector ).filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - }) ); - } - - ret = []; - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, this[ i ], 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; - return ret; - }, - - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter(function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[i] ) ) { - return true; - } - } - }); - }, - - not: function( selector ) { - return this.pushStack( winnow(this, selector, false) ); - }, - - filter: function( selector ) { - return this.pushStack( winnow(this, selector, true) ); - }, - - is: function( selector ) { - return !!selector && ( - typeof selector === "string" ? - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - rneedsContext.test( selector ) ? - jQuery( selector, this.context ).index( this[0] ) >= 0 : - jQuery.filter( selector, this ).length > 0 : - this.filter( selector ).length > 0 ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - ret = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - cur = this[i]; - - while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { - if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { - ret.push( cur ); - break; - } - cur = cur.parentNode; - } - } - - return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[0], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[0] : elem, this ); - }, - - add: function( selector, context ) { - var set = typeof selector === "string" ? - jQuery( selector, context ) : - jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), - all = jQuery.merge( this.get(), set ); - - return this.pushStack( jQuery.unique(all) ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter(selector) - ); - } -}); - -jQuery.fn.andSelf = jQuery.fn.addBack; - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each({ - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return jQuery.dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return jQuery.dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return jQuery.dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return jQuery.dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return jQuery.dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return jQuery.dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return jQuery.sibling( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( !runtil.test( name ) ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; - - if ( this.length > 1 && rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - - return this.pushStack( ret ); - }; -}); - -jQuery.extend({ - filter: function( expr, elems, not ) { - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 ? - jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : - jQuery.find.matches(expr, elems); - }, - - dir: function( elem, dir, until ) { - var matched = [], - cur = elem[ dir ]; - - while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { - if ( cur.nodeType === 1 ) { - matched.push( cur ); - } - cur = cur[dir]; - } - return matched; - }, - - sibling: function( n, elem ) { - var r = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - r.push( n ); - } - } - - return r; - } -}); - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, keep ) { - - // Can't pass null or undefined to indexOf in Firefox 4 - // Set to 0 to skip string check - qualifier = qualifier || 0; - - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep(elements, function( elem, i ) { - var retVal = !!qualifier.call( elem, i, elem ); - return retVal === keep; - }); - - } else if ( qualifier.nodeType ) { - return jQuery.grep(elements, function( elem ) { - return ( elem === qualifier ) === keep; - }); - - } else if ( typeof qualifier === "string" ) { - var filtered = jQuery.grep(elements, function( elem ) { - return elem.nodeType === 1; - }); - - if ( isSimple.test( qualifier ) ) { - return jQuery.filter(qualifier, filtered, !keep); - } else { - qualifier = jQuery.filter( qualifier, filtered ); - } - } - - return jQuery.grep(elements, function( elem ) { - return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; - }); -} -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + - "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", - rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), - rleadingWhitespace = /^\s+/, - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, - rtagName = /<([\w:]+)/, - rtbody = /\s*$/g, - - // We have to close these tags to support XHTML (#13200) - wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
        ", "
        " ], - area: [ 1, "", "" ], - param: [ 1, "", "" ], - thead: [ 1, "", "
        " ], - tr: [ 2, "", "
        " ], - col: [ 2, "", "
        " ], - td: [ 3, "", "
        " ], - - // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, - // unless wrapped in a div with non-breaking characters in front of it. - _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
        ", "
        " ] - }, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement("div") ); - -wrapMap.optgroup = wrapMap.option; -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - -jQuery.fn.extend({ - text: function( value ) { - return jQuery.access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); - }, null, value, arguments.length ); - }, - - wrapAll: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapAll( html.call(this, i) ); - }); - } - - if ( this[0] ) { - // The elements to wrap the target around - var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); - - if ( this[0].parentNode ) { - wrap.insertBefore( this[0] ); - } - - wrap.map(function() { - var elem = this; - - while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { - elem = elem.firstChild; - } - - return elem; - }).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each(function(i) { - jQuery(this).wrapInner( html.call(this, i) ); - }); - } - - return this.each(function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - }); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each(function(i) { - jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); - }); - }, - - unwrap: function() { - return this.parent().each(function() { - if ( !jQuery.nodeName( this, "body" ) ) { - jQuery( this ).replaceWith( this.childNodes ); - } - }).end(); - }, - - append: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.appendChild( elem ); - } - }); - }, - - prepend: function() { - return this.domManip(arguments, true, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.insertBefore( elem, this.firstChild ); - } - }); - }, - - before: function() { - return this.domManip( arguments, false, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - }); - }, - - after: function() { - return this.domManip( arguments, false, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - }); - }, - - // keepData is for internal use only--do not document - remove: function( selector, keepData ) { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem ) ); - } - - if ( elem.parentNode ) { - if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { - setGlobalEval( getAll( elem, "script" ) ); - } - elem.parentNode.removeChild( elem ); - } - } - } - - return this; - }, - - empty: function() { - var elem, - i = 0; - - for ( ; (elem = this[i]) != null; i++ ) { - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - - // If this is a select, ensure that it displays empty (#12336) - // Support: IE<9 - if ( elem.options && jQuery.nodeName( elem, "select" ) ) { - elem.options.length = 0; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function () { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - }); - }, - - html: function( value ) { - return jQuery.access( this, function( value ) { - var elem = this[0] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { - - value = value.replace( rxhtmlTag, "<$1>" ); - - try { - for (; i < l; i++ ) { - // Remove element nodes and prevent memory leaks - elem = this[i] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch(e) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function( value ) { - var isFunc = jQuery.isFunction( value ); - - // Make sure that the elements are removed from the DOM before they are inserted - // this can help fix replacing a parent with child elements - if ( !isFunc && typeof value !== "string" ) { - value = jQuery( value ).not( this ).detach(); - } - - return this.domManip( [ value ], true, function( elem ) { - var next = this.nextSibling, - parent = this.parentNode; - - if ( parent ) { - jQuery( this ).remove(); - parent.insertBefore( elem, next ); - } - }); - }, - - detach: function( selector ) { - return this.remove( selector, true ); - }, - - domManip: function( args, table, callback ) { - - // Flatten any nested arrays - args = core_concat.apply( [], args ); - - var first, node, hasScripts, - scripts, doc, fragment, - i = 0, - l = this.length, - set = this, - iNoClone = l - 1, - value = args[0], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { - return this.each(function( index ) { - var self = set.eq( index ); - if ( isFunction ) { - args[0] = value.call( this, index, table ? self.html() : undefined ); - } - self.domManip( args, table, callback ); - }); - } - - if ( l ) { - fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - if ( first ) { - table = table && jQuery.nodeName( first, "tr" ); - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( - table && jQuery.nodeName( this[i], "table" ) ? - findOrAppend( this[i], "tbody" ) : - this[i], - node, - i - ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { - - if ( node.src ) { - // Hope ajax is available... - jQuery.ajax({ - url: node.src, - type: "GET", - dataType: "script", - async: false, - global: false, - "throws": true - }); - } else { - jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); - } - } - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - } - } - - return this; - } -}); - -function findOrAppend( elem, tag ) { - return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - var attr = elem.getAttributeNode("type"); - elem.type = ( attr && attr.specified ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - if ( match ) { - elem.type = match[1]; - } else { - elem.removeAttribute("type"); - } - return elem; -} - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var elem, - i = 0; - for ( ; (elem = elems[i]) != null; i++ ) { - jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); - } -} - -function cloneCopyEvent( src, dest ) { - - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function fixCloneNodeIssues( src, dest ) { - var nodeName, e, data; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - nodeName = dest.nodeName.toLowerCase(); - - // IE6-8 copies events bound via attachEvent when using cloneNode. - if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { - data = jQuery._data( dest ); - - for ( e in data.events ) { - jQuery.removeEvent( dest, e, data.handle ); - } - - // Event data gets referenced instead of copied if the expando gets copied too - dest.removeAttribute( jQuery.expando ); - } - - // IE blanks contents when cloning scripts, and tries to evaluate newly-set text - if ( nodeName === "script" && dest.text !== src.text ) { - disableScript( dest ).text = src.text; - restoreScript( dest ); - - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - } else if ( nodeName === "object" ) { - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.defaultSelected = dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -jQuery.each({ - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone(true); - jQuery( insert[i] )[ original ]( elems ); - - // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() - core_push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -}); - -function getAll( context, tag ) { - var elems, elem, - i = 0, - found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : - typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : - undefined; - - if ( !found ) { - for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { - if ( !tag || jQuery.nodeName( elem, tag ) ) { - found.push( elem ); - } else { - jQuery.merge( found, getAll( elem, tag ) ); - } - } - } - - return tag === undefined || tag && jQuery.nodeName( context, tag ) ? - jQuery.merge( [ context ], found ) : - found; -} - -// Used in buildFragment, fixes the defaultChecked property -function fixDefaultChecked( elem ) { - if ( manipulation_rcheckableType.test( elem.type ) ) { - elem.defaultChecked = elem.checked; - } -} - -jQuery.extend({ - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var destElements, node, clone, i, srcElements, - inPage = jQuery.contains( elem.ownerDocument, elem ); - - if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && - (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { - - // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - // Fix all IE cloning issues - for ( i = 0; (node = srcElements[i]) != null; ++i ) { - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[i] ) { - fixCloneNodeIssues( node, destElements[i] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0; (node = srcElements[i]) != null; i++ ) { - cloneCopyEvent( node, destElements[i] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - destElements = srcElements = node = null; - - // Return the cloned set - return clone; - }, - - buildFragment: function( elems, context, scripts, selection ) { - var j, elem, contains, - tmp, tag, tbody, wrap, - l = elems.length, - - // Ensure a safe fragment - safe = createSafeFragment( context ), - - nodes = [], - i = 0; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || safe.appendChild( context.createElement("div") ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - - tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1>" ) + wrap[2]; - - // Descend through wrappers to the right content - j = wrap[0]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Manually add leading whitespace removed by IE - if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { - nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); - } - - // Remove IE's autoinserted from table fragments - if ( !jQuery.support.tbody ) { - - // String was a , *may* have spurious - elem = tag === "table" && !rtbody.test( elem ) ? - tmp.firstChild : - - // String was a bare or - wrap[1] === "
        " && !rtbody.test( elem ) ? - tmp : - 0; - - j = elem && elem.childNodes.length; - while ( j-- ) { - if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { - elem.removeChild( tbody ); - } - } - } - - jQuery.merge( nodes, tmp.childNodes ); - - // Fix #12392 for WebKit and IE > 9 - tmp.textContent = ""; - - // Fix #12392 for oldIE - while ( tmp.firstChild ) { - tmp.removeChild( tmp.firstChild ); - } - - // Remember the top-level container for proper cleanup - tmp = safe.lastChild; - } - } - } - - // Fix #11356: Clear elements from fragment - if ( tmp ) { - safe.removeChild( tmp ); - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !jQuery.support.appendChecked ) { - jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); - } - - i = 0; - while ( (elem = nodes[ i++ ]) ) { - - // #4087 - If origin and destination elements are the same, and this is - // that element, do not do anything - if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( safe.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( (elem = tmp[ j++ ]) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - tmp = null; - - return safe; - }, - - cleanData: function( elems, /* internal */ acceptData ) { - var elem, type, id, data, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - deleteExpando = jQuery.support.deleteExpando, - special = jQuery.event.special; - - for ( ; (elem = elems[i]) != null; i++ ) { - - if ( acceptData || jQuery.acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // IE does not allow us to delete expando properties from nodes, - // nor does it have a removeAttribute function on Document nodes; - // we must handle all of these cases - if ( deleteExpando ) { - delete elem[ internalKey ]; - - } else if ( typeof elem.removeAttribute !== core_strundefined ) { - elem.removeAttribute( internalKey ); - - } else { - elem[ internalKey ] = null; - } - - core_deletedIds.push( id ); - } - } - } - } - } -}); -var iframe, getStyles, curCSS, - ralpha = /alpha\([^)]*\)/i, - ropacity = /opacity\s*=\s*([^)]*)/, - rposition = /^(top|right|bottom|left)$/, - // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" - // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rmargin = /^margin/, - rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), - rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), - rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), - elemdisplay = { BODY: "block" }, - - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: 0, - fontWeight: 400 - }, - - cssExpand = [ "Top", "Right", "Bottom", "Left" ], - cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; - -// return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { - - // shortcut for names that are not vendor prefixed - if ( name in style ) { - return name; - } - - // check for vendor prefixed names - var capName = name.charAt(0).toUpperCase() + name.slice(1), - origName = name, - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in style ) { - return name; - } - } - - return origName; -} - -function isHidden( elem, el ) { - // isHidden might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); -} - -function showHide( elements, show ) { - var display, elem, hidden, - values = [], - index = 0, - length = elements.length; - - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - values[ index ] = jQuery._data( elem, "olddisplay" ); - display = elem.style.display; - if ( show ) { - // Reset the inline display of this element to learn if it is - // being hidden by cascaded rules or not - if ( !values[ index ] && display === "none" ) { - elem.style.display = ""; - } - - // Set elements which have been overridden with display: none - // in a stylesheet to whatever the default browser style is - // for such an element - if ( elem.style.display === "" && isHidden( elem ) ) { - values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); - } - } else { - - if ( !values[ index ] ) { - hidden = isHidden( elem ); - - if ( display && display !== "none" || !hidden ) { - jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); - } - } - } - } - - // Set the display of most of the elements in a second loop - // to avoid the constant reflow - for ( index = 0; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - if ( !show || elem.style.display === "none" || elem.style.display === "" ) { - elem.style.display = show ? values[ index ] || "" : "none"; - } - } - - return elements; -} - -jQuery.fn.extend({ - css: function( name, value ) { - return jQuery.access( this, function( elem, name, value ) { - var len, styles, - map = {}, - i = 0; - - if ( jQuery.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - }, - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - var bool = typeof state === "boolean"; - - return this.each(function() { - if ( bool ? state : isHidden( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - }); - } -}); - -jQuery.extend({ - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Exclude the following css properties to add px - cssNumber: { - "columnCount": true, - "fillOpacity": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - // normalize float css property - "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - style = elem.style; - - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // convert relative number strings (+= or -=) to relative numbers. #7345 - if ( type === "string" && (ret = rrelNum.exec( value )) ) { - value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); - // Fixes bug #9237 - type = "number"; - } - - // Make sure that NaN and null values aren't set. See: #7116 - if ( value == null || type === "number" && isNaN( value ) ) { - return; - } - - // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( type === "number" && !jQuery.cssNumber[ origName ] ) { - value += "px"; - } - - // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, - // but it would mean to define eight (for every problematic property) identical functions - if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { - - // Wrapped to prevent IE from throwing errors when 'invalid' values are provided - // Fixes bug #5509 - try { - style[ name ] = value; - } catch(e) {} - } - - } else { - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var num, val, hooks, - origName = jQuery.camelCase( name ); - - // Make sure that we're working with the right name - name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); - - // gets hook for the prefixed version - // followed by the unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - //convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Return, converting to number if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; - } - return val; - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; - } -}); - -// NOTE: we've included the "window" in window.getComputedStyle -// because jsdom on node.js will break without it. -if ( window.getComputedStyle ) { - getStyles = function( elem ) { - return window.getComputedStyle( elem, null ); - }; - - curCSS = function( elem, name, _computed ) { - var width, minWidth, maxWidth, - computed = _computed || getStyles( elem ), - - // getPropertyValue is only needed for .css('filter') in IE9, see #12537 - ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, - style = elem.style; - - if ( computed ) { - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right - // Safari 5.1.7 (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 ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret; - }; -} else if ( document.documentElement.currentStyle ) { - getStyles = function( elem ) { - return elem.currentStyle; - }; - - curCSS = function( elem, name, _computed ) { - var left, rs, rsLeft, - computed = _computed || getStyles( elem ), - ret = computed ? computed[ name ] : undefined, - style = elem.style; - - // Avoid setting ret to empty string here - // so we don't default to auto - if ( ret == null && style && style[ name ] ) { - ret = style[ name ]; - } - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - // but not position css attributes, as those are proportional to the parent element instead - // and we can't measure the parent instead because it might trigger a "stacking dolls" problem - if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { - - // Remember the original values - left = style.left; - rs = elem.runtimeStyle; - rsLeft = rs && rs.left; - - // Put in the new values to get a computed value out - if ( rsLeft ) { - rs.left = elem.currentStyle.left; - } - style.left = name === "fontSize" ? "1em" : ret; - ret = style.pixelLeft + "px"; - - // Revert the changed values - style.left = left; - if ( rsLeft ) { - rs.left = rsLeft; - } - } - - return ret === "" ? "auto" : ret; - }; -} - -function setPositiveNumber( elem, value, subtract ) { - var matches = rnumsplit.exec( value ); - return matches ? - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i = extra === ( isBorderBox ? "border" : "content" ) ? - // If we already have the right measurement, avoid augmentation - 4 : - // Otherwise initialize for horizontal or vertical properties - name === "width" ? 1 : 0, - - val = 0; - - for ( ; i < 4; i += 2 ) { - // both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); - } - - if ( isBorderBox ) { - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // at this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } else { - // at this point, extra isn't content, so add padding - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // at this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with offset property, which is equivalent to the border-box value - var valueIsBorderBox = true, - val = name === "width" ? elem.offsetWidth : elem.offsetHeight, - styles = getStyles( elem ), - isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // 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 - if ( val <= 0 || val == null ) { - // Fall back to computed then uncomputed css if necessary - val = curCSS( elem, name, styles ); - if ( val < 0 || val == null ) { - val = elem.style[ name ]; - } - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test(val) ) { - return val; - } - - // we need the check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - } - - // use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles - ) - ) + "px"; -} - -// Try to determine the default display value of an element -function css_defaultDisplay( nodeName ) { - var doc = document, - display = elemdisplay[ nodeName ]; - - if ( !display ) { - display = actualDisplay( nodeName, doc ); - - // If the simple way fails, read from inside an iframe - if ( display === "none" || !display ) { - // Use the already-created iframe if possible - iframe = ( iframe || - jQuery("
        +
        +
        + + +

        See this blog entry for more information.

        diff --git a/test/unit/event.js b/test/unit/event.js index a84ec087af..981e6702fc 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -2671,6 +2671,60 @@ test( ".off() removes the expando when there's no more data", function() { } }); +test( "preventDefault() on focusin does not throw exception", function( assert ) { + expect( 1 ); + + var done = assert.async(), + input = jQuery( "" ).appendTo( "#form" ); + input + .on( "focusin", function( event ) { + var exceptionCaught; + + try { + event.preventDefault(); + } catch ( theException ) { + exceptionCaught = theException; + } + + assert.strictEqual( exceptionCaught, undefined, + "Preventing default on focusin throws no exception" ); + + done(); + } ) + .focus(); +} ); + +test( "jQuery.event.simulate() event has no originalEvent", function( assert ) { + expect( 1 ); + + var done = assert.async(), + input = jQuery( "" ) + .on( "click", function( event ) { + assert.strictEqual( "originalEvent" in event, false, + "originalEvent not present on simulated event" ); + done(); + } ); + + jQuery.event.simulate( "click", input[ 0 ], new jQuery.Event(), true ); +} ); + +test( "Donor event interference", function( assert ) { + assert.expect( 4 ); + + jQuery( "#donor-outer" ).on( "click", function() { + assert.ok( true, "click bubbled to outer div" ); + } ); + jQuery( "#donor-input" ).on( "click", function( event ) { + assert.ok( true, "got a click event from the input" ); + assert.ok( !event.isPropagationStopped(), "propagation says it's not stopped" ); + } ); + jQuery( "#donor-input" ).on( "change", function( event ) { + assert.ok( true, "got a change event from the input" ); + event.stopPropagation(); + } ); + jQuery( "#donor-input" )[0].click(); +} ); + // This tests are unreliable in Firefox if ( !(/firefox/i.test( window.navigator.userAgent )) ) { test( "Check order of focusin/focusout events", 2, function() { From 6df669f0fb87cd9975a18bf6bbe3c3548afa4fee Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 20 May 2015 18:09:46 +0300 Subject: [PATCH 0316/1272] Event: remove outdated originalEvent hack Closes gh-2335 Ref 7475d5debeb7c53158921ed40f6c2fdb25a2cc86 --- src/event.js | 20 +++++++++----- test/unit/event.js | 65 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/event.js b/src/event.js index 9bc875e24c..8722268a80 100644 --- a/src/event.js +++ b/src/event.js @@ -601,23 +601,29 @@ jQuery.event = { } }, + // Piggyback on a donor event to simulate a different one simulate: function( type, elem, event, bubble ) { - // Piggyback on a donor event to simulate a different one. - // Fake originalEvent to avoid donor's stopPropagation, but if the - // simulated event prevents default then we do the same on the donor. var e = jQuery.extend( new jQuery.Event(), 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 compat 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 } ); - // This prevents stopPropagation(), stopImmediatePropagation(), and preventDefault() from - // preventing default on the donor event. - delete e.originalEvent; - if ( bubble ) { jQuery.event.trigger( e, null, elem ); } else { diff --git a/test/unit/event.js b/test/unit/event.js index 981e6702fc..ba3d9481a7 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -2694,35 +2694,68 @@ test( "preventDefault() on focusin does not throw exception", function( assert ) .focus(); } ); -test( "jQuery.event.simulate() event has no originalEvent", function( assert ) { - expect( 1 ); +test( "Donor event interference", function( assert ) { + assert.expect( 10 ); - var done = assert.async(), - input = jQuery( "" ) - .on( "click", function( event ) { - assert.strictEqual( "originalEvent" in event, false, - "originalEvent not present on simulated event" ); - done(); - } ); - - jQuery.event.simulate( "click", input[ 0 ], new jQuery.Event(), true ); -} ); + var html = "

        " + + "
        " + + "" + + "" + + "
        "; -test( "Donor event interference", function( assert ) { - assert.expect( 4 ); + jQuery( "#qunit-fixture" ).append( html ); - jQuery( "#donor-outer" ).on( "click", function() { + jQuery( "#donor-outer" ).on( "click", function( event ) { assert.ok( true, "click bubbled to outer div" ); + assert.equal( typeof event.originalEvent, "object", "make sure originalEvent exist" ); + assert.equal( event.type, "click", "make sure event type is correct" ); } ); jQuery( "#donor-input" ).on( "click", function( event ) { assert.ok( true, "got a click event from the input" ); assert.ok( !event.isPropagationStopped(), "propagation says it's not stopped" ); + assert.equal( event.type, "click", "make sure event type is correct" ); + assert.equal( typeof event.originalEvent, "object", "make sure originalEvent exist" ); } ); jQuery( "#donor-input" ).on( "change", function( event ) { + assert.equal( typeof event.originalEvent, "object", "make sure originalEvent exist" ); + assert.equal( event.type, "change", "make sure event type is correct" ); assert.ok( true, "got a change event from the input" ); event.stopPropagation(); } ); - jQuery( "#donor-input" )[0].click(); + jQuery( "#donor-input" )[ 0 ].click(); +} ); + +test( "originalEvent property for Chrome, Safari and FF of simualted event", function( assert ) { + var userAgent = window.navigator.userAgent; + + if ( !(/chrome/i.test( userAgent ) || + /firefox/i.test( userAgent ) || + /safari/i.test( userAgent ) ) ) { + assert.expect( 1 ); + assert.ok( true, "Assertions should run only in Chrome, Safari and FF" ); + return; + } + + assert.expect( 4 ); + + var html = "
        " + + "
        " + + "" + + "" + + "
        "; + + jQuery( "#qunit-fixture" ).append( html ); + + 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" ); + } ); + jQuery( "#donor-input" ).on( "focus", function() { + assert.ok( true, "got a focus event from the input" ); + } ); + jQuery( "#donor-input" ).trigger( "focus" ); } ); // This tests are unreliable in Firefox From d471842b3e3af83c9a1be06b5d16f75bfa96af8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 11 May 2015 23:23:09 +0200 Subject: [PATCH 0317/1272] CSS: Don't cache unrecognized CSS property names This prevents jQuery from caching a prefixed property name if provided directly by the user, e.g. the following code: elem.css( "msTransform", "translate(5px, 2px)" ); should not prevent one from from later setting the transition directly: elem.css( "transform", "translate(5px, 2px)" ); on a browser not understanding the unprefixed version which is the case for Safari 8 & transform. Fixes gh-2015 Closes gh-2298 --- src/css.js | 21 ++++++------- test/unit/css.js | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/src/css.js b/src/css.js index 7b011668ef..566f5a0fd6 100644 --- a/src/css.js +++ b/src/css.js @@ -3,6 +3,7 @@ define([ "./var/pnum", "./core/access", "./css/var/rmargin", + "./var/document", "./var/rcssNum", "./css/var/rnumnonpx", "./css/var/cssExpand", @@ -18,8 +19,8 @@ define([ "./core/init", "./core/ready", "./selector" // contains -], function( jQuery, pnum, access, rmargin, rcssNum, rnumnonpx, cssExpand, isHidden, - getStyles, swap, curCSS, adjustCSS, addGetHookIf, support, showHide ) { +], function( jQuery, pnum, access, rmargin, document, rcssNum, rnumnonpx, cssExpand, + isHidden, getStyles, swap, curCSS, adjustCSS, addGetHookIf, support, showHide ) { var // Swappable if display is none or starts with table @@ -34,29 +35,27 @@ var fontWeight: "400" }, - cssPrefixes = [ "Webkit", "Moz", "ms" ]; + cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style; // Return a css property mapped to a potentially vendor prefixed property -function vendorPropName( style, name ) { +function vendorPropName( name ) { // Shortcut for names that are not vendor prefixed - if ( name in style ) { + if ( name in emptyStyle ) { return name; } // Check for vendor prefixed names var capName = name[0].toUpperCase() + name.slice(1), - origName = name, i = cssPrefixes.length; while ( i-- ) { name = cssPrefixes[ i ] + capName; - if ( name in style ) { + if ( name in emptyStyle ) { return name; } } - - return origName; } function setPositiveNumber( elem, value, subtract ) { @@ -203,7 +202,7 @@ jQuery.extend({ style = elem.style; name = jQuery.cssProps[ origName ] || - ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); + ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); // Gets hook for the prefixed version, then unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; @@ -261,7 +260,7 @@ jQuery.extend({ // Make sure that we're working with the right name name = jQuery.cssProps[ origName ] || - ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); + ( jQuery.cssProps[ origName ] = vendorPropName( origName ) || origName ); // Try prefixed name followed by the unprefixed name hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; diff --git a/test/unit/css.js b/test/unit/css.js index 4d0e11b3b8..22a3c76365 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1116,4 +1116,84 @@ test( "Do not throw on frame elements from css method (#15098)", 1, function() { ok( false, "It did throw" ); } }); + +( function() { + var vendorPrefixes = [ "Webkit", "Moz", "ms" ]; + + function resetCssPropsFor( name ) { + delete jQuery.cssProps[ name ]; + jQuery.each( vendorPrefixes, function( index, prefix ) { + delete jQuery.cssProps[ prefix + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; + } ); + } + + test( "Don't default to a cached previously used wrong prefixed name (gh-2015)", function() { + // Note: this test needs a property we know is only supported in a prefixed version + // by at least one of our main supported browsers. This may get out of date so let's + // use -(webkit|moz)-appearance as well as those two are not on a standards track. + var appearanceName, transformName, elem, elemStyle, + transformVal = "translate(5px, 2px)", + emptyStyle = document.createElement( "div" ).style; + + if ( "appearance" in emptyStyle ) { + appearanceName = "appearance"; + } else { + jQuery.each( vendorPrefixes, function( index, prefix ) { + var prefixedProp = prefix + "Appearance"; + if ( prefixedProp in emptyStyle ) { + appearanceName = prefixedProp; + } + } ); + } + + if ( "transform" in emptyStyle ) { + transformName = "transform"; + } else { + jQuery.each( vendorPrefixes, function( index, prefix ) { + var prefixedProp = prefix + "Transform"; + if ( prefixedProp in emptyStyle ) { + transformName = prefixedProp; + } + } ); + } + + expect( !!appearanceName + !!transformName + 1 ); + + resetCssPropsFor( "appearance" ); + resetCssPropsFor( "transform" ); + + elem = jQuery( "
        " ) + .css( { + msAppearance: "none", + appearance: "none", + + // Only the ms prefix is used to make sure we haven't e.g. set + // webkitTransform ourselves in the test. + msTransform: transformVal, + transform: transformVal + } ); + elemStyle = elem[ 0 ].style; + + if ( appearanceName ) { + equal( elemStyle[ appearanceName ], "none", "setting properly-prefixed appearance" ); + } + if ( transformName ) { + equal( elemStyle[ transformName ], transformVal, "setting properly-prefixed transform" ); + } + equal( elemStyle.undefined, undefined, "Nothing writes to node.style.undefined" ); + } ); + + test( "Don't detect fake set properties on a node when caching the prefixed version", function() { + expect( 1 ); + + var elem = jQuery( "
        " ), + style = elem[ 0 ].style; + style.MozFakeProperty = "old value"; + elem.css( "fakeProperty", "new value" ); + + equal( style.MozFakeProperty, "old value", "Fake prefixed property is not cached" ); + } ); + +} )(); + } From 38a669735d08bcbd28cfb0d77eee82c67aa89eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Sat, 30 May 2015 19:09:32 +0200 Subject: [PATCH 0318/1272] Ajax: Remove remnants of the load event alias handling Refs 0705be475092aede1eddae01319ec931fb9c65fc Refs gh-2287 Closes gh-2362 --- src/ajax/load.js | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/ajax/load.js b/src/ajax/load.js index 00a9f46f66..8326e92875 100644 --- a/src/ajax/load.js +++ b/src/ajax/load.js @@ -4,22 +4,13 @@ define([ "../ajax", "../traversing", "../manipulation", - "../selector", - // Optional event/alias dependency - "../event/alias" + "../selector" ], 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 8e92e1ea3c533f3be82c99bbafaaf74b5bdedecc Mon Sep 17 00:00:00 2001 From: Gilad Peleg Date: Tue, 19 May 2015 14:05:21 +0300 Subject: [PATCH 0319/1272] Build: Update the license attribute Specifying the type and URL is deprecated: https://docs.npmjs.com/files/package.json#license http://npm1k.org/ Fixes gh-2331 Closes gh-2330 --- package.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/package.json b/package.json index cbda85661b..5c2ea7a735 100644 --- a/package.json +++ b/package.json @@ -22,12 +22,7 @@ "bugs": { "url": "https://github.com/jquery/jquery/issues" }, - "licenses": [ - { - "type": "MIT", - "url": "https://github.com/jquery/jquery/blob/master/LICENSE.txt" - } - ], + "license": "MIT", "dependencies": {}, "devDependencies": { "commitplease": "2.0.0", From 0019a463bdcb81dc6ba3434505a45774ca27f363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 1 Jun 2015 19:55:18 +0200 Subject: [PATCH 0320/1272] CSS: Don't name the anonymous swap function IE8 doesn't like named anonymous expressions. Not naming the function expression reduces the gzipped size by 5 bytes. In ECMAScript 2015 the function will get the name inferred from the variable name (here: swap) anyway. (cherry-picked from e847574fc755b5339f3de41bcebd5b2a3e140cfe) Refs 02a9d9f94b623ea8664b7b39fd57feb7de6c6a14 --- src/css/var/swap.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/var/swap.js b/src/css/var/swap.js index 61351f14b3..dbf6397291 100644 --- a/src/css/var/swap.js +++ b/src/css/var/swap.js @@ -1,7 +1,7 @@ define(function() { // A method for quickly swapping in/out CSS properties to get correct calculations. -return function swap( elem, options, callback, args ) { +return function( elem, options, callback, args ) { var ret, name, old = {}; From 3655c4e1908cc3ee49487e7e26e8cfca9fe8146d Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 29 May 2015 00:51:22 +0300 Subject: [PATCH 0321/1272] Event: remove preDispatch hook & simplify "simulate" signature Closes gh-2358 --- src/event.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/event.js b/src/event.js index 8722268a80..1e954513ab 100644 --- a/src/event.js +++ b/src/event.js @@ -602,7 +602,7 @@ jQuery.event = { }, // Piggyback on a donor event to simulate a different one - simulate: function( type, elem, event, bubble ) { + simulate: function( type, elem, event ) { var e = jQuery.extend( new jQuery.Event(), event, @@ -624,11 +624,8 @@ jQuery.event = { } ); - if ( bubble ) { - jQuery.event.trigger( e, null, elem ); - } else { - jQuery.event.dispatch.call( elem, e ); - } + jQuery.event.trigger( e, null, elem ); + if ( e.isDefaultPrevented() ) { event.preventDefault(); } @@ -771,7 +768,7 @@ if ( !support.focusin ) { // Attach a single capturing handler on the document while someone wants focusin/focusout var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); }; jQuery.event.special[ fix ] = { From 285cfbfccc4c61d50ee8e0fe6e23695dc663e166 Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Thu, 11 Jun 2015 16:25:36 +0300 Subject: [PATCH 0322/1272] Build: remove bower.json lint target Ref 26eca143c2dd857b9e3d1c446a467fed16e903d2 --- Gruntfile.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index b5482829b4..d22807bf48 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -71,10 +71,6 @@ module.exports = function( grunt ) { jsonlint: { pkg: { src: [ "package.json" ] - }, - - bower: { - src: [ "bower.json" ] } }, jshint: { From 1556c4661af647e355a9a5c0a814012955e231bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 1 Jun 2015 23:25:38 +0200 Subject: [PATCH 0323/1272] Build: Update grunt-contrib-jshint --- package.json | 2 +- test/.jshintrc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c2ea7a735..c0ee702811 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "grunt": "0.4.5", "grunt-cli": "0.1.13", "grunt-compare-size": "0.4.0", - "grunt-contrib-jshint": "0.10.0", + "grunt-contrib-jshint": "0.11.2", "grunt-contrib-uglify": "0.7.0", "grunt-contrib-watch": "0.6.1", "grunt-git-authors": "2.0.1", diff --git a/test/.jshintrc b/test/.jshintrc index 7d24cba5de..b55594f4f8 100644 --- a/test/.jshintrc +++ b/test/.jshintrc @@ -21,6 +21,7 @@ "require": false, "define": false, "DOMParser": false, + "Promise": false, "QUnit": false, "ok": false, "equal": false, From 9c8a3ecdc46156afd8f93aa44b6e6aea7c52c049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 1 Jun 2015 23:25:38 +0200 Subject: [PATCH 0324/1272] Build: Refactor Node smoke tests Utilize the assert module, avoid inline JSHint comments. --- build/tasks/node_smoke_tests.js | 3 ++- test/node_smoke_tests/.jshintrc | 14 +++++++++++++ test/node_smoke_tests/document_missing.js | 20 ++++++------------- test/node_smoke_tests/document_passed.js | 9 +++------ .../document_present_originally.js | 9 +++------ .../lib/ensure_global_not_created.js | 10 ++++------ test/node_smoke_tests/lib/ensure_jquery.js | 10 ++++------ 7 files changed, 36 insertions(+), 39 deletions(-) create mode 100644 test/node_smoke_tests/.jshintrc diff --git a/build/tasks/node_smoke_tests.js b/build/tasks/node_smoke_tests.js index 077745b83f..5c23dae2ba 100644 --- a/build/tasks/node_smoke_tests.js +++ b/build/tasks/node_smoke_tests.js @@ -15,7 +15,8 @@ module.exports = function( grunt ) { fs.readdirSync( testsDir ) .filter( function( testFilePath ) { - return fs.statSync( testsDir + testFilePath ).isFile(); + return fs.statSync( testsDir + testFilePath ).isFile() && + /\.js$/.test( testFilePath ); } ) .forEach( function( testFilePath ) { var taskName = "node_" + testFilePath.replace( /\.js$/, "" ); diff --git a/test/node_smoke_tests/.jshintrc b/test/node_smoke_tests/.jshintrc new file mode 100644 index 0000000000..1445c7b18b --- /dev/null +++ b/test/node_smoke_tests/.jshintrc @@ -0,0 +1,14 @@ +{ + "boss": true, + "curly": true, + "eqeqeq": true, + "eqnull": true, + "expr": true, + "immed": true, + "noarg": true, + "quotmark": "double", + "undef": true, + "unused": true, + + "node": true +} diff --git a/test/node_smoke_tests/document_missing.js b/test/node_smoke_tests/document_missing.js index 0a0bda3503..4a0ad2e2bd 100644 --- a/test/node_smoke_tests/document_missing.js +++ b/test/node_smoke_tests/document_missing.js @@ -1,19 +1,11 @@ -/* jshint node: true */ - "use strict"; -var ensureGlobalNotCreated = require( "./lib/ensure_global_not_created" ), +var assert = require( "assert" ), + ensureGlobalNotCreated = require( "./lib/ensure_global_not_created" ), jQueryFactory = require( "../../dist/jquery.js" ); -try { +assert.throws( function () { jQueryFactory( {} ); - console.error( "The jQuery factory should reject window without a document" ); - process.exit( 1 ); -} catch ( e ) { - if ( e.message === "jQuery requires a window with a document" ) { - ensureGlobalNotCreated( module.exports ); - process.exit( 0 ); - } - console.error( "An unexpected error thrown; message: ", e.message ); - process.exit( 1 ); -} +}, /jQuery requires a window with a document/ ); + +ensureGlobalNotCreated( module.exports ); diff --git a/test/node_smoke_tests/document_passed.js b/test/node_smoke_tests/document_passed.js index 5bbddb7185..5999cc7441 100644 --- a/test/node_smoke_tests/document_passed.js +++ b/test/node_smoke_tests/document_passed.js @@ -1,12 +1,9 @@ -/* jshint node: true */ - "use strict"; +var assert = require( "assert" ); + require( "jsdom" ).env( "", function( errors, window ) { - if ( errors ) { - console.error( errors ); - process.exit( 1 ); - } + assert.ifError( errors ); var ensureJQuery = require( "./lib/ensure_jquery" ), ensureGlobalNotCreated = require( "./lib/ensure_global_not_created" ), diff --git a/test/node_smoke_tests/document_present_originally.js b/test/node_smoke_tests/document_present_originally.js index 76fa88e861..f751487080 100644 --- a/test/node_smoke_tests/document_present_originally.js +++ b/test/node_smoke_tests/document_present_originally.js @@ -1,12 +1,9 @@ -/* jshint node: true */ - "use strict"; +var assert = require( "assert" ); + require( "jsdom" ).env( "", function( errors, window ) { - if ( errors ) { - console.error( errors ); - process.exit( 1 ); - } + assert.ifError( errors ); // Pretend the window is a global. global.window = window; diff --git a/test/node_smoke_tests/lib/ensure_global_not_created.js b/test/node_smoke_tests/lib/ensure_global_not_created.js index e2ce98309c..7cc83b5411 100644 --- a/test/node_smoke_tests/lib/ensure_global_not_created.js +++ b/test/node_smoke_tests/lib/ensure_global_not_created.js @@ -1,7 +1,7 @@ -/* jshint node: true */ - "use strict"; +var assert = require( "assert" ); + // Ensure the jQuery property on global/window/module.exports/etc. was not // created in a CommonJS environment. // `global` is always checked in addition to passed parameters. @@ -9,9 +9,7 @@ module.exports = function ensureGlobalNotCreated() { var args = [].slice.call( arguments ).concat( global ); args.forEach( function( object ) { - if ( object.jQuery ) { - console.error( "A jQuery global was created in a CommonJS environment." ); - process.exit( 1 ); - } + assert.strictEqual( object.jQuery, undefined, + "A jQuery global was created in a CommonJS environment." ); } ); }; diff --git a/test/node_smoke_tests/lib/ensure_jquery.js b/test/node_smoke_tests/lib/ensure_jquery.js index f121f6652f..0933a1d338 100644 --- a/test/node_smoke_tests/lib/ensure_jquery.js +++ b/test/node_smoke_tests/lib/ensure_jquery.js @@ -1,11 +1,9 @@ -/* jshint node: true */ - "use strict"; +var assert = require( "assert" ); + // Check if the object we got is the jQuery object by invoking a basic API. module.exports = function ensureJQuery( jQuery ) { - if ( !/^jQuery/.test( jQuery.expando ) ) { - console.error( "jQuery.expando was not detected, the jQuery bootstrap process has failed" ); - process.exit( 1 ); - } + assert( /^jQuery/.test( jQuery.expando ), + "jQuery.expando was not detected, the jQuery bootstrap process has failed" ); }; From bb026fc12c3c2ad37f47f0919e484bddcdc3d291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 1 Jun 2015 23:25:38 +0200 Subject: [PATCH 0325/1272] Core: Make jQuery objects iterable Make iterating over jQuery objects possible using ES 2015 for-of: for ( node of $( "
        " ) ) { console.log( node.id ); // "narwhal" } Fixes gh-1693 --- .gitignore | 2 ++ .jscsrc | 3 ++- .jshintignore | 1 + Gruntfile.js | 12 +++++++++ build/tasks/node_smoke_tests.js | 2 +- package.json | 2 ++ src/core.js | 10 ++++++++ test/.jshintrc | 1 + .../iterable_with_native_symbol.js | 8 ++++++ .../iterable_with_symbol_polyfill.js | 13 ++++++++++ .../lib/ensure_iterability_es6.js | 25 +++++++++++++++++++ test/unit/core.js | 20 +++++++++++++++ 12 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 test/node_smoke_tests/iterable_with_native_symbol.js create mode 100644 test/node_smoke_tests/iterable_with_symbol_polyfill.js create mode 100644 test/node_smoke_tests/lib/ensure_iterability_es6.js diff --git a/.gitignore b/.gitignore index 463dea4268..eae5df6e6c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ /dist /node_modules + +/test/node_smoke_tests/lib/ensure_iterability.js diff --git a/.jscsrc b/.jscsrc index fa91a9d9e5..14f3491337 100644 --- a/.jscsrc +++ b/.jscsrc @@ -1,5 +1,6 @@ { "preset": "jquery", - "excludeFiles": [ "external", "src/intro.js", "src/outro.js" ] + "excludeFiles": [ "external", "src/intro.js", "src/outro.js", + "test/node_smoke_tests/lib/ensure_iterability.js" ] } diff --git a/.jshintignore b/.jshintignore index 19f1b9c523..1ddafd635a 100644 --- a/.jshintignore +++ b/.jshintignore @@ -9,3 +9,4 @@ test/data/readywaitasset.js test/data/readywaitloader.js test/data/support/csp.js test/data/support/getComputedSupport.js +test/node_smoke_tests/lib/ensure_iterability.js diff --git a/Gruntfile.js b/Gruntfile.js index d22807bf48..0bf20d4542 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -30,6 +30,18 @@ module.exports = function( grunt ) { cache: "build/.sizecache.json" } }, + babel: { + options: { + sourceMap: "inline", + retainLines: true + }, + nodeSmokeTests: { + files: { + "test/node_smoke_tests/lib/ensure_iterability.js": + "test/node_smoke_tests/lib/ensure_iterability_es6.js" + } + } + }, build: { all: { dest: "dist/jquery.js", diff --git a/build/tasks/node_smoke_tests.js b/build/tasks/node_smoke_tests.js index 5c23dae2ba..9334516d9e 100644 --- a/build/tasks/node_smoke_tests.js +++ b/build/tasks/node_smoke_tests.js @@ -5,7 +5,7 @@ module.exports = function( grunt ) { var fs = require( "fs" ), spawnTest = require( "./lib/spawn_test.js" ), testsDir = "./test/node_smoke_tests/", - nodeSmokeTests = [ "jsdom" ]; + nodeSmokeTests = [ "jsdom", "babel:nodeSmokeTests" ]; // Fire up all tests defined in test/node_smoke_tests/*.js in spawned sub-processes. // All the files under test/node_smoke_tests/*.js are supposed to exit with 0 code diff --git a/package.json b/package.json index c0ee702811..5d82995343 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "dependencies": {}, "devDependencies": { "commitplease": "2.0.0", + "core-js": "0.9.17", "grunt": "0.4.5", + "grunt-babel": "5.0.1", "grunt-cli": "0.1.13", "grunt-compare-size": "0.4.0", "grunt-contrib-jshint": "0.11.2", diff --git a/src/core.js b/src/core.js index 88b9a3c5d8..ba6eeceb8f 100644 --- a/src/core.js +++ b/src/core.js @@ -425,6 +425,16 @@ jQuery.extend({ support: support }); +// JSHint would error on this code due to the Symbol not being defined in ES5. +// Defining this global in .jshintrc would create a danger of using the global +// unguarded in another place, it seems safer to just disable JSHint for these +// three lines. +/* jshint ignore: start */ +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} +/* jshint ignore: end */ + // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { diff --git a/test/.jshintrc b/test/.jshintrc index b55594f4f8..7aef665c68 100644 --- a/test/.jshintrc +++ b/test/.jshintrc @@ -22,6 +22,7 @@ "define": false, "DOMParser": false, "Promise": false, + "Symbol": false, "QUnit": false, "ok": false, "equal": false, diff --git a/test/node_smoke_tests/iterable_with_native_symbol.js b/test/node_smoke_tests/iterable_with_native_symbol.js new file mode 100644 index 0000000000..3376ebdc55 --- /dev/null +++ b/test/node_smoke_tests/iterable_with_native_symbol.js @@ -0,0 +1,8 @@ +"use strict"; + +if ( typeof Symbol === "undefined" ) { + console.log( "Symbols not supported, skipping the test..." ); + process.exit(); +} + +require( "./lib/ensure_iterability_es6" )(); diff --git a/test/node_smoke_tests/iterable_with_symbol_polyfill.js b/test/node_smoke_tests/iterable_with_symbol_polyfill.js new file mode 100644 index 0000000000..dd377f19c2 --- /dev/null +++ b/test/node_smoke_tests/iterable_with_symbol_polyfill.js @@ -0,0 +1,13 @@ +/* jshint esnext: true */ + +"use strict"; + +var assert = require( "assert" ); + +delete global.Symbol; +require( "core-js" ); + +assert.strictEqual( typeof Symbol, "function", "Expected Symbol to be a function" ); +assert.notEqual( typeof Symbol.iterator, "symbol", "Expected Symbol.iterator to be polyfilled" ); + +require( "./lib/ensure_iterability" )(); diff --git a/test/node_smoke_tests/lib/ensure_iterability_es6.js b/test/node_smoke_tests/lib/ensure_iterability_es6.js new file mode 100644 index 0000000000..ebe68539e1 --- /dev/null +++ b/test/node_smoke_tests/lib/ensure_iterability_es6.js @@ -0,0 +1,25 @@ +/* jshint esnext: true */ + +"use strict"; + +var assert = require( "assert" ); + +module.exports = function ensureIterability() { + require( "jsdom" ).env( "", function( errors, window ) { + assert.ifError( errors ); + + var i, + ensureJQuery = require( "./ensure_jquery" ), + jQuery = require( "../../../dist/jquery.js" )( window ), + elem = jQuery( "
        " ), + result = ""; + + ensureJQuery( jQuery ); + + for ( i of elem ) { + result += i.nodeName; + } + + assert.strictEqual( result, "DIVSPANA", "for-of doesn't work on jQuery objects" ); + } ); +}; diff --git a/test/unit/core.js b/test/unit/core.js index 0a018dea4e..d8370637bb 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1538,3 +1538,23 @@ testIframeWithCallback( "Don't call window.onready (#14802)", "core/onready.html equal( error, false, "no call to user-defined onready" ); } ); + +test( "Iterability of jQuery objects (gh-1693)", function() { + /* jshint unused: false */ + expect( 1 ); + + var i, elem, result; + + if ( typeof Symbol === "function" ) { + + elem = jQuery( "
        " ); + result = ""; + + try { + eval( "for ( i of elem ) { result += i.nodeName; }" ); + } catch ( e ) {} + equal( result, "DIVSPANA", "for-of works on jQuery objects" ); + } else { + ok( true, "The browser doesn't support Symbols" ); + } +} ); From 04a29696e5b176ac66401120e433d52425222f0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 1 Jun 2015 21:34:57 +0200 Subject: [PATCH 0326/1272] Event: Remove an internal argument to the on method Refs gh-2301 --- src/event.js | 106 ++++++++++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/src/event.js b/src/event.js index 1e954513ab..04ee403d5d 100644 --- a/src/event.js +++ b/src/event.js @@ -34,6 +34,58 @@ function safeActiveElement() { } catch ( err ) { } } +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + }); +} + /* * Helper functions for managing events -- not part of the public interface. * Props to Dean Edwards' addEvent library for many of the ideas. @@ -799,59 +851,11 @@ if ( !support.focusin ) { jQuery.fn.extend({ - on: function( types, selector, data, fn, /*INTERNAL*/ one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - this.on( type, selector, data, types[ type ], one ); - } - return this; - } - - if ( data == null && fn == null ) { - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return this.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - }); + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); }, one: function( types, selector, data, fn ) { - return this.on( types, selector, data, fn, 1 ); + return on( this, types, selector, data, fn, 1 ); }, off: function( types, selector, fn ) { var handleObj, type; From 349edbd6c53aa93d4fd207d3c0c4c24a7b0314dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 1 Jun 2015 21:35:13 +0200 Subject: [PATCH 0327/1272] Manipulation: Remove an internal argument to the remove method Fixes gh-2301 Closes gh-2366 --- src/manipulation.js | 54 ++++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/manipulation.js b/src/manipulation.js index 6424d8394c..4bac1417fa 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -196,6 +196,27 @@ function domManip( collection, args, callback, ignored ) { return collection; } +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; (node = nodes[i]) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + jQuery.extend({ htmlPrefilter: function( html ) { return html.replace( rxhtmlTag, "<$1>" ); @@ -268,6 +289,14 @@ jQuery.extend({ }); jQuery.fn.extend({ + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + text: function( value ) { return access( this, function( value ) { return value === undefined ? @@ -314,27 +343,6 @@ jQuery.fn.extend({ }); }, - remove: function( selector, keepData /* Internal Use Only */ ) { - var elem, - elems = selector ? jQuery.filter( selector, this ) : this, - i = 0; - - for ( ; (elem = elems[i]) != null; i++ ) { - if ( !keepData && elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem ) ); - } - - if ( elem.parentNode ) { - if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { - setGlobalEval( getAll( elem, "script" ) ); - } - elem.parentNode.removeChild( elem ); - } - } - - return this; - }, - empty: function() { var elem, i = 0; @@ -417,10 +425,6 @@ jQuery.fn.extend({ // Force callback invocation }, ignored ); - }, - - detach: function( selector ) { - return this.remove( selector, true ); } }); From c17543fd3c14ff86c448dbb90f9fe1223661a73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Sun, 14 Jun 2015 00:37:31 +0200 Subject: [PATCH 0328/1272] Tests: Correct a typo in the regex matching Safari 8 --- 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 bf3e114d83..5a96d28a11 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -107,7 +107,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec "radioValue": false, "reliableMarginRight": true }; - } else if ( /8.0(\.\d+|) safari/i.test( userAgent ) ) { + } else if ( /8\.0(\.\d+|) safari/i.test( userAgent ) ) { expected = { "ajax": true, "boxSizingReliable": true, From 8e111df641cca3e1b75b31a1971bfc89014b4ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Sun, 14 Jun 2015 00:50:05 +0200 Subject: [PATCH 0329/1272] Tests: Add Microsoft Edge results (from Windows 10 build 10130) The Microsoft Edge user agent contains "Chrome" so it needs to be checked before Chrome. --- test/unit/support.js | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/test/unit/support.js b/test/unit/support.js index 5a96d28a11..d1e0d189af 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -51,15 +51,13 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec var expected, userAgent = window.navigator.userAgent; - if ( /chrome/i.test( userAgent ) ) { - // Catches Chrome on Android as well (i.e. the default - // Android browser on Android >= 4.4). + if ( /edge\/12/i.test( userAgent ) ) { expected = { "ajax": true, "boxSizingReliable": true, "checkClone": true, "checkOn": true, - "clearCloneStyle": true, + "clearCloneStyle": false, "cors": true, "createHTMLDocument": true, "focusin": false, @@ -107,6 +105,26 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec "radioValue": false, "reliableMarginRight": true }; + } else if ( /chrome/i.test( userAgent ) ) { + // Catches Chrome on Android as well (i.e. the default + // Android browser on Android >= 4.4). + 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": true, + "radioValue": true, + "reliableMarginRight": true + }; } else if ( /8\.0(\.\d+|) safari/i.test( userAgent ) ) { expected = { "ajax": true, From 5a1217e40193c8884155ccaf415091d326ddb52a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Tue, 16 Jun 2015 14:44:24 +0200 Subject: [PATCH 0330/1272] Tests: Remove Edge version from the user agent The version will change in the future, matching by /edge\//i is enough Refs 8e111df641cca3e1b75b31a1971bfc89014b4ded --- 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 d1e0d189af..46f904efad 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -51,7 +51,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec var expected, userAgent = window.navigator.userAgent; - if ( /edge\/12/i.test( userAgent ) ) { + if ( /edge\//i.test( userAgent ) ) { expected = { "ajax": true, "boxSizingReliable": true, From e831856490d2212bdbaff4cd76137b93ccf26d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Tue, 16 Jun 2015 16:25:16 +0200 Subject: [PATCH 0331/1272] Tests: Remove test/data/ua.txt The file was used by $.browser tests but $.browser now doesn't exists in Core and this file hasn't been updated for a few years. Fixes gh-2398 --- test/data/ua.txt | 272 ----------------------------------------------- 1 file changed, 272 deletions(-) delete mode 100644 test/data/ua.txt diff --git a/test/data/ua.txt b/test/data/ua.txt deleted file mode 100644 index 95e522e258..0000000000 --- a/test/data/ua.txt +++ /dev/null @@ -1,272 +0,0 @@ -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows 98; Win 9x 4.90; http://www.Abolimba.de) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; JyxoToolbar1.0; http://www.Abolimba.de; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322) - 0 Mozilla/5.0 (compatible; ABrowse 0.4; Syllable) -webkit 420 Mozilla/5.0 (compatible; U; ABrowse 0.6; Syllable) AppleWebKit/420+ (KHTML, like Gecko) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Acoo Browser; InfoPath.2; .NET CLR 2.0.50727; Alexa Toolbar) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Acoo Browser; .NET CLR 1.1.4322; .NET CLR 2.0.50727) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Acoo Browser; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506) - 0 amaya/9.52 libwww/5.4.0 - 0 amaya/11.1 libwww/5.4.0 - 0 Amiga-AWeb/3.5.07 beta - 0 AmigaVoyager/3.4.4 (MorphOS/PPC native) - 0 AmigaVoyager/2.95 (compatible; MC680x0; AmigaOS) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; AOL 7.0; Windows NT 5.1; FunWebProducts) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; AOL 8.0; Windows NT 5.1; SV1) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.0; Windows NT 5.1; .NET CLR 1.1.4322; Zango 10.1.181.0) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; AOL 6.0; Windows NT 5.1) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; AOL 9.5; AOLBuild 4337.35; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) -webkit 523.15 Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30) -webkit 527 Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6 -webkit 523.15 Mozilla/5.0 (X11; U; Linux; C -) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.5 -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Avant Browser; Avant Browser; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1) - 0 Avant Browser (http://www.avantbrowser.com) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; JyxoToolbar1.0; Embedded Web Browser from: http://bsalsa.com/; Avant Browser; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB5; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; Avant Browser) -mozilla 0 Mozilla/5.0 (Windows; U; Win9x; en; Stable) Gecko/20020911 Beonex/0.8.1-stable -mozilla 0 Mozilla/5.0 (Windows; U; WinNT; en; Preview) Gecko/20020603 Beonex/0.8-stable -mozilla 1.0.2 Mozilla/5.0 (Windows; U; WinNT; en; rv:1.0.2) Gecko/20030311 Beonex/0.8.2-stable -mozilla 1.9 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9) Gecko/2008120120 Blackbird/0.9991 -webkit 527 Mozilla/5.0 (X11; 78; CentOS; US-en) AppleWebKit/527+ (KHTML, like Gecko) Bolt/0.862 Version/3.0 Safari/523.15 -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Browzar) - 0 Bunjalloo/0.7.4(Nintendo DS;U;en) - 0 Bunjalloo/0.7.6(Nintendo DS;U;en) -mozilla 1.8.1.4pre Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en; rv:1.8.1.4pre) Gecko/20070511 Camino/1.6pre -mozilla 1.7.2 Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.7.2) Gecko/20040825 Camino/0.8.1 -mozilla 1.8.1.12 Mozilla/5.0 (Macintosh; U; Intel Mac OS X Mach-O; en; rv:1.8.1.12) Gecko/20080206 Camino/1.5.5 -mozilla 1.0.1 Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.0.1) Gecko/20030111 Chimera/0.6 -mozilla 1.8.0.10 Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.10) Gecko/20070228 Camino/1.0.4 -webkit 418.9 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/418.9 (KHTML, like Gecko, Safari) Safari/419.3 Cheshire/1.0.ALPHA -webkit 419 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/419 (KHTML, like Gecko, Safari/419.3) Cheshire/1.0.ALPHA -chrome 1.0.154.36 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.36 Safari/525.19 -chrome 1.0.154.53 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/1.0.154.53 Safari/525.19 -mozilla 1.9.0.10 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.10) Gecko/2009042815 Firefox/3.0.10 CometBird/3.0.10 -mozilla 1.9.0.5 Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.5) Gecko/2009011615 Firefox/3.0.5 CometBird/3.0.5 -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; Crazy Browser 3.0.0 Beta2) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; Crazy Browser 2.0.1) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Crazy Browser 1.0.5; .NET CLR 1.1.4322; InfoPath.1) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Deepnet Explorer 1.5.0; .NET CLR 1.0.3705) -webkit 525.27.1 Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Demeter/1.0.9 Safari/125 -webkit 312.8 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; pl-pl) AppleWebKit/312.8 (KHTML, like Gecko, Safari) DeskBrowse/1.0 - 0 Dillo/0.8.5 - 0 Dillo/2.0 - 0 DocZilla/1.0 (Windows; U; WinNT4.0; en-US; rv:1.0.0) Gecko/20020804 - 0 DocZilla/2.7 (Windows; U; Windows NT 5.1; en-US; rv:2.7.0) Gecko/20050706 CiTEC Information -webkit 527 Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Dooble - 0 Doris/1.15 [en] (Symbian) - 0 edbrowse/1.5.17-2 - 0 edbrowse/2.2.10 - 0 edbrowse/3.1.2-1 - 0 ELinks/0.13.GIT (textmode; Linux 2.6.22-2-686 i686; 148x68-3) - 0 ELinks/0.9.3 (textmode; Linux 2.6.11 i686; 79x24) - 0 Enigma Browser -mozilla 1.8.1.12 Mozilla/5.0 (X11; U; Linux i686; en; rv:1.8.1.12) Gecko/20080208 (Debian-1.8.1.12-2) Epiphany/2.20 -mozilla 1.9.0.12 Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9.0.12) Gecko/20080528 Fedora/2.24.3-8.fc10 Epiphany/2.22 Firefox/3.0 -mozilla 1.7.3 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.3) Gecko/20041007 Epiphany/1.4.7 -mozilla 1.5 Mozilla/5.0 (Windows; U; Win98; en-US; rv:1.5) Gecko/20031007 Firebird/0.7 -mozilla 1.5 Mozilla/5.0 (Windows; U; Win95; en-US; rv:1.5) Gecko/20031007 Firebird/0.7 -mozilla 1.8.0.3 Mozilla/5.0 (Windows; U; Windows NT 5.0; es-ES; rv:1.8.0.3) Gecko/20060426 Firefox/1.5.0.3 -mozilla 1.9.1b2 Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ko; rv:1.9.1b2) Gecko/20081201 Firefox/3.1b2 -mozilla 1.9.0.8 Mozilla/5.0 (Windows; U; Windows NT 5.1; cs; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8 -mozilla 1.7.9 Mozilla/5.0 (Windows; U; WinNT4.0; en-US; rv:1.7.9) Gecko/20050711 Firefox/1.0.5 -mozilla 1.9b5 Mozilla/5.0 (X11; U; SunOS sun4u; en-US; rv:1.9b5) Gecko/2008032620 Firefox/3.0b5 -mozilla 1.8.0.5 Mozilla/5.0 (X11; U; OpenBSD i386; en-US; rv:1.8.0.5) Gecko/20060819 Firefox/1.5.0.5 -mozilla 1.9.1b3 Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3) Gecko/20090305 Firefox/3.1b3 GTB5 -mozilla 1.8.1.12 Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.12) Gecko/20080214 Firefox/2.0.0.12 -mozilla 1.8.1.9 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071113 BonEcho/2.0.0.9 -mozilla 1.8.1 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1) Gecko/20061026 BonEcho/2.0 -mozilla 1.8.1.21pre Mozilla/5.0 (BeOS; U; Haiku BePC; en-US; rv:1.8.1.21pre) Gecko/20090227 BonEcho/2.0.0.21pre -mozilla 1.9.0.8 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko/2009033017 GranParadiso/3.0.8 -mozilla 1.9.2a2pre Mozilla/5.0 (Windows; U; Windows NT 6.1; cs; rv:1.9.2a2pre) Gecko/20090912 Namoroka/3.6a2pre (.NET CLR 3.5.30729) -mozilla 1.9.2a2pre Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2a2pre) Gecko/20090901 Ubuntu/9.10 (karmic) Namoroka/3.6a2pre -mozilla 1.9.2a1 Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2a1) Gecko/20090806 Namoroka/3.6a1 -mozilla 1.9.1b3pre Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1b3pre) Gecko/20090109 Shiretoko/3.1b3pre -mozilla 1.9.1b4pre Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1b4pre) Gecko/20090311 Shiretoko/3.1b4pre -mozilla 1.8.0.1 Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.0.1) Gecko/20060314 Flock/0.5.13.2 -mozilla 1.9.0.2 Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.2) Gecko/2008092122 Firefox/3.0.2 Flock/2.0b3 -webkit 525.13 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.13 (KHTML, like Gecko) Fluid/0.9.4 Safari/525.13 -mozilla 1.7.12 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.12) Gecko/20050929 Galeon/1.3.21 -mozilla 1.9.0.8 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko/20090327 Galeon/2.0.7 -mozilla 1.9.1.5 Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091105 Firefox/3.5.5 compat GlobalMojo/1.5.5 GlobalMojoExt/1.5 -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; GreenBrowser) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; GreenBrowser) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; GreenBrowser) - 0 HotJava/1.1.2 FCS -mozilla 0 Mozilla/3.0 (x86 [cs] Windows NT 5.1; Sun) -mozilla 1.8.0.3 Mozilla/5.1 (X11; U; Linux i686; en-US; rv:1.8.0.3) Gecko/20060425 SUSE/1.5.0.3-7 Hv3/alpha -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SIMBAR={CFBFDAEA-F21E-4D6E-A9B0-E100A69B860F}; Hydra Browser; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Hydra Browser; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) - 0 IBrowse/2.3 (AmigaOS 3.9) - 0 Mozilla/5.0 (compatible; IBrowse 3.0; AmigaOS4.0) - 0 iCab/4.0 (Macintosh; U; Intel Mac OS X) - 0 Mozilla/4.5 (compatible; iCab 2.9.1; Macintosh; U; PPC) - 0 iCab/3.0.2 (Macintosh; U; PPC Mac OS X) - 0 ICE Browser/v5_4_3 (Java 1.4.2; Windows XP 5.1 x86) -mozilla 0 Mozilla/5.0 (Java 1.6.0_01; Windows XP 5.1 x86; en) ICEbrowser/v6_1_2 - 0 ICE Browser/5.05 (Java 1.4.0; Windows 2000 5.0 x86) -mozilla 1.8.1.9 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.9) Gecko/20071030 Iceape/1.1.6 (Debian-1.1.6-3) -mozilla 1.8.1.8 Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.8) Gecko/20071008 Iceape/1.1.5 (Ubuntu-1.1.5-1ubuntu0.7.10) -mozilla 1.9.0.3 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.3) Gecko/2008092921 IceCat/3.0.3-g1 -mozilla 1.8.1.11 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.11) Gecko/20071203 IceCat/2.0.0.11-g1 -mozilla 1.9.0.5 Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.0.5) Gecko/2008122011 Iceweasel/3.0.5 (Debian-3.0.5-1) -mozilla 1.8.1.1 Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1.1) Gecko/20061205 Iceweasel/2.0.0.1 (Debian-2.0.0.1+dfsg-4) -mozilla 1.9.0.5 Mozilla/5.0 (X11; U; Linux i686; it; rv:1.9.0.5) Gecko/2008122011 Iceweasel/3.0.5 (Debian-3.0.5-1) -msie 4.0 Mozilla/2.0 (compatible; MSIE 4.0; Windows 98) -msie 6.0 Mozilla/4.0 (Windows; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727) -msie 7.0 Mozilla/4.0 (Mozilla/4.0; MSIE 7.0; Windows NT 5.1; FDM; SV1; .NET CLR 3.0.04506.30) -msie 5.01 Mozilla/4.0 (compatible; MSIE 5.01; Windows NT) -msie 8.0 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; InfoPath.2; .NET CLR 3.5.21022; .NET CLR 3.5.30729; MS-RTC LM 8; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; .NET CLR 3.0.30729) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0; .NET CLR 2.0.50727) -msie 5.0b1 Mozilla/4.0 (compatible; MSIE 5.0b1; Mac_PowerPC) -msie 5.0 Mozilla/4.0 (compatible; MSIE 5.0; Windows NT;) -msie 5.23 Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; GTB6; Ant.com Toolbar 1.6; MSIECrawler) -msie 8.0 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; GTB5; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; InfoPath.2; OfficeLiveConnector.1.3; OfficeLivePatch.0.0) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; InfoPath.2; .NET CLR 3.5.21022; .NET CLR 3.5.30729; MS-RTC LM 8; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; .NET CLR 3.0.30729) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; InfoPath.2) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; iRider 2.21.1108; FDM) -webkit 528.5 Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.5 (KHTML, like Gecko) Iron/0.4.155.0 Safari/528.5 -webkit 528.7 Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/528.7 (KHTML, like Gecko) Iron/1.0.155.0 Safari/528.7 -webkit 525.19 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Iron/0.2.152.0 Safari/12081672.525 -webkit 531.0 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/531.0 (KHTML, like Gecko) Iron/3.0.189.0 Safari/531.0 -mozilla 1.8.1.19 Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.8.1.19) Gecko/20081217 K-Meleon/1.5.2 -mozilla 1.8.1.21 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 -mozilla 1.8.0.5 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.5) Gecko/20060706 K-Meleon/1.0 -mozilla 1.8.1.21 Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.8.1.21) Gecko/20090331 K-Meleon/1.5.3 -mozilla 1.8.0.6 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.6) Gecko/20060731 K-Ninja/2.0.2 -mozilla 1.8.1.4pre Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.4pre) Gecko/20070404 K-Ninja/2.1.3 -mozilla 1.8.1.2pre Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1 -mozilla 1.9 Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0 -mozilla 0 Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5 -mozilla 1.9.0.8 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.8) Gecko Fedora/1.9.0.8-1.fc10 Kazehakase/0.5.6 -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KKman2.0) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; KKMAN3.2) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; KKman3.0) - 0 Mozilla/5.0 (compatible; Konqueror/3.1-rc5; i686 Linux; 20020712) - 0 Mozilla/5.0 (compatible; Konqueror/4.3; Windows) KHTML/4.3.0 (like Gecko) - 0 Mozilla/5.0 (compatible; Konqueror/2.2.1; Linux) - 0 Mozilla/5.0 (compatible; Konqueror/3.5; SunOS) - 0 Mozilla/5.0 (compatible; Konqueror/4.1; OpenBSD) KHTML/4.1.4 (like Gecko) - 0 Links (0.96; Linux 2.4.20-18.7 i586) - 0 Links (0.98; Win32; 80x25) - 0 Links (2.1pre18; Linux 2.4.31 i686; 100x37) - 0 Links (2.1; Linux 2.6.18-gentoo-r6 x86_64; 80x24) - 0 Links (2.2; Linux 2.6.25-gentoo-r9 sparc64; 166x52) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Linux 2.6.26-1-amd64) Lobo/0.98.3 -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows XP 5.1) Lobo/0.98.4 - 0 Mozilla/4.0 (compatible; Lotus-Notes/5.0; Windows-NT) - 0 Mozilla/4.0 (compatible; Lotus-Notes/6.0; Windows-NT) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; Lunascape 2.1.3) -mozilla 1.9.1b3pre Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1b3pre) Gecko/2008 Lunascape/4.9.9.98 -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; JyxoToolbar1.0; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; Lunascape 5.1.4.5) -webkit 528 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/528+ (KHTML, like Gecko, Safari/528.0) Lunascape/5.0.2.0 -mozilla 1.9.1.2 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.2) Gecko/20090804 Firefox/3.5.2 Lunascape/5.1.4.5 - 0 Lynx/2.8.6rel.4 libwww-FM/2.14 SSL-MM/1.4.1 GNUTLS/1.6.3 - 0 Lynx/2.8.3dev.6 libwww-FM/2.14 - 0 Lynx/2.8.5dev.16 libwww-FM/2.14 SSL-MM/1.4.1 OpenSSL/0.9.7a -mozilla 1.7.12 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20051001 Firefox/1.0.7 Madfox/0.3.2u3 -webkit 530.6 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.6 (KHTML, like Gecko) Maxthon/3.0 Safari/530.6 -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; SV1; Maxthon; .NET CLR 1.1.4322) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2) -msie 8.0 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727; MAXTHON 2.0) - 0 Midori/0.1.7 -webkit 532 Midori/0.1.5 (X11; Linux; U; en-gb) WebKit/532+ -mozilla 1.0.1 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.0.1) Gecko/20020919 -mozilla 1.7.12 Mozilla/5.0 (Windows; U; Windows NT 5.0; it-IT; rv:1.7.12) Gecko/20050915 -mozilla 1.4 Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4; MultiZilla v1.5.0.0f) Gecko/20030624 -mozilla 1.2.1 Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.2.1; MultiZilla v1.1.32 final) Gecko/20021130 - 0 NCSA_Mosaic/2.0 (Windows 3.1) - 0 NCSA_Mosaic/3.0 (Windows 95) - 0 NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m) - 0 NCSA_Mosaic/2.6 (X11; SunOS 4.1.3 sun4m) - 0 Mozilla/3.01 (compatible; Netbox/3.5 R92; Linux 2.2) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NetCaptor 7.5.4; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) -msie 5.01 Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; NetCaptor 6.5.0RC1) -mozilla 1.7.5 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20060127 Netscape/8.1 -mozilla 0 Mozilla/4.04 [en] (X11; I; IRIX 5.3 IP22) -mozilla 0.9.2 Mozilla/5.0 (Windows; U; Win 9x 4.90; de-DE; rv:0.9.2) Gecko/20010726 Netscape6/6.1 -mozilla 1.8.1.12 Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.12) Gecko/20080219 Firefox/2.0.0.12 Navigator/9.0.0.6 -mozilla 0 Mozilla/4.08 [en] (WinNT; U ;Nav) -mozilla 1.0.2 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.0.2) Gecko/20030208 Netscape/7.02 -mozilla 0 Mozilla/3.0 (Win95; I) -mozilla 0 Mozilla/4.51 [en] (Win98; U) - 0 NetSurf/2.0 (RISC OS; armv3l) - 0 NetSurf/1.2 (Linux; i686) - 0 Mozilla/4.7 (compatible; OffByOne; Windows 2000) - 0 Mozilla/4.7 (compatible; OffByOne; Windows 98) - 0 Mozilla/4.5 (compatible; OmniWeb/4.1.1-v424.6; Mac_PowerPC) - 0 OmniWeb/2.7-beta-3 OWF/1.0 -webkit 420 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-US) AppleWebKit/420+ (KHTML, like Gecko, Safari) OmniWeb/v595 -opera 6.0 Opera/6.0 (Windows 2000; U) [fr] -opera 7.10 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Opera 7.10 [en] -opera 10.00 Opera/9.80 (Windows NT 5.1; U; cs) Presto/2.2.15 Version/10.00 -opera 5.11 Opera/5.11 (Windows 98; U) [en] -opera 9.51 Opera/9.51 (Macintosh; Intel Mac OS X; U; en) -opera 6.01 Mozilla/4.0 (compatible; MSIE 5.0; Windows NT 4.0) Opera 6.01 [en] -opera 9.02 Opera/9.02 (Windows XP; U; ru) -opera 5.12 Mozilla/4.0 (compatible; MSIE 5.0; Windows 98) Opera 5.12 [en] -opera 9.70 Opera/9.70 (Linux i686 ; U; en) Presto/2.2.1 -opera 7.03 Opera/7.03 (Windows NT 5.0; U) [en] -opera 9.24 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 9.24 -mozilla 1.9.0.7 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.7) Gecko/2009030821 Firefox/3.0.7 Orca/1.1 build 2 -mozilla 1.9.0.6 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009022300 Firefox/3.0.6 Orca/1.1 build 1 - 0 Mozilla/1.10 [en] (Compatible; RISC OS 3.70; Oregano 1.10) -webkit 530.0 Mozilla/5.0 (compatible; Origyn Web Browser; AmigaOS 4.1; ppc; U; en) AppleWebKit/530.0+ (KHTML, like Gecko, Safari/530.0+) -webkit 531.0 Mozilla/5.0 (compatible; Origyn Web Browser; AmigaOS 4.0; U; en) AppleWebKit/531.0+ (KHTML, like Gecko, Safari/531.0+) -webkit 528.5 Mozilla/5.0 (compatible; Origyn Web Browser; MorphOS; PPC; U) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; PhaseOut-www.phaseout.net) -mozilla 1.4a Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.4a) Gecko/20030411 Phoenix/0.5 -mozilla 1.2b Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.2b) Gecko/20021029 Phoenix/0.4 -webkit 527 Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/2.5 http://www.QtWeb.net -webkit 527 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/1.2 http://www.QtWeb.net -webkit 527 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/527+ (KHTML, like Gecko) QtWeb Internet Browser/1.7 http://www.QtWeb.net -webkit 527 Mozilla/5.0 (X11; U; Linux; cs-CZ) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) rekonq - 0 retawq/0.2.6c [en] (text) -webkit 312.8 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.8 (KHTML, like Gecko) Safari/312.6 -webkit 528.16 Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10_5_6; it-it) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 -webkit 523.15 Mozilla/5.0 (Windows; U; Windows NT 5.1; cs-CZ) AppleWebKit/523.15 (KHTML, like Gecko) Version/3.0 Safari/523.15 -webkit 125.2 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; de-de) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.7 -webkit 528.16 Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16 -webkit 420 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; fi-fi) AppleWebKit/420+ (KHTML, like Gecko) Safari/419.3 -mozilla 1.8.1.13 Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.13) Gecko/20080313 SeaMonkey/1.1.9 -mozilla 1.9.1a2pre Mozilla/5.0 (X11; U; Linux i686; rv:1.9.1a2pre) Gecko/20080824052448 SeaMonkey/2.0a1pre -mozilla 1.8.1.6 Mozilla/5.0 (Windows; U; Win 9x 4.90; en-GB; rv:1.8.1.6) Gecko/20070802 SeaMonkey/1.1.4 -mozilla 1.9.1b3pre Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b3pre) Gecko/20081208 SeaMonkey/2.0a3pre -mozilla 1.9a1 Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.9a1) Gecko/20060702 SeaMonkey/1.5a -mozilla 1.9.1b3pre Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081202 SeaMonkey/2.0a2 -webkit 419 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; ja-jp) AppleWebKit/419 (KHTML, like Gecko) Shiira/1.2.3 Safari/125 -webkit 417.9 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/417.9 (KHTML, like Gecko, Safari) Shiira/1.1 -webkit 418.9.1 Mozilla/5.0 (Macintosh; U; Intel Mac OS X; fr) AppleWebKit/418.9.1 (KHTML, like Gecko) Shiira Safari/125 -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1) Sleipnir/2.8.1 -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727) Sleipnir/2.8.4 -webkit 525.27.1 Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.27.1 (KHTML, like Gecko) Stainless/0.4 Safari/525.20.1 -webkit 528.16 Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_6; en-us) AppleWebKit/528.16 (KHTML, like Gecko) Stainless/0.5.3 Safari/525.20.1 -webkit 525.18 Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_4_11; en) AppleWebKit/525.18 (KHTML, like Gecko) Sunrise/1.7.4 like Safari/4525.22 -webkit 125.5.7 Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/125.5.7 (KHTML, like Gecko) SunriseBrowser/0.853 -mozilla 1.9.0.10pre Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.10pre) Gecko/2009041814 Firefox/3.0.10pre (Swiftfox) -msie 6.0 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322; TheWorld) -webkit 1.1.8 Webkit/1.1.8 (Linux; en-us) Uzbl -webkit 1.1.10 Uzbl (X11; U; Linux x86_64; en-GB) AppleWebkit/1.1.10 -webkit 1.1.9 Uzbl (Webkit 1.1.9) (Linux) -webkit 1.1.10 Uzbl (U; Linux x86_64; en-GB) Webkit 1.1.10 - 0 w3m/0.5.1 - 0 w3m/0.5.2 -webkit 103u Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/103u (KHTML, like Gecko) wKiosk/100 -mozilla 1.9.0.9 Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.9) Gecko/2009042410 Firefox/3.0.9 Wyzo/3.0.3 - 0 X-Smiles/1.2-20081113 -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.0.04506.30; MEGAUPLOAD 2.0) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30) -mozilla 1.9.0.4 Mozilla/5.0 (X11; U; Linux i686; en-GB; rv:1.9.0.4) Gecko/2008111217 Fedora/3.0.4-1.fc9 Firefox/3.0.4 -mozilla 1.9.0.4 Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4 -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322; FDM) -msie 6.0 mozilla/4.0 (compatible; msie 6.0; windows nt 5.1; mra 4.6 (build 01425); .net clr 2.0.50727) -msie 7.0 mozilla/4.0 (compatible; msie 7.0; windows nt 5.1; mra 4.9 (build 01863)) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; InfoPath?.2; .NET CLR 3.5.21022; .NET CLR 3.5.30729; .NET CLR 3.0.30618; MS-RTC LM 8; .NET CLR 1.1.4322) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; InfoPath?.2; .NET CLR 3.5.21022) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Sky Broadband; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.1.4322) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; InfoPath.2; .NET CLR 3.5.21022; .NET CLR 3.5.30729; .NET CLR 3.0.30618; MS-RTC LM 8; .NET CLR 1.1.4322) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; InfoPath.2; .NET CLR 3.5.21022) -msie 7.0 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; GTB6; User-agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; http://bsalsa.com); .NET CLR 1.1.4322; .NET CLR 2.0.50727 -opera 10.00 Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00 -msie 8.0 Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; .NET CLR 1.1.4322; InfoPath?.2; .NET CLR 2.0.50727; CIBA; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729) -opera 10.00 Opera/9.80 (X11; Linux x86_64; U; de) Presto/2.2.15 Version/10.00 -opera 10.50 Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.5.18 Version/10.50 From 578dcee96a8d4d759b3a7e623177fa36a5133ba7 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 15 Jun 2015 10:56:29 -0400 Subject: [PATCH 0332/1272] Revert "Offset: allow offset setter to throw for disconnected elements" This reverts commit 0d11c1182f2012cd6eb06ce1e3fa5a495af9bee3. --- src/offset.js | 2 +- test/unit/core.js | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/offset.js b/src/offset.js index 5ae7153f1c..a6aa2f1d5d 100644 --- a/src/offset.js +++ b/src/offset.js @@ -32,7 +32,7 @@ jQuery.offset = { elem.style.position = "relative"; } - curOffset = curElem.offset(); + curOffset = curElem.offset() || { top: 0, left: 0 }; curCSSTop = jQuery.css( elem, "top" ); curCSSLeft = jQuery.css( elem, "left" ); calculatePosition = ( position === "absolute" || position === "fixed" ) && diff --git a/test/unit/core.js b/test/unit/core.js index d8370637bb..5a87e2f0cf 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -36,6 +36,10 @@ test("jQuery()", function() { 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 }; @@ -101,12 +105,16 @@ test("jQuery()", function() { elem = jQuery("\n\nworld")[0]; equal( elem.nodeName.toLowerCase(), "em", "leading newlines" ); - elem = jQuery( "
        ", attrObj ); + elem = jQuery("
        ", attrObj ); if ( jQuery.fn.width ) { equal( elem[0].style.width, "10px", "jQuery() quick setter width"); } + if ( jQuery.fn.offset ) { + equal( elem[0].style.top, "1px", "jQuery() quick setter offset"); + } + if ( jQuery.fn.css ) { equal( elem[0].style.paddingLeft, "1px", "jQuery quick setter css"); equal( elem[0].style.paddingRight, "1px", "jQuery quick setter css"); From 40dcc767640c41a4387a343f1ef53ac57ed631c5 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 15 Jun 2015 11:02:08 -0400 Subject: [PATCH 0333/1272] Offset: return zeros for disconnected/hidden elements Fixes gh-2310 Close gh-2396 --- src/offset.js | 5 ++++- test/unit/offset.js | 22 ++++++++-------------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/offset.js b/src/offset.js index a6aa2f1d5d..fcb7b14de1 100644 --- a/src/offset.js +++ b/src/offset.js @@ -32,7 +32,7 @@ jQuery.offset = { elem.style.position = "relative"; } - curOffset = curElem.offset() || { top: 0, left: 0 }; + curOffset = curElem.offset(); curCSSTop = jQuery.css( elem, "top" ); curCSSLeft = jQuery.css( elem, "left" ); calculatePosition = ( position === "absolute" || position === "fixed" ) && @@ -103,6 +103,9 @@ jQuery.fn.extend({ left: rect.left + win.pageXOffset - docElem.clientLeft }; } + + // Return zeros for disconnected and hidden elements (gh-2310) + return rect; }, position: function() { diff --git a/test/unit/offset.js b/test/unit/offset.js index 7b2ecc905d..bffe87dd10 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -48,30 +48,24 @@ test("empty set", function() { }); test("disconnected element", function() { - expect(1); - - var result; + expect( 2 ); - try { - result = jQuery( document.createElement("div") ).offset(); - } catch ( e ) {} + var result = jQuery( document.createElement( "div" ) ).offset(); - ok( !result, "no position for disconnected element" ); + equal( result.top, 0, "Retrieving offset on disconnected elements returns zeros (gh-2310)" ); + equal( result.left, 0, "Retrieving offset on disconnected elements returns zeros (gh-2310)" ); }); test("hidden (display: none) element", function() { - expect(1); - - var result, - node = jQuery("
        ").appendTo("#qunit-fixture"); + expect( 2 ); - try { + var node = jQuery("
        ").appendTo("#qunit-fixture"), result = node.offset(); - } catch ( e ) {} node.remove(); - ok( !result, "no position for hidden (display: none) element" ); + equal( result.top, 0, "Retrieving offset on hidden elements returns zeros (gh-2310)" ); + equal( result.left, 0, "Retrieving offset on hidden elements returns zeros (gh-2310)" ); }); testIframe("offset/absolute", "absolute", function($, iframe) { From 0e4477c676db0427bb9b0bf39df8631501e62f24 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Tue, 16 Jun 2015 11:21:58 -0400 Subject: [PATCH 0334/1272] Offset: return before getBoundingClientRect to avoid error in IE8-11 --- src/offset.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/offset.js b/src/offset.js index fcb7b14de1..f0139d5eff 100644 --- a/src/offset.js +++ b/src/offset.js @@ -90,10 +90,17 @@ jQuery.fn.extend({ return; } + // Support: IE<=11+ + // Running getBoundingClientRect on a + // disconnected node in IE throws an error + if ( !elem.getClientRects().length ) { + return { top: 0, left: 0 }; + } + rect = elem.getBoundingClientRect(); - // Make sure element is not hidden (display: none) or disconnected - if ( rect.width || rect.height || elem.getClientRects().length ) { + // Make sure element is not hidden (display: none) + if ( rect.width || rect.height ) { doc = elem.ownerDocument; win = getWindow( doc ); docElem = doc.documentElement; From b04124222395a05c80d4f1c3a70333fdb07bfe3d Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Tue, 16 Jun 2015 13:24:12 -0400 Subject: [PATCH 0335/1272] Offset: add tests for hidden elements + scroll - Also add comments to hidden/disconnected tests noting this is to ensure consistency between branches --- test/data/offset/scroll.html | 2 ++ test/unit/offset.js | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/test/data/offset/scroll.html b/test/data/offset/scroll.html index 113400ce40..ad35ab84a3 100644 --- a/test/data/offset/scroll.html +++ b/test/data/offset/scroll.html @@ -11,6 +11,7 @@ #scroll-1-1 { top: 1px; left: 1px; } #scroll-1-1-1 { top: 1px; left: 1px; } #forceScroll { width: 5000px; height: 5000px; } + #hidden { display: none; } #marker { position: absolute; border: 2px solid #000; width: 50px; height: 50px; background: #ccc; } @@ -32,6 +33,7 @@
        +

        Click the white box to move the marker to it.

        diff --git a/test/unit/offset.js b/test/unit/offset.js index bffe87dd10..65243387f4 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -52,6 +52,9 @@ test("disconnected element", function() { var result = jQuery( document.createElement( "div" ) ).offset(); + // 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, "Retrieving offset on disconnected elements returns zeros (gh-2310)" ); equal( result.left, 0, "Retrieving offset on disconnected elements returns zeros (gh-2310)" ); }); @@ -64,6 +67,9 @@ test("hidden (display: none) element", function() { node.remove(); + // 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, "Retrieving offset on hidden elements returns zeros (gh-2310)" ); equal( result.left, 0, "Retrieving offset on hidden elements returns zeros (gh-2310)" ); }); @@ -401,7 +407,7 @@ testIframe("offset/table", "table", function( $ ) { }); testIframe("offset/scroll", "scroll", function( $, win ) { - expect(28); + expect( 30 ); equal( $("#scroll-1").offset().top, 7, "jQuery('#scroll-1').offset().top" ); equal( $("#scroll-1").offset().left, 7, "jQuery('#scroll-1').offset().left" ); @@ -409,6 +415,12 @@ testIframe("offset/scroll", "scroll", function( $, win ) { equal( $("#scroll-1-1").offset().top, 11, "jQuery('#scroll-1-1').offset().top" ); equal( $("#scroll-1-1").offset().left, 11, "jQuery('#scroll-1-1').offset().left" ); + // 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( $("#hidden").offset().top, 0, "Hidden elements do not subtract scroll" ); + equal( $("#hidden").offset().left, 0, "Hidden elements do not subtract scroll" ); + // scroll offset tests .scrollTop/Left equal( $("#scroll-1").scrollTop(), 5, "jQuery('#scroll-1').scrollTop()" ); equal( $("#scroll-1").scrollLeft(), 5, "jQuery('#scroll-1').scrollLeft()" ); From 219c7494938a10b985b7827990bc419e41585b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Sun, 14 Jun 2015 19:21:57 +0200 Subject: [PATCH 0336/1272] Core: Use window.setTimeout & friends instead of global equivalents Fixes gh-2177 --- src/.jshintrc | 4 ---- src/ajax.js | 5 ++++- src/core/ready.js | 3 ++- src/deferred.js | 3 ++- src/effects.js | 6 +++++- src/queue/delay.js | 4 +++- src/var/clearInterval.js | 3 +++ src/var/clearTimeout.js | 3 +++ src/var/setInterval.js | 3 +++ src/var/setTimeout.js | 3 +++ 10 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 src/var/clearInterval.js create mode 100644 src/var/clearTimeout.js create mode 100644 src/var/setInterval.js create mode 100644 src/var/setTimeout.js diff --git a/src/.jshintrc b/src/.jshintrc index a48233b29e..6144bf420e 100644 --- a/src/.jshintrc +++ b/src/.jshintrc @@ -14,10 +14,6 @@ "globals": { "window": true, - "setTimeout": true, - "clearTimeout": true, - "setInterval": true, - "clearInterval": true, "jQuery": true, "define": true, diff --git a/src/ajax.js b/src/ajax.js index 70bb49691a..21668165e6 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -2,6 +2,8 @@ define([ "./core", "./var/document", "./var/rnotwhite", + "./var/setTimeout", + "./var/clearTimeout", "./ajax/var/location", "./ajax/var/nonce", "./ajax/var/rquery", @@ -9,7 +11,8 @@ define([ "./ajax/parseJSON", "./ajax/parseXML", "./deferred" -], function( jQuery, document, rnotwhite, location, nonce, rquery ) { +], function( jQuery, document, rnotwhite, setTimeout, clearTimeout, + location, nonce, rquery ) { var rhash = /#.*$/, diff --git a/src/core/ready.js b/src/core/ready.js index bea0496da1..b78b474cdb 100644 --- a/src/core/ready.js +++ b/src/core/ready.js @@ -1,8 +1,9 @@ define([ "../core", "../var/document", + "../var/setTimeout", "../deferred" -], function( jQuery, document ) { +], function( jQuery, document, setTimeout ) { // The deferred used on DOM ready var readyList; diff --git a/src/deferred.js b/src/deferred.js index cdb7f1cc4e..043bf0c04d 100644 --- a/src/deferred.js +++ b/src/deferred.js @@ -1,8 +1,9 @@ define([ "./core", "./var/slice", + "./var/setTimeout", "./callbacks" -], function( jQuery, slice ) { +], function( jQuery, slice, setTimeout ) { function Identity( v ) { return v; diff --git a/src/effects.js b/src/effects.js index 3268fcda9a..63874fe78e 100644 --- a/src/effects.js +++ b/src/effects.js @@ -2,6 +2,9 @@ define([ "./core", "./var/document", "./var/rcssNum", + "./var/setInterval", + "./var/clearInterval", + "./var/setTimeout", "./css/var/cssExpand", "./css/var/isHidden", "./css/var/swap", @@ -16,7 +19,8 @@ define([ "./manipulation", "./css", "./effects/Tween" -], function( jQuery, document, rcssNum, cssExpand, isHidden, swap, adjustCSS, dataPriv, showHide ) { +], function( jQuery, document, rcssNum, setInterval, clearInterval, setTimeout, + cssExpand, isHidden, swap, adjustCSS, dataPriv, showHide ) { var fxNow, timerId, diff --git a/src/queue/delay.js b/src/queue/delay.js index 037ef0998e..d2aa7e4092 100644 --- a/src/queue/delay.js +++ b/src/queue/delay.js @@ -1,8 +1,10 @@ define([ "../core", + "../var/setTimeout", + "../var/clearTimeout", "../queue", "../effects" // Delay is optional because of this dependency -], function( jQuery ) { +], function( jQuery, setTimeout, clearTimeout ) { // Based off of the plugin by Clint Helfers, with permission. // http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ diff --git a/src/var/clearInterval.js b/src/var/clearInterval.js new file mode 100644 index 0000000000..b8fcf31555 --- /dev/null +++ b/src/var/clearInterval.js @@ -0,0 +1,3 @@ +define(function() { + return window.clearInterval; +}); diff --git a/src/var/clearTimeout.js b/src/var/clearTimeout.js new file mode 100644 index 0000000000..ab77b074af --- /dev/null +++ b/src/var/clearTimeout.js @@ -0,0 +1,3 @@ +define(function() { + return window.clearTimeout; +}); diff --git a/src/var/setInterval.js b/src/var/setInterval.js new file mode 100644 index 0000000000..7d9906b1d1 --- /dev/null +++ b/src/var/setInterval.js @@ -0,0 +1,3 @@ +define(function() { + return window.setInterval; +}); diff --git a/src/var/setTimeout.js b/src/var/setTimeout.js new file mode 100644 index 0000000000..cda6b55ad8 --- /dev/null +++ b/src/var/setTimeout.js @@ -0,0 +1,3 @@ +define(function() { + return window.setTimeout; +}); From 842958e7aecd0d75a7ee9e2aaec83457701aa2f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Wed, 17 Jun 2015 12:55:59 +0200 Subject: [PATCH 0337/1272] Core: Switch from modules to just window.setTimeout etc. Using modules for window.setTimeout etc. made those functions cached and disabled Sinon mocking, making effects tests fail. Just writing window.setTimeout directly is smaller anyway. --- src/ajax.js | 9 +++------ src/core/ready.js | 5 ++--- src/deferred.js | 5 ++--- src/effects.js | 12 ++++-------- src/queue/delay.js | 8 +++----- src/var/clearInterval.js | 3 --- src/var/clearTimeout.js | 3 --- src/var/setInterval.js | 3 --- src/var/setTimeout.js | 3 --- 9 files changed, 14 insertions(+), 37 deletions(-) delete mode 100644 src/var/clearInterval.js delete mode 100644 src/var/clearTimeout.js delete mode 100644 src/var/setInterval.js delete mode 100644 src/var/setTimeout.js diff --git a/src/ajax.js b/src/ajax.js index 21668165e6..9c1d6ca853 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -2,8 +2,6 @@ define([ "./core", "./var/document", "./var/rnotwhite", - "./var/setTimeout", - "./var/clearTimeout", "./ajax/var/location", "./ajax/var/nonce", "./ajax/var/rquery", @@ -11,8 +9,7 @@ define([ "./ajax/parseJSON", "./ajax/parseXML", "./deferred" -], function( jQuery, document, rnotwhite, setTimeout, clearTimeout, - location, nonce, rquery ) { +], function( jQuery, document, rnotwhite, location, nonce, rquery ) { var rhash = /#.*$/, @@ -645,7 +642,7 @@ jQuery.extend({ // Timeout if ( s.async && s.timeout > 0 ) { - timeoutTimer = setTimeout(function() { + timeoutTimer = window.setTimeout(function() { jqXHR.abort("timeout"); }, s.timeout ); } @@ -679,7 +676,7 @@ jQuery.extend({ // Clear timeout if it exists if ( timeoutTimer ) { - clearTimeout( timeoutTimer ); + window.clearTimeout( timeoutTimer ); } // Dereference transport for early garbage collection diff --git a/src/core/ready.js b/src/core/ready.js index b78b474cdb..085d19a931 100644 --- a/src/core/ready.js +++ b/src/core/ready.js @@ -1,9 +1,8 @@ define([ "../core", "../var/document", - "../var/setTimeout", "../deferred" -], function( jQuery, document, setTimeout ) { +], function( jQuery, document ) { // The deferred used on DOM ready var readyList; @@ -74,7 +73,7 @@ jQuery.ready.promise = function( obj ) { // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready - setTimeout( jQuery.ready ); + window.setTimeout( jQuery.ready ); } else { diff --git a/src/deferred.js b/src/deferred.js index 043bf0c04d..188303c975 100644 --- a/src/deferred.js +++ b/src/deferred.js @@ -1,9 +1,8 @@ define([ "./core", "./var/slice", - "./var/setTimeout", "./callbacks" -], function( jQuery, slice, setTimeout ) { +], function( jQuery, slice ) { function Identity( v ) { return v; @@ -174,7 +173,7 @@ jQuery.extend({ if ( depth ) { process(); } else { - setTimeout( process ); + window.setTimeout( process ); } }; } diff --git a/src/effects.js b/src/effects.js index 63874fe78e..53b73fd848 100644 --- a/src/effects.js +++ b/src/effects.js @@ -2,9 +2,6 @@ define([ "./core", "./var/document", "./var/rcssNum", - "./var/setInterval", - "./var/clearInterval", - "./var/setTimeout", "./css/var/cssExpand", "./css/var/isHidden", "./css/var/swap", @@ -19,8 +16,7 @@ define([ "./manipulation", "./css", "./effects/Tween" -], function( jQuery, document, rcssNum, setInterval, clearInterval, setTimeout, - cssExpand, isHidden, swap, adjustCSS, dataPriv, showHide ) { +], function( jQuery, document, rcssNum, cssExpand, isHidden, swap, adjustCSS, dataPriv, showHide ) { var fxNow, timerId, @@ -44,7 +40,7 @@ function raf() { // Animations created synchronously will run synchronously function createFxNow() { - setTimeout(function() { + window.setTimeout(function() { fxNow = undefined; }); return ( fxNow = jQuery.now() ); @@ -638,7 +634,7 @@ jQuery.fx.start = function() { if ( !timerId ) { timerId = window.requestAnimationFrame ? window.requestAnimationFrame( raf ) : - setInterval( jQuery.fx.tick, jQuery.fx.interval ); + window.setInterval( jQuery.fx.tick, jQuery.fx.interval ); } }; @@ -646,7 +642,7 @@ jQuery.fx.stop = function() { if ( window.cancelAnimationFrame ) { window.cancelAnimationFrame( timerId ); } else { - clearInterval( timerId ); + window.clearInterval( timerId ); } timerId = null; diff --git a/src/queue/delay.js b/src/queue/delay.js index d2aa7e4092..93abd0bf26 100644 --- a/src/queue/delay.js +++ b/src/queue/delay.js @@ -1,10 +1,8 @@ define([ "../core", - "../var/setTimeout", - "../var/clearTimeout", "../queue", "../effects" // Delay is optional because of this dependency -], function( jQuery, setTimeout, clearTimeout ) { +], function( jQuery ) { // Based off of the plugin by Clint Helfers, with permission. // http://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ @@ -13,9 +11,9 @@ jQuery.fn.delay = function( time, type ) { type = type || "fx"; return this.queue( type, function( next, hooks ) { - var timeout = setTimeout( next, time ); + var timeout = window.setTimeout( next, time ); hooks.stop = function() { - clearTimeout( timeout ); + window.clearTimeout( timeout ); }; }); }; diff --git a/src/var/clearInterval.js b/src/var/clearInterval.js deleted file mode 100644 index b8fcf31555..0000000000 --- a/src/var/clearInterval.js +++ /dev/null @@ -1,3 +0,0 @@ -define(function() { - return window.clearInterval; -}); diff --git a/src/var/clearTimeout.js b/src/var/clearTimeout.js deleted file mode 100644 index ab77b074af..0000000000 --- a/src/var/clearTimeout.js +++ /dev/null @@ -1,3 +0,0 @@ -define(function() { - return window.clearTimeout; -}); diff --git a/src/var/setInterval.js b/src/var/setInterval.js deleted file mode 100644 index 7d9906b1d1..0000000000 --- a/src/var/setInterval.js +++ /dev/null @@ -1,3 +0,0 @@ -define(function() { - return window.setInterval; -}); diff --git a/src/var/setTimeout.js b/src/var/setTimeout.js deleted file mode 100644 index cda6b55ad8..0000000000 --- a/src/var/setTimeout.js +++ /dev/null @@ -1,3 +0,0 @@ -define(function() { - return window.setTimeout; -}); From 63a577aa0bcb439c1730c3825407d86c128b17be Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Tue, 16 Jun 2015 11:24:21 -0400 Subject: [PATCH 0338/1272] Build: space between curly and paren is optional Fixes gh-2399 Close gh-2400 --- build/tasks/build.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/tasks/build.js b/build/tasks/build.js index f59a3340b8..ead3deb19d 100644 --- a/build/tasks/build.js +++ b/build/tasks/build.js @@ -11,7 +11,7 @@ module.exports = function( grunt ) { var fs = require( "fs" ), requirejs = require( "requirejs" ), srcFolder = __dirname + "/../../src/", - rdefineEnd = /\}\);[^}\w]*$/, + rdefineEnd = /\}\s*?\);[^}\w]*$/, config = { baseUrl: "src", name: "jquery", @@ -62,7 +62,7 @@ module.exports = function( grunt ) { } else { contents = contents - .replace( /\s*return\s+[^\}]+(\}\);[^\w\}]*)$/, "$1" ) + .replace( /\s*return\s+[^\}]+(\}\s*?\);[^\w\}]*)$/, "$1" ) // Multiple exports .replace( /\s*exports\.\w+\s*=\s*\w+;/g, "" ); From 90d828bad0d6d318d73d6cf6209d9dc7ac13878c Mon Sep 17 00:00:00 2001 From: Martin Naumann Date: Tue, 16 Jun 2015 23:55:21 +0200 Subject: [PATCH 0339/1272] CSS: Work around an IE11 fullscreen dimensions bug Fixes gh-1764 Closes gh-2401 --- src/css.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/css.js b/src/css.js index 566f5a0fd6..922f44162c 100644 --- a/src/css.js +++ b/src/css.js @@ -113,6 +113,17 @@ function getWidthOrHeight( elem, name, extra ) { styles = getStyles( elem ), isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + // Support: IE11 only + // Fix for edge case in IE 11. See 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 5153b5334eb2c8317372b46209bd9d092a91afdc Mon Sep 17 00:00:00 2001 From: Gilad Peleg Date: Wed, 10 Jun 2015 17:56:17 +0300 Subject: [PATCH 0340/1272] Core: organize prop & attr code to be similar Closes gh-2384 --- src/attributes/attr.js | 70 ++++++++++++++++++++---------------------- src/attributes/prop.js | 40 +++++++++++++----------- 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/src/attributes/attr.js b/src/attributes/attr.js index bec86c1f5a..07576738a1 100644 --- a/src/attributes/attr.js +++ b/src/attributes/attr.js @@ -1,10 +1,10 @@ define([ "../core", - "../var/rnotwhite", "../core/access", "./support", + "../var/rnotwhite", "../selector" -], function( jQuery, rnotwhite, access, support ) { +], function( jQuery, access, support, rnotwhite ) { var boolHook, attrHandle = jQuery.expr.attrHandle; @@ -23,10 +23,10 @@ jQuery.fn.extend({ jQuery.extend({ attr: function( elem, name, value ) { - var hooks, ret, + var ret, hooks, nType = elem.nodeType; - // don't get/set attributes on text, comment and attribute nodes + // Don't get/set attributes on text, comment and attribute nodes if ( nType === 3 || nType === 8 || nType === 2 ) { return; } @@ -45,30 +45,43 @@ jQuery.extend({ } if ( value !== undefined ) { - if ( value === null ) { jQuery.removeAttr( elem, name ); + return; + } - } else if ( hooks && "set" in hooks && - (ret = hooks.set( elem, value, name )) !== undefined ) { - + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { return ret; - - } else { - elem.setAttribute( name, value + "" ); - return value; } - } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { return ret; + } - } else { - ret = jQuery.find.attr( elem, name ); + ret = jQuery.find.attr( elem, name ); - // Non-existent attributes return null, we normalize to undefined - return ret == null ? - undefined : - ret; + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + jQuery.nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } } }, @@ -78,11 +91,12 @@ jQuery.extend({ attrNames = value && value.match( rnotwhite ); if ( attrNames && elem.nodeType === 1 ) { - while ( (name = attrNames[i++]) ) { + 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; } @@ -90,22 +104,6 @@ jQuery.extend({ elem.removeAttribute( name ); } } - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - jQuery.nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } } }); diff --git a/src/attributes/prop.js b/src/attributes/prop.js index 58ed765113..4c7b51e8c8 100644 --- a/src/attributes/prop.js +++ b/src/attributes/prop.js @@ -1,7 +1,8 @@ define([ "../core", "../core/access", - "./support" + "./support", + "../selector" ], function( jQuery, access, support ) { var rfocusable = /^(?:input|select|textarea|button)$/i; @@ -19,38 +20,36 @@ jQuery.fn.extend({ }); jQuery.extend({ - propFix: { - "for": "htmlFor", - "class": "className" - }, - prop: function( elem, name, value ) { - var ret, hooks, notxml, + var ret, hooks, nType = elem.nodeType; // Don't get/set properties on text, comment and attribute nodes - if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { + if ( nType === 3 || nType === 8 || nType === 2 ) { return; } - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - if ( notxml ) { // Fix name and attach hooks name = jQuery.propFix[ name ] || name; hooks = jQuery.propHooks[ name ]; } if ( value !== undefined ) { - return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ? - ret : - ( elem[ name ] = value ); - - } else { - return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ? - ret : - elem[ name ]; + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; }, propHooks: { @@ -62,6 +61,11 @@ jQuery.extend({ -1; } } + }, + + propFix: { + "for": "htmlFor", + "class": "className" } }); From 3a0d582cf63b6e8f77150d9c38d2bf34d0c7790e Mon Sep 17 00:00:00 2001 From: Thomas Tortorini Date: Sun, 14 Jun 2015 23:58:44 +0200 Subject: [PATCH 0341/1272] CSS: make the getStyles function more readable The new version is not only simpler to read but also smaller by 6 bytes gzipped. Closes gh-2393 --- src/css/var/getStyles.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/css/var/getStyles.js b/src/css/var/getStyles.js index 0d1d51af62..31dfc298ea 100644 --- a/src/css/var/getStyles.js +++ b/src/css/var/getStyles.js @@ -1,12 +1,15 @@ define(function() { return function( elem ) { + // Support: IE<=11+, Firefox<=30+ (#15098, #14150) // IE throws on elements created in popups // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - if ( elem.ownerDocument.defaultView.opener ) { - return elem.ownerDocument.defaultView.getComputedStyle( elem ); + var view = elem.ownerDocument.defaultView; + + if ( !view.opener ) { + view = window; } - return window.getComputedStyle( elem ); + return view.getComputedStyle( elem ); }; }); From cdaed15c7ea1bbfdde5a5bea691c583ce7961526 Mon Sep 17 00:00:00 2001 From: Corey Frang Date: Mon, 18 May 2015 17:11:21 -0400 Subject: [PATCH 0342/1272] Effects: Add tests for jQuery.Tween --- Gruntfile.js | 5 +- external/sinon/LICENSE.txt | 27 - external/sinon/fake_timers.js | 409 --- external/sinon/sinon-1.14.1.js | 5931 ++++++++++++++++++++++++++++++++ src/effects/Tween.js | 8 +- src/selector-native.js | 3 +- test/data/testinit.js | 3 +- test/index.html | 2 +- test/unit/effects.js | 6 +- test/unit/tween.js | 298 ++ 10 files changed, 6246 insertions(+), 446 deletions(-) delete mode 100644 external/sinon/LICENSE.txt delete mode 100644 external/sinon/fake_timers.js create mode 100644 external/sinon/sinon-1.14.1.js create mode 100644 test/unit/tween.js diff --git a/Gruntfile.js b/Gruntfile.js index 0bf20d4542..8c88370e49 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -104,7 +104,7 @@ module.exports = function( grunt ) { gruntfile: "Gruntfile.js", // Right now, check only test helpers - test: [ "test/data/testrunner.js" ], + test: [ "test/data/testrunner.js", "test/unit/tween.js" ], release: [ "build/*.js", "!build/release-notes.js" ], tasks: "build/tasks/*.js" }, @@ -126,7 +126,8 @@ module.exports = function( grunt ) { "selector", "serialize", "support", - "traversing" + "traversing", + "tween" ] }, watch: { diff --git a/external/sinon/LICENSE.txt b/external/sinon/LICENSE.txt deleted file mode 100644 index e7f50d123b..0000000000 --- a/external/sinon/LICENSE.txt +++ /dev/null @@ -1,27 +0,0 @@ -(The BSD License) - -Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Christian Johansen nor the names of his contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/external/sinon/fake_timers.js b/external/sinon/fake_timers.js deleted file mode 100644 index 0d51368276..0000000000 --- a/external/sinon/fake_timers.js +++ /dev/null @@ -1,409 +0,0 @@ -/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/ -/*global module, require, window*/ -/** - * Fake timer API - * setTimeout - * setInterval - * clearTimeout - * clearInterval - * tick - * reset - * Date - * - * Inspired by jsUnitMockTimeOut from JsUnit - * - * @author Christian Johansen (christian@cjohansen.no) - * @license BSD - * - * Copyright (c) 2010-2013 Christian Johansen - */ -"use strict"; - -if (typeof sinon == "undefined") { - var sinon = {}; -} - -(function (global) { - // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref() - // browsers, a number. - // see https://github.com/cjohansen/Sinon.JS/pull/436 - var timeoutResult = setTimeout(function() {}, 0); - var addTimerReturnsObject = typeof timeoutResult === 'object'; - clearTimeout(timeoutResult); - - var id = 1; - - function addTimer(args, recurring) { - if (args.length === 0) { - throw new Error("Function requires at least 1 parameter"); - } - - if (typeof args[0] === "undefined") { - throw new Error("Callback must be provided to timer calls"); - } - - var toId = id++; - var delay = args[1] || 0; - - if (!this.timeouts) { - this.timeouts = {}; - } - - this.timeouts[toId] = { - id: toId, - func: args[0], - callAt: this.now + delay, - invokeArgs: Array.prototype.slice.call(args, 2) - }; - - if (recurring === true) { - this.timeouts[toId].interval = delay; - } - - if (addTimerReturnsObject) { - return { - id: toId, - ref: function() {}, - unref: function() {} - }; - } - else { - return toId; - } - } - - function parseTime(str) { - if (!str) { - return 0; - } - - var strings = str.split(":"); - var l = strings.length, i = l; - var ms = 0, parsed; - - if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { - throw new Error("tick only understands numbers and 'h:m:s'"); - } - - while (i--) { - parsed = parseInt(strings[i], 10); - - if (parsed >= 60) { - throw new Error("Invalid time " + str); - } - - ms += parsed * Math.pow(60, (l - i - 1)); - } - - return ms * 1000; - } - - function createObject(object) { - var newObject; - - if (Object.create) { - newObject = Object.create(object); - } else { - var F = function () {}; - F.prototype = object; - newObject = new F(); - } - - newObject.Date.clock = newObject; - return newObject; - } - - sinon.clock = { - now: 0, - - create: function create(now) { - var clock = createObject(this); - - if (typeof now == "number") { - clock.now = now; - } - - if (!!now && typeof now == "object") { - throw new TypeError("now should be milliseconds since UNIX epoch"); - } - - return clock; - }, - - setTimeout: function setTimeout(callback, timeout) { - return addTimer.call(this, arguments, false); - }, - - clearTimeout: function clearTimeout(timerId) { - if (!timerId) { - // null appears to be allowed in most browsers, and appears to be relied upon by some libraries, like Bootstrap carousel - return; - } - if (!this.timeouts) { - this.timeouts = []; - } - // in Node, timerId is an object with .ref()/.unref(), and - // its .id field is the actual timer id. - if (typeof timerId === 'object') { - timerId = timerId.id - } - if (timerId in this.timeouts) { - delete this.timeouts[timerId]; - } - }, - - setInterval: function setInterval(callback, timeout) { - return addTimer.call(this, arguments, true); - }, - - clearInterval: function clearInterval(timerId) { - this.clearTimeout(timerId); - }, - - setImmediate: function setImmediate(callback) { - var passThruArgs = Array.prototype.slice.call(arguments, 1); - - return addTimer.call(this, [callback, 0].concat(passThruArgs), false); - }, - - clearImmediate: function clearImmediate(timerId) { - this.clearTimeout(timerId); - }, - - tick: function tick(ms) { - ms = typeof ms == "number" ? ms : parseTime(ms); - var tickFrom = this.now, tickTo = this.now + ms, previous = this.now; - var timer = this.firstTimerInRange(tickFrom, tickTo); - - var firstException; - while (timer && tickFrom <= tickTo) { - if (this.timeouts[timer.id]) { - tickFrom = this.now = timer.callAt; - try { - this.callTimer(timer); - } catch (e) { - firstException = firstException || e; - } - } - - timer = this.firstTimerInRange(previous, tickTo); - previous = tickFrom; - } - - this.now = tickTo; - - if (firstException) { - throw firstException; - } - - return this.now; - }, - - firstTimerInRange: function (from, to) { - var timer, smallest = null, originalTimer; - - for (var id in this.timeouts) { - if (this.timeouts.hasOwnProperty(id)) { - if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) { - continue; - } - - if (smallest === null || this.timeouts[id].callAt < smallest) { - originalTimer = this.timeouts[id]; - smallest = this.timeouts[id].callAt; - - timer = { - func: this.timeouts[id].func, - callAt: this.timeouts[id].callAt, - interval: this.timeouts[id].interval, - id: this.timeouts[id].id, - invokeArgs: this.timeouts[id].invokeArgs - }; - } - } - } - - return timer || null; - }, - - callTimer: function (timer) { - if (typeof timer.interval == "number") { - this.timeouts[timer.id].callAt += timer.interval; - } else { - delete this.timeouts[timer.id]; - } - - try { - if (typeof timer.func == "function") { - timer.func.apply(null, timer.invokeArgs); - } else { - eval(timer.func); - } - } catch (e) { - var exception = e; - } - - if (!this.timeouts[timer.id]) { - if (exception) { - throw exception; - } - return; - } - - if (exception) { - throw exception; - } - }, - - reset: function reset() { - this.timeouts = {}; - }, - - Date: (function () { - var NativeDate = Date; - - function ClockDate(year, month, date, hour, minute, second, ms) { - // Defensive and verbose to avoid potential harm in passing - // explicit undefined when user does not pass argument - switch (arguments.length) { - case 0: - return new NativeDate(ClockDate.clock.now); - case 1: - return new NativeDate(year); - case 2: - return new NativeDate(year, month); - case 3: - return new NativeDate(year, month, date); - case 4: - return new NativeDate(year, month, date, hour); - case 5: - return new NativeDate(year, month, date, hour, minute); - case 6: - return new NativeDate(year, month, date, hour, minute, second); - default: - return new NativeDate(year, month, date, hour, minute, second, ms); - } - } - - return mirrorDateProperties(ClockDate, NativeDate); - }()) - }; - - function mirrorDateProperties(target, source) { - if (source.now) { - target.now = function now() { - return target.clock.now; - }; - } else { - delete target.now; - } - - if (source.toSource) { - target.toSource = function toSource() { - return source.toSource(); - }; - } else { - delete target.toSource; - } - - target.toString = function toString() { - return source.toString(); - }; - - target.prototype = source.prototype; - target.parse = source.parse; - target.UTC = source.UTC; - target.prototype.toUTCString = source.prototype.toUTCString; - - for (var prop in source) { - if (source.hasOwnProperty(prop)) { - target[prop] = source[prop]; - } - } - - return target; - } - - var methods = ["Date", "setTimeout", "setInterval", - "clearTimeout", "clearInterval"]; - - if (typeof global.setImmediate !== "undefined") { - methods.push("setImmediate"); - } - - if (typeof global.clearImmediate !== "undefined") { - methods.push("clearImmediate"); - } - - function restore() { - var method; - - for (var i = 0, l = this.methods.length; i < l; i++) { - method = this.methods[i]; - - if (global[method].hadOwnProperty) { - global[method] = this["_" + method]; - } else { - try { - delete global[method]; - } catch (e) {} - } - } - - // Prevent multiple executions which will completely remove these props - this.methods = []; - } - - function stubGlobal(method, clock) { - clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method); - clock["_" + method] = global[method]; - - if (method == "Date") { - var date = mirrorDateProperties(clock[method], global[method]); - global[method] = date; - } else { - global[method] = function () { - return clock[method].apply(clock, arguments); - }; - - for (var prop in clock[method]) { - if (clock[method].hasOwnProperty(prop)) { - global[method][prop] = clock[method][prop]; - } - } - } - - global[method].clock = clock; - } - - sinon.useFakeTimers = function useFakeTimers(now) { - var clock = sinon.clock.create(now); - clock.restore = restore; - clock.methods = Array.prototype.slice.call(arguments, - typeof now == "number" ? 1 : 0); - - if (clock.methods.length === 0) { - clock.methods = methods; - } - - for (var i = 0, l = clock.methods.length; i < l; i++) { - stubGlobal(clock.methods[i], clock); - } - - return clock; - }; -}(typeof global != "undefined" && typeof global !== "function" ? global : this)); - -sinon.timers = { - setTimeout: setTimeout, - clearTimeout: clearTimeout, - setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), - clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined), - setInterval: setInterval, - clearInterval: clearInterval, - Date: Date -}; - -if (typeof module !== 'undefined' && module.exports) { - module.exports = sinon; -} diff --git a/external/sinon/sinon-1.14.1.js b/external/sinon/sinon-1.14.1.js new file mode 100644 index 0000000000..dfbeae46a5 --- /dev/null +++ b/external/sinon/sinon-1.14.1.js @@ -0,0 +1,5931 @@ +/** + * Sinon.JS 1.14.1, 2015/03/16 + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS + * + * (The BSD License) + * + * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Christian Johansen nor the names of his contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define('sinon', [], function () { + return (root.sinon = factory()); + }); + } else if (typeof exports === 'object') { + module.exports = factory(); + } else { + root.sinon = factory(); + } +}(this, function () { + var samsam, formatio; + (function () { + function define(mod, deps, fn) { + if (mod == "samsam") { + samsam = deps(); + } else if (typeof deps === "function" && mod.length === 0) { + lolex = deps(); + } else if (typeof fn === "function") { + formatio = fn(samsam); + } + } + define.amd = {}; +((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) || + (typeof module === "object" && + function (m) { module.exports = m(); }) || // Node + function (m) { this.samsam = m(); } // Browser globals +)(function () { + var o = Object.prototype; + var div = typeof document !== "undefined" && document.createElement("div"); + + function isNaN(value) { + // Unlike global isNaN, this avoids type coercion + // typeof check avoids IE host object issues, hat tip to + // lodash + var val = value; // JsLint thinks value !== value is "weird" + return typeof value === "number" && value !== val; + } + + function getClass(value) { + // Returns the internal [[Class]] by calling Object.prototype.toString + // with the provided value as this. Return value is a string, naming the + // internal class, e.g. "Array" + return o.toString.call(value).split(/[ \]]/)[1]; + } + + /** + * @name samsam.isArguments + * @param Object object + * + * Returns ``true`` if ``object`` is an ``arguments`` object, + * ``false`` otherwise. + */ + function isArguments(object) { + if (getClass(object) === 'Arguments') { return true; } + if (typeof object !== "object" || typeof object.length !== "number" || + getClass(object) === "Array") { + return false; + } + if (typeof object.callee == "function") { return true; } + try { + object[object.length] = 6; + delete object[object.length]; + } catch (e) { + return true; + } + return false; + } + + /** + * @name samsam.isElement + * @param Object object + * + * Returns ``true`` if ``object`` is a DOM element node. Unlike + * Underscore.js/lodash, this function will return ``false`` if ``object`` + * is an *element-like* object, i.e. a regular object with a ``nodeType`` + * property that holds the value ``1``. + */ + function isElement(object) { + if (!object || object.nodeType !== 1 || !div) { return false; } + try { + object.appendChild(div); + object.removeChild(div); + } catch (e) { + return false; + } + return true; + } + + /** + * @name samsam.keys + * @param Object object + * + * Return an array of own property names. + */ + function keys(object) { + var ks = [], prop; + for (prop in object) { + if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); } + } + return ks; + } + + /** + * @name samsam.isDate + * @param Object value + * + * Returns true if the object is a ``Date``, or *date-like*. Duck typing + * of date objects work by checking that the object has a ``getTime`` + * function whose return value equals the return value from the object's + * ``valueOf``. + */ + function isDate(value) { + return typeof value.getTime == "function" && + value.getTime() == value.valueOf(); + } + + /** + * @name samsam.isNegZero + * @param Object value + * + * Returns ``true`` if ``value`` is ``-0``. + */ + function isNegZero(value) { + return value === 0 && 1 / value === -Infinity; + } + + /** + * @name samsam.equal + * @param Object obj1 + * @param Object obj2 + * + * Returns ``true`` if two objects are strictly equal. Compared to + * ``===`` there are two exceptions: + * + * - NaN is considered equal to NaN + * - -0 and +0 are not considered equal + */ + function identical(obj1, obj2) { + if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) { + return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2); + } + } + + + /** + * @name samsam.deepEqual + * @param Object obj1 + * @param Object obj2 + * + * Deep equal comparison. Two values are "deep equal" if: + * + * - They are equal, according to samsam.identical + * - They are both date objects representing the same time + * - They are both arrays containing elements that are all deepEqual + * - They are objects with the same set of properties, and each property + * in ``obj1`` is deepEqual to the corresponding property in ``obj2`` + * + * Supports cyclic objects. + */ + function deepEqualCyclic(obj1, obj2) { + + // used for cyclic comparison + // contain already visited objects + var objects1 = [], + objects2 = [], + // contain pathes (position in the object structure) + // of the already visited objects + // indexes same as in objects arrays + paths1 = [], + paths2 = [], + // contains combinations of already compared objects + // in the manner: { "$1['ref']$2['ref']": true } + compared = {}; + + /** + * used to check, if the value of a property is an object + * (cyclic logic is only needed for objects) + * only needed for cyclic logic + */ + function isObject(value) { + + if (typeof value === 'object' && value !== null && + !(value instanceof Boolean) && + !(value instanceof Date) && + !(value instanceof Number) && + !(value instanceof RegExp) && + !(value instanceof String)) { + + return true; + } + + return false; + } + + /** + * returns the index of the given object in the + * given objects array, -1 if not contained + * only needed for cyclic logic + */ + function getIndex(objects, obj) { + + var i; + for (i = 0; i < objects.length; i++) { + if (objects[i] === obj) { + return i; + } + } + + return -1; + } + + // does the recursion for the deep equal check + return (function deepEqual(obj1, obj2, path1, path2) { + var type1 = typeof obj1; + var type2 = typeof obj2; + + // == null also matches undefined + if (obj1 === obj2 || + isNaN(obj1) || isNaN(obj2) || + obj1 == null || obj2 == null || + type1 !== "object" || type2 !== "object") { + + return identical(obj1, obj2); + } + + // Elements are only equal if identical(expected, actual) + if (isElement(obj1) || isElement(obj2)) { return false; } + + var isDate1 = isDate(obj1), isDate2 = isDate(obj2); + if (isDate1 || isDate2) { + if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) { + return false; + } + } + + if (obj1 instanceof RegExp && obj2 instanceof RegExp) { + if (obj1.toString() !== obj2.toString()) { return false; } + } + + var class1 = getClass(obj1); + var class2 = getClass(obj2); + var keys1 = keys(obj1); + var keys2 = keys(obj2); + + if (isArguments(obj1) || isArguments(obj2)) { + if (obj1.length !== obj2.length) { return false; } + } else { + if (type1 !== type2 || class1 !== class2 || + keys1.length !== keys2.length) { + return false; + } + } + + var key, i, l, + // following vars are used for the cyclic logic + value1, value2, + isObject1, isObject2, + index1, index2, + newPath1, newPath2; + + for (i = 0, l = keys1.length; i < l; i++) { + key = keys1[i]; + if (!o.hasOwnProperty.call(obj2, key)) { + return false; + } + + // Start of the cyclic logic + + value1 = obj1[key]; + value2 = obj2[key]; + + isObject1 = isObject(value1); + isObject2 = isObject(value2); + + // determine, if the objects were already visited + // (it's faster to check for isObject first, than to + // get -1 from getIndex for non objects) + index1 = isObject1 ? getIndex(objects1, value1) : -1; + index2 = isObject2 ? getIndex(objects2, value2) : -1; + + // determine the new pathes of the objects + // - for non cyclic objects the current path will be extended + // by current property name + // - for cyclic objects the stored path is taken + newPath1 = index1 !== -1 + ? paths1[index1] + : path1 + '[' + JSON.stringify(key) + ']'; + newPath2 = index2 !== -1 + ? paths2[index2] + : path2 + '[' + JSON.stringify(key) + ']'; + + // stop recursion if current objects are already compared + if (compared[newPath1 + newPath2]) { + return true; + } + + // remember the current objects and their pathes + if (index1 === -1 && isObject1) { + objects1.push(value1); + paths1.push(newPath1); + } + if (index2 === -1 && isObject2) { + objects2.push(value2); + paths2.push(newPath2); + } + + // remember that the current objects are already compared + if (isObject1 && isObject2) { + compared[newPath1 + newPath2] = true; + } + + // End of cyclic logic + + // neither value1 nor value2 is a cycle + // continue with next level + if (!deepEqual(value1, value2, newPath1, newPath2)) { + return false; + } + } + + return true; + + }(obj1, obj2, '$1', '$2')); + } + + var match; + + function arrayContains(array, subset) { + if (subset.length === 0) { return true; } + var i, l, j, k; + for (i = 0, l = array.length; i < l; ++i) { + if (match(array[i], subset[0])) { + for (j = 0, k = subset.length; j < k; ++j) { + if (!match(array[i + j], subset[j])) { return false; } + } + return true; + } + } + return false; + } + + /** + * @name samsam.match + * @param Object object + * @param Object matcher + * + * Compare arbitrary value ``object`` with matcher. + */ + match = function match(object, matcher) { + if (matcher && typeof matcher.test === "function") { + return matcher.test(object); + } + + if (typeof matcher === "function") { + return matcher(object) === true; + } + + if (typeof matcher === "string") { + matcher = matcher.toLowerCase(); + var notNull = typeof object === "string" || !!object; + return notNull && + (String(object)).toLowerCase().indexOf(matcher) >= 0; + } + + if (typeof matcher === "number") { + return matcher === object; + } + + if (typeof matcher === "boolean") { + return matcher === object; + } + + if (typeof(matcher) === "undefined") { + return typeof(object) === "undefined"; + } + + if (matcher === null) { + return object === null; + } + + if (getClass(object) === "Array" && getClass(matcher) === "Array") { + return arrayContains(object, matcher); + } + + if (matcher && typeof matcher === "object") { + if (matcher === object) { + return true; + } + var prop; + for (prop in matcher) { + var value = object[prop]; + if (typeof value === "undefined" && + typeof object.getAttribute === "function") { + value = object.getAttribute(prop); + } + if (matcher[prop] === null || typeof matcher[prop] === 'undefined') { + if (value !== matcher[prop]) { + return false; + } + } else if (typeof value === "undefined" || !match(value, matcher[prop])) { + return false; + } + } + return true; + } + + throw new Error("Matcher was not a string, a number, a " + + "function, a boolean or an object"); + }; + + return { + isArguments: isArguments, + isElement: isElement, + isDate: isDate, + isNegZero: isNegZero, + identical: identical, + deepEqual: deepEqualCyclic, + match: match, + keys: keys + }; +}); +((typeof define === "function" && define.amd && function (m) { + define("formatio", ["samsam"], m); +}) || (typeof module === "object" && function (m) { + module.exports = m(require("samsam")); +}) || function (m) { this.formatio = m(this.samsam); } +)(function (samsam) { + + var formatio = { + excludeConstructors: ["Object", /^.$/], + quoteStrings: true, + limitChildrenCount: 0 + }; + + var hasOwn = Object.prototype.hasOwnProperty; + + var specialObjects = []; + if (typeof global !== "undefined") { + specialObjects.push({ object: global, value: "[object global]" }); + } + if (typeof document !== "undefined") { + specialObjects.push({ + object: document, + value: "[object HTMLDocument]" + }); + } + if (typeof window !== "undefined") { + specialObjects.push({ object: window, value: "[object Window]" }); + } + + function functionName(func) { + if (!func) { return ""; } + if (func.displayName) { return func.displayName; } + if (func.name) { return func.name; } + var matches = func.toString().match(/function\s+([^\(]+)/m); + return (matches && matches[1]) || ""; + } + + function constructorName(f, object) { + var name = functionName(object && object.constructor); + var excludes = f.excludeConstructors || + formatio.excludeConstructors || []; + + var i, l; + for (i = 0, l = excludes.length; i < l; ++i) { + if (typeof excludes[i] === "string" && excludes[i] === name) { + return ""; + } else if (excludes[i].test && excludes[i].test(name)) { + return ""; + } + } + + return name; + } + + function isCircular(object, objects) { + if (typeof object !== "object") { return false; } + var i, l; + for (i = 0, l = objects.length; i < l; ++i) { + if (objects[i] === object) { return true; } + } + return false; + } + + function ascii(f, object, processed, indent) { + if (typeof object === "string") { + var qs = f.quoteStrings; + var quote = typeof qs !== "boolean" || qs; + return processed || quote ? '"' + object + '"' : object; + } + + if (typeof object === "function" && !(object instanceof RegExp)) { + return ascii.func(object); + } + + processed = processed || []; + + if (isCircular(object, processed)) { return "[Circular]"; } + + if (Object.prototype.toString.call(object) === "[object Array]") { + return ascii.array.call(f, object, processed); + } + + if (!object) { return String((1/object) === -Infinity ? "-0" : object); } + if (samsam.isElement(object)) { return ascii.element(object); } + + if (typeof object.toString === "function" && + object.toString !== Object.prototype.toString) { + return object.toString(); + } + + var i, l; + for (i = 0, l = specialObjects.length; i < l; i++) { + if (object === specialObjects[i].object) { + return specialObjects[i].value; + } + } + + return ascii.object.call(f, object, processed, indent); + } + + ascii.func = function (func) { + return "function " + functionName(func) + "() {}"; + }; + + ascii.array = function (array, processed) { + processed = processed || []; + processed.push(array); + var pieces = []; + var i, l; + l = (this.limitChildrenCount > 0) ? + Math.min(this.limitChildrenCount, array.length) : array.length; + + for (i = 0; i < l; ++i) { + pieces.push(ascii(this, array[i], processed)); + } + + if(l < array.length) + pieces.push("[... " + (array.length - l) + " more elements]"); + + return "[" + pieces.join(", ") + "]"; + }; + + ascii.object = function (object, processed, indent) { + processed = processed || []; + processed.push(object); + indent = indent || 0; + var pieces = [], properties = samsam.keys(object).sort(); + var length = 3; + var prop, str, obj, i, k, l; + l = (this.limitChildrenCount > 0) ? + Math.min(this.limitChildrenCount, properties.length) : properties.length; + + for (i = 0; i < l; ++i) { + prop = properties[i]; + obj = object[prop]; + + if (isCircular(obj, processed)) { + str = "[Circular]"; + } else { + str = ascii(this, obj, processed, indent + 2); + } + + str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str; + length += str.length; + pieces.push(str); + } + + var cons = constructorName(this, object); + var prefix = cons ? "[" + cons + "] " : ""; + var is = ""; + for (i = 0, k = indent; i < k; ++i) { is += " "; } + + if(l < properties.length) + pieces.push("[... " + (properties.length - l) + " more elements]"); + + if (length + indent > 80) { + return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + + is + "}"; + } + return prefix + "{ " + pieces.join(", ") + " }"; + }; + + ascii.element = function (element) { + var tagName = element.tagName.toLowerCase(); + var attrs = element.attributes, attr, pairs = [], attrName, i, l, val; + + for (i = 0, l = attrs.length; i < l; ++i) { + attr = attrs.item(i); + attrName = attr.nodeName.toLowerCase().replace("html:", ""); + val = attr.nodeValue; + if (attrName !== "contenteditable" || val !== "inherit") { + if (!!val) { pairs.push(attrName + "=\"" + val + "\""); } + } + } + + var formatted = "<" + tagName + (pairs.length > 0 ? " " : ""); + var content = element.innerHTML; + + if (content.length > 20) { + content = content.substr(0, 20) + "[...]"; + } + + var res = formatted + pairs.join(" ") + ">" + content + + ""; + + return res.replace(/ contentEditable="inherit"/, ""); + }; + + function Formatio(options) { + for (var opt in options) { + this[opt] = options[opt]; + } + } + + Formatio.prototype = { + functionName: functionName, + + configure: function (options) { + return new Formatio(options); + }, + + constructorName: function (object) { + return constructorName(this, object); + }, + + ascii: function (object, processed, indent) { + return ascii(this, object, processed, indent); + } + }; + + return Formatio.prototype; +}); +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.lolex=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { + throw new Error("tick only understands numbers and 'h:m:s'"); + } + + while (i--) { + parsed = parseInt(strings[i], 10); + + if (parsed >= 60) { + throw new Error("Invalid time " + str); + } + + ms += parsed * Math.pow(60, (l - i - 1)); + } + + return ms * 1000; +} + +/** + * Used to grok the `now` parameter to createClock. + */ +function getEpoch(epoch) { + if (!epoch) { return 0; } + if (typeof epoch.getTime === "function") { return epoch.getTime(); } + if (typeof epoch === "number") { return epoch; } + throw new TypeError("now should be milliseconds since UNIX epoch"); +} + +function inRange(from, to, timer) { + return timer && timer.callAt >= from && timer.callAt <= to; +} + +function mirrorDateProperties(target, source) { + if (source.now) { + target.now = function now() { + return target.clock.now; + }; + } else { + delete target.now; + } + + if (source.toSource) { + target.toSource = function toSource() { + return source.toSource(); + }; + } else { + delete target.toSource; + } + + target.toString = function toString() { + return source.toString(); + }; + + target.prototype = source.prototype; + target.parse = source.parse; + target.UTC = source.UTC; + target.prototype.toUTCString = source.prototype.toUTCString; + + for (var prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + + return target; +} + +function createDate() { + function ClockDate(year, month, date, hour, minute, second, ms) { + // Defensive and verbose to avoid potential harm in passing + // explicit undefined when user does not pass argument + switch (arguments.length) { + case 0: + return new NativeDate(ClockDate.clock.now); + case 1: + return new NativeDate(year); + case 2: + return new NativeDate(year, month); + case 3: + return new NativeDate(year, month, date); + case 4: + return new NativeDate(year, month, date, hour); + case 5: + return new NativeDate(year, month, date, hour, minute); + case 6: + return new NativeDate(year, month, date, hour, minute, second); + default: + return new NativeDate(year, month, date, hour, minute, second, ms); + } + } + + return mirrorDateProperties(ClockDate, NativeDate); +} + +function addTimer(clock, timer) { + if (typeof timer.func === "undefined") { + throw new Error("Callback must be provided to timer calls"); + } + + if (!clock.timers) { + clock.timers = {}; + } + + timer.id = id++; + timer.createdAt = clock.now; + timer.callAt = clock.now + (timer.delay || 0); + + clock.timers[timer.id] = timer; + + if (addTimerReturnsObject) { + return { + id: timer.id, + ref: function() {}, + unref: function() {} + }; + } + else { + return timer.id; + } +} + +function firstTimerInRange(clock, from, to) { + var timers = clock.timers, timer = null; + + for (var id in timers) { + if (!inRange(from, to, timers[id])) { + continue; + } + + if (!timer || ~compareTimers(timer, timers[id])) { + timer = timers[id]; + } + } + + return timer; +} + +function compareTimers(a, b) { + // Sort first by absolute timing + if (a.callAt < b.callAt) { + return -1; + } + if (a.callAt > b.callAt) { + return 1; + } + + // Sort next by immediate, immediate timers take precedence + if (a.immediate && !b.immediate) { + return -1; + } + if (!a.immediate && b.immediate) { + return 1; + } + + // Sort next by creation time, earlier-created timers take precedence + if (a.createdAt < b.createdAt) { + return -1; + } + if (a.createdAt > b.createdAt) { + return 1; + } + + // Sort next by id, lower-id timers take precedence + if (a.id < b.id) { + return -1; + } + if (a.id > b.id) { + return 1; + } + + // As timer ids are unique, no fallback `0` is necessary +} + +function callTimer(clock, timer) { + if (typeof timer.interval == "number") { + clock.timers[timer.id].callAt += timer.interval; + } else { + delete clock.timers[timer.id]; + } + + try { + if (typeof timer.func == "function") { + timer.func.apply(null, timer.args); + } else { + eval(timer.func); + } + } catch (e) { + var exception = e; + } + + if (!clock.timers[timer.id]) { + if (exception) { + throw exception; + } + return; + } + + if (exception) { + throw exception; + } +} + +function uninstall(clock, target) { + var method; + + for (var i = 0, l = clock.methods.length; i < l; i++) { + method = clock.methods[i]; + + if (target[method].hadOwnProperty) { + target[method] = clock["_" + method]; + } else { + try { + delete target[method]; + } catch (e) {} + } + } + + // Prevent multiple executions which will completely remove these props + clock.methods = []; +} + +function hijackMethod(target, method, clock) { + clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method); + clock["_" + method] = target[method]; + + if (method == "Date") { + var date = mirrorDateProperties(clock[method], target[method]); + target[method] = date; + } else { + target[method] = function () { + return clock[method].apply(clock, arguments); + }; + + for (var prop in clock[method]) { + if (clock[method].hasOwnProperty(prop)) { + target[method][prop] = clock[method][prop]; + } + } + } + + target[method].clock = clock; +} + +var timers = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), + clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined), + setInterval: setInterval, + clearInterval: clearInterval, + Date: Date +}; + +var keys = Object.keys || function (obj) { + var ks = []; + for (var key in obj) { + ks.push(key); + } + return ks; +}; + +exports.timers = timers; + +var createClock = exports.createClock = function (now) { + var clock = { + now: getEpoch(now), + timeouts: {}, + Date: createDate() + }; + + clock.Date.clock = clock; + + clock.setTimeout = function setTimeout(func, timeout) { + return addTimer(clock, { + func: func, + args: Array.prototype.slice.call(arguments, 2), + delay: timeout + }); + }; + + clock.clearTimeout = function clearTimeout(timerId) { + if (!timerId) { + // null appears to be allowed in most browsers, and appears to be + // relied upon by some libraries, like Bootstrap carousel + return; + } + if (!clock.timers) { + clock.timers = []; + } + // in Node, timerId is an object with .ref()/.unref(), and + // its .id field is the actual timer id. + if (typeof timerId === "object") { + timerId = timerId.id + } + if (timerId in clock.timers) { + delete clock.timers[timerId]; + } + }; + + clock.setInterval = function setInterval(func, timeout) { + return addTimer(clock, { + func: func, + args: Array.prototype.slice.call(arguments, 2), + delay: timeout, + interval: timeout + }); + }; + + clock.clearInterval = function clearInterval(timerId) { + clock.clearTimeout(timerId); + }; + + clock.setImmediate = function setImmediate(func) { + return addTimer(clock, { + func: func, + args: Array.prototype.slice.call(arguments, 1), + immediate: true + }); + }; + + clock.clearImmediate = function clearImmediate(timerId) { + clock.clearTimeout(timerId); + }; + + clock.tick = function tick(ms) { + ms = typeof ms == "number" ? ms : parseTime(ms); + var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now; + var timer = firstTimerInRange(clock, tickFrom, tickTo); + + var firstException; + while (timer && tickFrom <= tickTo) { + if (clock.timers[timer.id]) { + tickFrom = clock.now = timer.callAt; + try { + callTimer(clock, timer); + } catch (e) { + firstException = firstException || e; + } + } + + timer = firstTimerInRange(clock, previous, tickTo); + previous = tickFrom; + } + + clock.now = tickTo; + + if (firstException) { + throw firstException; + } + + return clock.now; + }; + + clock.reset = function reset() { + clock.timers = {}; + }; + + return clock; +}; + +exports.install = function install(target, now, toFake) { + if (typeof target === "number") { + toFake = now; + now = target; + target = null; + } + + if (!target) { + target = global; + } + + var clock = createClock(now); + + clock.uninstall = function () { + uninstall(clock, target); + }; + + clock.methods = toFake || []; + + if (clock.methods.length === 0) { + clock.methods = keys(timers); + } + + for (var i = 0, l = clock.methods.length; i < l; i++) { + hijackMethod(target, clock.methods[i], clock); + } + + return clock; +}; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}]},{},[1])(1) +}); + })(); + var define; +/** + * Sinon core utilities. For internal use only. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +var sinon = (function () { +"use strict"; + + var sinon; + var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + sinon = module.exports = require("./sinon/util/core"); + require("./sinon/extend"); + require("./sinon/typeOf"); + require("./sinon/times_in_words"); + require("./sinon/spy"); + require("./sinon/call"); + require("./sinon/behavior"); + require("./sinon/stub"); + require("./sinon/mock"); + require("./sinon/collection"); + require("./sinon/assert"); + require("./sinon/sandbox"); + require("./sinon/test"); + require("./sinon/test_case"); + require("./sinon/match"); + require("./sinon/format"); + require("./sinon/log_error"); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + sinon = module.exports; + } else { + sinon = {}; + } + + return sinon; +}()); + +/** + * @depend ../../sinon.js + */ +/** + * Sinon core utilities. For internal use only. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var div = typeof document != "undefined" && document.createElement("div"); + var hasOwn = Object.prototype.hasOwnProperty; + + function isDOMNode(obj) { + var success = false; + + try { + obj.appendChild(div); + success = div.parentNode == obj; + } catch (e) { + return false; + } finally { + try { + obj.removeChild(div); + } catch (e) { + // Remove failed, not much we can do about that + } + } + + return success; + } + + function isElement(obj) { + return div && obj && obj.nodeType === 1 && isDOMNode(obj); + } + + function isFunction(obj) { + return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply); + } + + function isReallyNaN(val) { + return typeof val === "number" && isNaN(val); + } + + function mirrorProperties(target, source) { + for (var prop in source) { + if (!hasOwn.call(target, prop)) { + target[prop] = source[prop]; + } + } + } + + function isRestorable(obj) { + return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon; + } + + // Cheap way to detect if we have ES5 support. + var hasES5Support = "keys" in Object; + + function makeApi(sinon) { + sinon.wrapMethod = function wrapMethod(object, property, method) { + if (!object) { + throw new TypeError("Should wrap property of object"); + } + + if (typeof method != "function" && typeof method != "object") { + throw new TypeError("Method wrapper should be a function or a property descriptor"); + } + + function checkWrappedMethod(wrappedMethod) { + if (!isFunction(wrappedMethod)) { + error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + + property + " as function"); + } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) { + error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); + } else if (wrappedMethod.calledBefore) { + var verb = !!wrappedMethod.returns ? "stubbed" : "spied on"; + error = new TypeError("Attempted to wrap " + property + " which is already " + verb); + } + + if (error) { + if (wrappedMethod && wrappedMethod.stackTrace) { + error.stack += "\n--------------\n" + wrappedMethod.stackTrace; + } + throw error; + } + } + + var error, wrappedMethod; + + // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem + // when using hasOwn.call on objects from other frames. + var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property); + + if (hasES5Support) { + var methodDesc = (typeof method == "function") ? {value: method} : method, + wrappedMethodDesc = sinon.getPropertyDescriptor(object, property), + i; + + if (!wrappedMethodDesc) { + error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + + property + " as function"); + } else if (wrappedMethodDesc.restore && wrappedMethodDesc.restore.sinon) { + error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); + } + if (error) { + if (wrappedMethodDesc && wrappedMethodDesc.stackTrace) { + error.stack += "\n--------------\n" + wrappedMethodDesc.stackTrace; + } + throw error; + } + + var types = sinon.objectKeys(methodDesc); + for (i = 0; i < types.length; i++) { + wrappedMethod = wrappedMethodDesc[types[i]]; + checkWrappedMethod(wrappedMethod); + } + + mirrorProperties(methodDesc, wrappedMethodDesc); + for (i = 0; i < types.length; i++) { + mirrorProperties(methodDesc[types[i]], wrappedMethodDesc[types[i]]); + } + Object.defineProperty(object, property, methodDesc); + } else { + wrappedMethod = object[property]; + checkWrappedMethod(wrappedMethod); + object[property] = method; + method.displayName = property; + } + + method.displayName = property; + + // Set up a stack trace which can be used later to find what line of + // code the original method was created on. + method.stackTrace = (new Error("Stack Trace for original")).stack; + + method.restore = function () { + // For prototype properties try to reset by delete first. + // If this fails (ex: localStorage on mobile safari) then force a reset + // via direct assignment. + if (!owned) { + try { + delete object[property]; + } catch (e) {} + // For native code functions `delete` fails without throwing an error + // on Chrome < 43, PhantomJS, etc. + // Use strict equality comparison to check failures then force a reset + // via direct assignment. + if (object[property] === method) { + object[property] = wrappedMethod; + } + } else if (hasES5Support) { + Object.defineProperty(object, property, wrappedMethodDesc); + } + + if (!hasES5Support && object[property] === method) { + object[property] = wrappedMethod; + } + }; + + method.restore.sinon = true; + + if (!hasES5Support) { + mirrorProperties(method, wrappedMethod); + } + + return method; + }; + + sinon.create = function create(proto) { + var F = function () {}; + F.prototype = proto; + return new F(); + }; + + sinon.deepEqual = function deepEqual(a, b) { + if (sinon.match && sinon.match.isMatcher(a)) { + return a.test(b); + } + + if (typeof a != "object" || typeof b != "object") { + if (isReallyNaN(a) && isReallyNaN(b)) { + return true; + } else { + return a === b; + } + } + + if (isElement(a) || isElement(b)) { + return a === b; + } + + if (a === b) { + return true; + } + + if ((a === null && b !== null) || (a !== null && b === null)) { + return false; + } + + if (a instanceof RegExp && b instanceof RegExp) { + return (a.source === b.source) && (a.global === b.global) && + (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline); + } + + var aString = Object.prototype.toString.call(a); + if (aString != Object.prototype.toString.call(b)) { + return false; + } + + if (aString == "[object Date]") { + return a.valueOf() === b.valueOf(); + } + + var prop, aLength = 0, bLength = 0; + + if (aString == "[object Array]" && a.length !== b.length) { + return false; + } + + for (prop in a) { + aLength += 1; + + if (!(prop in b)) { + return false; + } + + if (!deepEqual(a[prop], b[prop])) { + return false; + } + } + + for (prop in b) { + bLength += 1; + } + + return aLength == bLength; + }; + + sinon.functionName = function functionName(func) { + var name = func.displayName || func.name; + + // Use function decomposition as a last resort to get function + // name. Does not rely on function decomposition to work - if it + // doesn't debugging will be slightly less informative + // (i.e. toString will say 'spy' rather than 'myFunc'). + if (!name) { + var matches = func.toString().match(/function ([^\s\(]+)/); + name = matches && matches[1]; + } + + return name; + }; + + sinon.functionToString = function toString() { + if (this.getCall && this.callCount) { + var thisValue, prop, i = this.callCount; + + while (i--) { + thisValue = this.getCall(i).thisValue; + + for (prop in thisValue) { + if (thisValue[prop] === this) { + return prop; + } + } + } + } + + return this.displayName || "sinon fake"; + }; + + sinon.objectKeys = function objectKeys(obj) { + if (obj !== Object(obj)) { + throw new TypeError("sinon.objectKeys called on a non-object"); + } + + var keys = []; + var key; + for (key in obj) { + if (hasOwn.call(obj, key)) { + keys.push(key); + } + } + + return keys; + }; + + sinon.getPropertyDescriptor = function getPropertyDescriptor(object, property) { + var proto = object, descriptor; + while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) { + proto = Object.getPrototypeOf(proto); + } + return descriptor; + } + + sinon.getConfig = function (custom) { + var config = {}; + custom = custom || {}; + var defaults = sinon.defaultConfig; + + for (var prop in defaults) { + if (defaults.hasOwnProperty(prop)) { + config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop]; + } + } + + return config; + }; + + sinon.defaultConfig = { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "server", "requests"], + useFakeTimers: true, + useFakeServer: true + }; + + sinon.timesInWords = function timesInWords(count) { + return count == 1 && "once" || + count == 2 && "twice" || + count == 3 && "thrice" || + (count || 0) + " times"; + }; + + sinon.calledInOrder = function (spies) { + for (var i = 1, l = spies.length; i < l; i++) { + if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) { + return false; + } + } + + return true; + }; + + sinon.orderByFirstCall = function (spies) { + return spies.sort(function (a, b) { + // uuid, won't ever be equal + var aCall = a.getCall(0); + var bCall = b.getCall(0); + var aId = aCall && aCall.callId || -1; + var bId = bCall && bCall.callId || -1; + + return aId < bId ? -1 : 1; + }); + }; + + sinon.createStubInstance = function (constructor) { + if (typeof constructor !== "function") { + throw new TypeError("The constructor should be a function."); + } + return sinon.stub(sinon.create(constructor.prototype)); + }; + + sinon.restore = function (object) { + if (object !== null && typeof object === "object") { + for (var prop in object) { + if (isRestorable(object[prop])) { + object[prop].restore(); + } + } + } else if (isRestorable(object)) { + object.restore(); + } + }; + + return sinon; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports) { + makeApi(exports); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend util/core.js + */ + +(function (sinon) { + function makeApi(sinon) { + + // Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug + var hasDontEnumBug = (function () { + var obj = { + constructor: function () { + return "0"; + }, + toString: function () { + return "1"; + }, + valueOf: function () { + return "2"; + }, + toLocaleString: function () { + return "3"; + }, + prototype: function () { + return "4"; + }, + isPrototypeOf: function () { + return "5"; + }, + propertyIsEnumerable: function () { + return "6"; + }, + hasOwnProperty: function () { + return "7"; + }, + length: function () { + return "8"; + }, + unique: function () { + return "9" + } + }; + + var result = []; + for (var prop in obj) { + result.push(obj[prop]()); + } + return result.join("") !== "0123456789"; + })(); + + /* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will + * override properties in previous sources. + * + * target - The Object to extend + * sources - Objects to copy properties from. + * + * Returns the extended target + */ + function extend(target /*, sources */) { + var sources = Array.prototype.slice.call(arguments, 1), + source, i, prop; + + for (i = 0; i < sources.length; i++) { + source = sources[i]; + + for (prop in source) { + if (source.hasOwnProperty(prop)) { + target[prop] = source[prop]; + } + } + + // Make sure we copy (own) toString method even when in JScript with DontEnum bug + // See https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug + if (hasDontEnumBug && source.hasOwnProperty("toString") && source.toString !== target.toString) { + target.toString = source.toString; + } + } + + return target; + }; + + sinon.extend = extend; + return sinon.extend; + } + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + module.exports = makeApi(sinon); + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend util/core.js + */ + +(function (sinon) { + function makeApi(sinon) { + + function timesInWords(count) { + switch (count) { + case 1: + return "once"; + case 2: + return "twice"; + case 3: + return "thrice"; + default: + return (count || 0) + " times"; + } + } + + sinon.timesInWords = timesInWords; + return sinon.timesInWords; + } + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + module.exports = makeApi(sinon); + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend util/core.js + */ +/** + * Format functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2014 Christian Johansen + */ + +(function (sinon, formatio) { + function makeApi(sinon) { + function typeOf(value) { + if (value === null) { + return "null"; + } else if (value === undefined) { + return "undefined"; + } + var string = Object.prototype.toString.call(value); + return string.substring(8, string.length - 1).toLowerCase(); + }; + + sinon.typeOf = typeOf; + return sinon.typeOf; + } + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + module.exports = makeApi(sinon); + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}( + (typeof sinon == "object" && sinon || null), + (typeof formatio == "object" && formatio) +)); + +/** + * @depend util/core.js + * @depend typeOf.js + */ +/*jslint eqeqeq: false, onevar: false, plusplus: false*/ +/*global module, require, sinon*/ +/** + * Match functions + * + * @author Maximilian Antoni (mail@maxantoni.de) + * @license BSD + * + * Copyright (c) 2012 Maximilian Antoni + */ + +(function (sinon) { + function makeApi(sinon) { + function assertType(value, type, name) { + var actual = sinon.typeOf(value); + if (actual !== type) { + throw new TypeError("Expected type of " + name + " to be " + + type + ", but was " + actual); + } + } + + var matcher = { + toString: function () { + return this.message; + } + }; + + function isMatcher(object) { + return matcher.isPrototypeOf(object); + } + + function matchObject(expectation, actual) { + if (actual === null || actual === undefined) { + return false; + } + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + var exp = expectation[key]; + var act = actual[key]; + if (match.isMatcher(exp)) { + if (!exp.test(act)) { + return false; + } + } else if (sinon.typeOf(exp) === "object") { + if (!matchObject(exp, act)) { + return false; + } + } else if (!sinon.deepEqual(exp, act)) { + return false; + } + } + } + return true; + } + + matcher.or = function (m2) { + if (!arguments.length) { + throw new TypeError("Matcher expected"); + } else if (!isMatcher(m2)) { + m2 = match(m2); + } + var m1 = this; + var or = sinon.create(matcher); + or.test = function (actual) { + return m1.test(actual) || m2.test(actual); + }; + or.message = m1.message + ".or(" + m2.message + ")"; + return or; + }; + + matcher.and = function (m2) { + if (!arguments.length) { + throw new TypeError("Matcher expected"); + } else if (!isMatcher(m2)) { + m2 = match(m2); + } + var m1 = this; + var and = sinon.create(matcher); + and.test = function (actual) { + return m1.test(actual) && m2.test(actual); + }; + and.message = m1.message + ".and(" + m2.message + ")"; + return and; + }; + + var match = function (expectation, message) { + var m = sinon.create(matcher); + var type = sinon.typeOf(expectation); + switch (type) { + case "object": + if (typeof expectation.test === "function") { + m.test = function (actual) { + return expectation.test(actual) === true; + }; + m.message = "match(" + sinon.functionName(expectation.test) + ")"; + return m; + } + var str = []; + for (var key in expectation) { + if (expectation.hasOwnProperty(key)) { + str.push(key + ": " + expectation[key]); + } + } + m.test = function (actual) { + return matchObject(expectation, actual); + }; + m.message = "match(" + str.join(", ") + ")"; + break; + case "number": + m.test = function (actual) { + return expectation == actual; + }; + break; + case "string": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return actual.indexOf(expectation) !== -1; + }; + m.message = "match(\"" + expectation + "\")"; + break; + case "regexp": + m.test = function (actual) { + if (typeof actual !== "string") { + return false; + } + return expectation.test(actual); + }; + break; + case "function": + m.test = expectation; + if (message) { + m.message = message; + } else { + m.message = "match(" + sinon.functionName(expectation) + ")"; + } + break; + default: + m.test = function (actual) { + return sinon.deepEqual(expectation, actual); + }; + } + if (!m.message) { + m.message = "match(" + expectation + ")"; + } + return m; + }; + + match.isMatcher = isMatcher; + + match.any = match(function () { + return true; + }, "any"); + + match.defined = match(function (actual) { + return actual !== null && actual !== undefined; + }, "defined"); + + match.truthy = match(function (actual) { + return !!actual; + }, "truthy"); + + match.falsy = match(function (actual) { + return !actual; + }, "falsy"); + + match.same = function (expectation) { + return match(function (actual) { + return expectation === actual; + }, "same(" + expectation + ")"); + }; + + match.typeOf = function (type) { + assertType(type, "string", "type"); + return match(function (actual) { + return sinon.typeOf(actual) === type; + }, "typeOf(\"" + type + "\")"); + }; + + match.instanceOf = function (type) { + assertType(type, "function", "type"); + return match(function (actual) { + return actual instanceof type; + }, "instanceOf(" + sinon.functionName(type) + ")"); + }; + + function createPropertyMatcher(propertyTest, messagePrefix) { + return function (property, value) { + assertType(property, "string", "property"); + var onlyProperty = arguments.length === 1; + var message = messagePrefix + "(\"" + property + "\""; + if (!onlyProperty) { + message += ", " + value; + } + message += ")"; + return match(function (actual) { + if (actual === undefined || actual === null || + !propertyTest(actual, property)) { + return false; + } + return onlyProperty || sinon.deepEqual(value, actual[property]); + }, message); + }; + } + + match.has = createPropertyMatcher(function (actual, property) { + if (typeof actual === "object") { + return property in actual; + } + return actual[property] !== undefined; + }, "has"); + + match.hasOwn = createPropertyMatcher(function (actual, property) { + return actual.hasOwnProperty(property); + }, "hasOwn"); + + match.bool = match.typeOf("boolean"); + match.number = match.typeOf("number"); + match.string = match.typeOf("string"); + match.object = match.typeOf("object"); + match.func = match.typeOf("function"); + match.array = match.typeOf("array"); + match.regexp = match.typeOf("regexp"); + match.date = match.typeOf("date"); + + sinon.match = match; + return match; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./typeOf"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend util/core.js + */ +/** + * Format functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2014 Christian Johansen + */ + +(function (sinon, formatio) { + function makeApi(sinon) { + function valueFormatter(value) { + return "" + value; + } + + function getFormatioFormatter() { + var formatter = formatio.configure({ + quoteStrings: false, + limitChildrenCount: 250 + }); + + function format() { + return formatter.ascii.apply(formatter, arguments); + }; + + return format; + } + + function getNodeFormatter(value) { + function format(value) { + return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value; + }; + + try { + var util = require("util"); + } catch (e) { + /* Node, but no util module - would be very old, but better safe than sorry */ + } + + return util ? format : valueFormatter; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function", + formatter; + + if (isNode) { + try { + formatio = require("formatio"); + } catch (e) {} + } + + if (formatio) { + formatter = getFormatioFormatter() + } else if (isNode) { + formatter = getNodeFormatter(); + } else { + formatter = valueFormatter; + } + + sinon.format = formatter; + return sinon.format; + } + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + module.exports = makeApi(sinon); + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}( + (typeof sinon == "object" && sinon || null), + (typeof formatio == "object" && formatio) +)); + +/** + * @depend util/core.js + * @depend match.js + * @depend format.js + */ +/** + * Spy calls + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Maximilian Antoni (mail@maxantoni.de) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + * Copyright (c) 2013 Maximilian Antoni + */ + +(function (sinon) { + function makeApi(sinon) { + function throwYieldError(proxy, text, args) { + var msg = sinon.functionName(proxy) + text; + if (args.length) { + msg += " Received [" + slice.call(args).join(", ") + "]"; + } + throw new Error(msg); + } + + var slice = Array.prototype.slice; + + var callProto = { + calledOn: function calledOn(thisValue) { + if (sinon.match && sinon.match.isMatcher(thisValue)) { + return thisValue.test(this.thisValue); + } + return this.thisValue === thisValue; + }, + + calledWith: function calledWith() { + var l = arguments.length; + if (l > this.args.length) { + return false; + } + for (var i = 0; i < l; i += 1) { + if (!sinon.deepEqual(arguments[i], this.args[i])) { + return false; + } + } + + return true; + }, + + calledWithMatch: function calledWithMatch() { + var l = arguments.length; + if (l > this.args.length) { + return false; + } + for (var i = 0; i < l; i += 1) { + var actual = this.args[i]; + var expectation = arguments[i]; + if (!sinon.match || !sinon.match(expectation).test(actual)) { + return false; + } + } + return true; + }, + + calledWithExactly: function calledWithExactly() { + return arguments.length == this.args.length && + this.calledWith.apply(this, arguments); + }, + + notCalledWith: function notCalledWith() { + return !this.calledWith.apply(this, arguments); + }, + + notCalledWithMatch: function notCalledWithMatch() { + return !this.calledWithMatch.apply(this, arguments); + }, + + returned: function returned(value) { + return sinon.deepEqual(value, this.returnValue); + }, + + threw: function threw(error) { + if (typeof error === "undefined" || !this.exception) { + return !!this.exception; + } + + return this.exception === error || this.exception.name === error; + }, + + calledWithNew: function calledWithNew() { + return this.proxy.prototype && this.thisValue instanceof this.proxy; + }, + + calledBefore: function (other) { + return this.callId < other.callId; + }, + + calledAfter: function (other) { + return this.callId > other.callId; + }, + + callArg: function (pos) { + this.args[pos](); + }, + + callArgOn: function (pos, thisValue) { + this.args[pos].apply(thisValue); + }, + + callArgWith: function (pos) { + this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1))); + }, + + callArgOnWith: function (pos, thisValue) { + var args = slice.call(arguments, 2); + this.args[pos].apply(thisValue, args); + }, + + yield: function () { + this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0))); + }, + + yieldOn: function (thisValue) { + var args = this.args; + for (var i = 0, l = args.length; i < l; ++i) { + if (typeof args[i] === "function") { + args[i].apply(thisValue, slice.call(arguments, 1)); + return; + } + } + throwYieldError(this.proxy, " cannot yield since no callback was passed.", args); + }, + + yieldTo: function (prop) { + this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1))); + }, + + yieldToOn: function (prop, thisValue) { + var args = this.args; + for (var i = 0, l = args.length; i < l; ++i) { + if (args[i] && typeof args[i][prop] === "function") { + args[i][prop].apply(thisValue, slice.call(arguments, 2)); + return; + } + } + throwYieldError(this.proxy, " cannot yield to '" + prop + + "' since no callback was passed.", args); + }, + + toString: function () { + var callStr = this.proxy.toString() + "("; + var args = []; + + for (var i = 0, l = this.args.length; i < l; ++i) { + args.push(sinon.format(this.args[i])); + } + + callStr = callStr + args.join(", ") + ")"; + + if (typeof this.returnValue != "undefined") { + callStr += " => " + sinon.format(this.returnValue); + } + + if (this.exception) { + callStr += " !" + this.exception.name; + + if (this.exception.message) { + callStr += "(" + this.exception.message + ")"; + } + } + + return callStr; + } + }; + + callProto.invokeCallback = callProto.yield; + + function createSpyCall(spy, thisValue, args, returnValue, exception, id) { + if (typeof id !== "number") { + throw new TypeError("Call id is not a number"); + } + var proxyCall = sinon.create(callProto); + proxyCall.proxy = spy; + proxyCall.thisValue = thisValue; + proxyCall.args = args; + proxyCall.returnValue = returnValue; + proxyCall.exception = exception; + proxyCall.callId = id; + + return proxyCall; + } + createSpyCall.toString = callProto.toString; // used by mocks + + sinon.spyCall = createSpyCall; + return createSpyCall; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./match"); + require("./format"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend times_in_words.js + * @depend util/core.js + * @depend extend.js + * @depend call.js + * @depend format.js + */ +/** + * Spy functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + + function makeApi(sinon) { + var push = Array.prototype.push; + var slice = Array.prototype.slice; + var callId = 0; + + function spy(object, property, types) { + if (!property && typeof object == "function") { + return spy.create(object); + } + + if (!object && !property) { + return spy.create(function () { }); + } + + if (types) { + var methodDesc = sinon.getPropertyDescriptor(object, property); + for (var i = 0; i < types.length; i++) { + methodDesc[types[i]] = spy.create(methodDesc[types[i]]); + } + return sinon.wrapMethod(object, property, methodDesc); + } else { + var method = object[property]; + return sinon.wrapMethod(object, property, spy.create(method)); + } + } + + function matchingFake(fakes, args, strict) { + if (!fakes) { + return; + } + + for (var i = 0, l = fakes.length; i < l; i++) { + if (fakes[i].matches(args, strict)) { + return fakes[i]; + } + } + } + + function incrementCallCount() { + this.called = true; + this.callCount += 1; + this.notCalled = false; + this.calledOnce = this.callCount == 1; + this.calledTwice = this.callCount == 2; + this.calledThrice = this.callCount == 3; + } + + function createCallProperties() { + this.firstCall = this.getCall(0); + this.secondCall = this.getCall(1); + this.thirdCall = this.getCall(2); + this.lastCall = this.getCall(this.callCount - 1); + } + + var vars = "a,b,c,d,e,f,g,h,i,j,k,l"; + function createProxy(func, proxyLength) { + // Retain the function length: + var p; + if (proxyLength) { + eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) + + ") { return p.invoke(func, this, slice.call(arguments)); });"); + } else { + p = function proxy() { + return p.invoke(func, this, slice.call(arguments)); + }; + } + return p; + } + + var uuid = 0; + + // Public API + var spyApi = { + reset: function () { + if (this.invoking) { + var err = new Error("Cannot reset Sinon function while invoking it. " + + "Move the call to .reset outside of the callback."); + err.name = "InvalidResetException"; + throw err; + } + + this.called = false; + this.notCalled = true; + this.calledOnce = false; + this.calledTwice = false; + this.calledThrice = false; + this.callCount = 0; + this.firstCall = null; + this.secondCall = null; + this.thirdCall = null; + this.lastCall = null; + this.args = []; + this.returnValues = []; + this.thisValues = []; + this.exceptions = []; + this.callIds = []; + if (this.fakes) { + for (var i = 0; i < this.fakes.length; i++) { + this.fakes[i].reset(); + } + } + + return this; + }, + + create: function create(func, spyLength) { + var name; + + if (typeof func != "function") { + func = function () { }; + } else { + name = sinon.functionName(func); + } + + if (!spyLength) { + spyLength = func.length; + } + + var proxy = createProxy(func, spyLength); + + sinon.extend(proxy, spy); + delete proxy.create; + sinon.extend(proxy, func); + + proxy.reset(); + proxy.prototype = func.prototype; + proxy.displayName = name || "spy"; + proxy.toString = sinon.functionToString; + proxy.instantiateFake = sinon.spy.create; + proxy.id = "spy#" + uuid++; + + return proxy; + }, + + invoke: function invoke(func, thisValue, args) { + var matching = matchingFake(this.fakes, args); + var exception, returnValue; + + incrementCallCount.call(this); + push.call(this.thisValues, thisValue); + push.call(this.args, args); + push.call(this.callIds, callId++); + + // Make call properties available from within the spied function: + createCallProperties.call(this); + + try { + this.invoking = true; + + if (matching) { + returnValue = matching.invoke(func, thisValue, args); + } else { + returnValue = (this.func || func).apply(thisValue, args); + } + + var thisCall = this.getCall(this.callCount - 1); + if (thisCall.calledWithNew() && typeof returnValue !== "object") { + returnValue = thisValue; + } + } catch (e) { + exception = e; + } finally { + delete this.invoking; + } + + push.call(this.exceptions, exception); + push.call(this.returnValues, returnValue); + + // Make return value and exception available in the calls: + createCallProperties.call(this); + + if (exception !== undefined) { + throw exception; + } + + return returnValue; + }, + + named: function named(name) { + this.displayName = name; + return this; + }, + + getCall: function getCall(i) { + if (i < 0 || i >= this.callCount) { + return null; + } + + return sinon.spyCall(this, this.thisValues[i], this.args[i], + this.returnValues[i], this.exceptions[i], + this.callIds[i]); + }, + + getCalls: function () { + var calls = []; + var i; + + for (i = 0; i < this.callCount; i++) { + calls.push(this.getCall(i)); + } + + return calls; + }, + + calledBefore: function calledBefore(spyFn) { + if (!this.called) { + return false; + } + + if (!spyFn.called) { + return true; + } + + return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; + }, + + calledAfter: function calledAfter(spyFn) { + if (!this.called || !spyFn.called) { + return false; + } + + return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; + }, + + withArgs: function () { + var args = slice.call(arguments); + + if (this.fakes) { + var match = matchingFake(this.fakes, args, true); + + if (match) { + return match; + } + } else { + this.fakes = []; + } + + var original = this; + var fake = this.instantiateFake(); + fake.matchingAguments = args; + fake.parent = this; + push.call(this.fakes, fake); + + fake.withArgs = function () { + return original.withArgs.apply(original, arguments); + }; + + for (var i = 0; i < this.args.length; i++) { + if (fake.matches(this.args[i])) { + incrementCallCount.call(fake); + push.call(fake.thisValues, this.thisValues[i]); + push.call(fake.args, this.args[i]); + push.call(fake.returnValues, this.returnValues[i]); + push.call(fake.exceptions, this.exceptions[i]); + push.call(fake.callIds, this.callIds[i]); + } + } + createCallProperties.call(fake); + + return fake; + }, + + matches: function (args, strict) { + var margs = this.matchingAguments; + + if (margs.length <= args.length && + sinon.deepEqual(margs, args.slice(0, margs.length))) { + return !strict || margs.length == args.length; + } + }, + + printf: function (format) { + var spy = this; + var args = slice.call(arguments, 1); + var formatter; + + return (format || "").replace(/%(.)/g, function (match, specifyer) { + formatter = spyApi.formatters[specifyer]; + + if (typeof formatter == "function") { + return formatter.call(null, spy, args); + } else if (!isNaN(parseInt(specifyer, 10))) { + return sinon.format(args[specifyer - 1]); + } + + return "%" + specifyer; + }); + } + }; + + function delegateToCalls(method, matchAny, actual, notCalled) { + spyApi[method] = function () { + if (!this.called) { + if (notCalled) { + return notCalled.apply(this, arguments); + } + return false; + } + + var currentCall; + var matches = 0; + + for (var i = 0, l = this.callCount; i < l; i += 1) { + currentCall = this.getCall(i); + + if (currentCall[actual || method].apply(currentCall, arguments)) { + matches += 1; + + if (matchAny) { + return true; + } + } + } + + return matches === this.callCount; + }; + } + + delegateToCalls("calledOn", true); + delegateToCalls("alwaysCalledOn", false, "calledOn"); + delegateToCalls("calledWith", true); + delegateToCalls("calledWithMatch", true); + delegateToCalls("alwaysCalledWith", false, "calledWith"); + delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch"); + delegateToCalls("calledWithExactly", true); + delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly"); + delegateToCalls("neverCalledWith", false, "notCalledWith", + function () { return true; }); + delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", + function () { return true; }); + delegateToCalls("threw", true); + delegateToCalls("alwaysThrew", false, "threw"); + delegateToCalls("returned", true); + delegateToCalls("alwaysReturned", false, "returned"); + delegateToCalls("calledWithNew", true); + delegateToCalls("alwaysCalledWithNew", false, "calledWithNew"); + delegateToCalls("callArg", false, "callArgWith", function () { + throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); + }); + spyApi.callArgWith = spyApi.callArg; + delegateToCalls("callArgOn", false, "callArgOnWith", function () { + throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); + }); + spyApi.callArgOnWith = spyApi.callArgOn; + delegateToCalls("yield", false, "yield", function () { + throw new Error(this.toString() + " cannot yield since it was not yet invoked."); + }); + // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. + spyApi.invokeCallback = spyApi.yield; + delegateToCalls("yieldOn", false, "yieldOn", function () { + throw new Error(this.toString() + " cannot yield since it was not yet invoked."); + }); + delegateToCalls("yieldTo", false, "yieldTo", function (property) { + throw new Error(this.toString() + " cannot yield to '" + property + + "' since it was not yet invoked."); + }); + delegateToCalls("yieldToOn", false, "yieldToOn", function (property) { + throw new Error(this.toString() + " cannot yield to '" + property + + "' since it was not yet invoked."); + }); + + spyApi.formatters = { + c: function (spy) { + return sinon.timesInWords(spy.callCount); + }, + + n: function (spy) { + return spy.toString(); + }, + + C: function (spy) { + var calls = []; + + for (var i = 0, l = spy.callCount; i < l; ++i) { + var stringifiedCall = " " + spy.getCall(i).toString(); + if (/\n/.test(calls[i - 1])) { + stringifiedCall = "\n" + stringifiedCall; + } + push.call(calls, stringifiedCall); + } + + return calls.length > 0 ? "\n" + calls.join("\n") : ""; + }, + + t: function (spy) { + var objects = []; + + for (var i = 0, l = spy.callCount; i < l; ++i) { + push.call(objects, sinon.format(spy.thisValues[i])); + } + + return objects.join(", "); + }, + + "*": function (spy, args) { + var formatted = []; + + for (var i = 0, l = args.length; i < l; ++i) { + push.call(formatted, sinon.format(args[i])); + } + + return formatted.join(", "); + } + }; + + sinon.extend(spy, spyApi); + + spy.spyCall = sinon.spyCall; + sinon.spy = spy; + + return spy; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./call"); + require("./extend"); + require("./times_in_words"); + require("./format"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend util/core.js + * @depend extend.js + */ +/** + * Stub behavior + * + * @author Christian Johansen (christian@cjohansen.no) + * @author Tim Fischbach (mail@timfischbach.de) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var slice = Array.prototype.slice; + var join = Array.prototype.join; + var useLeftMostCallback = -1; + var useRightMostCallback = -2; + + var nextTick = (function () { + if (typeof process === "object" && typeof process.nextTick === "function") { + return process.nextTick; + } else if (typeof setImmediate === "function") { + return setImmediate; + } else { + return function (callback) { + setTimeout(callback, 0); + }; + } + })(); + + function throwsException(error, message) { + if (typeof error == "string") { + this.exception = new Error(message || ""); + this.exception.name = error; + } else if (!error) { + this.exception = new Error("Error"); + } else { + this.exception = error; + } + + return this; + } + + function getCallback(behavior, args) { + var callArgAt = behavior.callArgAt; + + if (callArgAt >= 0) { + return args[callArgAt]; + } + + var argumentList; + + if (callArgAt === useLeftMostCallback) { + argumentList = args; + } + + if (callArgAt === useRightMostCallback) { + argumentList = slice.call(args).reverse(); + } + + var callArgProp = behavior.callArgProp; + + for (var i = 0, l = argumentList.length; i < l; ++i) { + if (!callArgProp && typeof argumentList[i] == "function") { + return argumentList[i]; + } + + if (callArgProp && argumentList[i] && + typeof argumentList[i][callArgProp] == "function") { + return argumentList[i][callArgProp]; + } + } + + return null; + } + + function makeApi(sinon) { + function getCallbackError(behavior, func, args) { + if (behavior.callArgAt < 0) { + var msg; + + if (behavior.callArgProp) { + msg = sinon.functionName(behavior.stub) + + " expected to yield to '" + behavior.callArgProp + + "', but no object with such a property was passed."; + } else { + msg = sinon.functionName(behavior.stub) + + " expected to yield, but no callback was passed."; + } + + if (args.length > 0) { + msg += " Received [" + join.call(args, ", ") + "]"; + } + + return msg; + } + + return "argument at index " + behavior.callArgAt + " is not a function: " + func; + } + + function callCallback(behavior, args) { + if (typeof behavior.callArgAt == "number") { + var func = getCallback(behavior, args); + + if (typeof func != "function") { + throw new TypeError(getCallbackError(behavior, func, args)); + } + + if (behavior.callbackAsync) { + nextTick(function () { + func.apply(behavior.callbackContext, behavior.callbackArguments); + }); + } else { + func.apply(behavior.callbackContext, behavior.callbackArguments); + } + } + } + + var proto = { + create: function create(stub) { + var behavior = sinon.extend({}, sinon.behavior); + delete behavior.create; + behavior.stub = stub; + + return behavior; + }, + + isPresent: function isPresent() { + return (typeof this.callArgAt == "number" || + this.exception || + typeof this.returnArgAt == "number" || + this.returnThis || + this.returnValueDefined); + }, + + invoke: function invoke(context, args) { + callCallback(this, args); + + if (this.exception) { + throw this.exception; + } else if (typeof this.returnArgAt == "number") { + return args[this.returnArgAt]; + } else if (this.returnThis) { + return context; + } + + return this.returnValue; + }, + + onCall: function onCall(index) { + return this.stub.onCall(index); + }, + + onFirstCall: function onFirstCall() { + return this.stub.onFirstCall(); + }, + + onSecondCall: function onSecondCall() { + return this.stub.onSecondCall(); + }, + + onThirdCall: function onThirdCall() { + return this.stub.onThirdCall(); + }, + + withArgs: function withArgs(/* arguments */) { + throw new Error("Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" is not supported. " + + "Use \"stub.withArgs(...).onCall(...)\" to define sequential behavior for calls with certain arguments."); + }, + + callsArg: function callsArg(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.callArgAt = pos; + this.callbackArguments = []; + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + callsArgOn: function callsArgOn(pos, context) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = pos; + this.callbackArguments = []; + this.callbackContext = context; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + callsArgWith: function callsArgWith(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.callArgAt = pos; + this.callbackArguments = slice.call(arguments, 1); + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + callsArgOnWith: function callsArgWith(pos, context) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = pos; + this.callbackArguments = slice.call(arguments, 2); + this.callbackContext = context; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yields: function () { + this.callArgAt = useLeftMostCallback; + this.callbackArguments = slice.call(arguments, 0); + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yieldsRight: function () { + this.callArgAt = useRightMostCallback; + this.callbackArguments = slice.call(arguments, 0); + this.callbackContext = undefined; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yieldsOn: function (context) { + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = useLeftMostCallback; + this.callbackArguments = slice.call(arguments, 1); + this.callbackContext = context; + this.callArgProp = undefined; + this.callbackAsync = false; + + return this; + }, + + yieldsTo: function (prop) { + this.callArgAt = useLeftMostCallback; + this.callbackArguments = slice.call(arguments, 1); + this.callbackContext = undefined; + this.callArgProp = prop; + this.callbackAsync = false; + + return this; + }, + + yieldsToOn: function (prop, context) { + if (typeof context != "object") { + throw new TypeError("argument context is not an object"); + } + + this.callArgAt = useLeftMostCallback; + this.callbackArguments = slice.call(arguments, 2); + this.callbackContext = context; + this.callArgProp = prop; + this.callbackAsync = false; + + return this; + }, + + throws: throwsException, + throwsException: throwsException, + + returns: function returns(value) { + this.returnValue = value; + this.returnValueDefined = true; + + return this; + }, + + returnsArg: function returnsArg(pos) { + if (typeof pos != "number") { + throw new TypeError("argument index is not number"); + } + + this.returnArgAt = pos; + + return this; + }, + + returnsThis: function returnsThis() { + this.returnThis = true; + + return this; + } + }; + + // create asynchronous versions of callsArg* and yields* methods + for (var method in proto) { + // need to avoid creating anotherasync versions of the newly added async methods + if (proto.hasOwnProperty(method) && + method.match(/^(callsArg|yields)/) && + !method.match(/Async/)) { + proto[method + "Async"] = (function (syncFnName) { + return function () { + var result = this[syncFnName].apply(this, arguments); + this.callbackAsync = true; + return result; + }; + })(method); + } + } + + sinon.behavior = proto; + return proto; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./extend"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend util/core.js + * @depend extend.js + * @depend spy.js + * @depend behavior.js + */ +/** + * Stub functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + function makeApi(sinon) { + function stub(object, property, func) { + if (!!func && typeof func != "function" && typeof func != "object") { + throw new TypeError("Custom stub should be a function or a property descriptor"); + } + + var wrapper; + + if (func) { + if (typeof func == "function") { + wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; + } else { + wrapper = func; + if (sinon.spy && sinon.spy.create) { + var types = sinon.objectKeys(wrapper); + for (var i = 0; i < types.length; i++) { + wrapper[types[i]] = sinon.spy.create(wrapper[types[i]]); + } + } + } + } else { + var stubLength = 0; + if (typeof object == "object" && typeof object[property] == "function") { + stubLength = object[property].length; + } + wrapper = stub.create(stubLength); + } + + if (!object && typeof property === "undefined") { + return sinon.stub.create(); + } + + if (typeof property === "undefined" && typeof object == "object") { + for (var prop in object) { + if (typeof object[prop] === "function") { + stub(object, prop); + } + } + + return object; + } + + return sinon.wrapMethod(object, property, wrapper); + } + + function getDefaultBehavior(stub) { + return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub); + } + + function getParentBehaviour(stub) { + return (stub.parent && getCurrentBehavior(stub.parent)); + } + + function getCurrentBehavior(stub) { + var behavior = stub.behaviors[stub.callCount - 1]; + return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub); + } + + var uuid = 0; + + var proto = { + create: function create(stubLength) { + var functionStub = function () { + return getCurrentBehavior(functionStub).invoke(this, arguments); + }; + + functionStub.id = "stub#" + uuid++; + var orig = functionStub; + functionStub = sinon.spy.create(functionStub, stubLength); + functionStub.func = orig; + + sinon.extend(functionStub, stub); + functionStub.instantiateFake = sinon.stub.create; + functionStub.displayName = "stub"; + functionStub.toString = sinon.functionToString; + + functionStub.defaultBehavior = null; + functionStub.behaviors = []; + + return functionStub; + }, + + resetBehavior: function () { + var i; + + this.defaultBehavior = null; + this.behaviors = []; + + delete this.returnValue; + delete this.returnArgAt; + this.returnThis = false; + + if (this.fakes) { + for (i = 0; i < this.fakes.length; i++) { + this.fakes[i].resetBehavior(); + } + } + }, + + onCall: function onCall(index) { + if (!this.behaviors[index]) { + this.behaviors[index] = sinon.behavior.create(this); + } + + return this.behaviors[index]; + }, + + onFirstCall: function onFirstCall() { + return this.onCall(0); + }, + + onSecondCall: function onSecondCall() { + return this.onCall(1); + }, + + onThirdCall: function onThirdCall() { + return this.onCall(2); + } + }; + + for (var method in sinon.behavior) { + if (sinon.behavior.hasOwnProperty(method) && + !proto.hasOwnProperty(method) && + method != "create" && + method != "withArgs" && + method != "invoke") { + proto[method] = (function (behaviorMethod) { + return function () { + this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); + this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); + return this; + }; + }(method)); + } + } + + sinon.extend(stub, proto); + sinon.stub = stub; + + return stub; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./behavior"); + require("./spy"); + require("./extend"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend times_in_words.js + * @depend util/core.js + * @depend call.js + * @depend extend.js + * @depend match.js + * @depend spy.js + * @depend stub.js + * @depend format.js + */ +/** + * Mock functions. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + function makeApi(sinon) { + var push = [].push; + var match = sinon.match; + + function mock(object) { + if (!object) { + return sinon.expectation.create("Anonymous mock"); + } + + return mock.create(object); + } + + function each(collection, callback) { + if (!collection) { + return; + } + + for (var i = 0, l = collection.length; i < l; i += 1) { + callback(collection[i]); + } + } + + sinon.extend(mock, { + create: function create(object) { + if (!object) { + throw new TypeError("object is null"); + } + + var mockObject = sinon.extend({}, mock); + mockObject.object = object; + delete mockObject.create; + + return mockObject; + }, + + expects: function expects(method) { + if (!method) { + throw new TypeError("method is falsy"); + } + + if (!this.expectations) { + this.expectations = {}; + this.proxies = []; + } + + if (!this.expectations[method]) { + this.expectations[method] = []; + var mockObject = this; + + sinon.wrapMethod(this.object, method, function () { + return mockObject.invokeMethod(method, this, arguments); + }); + + push.call(this.proxies, method); + } + + var expectation = sinon.expectation.create(method); + push.call(this.expectations[method], expectation); + + return expectation; + }, + + restore: function restore() { + var object = this.object; + + each(this.proxies, function (proxy) { + if (typeof object[proxy].restore == "function") { + object[proxy].restore(); + } + }); + }, + + verify: function verify() { + var expectations = this.expectations || {}; + var messages = [], met = []; + + each(this.proxies, function (proxy) { + each(expectations[proxy], function (expectation) { + if (!expectation.met()) { + push.call(messages, expectation.toString()); + } else { + push.call(met, expectation.toString()); + } + }); + }); + + this.restore(); + + if (messages.length > 0) { + sinon.expectation.fail(messages.concat(met).join("\n")); + } else if (met.length > 0) { + sinon.expectation.pass(messages.concat(met).join("\n")); + } + + return true; + }, + + invokeMethod: function invokeMethod(method, thisValue, args) { + var expectations = this.expectations && this.expectations[method]; + var length = expectations && expectations.length || 0, i; + + for (i = 0; i < length; i += 1) { + if (!expectations[i].met() && + expectations[i].allowsCall(thisValue, args)) { + return expectations[i].apply(thisValue, args); + } + } + + var messages = [], available, exhausted = 0; + + for (i = 0; i < length; i += 1) { + if (expectations[i].allowsCall(thisValue, args)) { + available = available || expectations[i]; + } else { + exhausted += 1; + } + push.call(messages, " " + expectations[i].toString()); + } + + if (exhausted === 0) { + return available.apply(thisValue, args); + } + + messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ + proxy: method, + args: args + })); + + sinon.expectation.fail(messages.join("\n")); + } + }); + + var times = sinon.timesInWords; + var slice = Array.prototype.slice; + + function callCountInWords(callCount) { + if (callCount == 0) { + return "never called"; + } else { + return "called " + times(callCount); + } + } + + function expectedCallCountInWords(expectation) { + var min = expectation.minCalls; + var max = expectation.maxCalls; + + if (typeof min == "number" && typeof max == "number") { + var str = times(min); + + if (min != max) { + str = "at least " + str + " and at most " + times(max); + } + + return str; + } + + if (typeof min == "number") { + return "at least " + times(min); + } + + return "at most " + times(max); + } + + function receivedMinCalls(expectation) { + var hasMinLimit = typeof expectation.minCalls == "number"; + return !hasMinLimit || expectation.callCount >= expectation.minCalls; + } + + function receivedMaxCalls(expectation) { + if (typeof expectation.maxCalls != "number") { + return false; + } + + return expectation.callCount == expectation.maxCalls; + } + + function verifyMatcher(possibleMatcher, arg) { + if (match && match.isMatcher(possibleMatcher)) { + return possibleMatcher.test(arg); + } else { + return true; + } + } + + sinon.expectation = { + minCalls: 1, + maxCalls: 1, + + create: function create(methodName) { + var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); + delete expectation.create; + expectation.method = methodName; + + return expectation; + }, + + invoke: function invoke(func, thisValue, args) { + this.verifyCallAllowed(thisValue, args); + + return sinon.spy.invoke.apply(this, arguments); + }, + + atLeast: function atLeast(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not number"); + } + + if (!this.limitsSet) { + this.maxCalls = null; + this.limitsSet = true; + } + + this.minCalls = num; + + return this; + }, + + atMost: function atMost(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not number"); + } + + if (!this.limitsSet) { + this.minCalls = null; + this.limitsSet = true; + } + + this.maxCalls = num; + + return this; + }, + + never: function never() { + return this.exactly(0); + }, + + once: function once() { + return this.exactly(1); + }, + + twice: function twice() { + return this.exactly(2); + }, + + thrice: function thrice() { + return this.exactly(3); + }, + + exactly: function exactly(num) { + if (typeof num != "number") { + throw new TypeError("'" + num + "' is not a number"); + } + + this.atLeast(num); + return this.atMost(num); + }, + + met: function met() { + return !this.failed && receivedMinCalls(this); + }, + + verifyCallAllowed: function verifyCallAllowed(thisValue, args) { + if (receivedMaxCalls(this)) { + this.failed = true; + sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); + } + + if ("expectedThis" in this && this.expectedThis !== thisValue) { + sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + + this.expectedThis); + } + + if (!("expectedArguments" in this)) { + return; + } + + if (!args) { + sinon.expectation.fail(this.method + " received no arguments, expected " + + sinon.format(this.expectedArguments)); + } + + if (args.length < this.expectedArguments.length) { + sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) + + "), expected " + sinon.format(this.expectedArguments)); + } + + if (this.expectsExactArgCount && + args.length != this.expectedArguments.length) { + sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + + "), expected " + sinon.format(this.expectedArguments)); + } + + for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { + + if (!verifyMatcher(this.expectedArguments[i], args[i])) { + sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + + ", didn't match " + this.expectedArguments.toString()); + } + + if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { + sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + + ", expected " + sinon.format(this.expectedArguments)); + } + } + }, + + allowsCall: function allowsCall(thisValue, args) { + if (this.met() && receivedMaxCalls(this)) { + return false; + } + + if ("expectedThis" in this && this.expectedThis !== thisValue) { + return false; + } + + if (!("expectedArguments" in this)) { + return true; + } + + args = args || []; + + if (args.length < this.expectedArguments.length) { + return false; + } + + if (this.expectsExactArgCount && + args.length != this.expectedArguments.length) { + return false; + } + + for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { + if (!verifyMatcher(this.expectedArguments[i], args[i])) { + return false; + } + + if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { + return false; + } + } + + return true; + }, + + withArgs: function withArgs() { + this.expectedArguments = slice.call(arguments); + return this; + }, + + withExactArgs: function withExactArgs() { + this.withArgs.apply(this, arguments); + this.expectsExactArgCount = true; + return this; + }, + + on: function on(thisValue) { + this.expectedThis = thisValue; + return this; + }, + + toString: function () { + var args = (this.expectedArguments || []).slice(); + + if (!this.expectsExactArgCount) { + push.call(args, "[...]"); + } + + var callStr = sinon.spyCall.toString.call({ + proxy: this.method || "anonymous mock expectation", + args: args + }); + + var message = callStr.replace(", [...", "[, ...") + " " + + expectedCallCountInWords(this); + + if (this.met()) { + return "Expectation met: " + message; + } + + return "Expected " + message + " (" + + callCountInWords(this.callCount) + ")"; + }, + + verify: function verify() { + if (!this.met()) { + sinon.expectation.fail(this.toString()); + } else { + sinon.expectation.pass(this.toString()); + } + + return true; + }, + + pass: function pass(message) { + sinon.assert.pass(message); + }, + + fail: function fail(message) { + var exception = new Error(message); + exception.name = "ExpectationError"; + + throw exception; + } + }; + + sinon.mock = mock; + return mock; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./times_in_words"); + require("./call"); + require("./extend"); + require("./match"); + require("./spy"); + require("./stub"); + require("./format"); + + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend util/core.js + * @depend spy.js + * @depend stub.js + * @depend mock.js + */ +/** + * Collections of stubs, spies and mocks. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + var push = [].push; + var hasOwnProperty = Object.prototype.hasOwnProperty; + + function getFakes(fakeCollection) { + if (!fakeCollection.fakes) { + fakeCollection.fakes = []; + } + + return fakeCollection.fakes; + } + + function each(fakeCollection, method) { + var fakes = getFakes(fakeCollection); + + for (var i = 0, l = fakes.length; i < l; i += 1) { + if (typeof fakes[i][method] == "function") { + fakes[i][method](); + } + } + } + + function compact(fakeCollection) { + var fakes = getFakes(fakeCollection); + var i = 0; + while (i < fakes.length) { + fakes.splice(i, 1); + } + } + + function makeApi(sinon) { + var collection = { + verify: function resolve() { + each(this, "verify"); + }, + + restore: function restore() { + each(this, "restore"); + compact(this); + }, + + reset: function restore() { + each(this, "reset"); + }, + + verifyAndRestore: function verifyAndRestore() { + var exception; + + try { + this.verify(); + } catch (e) { + exception = e; + } + + this.restore(); + + if (exception) { + throw exception; + } + }, + + add: function add(fake) { + push.call(getFakes(this), fake); + return fake; + }, + + spy: function spy() { + return this.add(sinon.spy.apply(sinon, arguments)); + }, + + stub: function stub(object, property, value) { + if (property) { + var original = object[property]; + + if (typeof original != "function") { + if (!hasOwnProperty.call(object, property)) { + throw new TypeError("Cannot stub non-existent own property " + property); + } + + object[property] = value; + + return this.add({ + restore: function () { + object[property] = original; + } + }); + } + } + if (!property && !!object && typeof object == "object") { + var stubbedObj = sinon.stub.apply(sinon, arguments); + + for (var prop in stubbedObj) { + if (typeof stubbedObj[prop] === "function") { + this.add(stubbedObj[prop]); + } + } + + return stubbedObj; + } + + return this.add(sinon.stub.apply(sinon, arguments)); + }, + + mock: function mock() { + return this.add(sinon.mock.apply(sinon, arguments)); + }, + + inject: function inject(obj) { + var col = this; + + obj.spy = function () { + return col.spy.apply(col, arguments); + }; + + obj.stub = function () { + return col.stub.apply(col, arguments); + }; + + obj.mock = function () { + return col.mock.apply(col, arguments); + }; + + return obj; + } + }; + + sinon.collection = collection; + return collection; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./mock"); + require("./spy"); + require("./stub"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/*global lolex */ + +/** + * Fake timer API + * setTimeout + * setInterval + * clearTimeout + * clearInterval + * tick + * reset + * Date + * + * Inspired by jsUnitMockTimeOut from JsUnit + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof sinon == "undefined") { + var sinon = {}; +} + +(function (global) { + function makeApi(sinon, lol) { + var llx = typeof lolex !== "undefined" ? lolex : lol; + + sinon.useFakeTimers = function () { + var now, methods = Array.prototype.slice.call(arguments); + + if (typeof methods[0] === "string") { + now = 0; + } else { + now = methods.shift(); + } + + var clock = llx.install(now || 0, methods); + clock.restore = clock.uninstall; + return clock; + }; + + sinon.clock = { + create: function (now) { + return llx.createClock(now); + } + }; + + sinon.timers = { + setTimeout: setTimeout, + clearTimeout: clearTimeout, + setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), + clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined), + setInterval: setInterval, + clearInterval: clearInterval, + Date: Date + }; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, epxorts, module, lolex) { + var sinon = require("./core"); + makeApi(sinon, lolex); + module.exports = sinon; + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module, require("lolex")); + } else { + makeApi(sinon); + } +}(typeof global != "undefined" && typeof global !== "function" ? global : this)); + +/** + * Minimal Event interface implementation + * + * Original implementation by Sven Fuchs: https://gist.github.com/995028 + * Modifications and tests by Christian Johansen. + * + * @author Sven Fuchs (svenfuchs@artweb-design.de) + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2011 Sven Fuchs, Christian Johansen + */ + +if (typeof sinon == "undefined") { + this.sinon = {}; +} + +(function () { + var push = [].push; + + function makeApi(sinon) { + sinon.Event = function Event(type, bubbles, cancelable, target) { + this.initEvent(type, bubbles, cancelable, target); + }; + + sinon.Event.prototype = { + initEvent: function (type, bubbles, cancelable, target) { + this.type = type; + this.bubbles = bubbles; + this.cancelable = cancelable; + this.target = target; + }, + + stopPropagation: function () {}, + + preventDefault: function () { + this.defaultPrevented = true; + } + }; + + sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) { + this.initEvent(type, false, false, target); + this.loaded = progressEventRaw.loaded || null; + this.total = progressEventRaw.total || null; + this.lengthComputable = !!progressEventRaw.total; + }; + + sinon.ProgressEvent.prototype = new sinon.Event(); + + sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; + + sinon.CustomEvent = function CustomEvent(type, customData, target) { + this.initEvent(type, false, false, target); + this.detail = customData.detail || null; + }; + + sinon.CustomEvent.prototype = new sinon.Event(); + + sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; + + sinon.EventTarget = { + addEventListener: function addEventListener(event, listener) { + this.eventListeners = this.eventListeners || {}; + this.eventListeners[event] = this.eventListeners[event] || []; + push.call(this.eventListeners[event], listener); + }, + + removeEventListener: function removeEventListener(event, listener) { + var listeners = this.eventListeners && this.eventListeners[event] || []; + + for (var i = 0, l = listeners.length; i < l; ++i) { + if (listeners[i] == listener) { + return listeners.splice(i, 1); + } + } + }, + + dispatchEvent: function dispatchEvent(event) { + var type = event.type; + var listeners = this.eventListeners && this.eventListeners[type] || []; + + for (var i = 0; i < listeners.length; i++) { + if (typeof listeners[i] == "function") { + listeners[i].call(this, event); + } else { + listeners[i].handleEvent(event); + } + } + + return !!event.defaultPrevented; + } + }; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require) { + var sinon = require("./core"); + makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require); + } else { + makeApi(sinon); + } +}()); + +/** + * @depend util/core.js + */ +/** + * Logs errors + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2014 Christian Johansen + */ + +(function (sinon) { + // cache a reference to setTimeout, so that our reference won't be stubbed out + // when using fake timers and errors will still get logged + // https://github.com/cjohansen/Sinon.JS/issues/381 + var realSetTimeout = setTimeout; + + function makeApi(sinon) { + + function log() {} + + function logError(label, err) { + var msg = label + " threw exception: "; + + sinon.log(msg + "[" + err.name + "] " + err.message); + + if (err.stack) { + sinon.log(err.stack); + } + + logError.setTimeout(function () { + err.message = msg + err.message; + throw err; + }, 0); + }; + + // wrap realSetTimeout with something we can stub in tests + logError.setTimeout = function (func, timeout) { + realSetTimeout(func, timeout); + } + + var exports = {}; + exports.log = sinon.log = log; + exports.logError = sinon.logError = logError; + + return exports; + } + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + module.exports = makeApi(sinon); + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend core.js + * @depend ../extend.js + * @depend event.js + * @depend ../log_error.js + */ +/** + * Fake XDomainRequest object + */ + +if (typeof sinon == "undefined") { + this.sinon = {}; +} + +// wrapper for global +(function (global) { + var xdr = { XDomainRequest: global.XDomainRequest }; + xdr.GlobalXDomainRequest = global.XDomainRequest; + xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined"; + xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; + + function makeApi(sinon) { + sinon.xdr = xdr; + + function FakeXDomainRequest() { + this.readyState = FakeXDomainRequest.UNSENT; + this.requestBody = null; + this.requestHeaders = {}; + this.status = 0; + this.timeout = null; + + if (typeof FakeXDomainRequest.onCreate == "function") { + FakeXDomainRequest.onCreate(this); + } + } + + function verifyState(xdr) { + if (xdr.readyState !== FakeXDomainRequest.OPENED) { + throw new Error("INVALID_STATE_ERR"); + } + + if (xdr.sendFlag) { + throw new Error("INVALID_STATE_ERR"); + } + } + + function verifyRequestSent(xdr) { + if (xdr.readyState == FakeXDomainRequest.UNSENT) { + throw new Error("Request not sent"); + } + if (xdr.readyState == FakeXDomainRequest.DONE) { + throw new Error("Request done"); + } + } + + function verifyResponseBodyType(body) { + if (typeof body != "string") { + var error = new Error("Attempted to respond to fake XDomainRequest with " + + body + ", which is not a string."); + error.name = "InvalidBodyException"; + throw error; + } + } + + sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, { + open: function open(method, url) { + this.method = method; + this.url = url; + + this.responseText = null; + this.sendFlag = false; + + this.readyStateChange(FakeXDomainRequest.OPENED); + }, + + readyStateChange: function readyStateChange(state) { + this.readyState = state; + var eventName = ""; + switch (this.readyState) { + case FakeXDomainRequest.UNSENT: + break; + case FakeXDomainRequest.OPENED: + break; + case FakeXDomainRequest.LOADING: + if (this.sendFlag) { + //raise the progress event + eventName = "onprogress"; + } + break; + case FakeXDomainRequest.DONE: + if (this.isTimeout) { + eventName = "ontimeout" + } else if (this.errorFlag || (this.status < 200 || this.status > 299)) { + eventName = "onerror"; + } else { + eventName = "onload" + } + break; + } + + // raising event (if defined) + if (eventName) { + if (typeof this[eventName] == "function") { + try { + this[eventName](); + } catch (e) { + sinon.logError("Fake XHR " + eventName + " handler", e); + } + } + } + }, + + send: function send(data) { + verifyState(this); + + if (!/^(get|head)$/i.test(this.method)) { + this.requestBody = data; + } + this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; + + this.errorFlag = false; + this.sendFlag = true; + this.readyStateChange(FakeXDomainRequest.OPENED); + + if (typeof this.onSend == "function") { + this.onSend(this); + } + }, + + abort: function abort() { + this.aborted = true; + this.responseText = null; + this.errorFlag = true; + + if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) { + this.readyStateChange(sinon.FakeXDomainRequest.DONE); + this.sendFlag = false; + } + }, + + setResponseBody: function setResponseBody(body) { + verifyRequestSent(this); + verifyResponseBodyType(body); + + var chunkSize = this.chunkSize || 10; + var index = 0; + this.responseText = ""; + + do { + this.readyStateChange(FakeXDomainRequest.LOADING); + this.responseText += body.substring(index, index + chunkSize); + index += chunkSize; + } while (index < body.length); + + this.readyStateChange(FakeXDomainRequest.DONE); + }, + + respond: function respond(status, contentType, body) { + // content-type ignored, since XDomainRequest does not carry this + // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease + // test integration across browsers + this.status = typeof status == "number" ? status : 200; + this.setResponseBody(body || ""); + }, + + simulatetimeout: function simulatetimeout() { + this.status = 0; + this.isTimeout = true; + // Access to this should actually throw an error + this.responseText = undefined; + this.readyStateChange(FakeXDomainRequest.DONE); + } + }); + + sinon.extend(FakeXDomainRequest, { + UNSENT: 0, + OPENED: 1, + LOADING: 3, + DONE: 4 + }); + + sinon.useFakeXDomainRequest = function useFakeXDomainRequest() { + sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) { + if (xdr.supportsXDR) { + global.XDomainRequest = xdr.GlobalXDomainRequest; + } + + delete sinon.FakeXDomainRequest.restore; + + if (keepOnCreate !== true) { + delete sinon.FakeXDomainRequest.onCreate; + } + }; + if (xdr.supportsXDR) { + global.XDomainRequest = sinon.FakeXDomainRequest; + } + return sinon.FakeXDomainRequest; + }; + + sinon.FakeXDomainRequest = FakeXDomainRequest; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./core"); + require("../extend"); + require("./event"); + require("../log_error"); + makeApi(sinon); + module.exports = sinon; + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else { + makeApi(sinon); + } +})(this); + +/** + * @depend core.js + * @depend ../extend.js + * @depend event.js + * @depend ../log_error.js + */ +/** + * Fake XMLHttpRequest object + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (global) { + + var supportsProgress = typeof ProgressEvent !== "undefined"; + var supportsCustomEvent = typeof CustomEvent !== "undefined"; + var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest }; + sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest; + sinonXhr.GlobalActiveXObject = global.ActiveXObject; + sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject != "undefined"; + sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest != "undefined"; + sinonXhr.workingXHR = sinonXhr.supportsXHR ? sinonXhr.GlobalXMLHttpRequest : sinonXhr.supportsActiveX + ? function () { return new sinonXhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false; + sinonXhr.supportsCORS = sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest()); + + /*jsl:ignore*/ + var unsafeHeaders = { + "Accept-Charset": true, + "Accept-Encoding": true, + Connection: true, + "Content-Length": true, + Cookie: true, + Cookie2: true, + "Content-Transfer-Encoding": true, + Date: true, + Expect: true, + Host: true, + "Keep-Alive": true, + Referer: true, + TE: true, + Trailer: true, + "Transfer-Encoding": true, + Upgrade: true, + "User-Agent": true, + Via: true + }; + /*jsl:end*/ + + function FakeXMLHttpRequest() { + this.readyState = FakeXMLHttpRequest.UNSENT; + this.requestHeaders = {}; + this.requestBody = null; + this.status = 0; + this.statusText = ""; + this.upload = new UploadProgress(); + if (sinonXhr.supportsCORS) { + this.withCredentials = false; + } + + var xhr = this; + var events = ["loadstart", "load", "abort", "loadend"]; + + function addEventListener(eventName) { + xhr.addEventListener(eventName, function (event) { + var listener = xhr["on" + eventName]; + + if (listener && typeof listener == "function") { + listener.call(this, event); + } + }); + } + + for (var i = events.length - 1; i >= 0; i--) { + addEventListener(events[i]); + } + + if (typeof FakeXMLHttpRequest.onCreate == "function") { + FakeXMLHttpRequest.onCreate(this); + } + } + + // An upload object is created for each + // FakeXMLHttpRequest and allows upload + // events to be simulated using uploadProgress + // and uploadError. + function UploadProgress() { + this.eventListeners = { + progress: [], + load: [], + abort: [], + error: [] + } + } + + UploadProgress.prototype.addEventListener = function addEventListener(event, listener) { + this.eventListeners[event].push(listener); + }; + + UploadProgress.prototype.removeEventListener = function removeEventListener(event, listener) { + var listeners = this.eventListeners[event] || []; + + for (var i = 0, l = listeners.length; i < l; ++i) { + if (listeners[i] == listener) { + return listeners.splice(i, 1); + } + } + }; + + UploadProgress.prototype.dispatchEvent = function dispatchEvent(event) { + var listeners = this.eventListeners[event.type] || []; + + for (var i = 0, listener; (listener = listeners[i]) != null; i++) { + listener(event); + } + }; + + function verifyState(xhr) { + if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { + throw new Error("INVALID_STATE_ERR"); + } + + if (xhr.sendFlag) { + throw new Error("INVALID_STATE_ERR"); + } + } + + function getHeader(headers, header) { + header = header.toLowerCase(); + + for (var h in headers) { + if (h.toLowerCase() == header) { + return h; + } + } + + return null; + } + + // filtering to enable a white-list version of Sinon FakeXhr, + // where whitelisted requests are passed through to real XHR + function each(collection, callback) { + if (!collection) { + return; + } + + for (var i = 0, l = collection.length; i < l; i += 1) { + callback(collection[i]); + } + } + function some(collection, callback) { + for (var index = 0; index < collection.length; index++) { + if (callback(collection[index]) === true) { + return true; + } + } + return false; + } + // largest arity in XHR is 5 - XHR#open + var apply = function (obj, method, args) { + switch (args.length) { + case 0: return obj[method](); + case 1: return obj[method](args[0]); + case 2: return obj[method](args[0], args[1]); + case 3: return obj[method](args[0], args[1], args[2]); + case 4: return obj[method](args[0], args[1], args[2], args[3]); + case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]); + } + }; + + FakeXMLHttpRequest.filters = []; + FakeXMLHttpRequest.addFilter = function addFilter(fn) { + this.filters.push(fn) + }; + var IE6Re = /MSIE 6/; + FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) { + var xhr = new sinonXhr.workingXHR(); + each([ + "open", + "setRequestHeader", + "send", + "abort", + "getResponseHeader", + "getAllResponseHeaders", + "addEventListener", + "overrideMimeType", + "removeEventListener" + ], function (method) { + fakeXhr[method] = function () { + return apply(xhr, method, arguments); + }; + }); + + var copyAttrs = function (args) { + each(args, function (attr) { + try { + fakeXhr[attr] = xhr[attr] + } catch (e) { + if (!IE6Re.test(navigator.userAgent)) { + throw e; + } + } + }); + }; + + var stateChange = function stateChange() { + fakeXhr.readyState = xhr.readyState; + if (xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { + copyAttrs(["status", "statusText"]); + } + if (xhr.readyState >= FakeXMLHttpRequest.LOADING) { + copyAttrs(["responseText", "response"]); + } + if (xhr.readyState === FakeXMLHttpRequest.DONE) { + copyAttrs(["responseXML"]); + } + if (fakeXhr.onreadystatechange) { + fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr }); + } + }; + + if (xhr.addEventListener) { + for (var event in fakeXhr.eventListeners) { + if (fakeXhr.eventListeners.hasOwnProperty(event)) { + each(fakeXhr.eventListeners[event], function (handler) { + xhr.addEventListener(event, handler); + }); + } + } + xhr.addEventListener("readystatechange", stateChange); + } else { + xhr.onreadystatechange = stateChange; + } + apply(xhr, "open", xhrArgs); + }; + FakeXMLHttpRequest.useFilters = false; + + function verifyRequestOpened(xhr) { + if (xhr.readyState != FakeXMLHttpRequest.OPENED) { + throw new Error("INVALID_STATE_ERR - " + xhr.readyState); + } + } + + function verifyRequestSent(xhr) { + if (xhr.readyState == FakeXMLHttpRequest.DONE) { + throw new Error("Request done"); + } + } + + function verifyHeadersReceived(xhr) { + if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) { + throw new Error("No headers received"); + } + } + + function verifyResponseBodyType(body) { + if (typeof body != "string") { + var error = new Error("Attempted to respond to fake XMLHttpRequest with " + + body + ", which is not a string."); + error.name = "InvalidBodyException"; + throw error; + } + } + + FakeXMLHttpRequest.parseXML = function parseXML(text) { + var xmlDoc; + + if (typeof DOMParser != "undefined") { + var parser = new DOMParser(); + xmlDoc = parser.parseFromString(text, "text/xml"); + } else { + xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async = "false"; + xmlDoc.loadXML(text); + } + + return xmlDoc; + }; + + FakeXMLHttpRequest.statusCodes = { + 100: "Continue", + 101: "Switching Protocols", + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Non-Authoritative Information", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 207: "Multi-Status", + 300: "Multiple Choice", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 307: "Temporary Redirect", + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Request Entity Too Large", + 414: "Request-URI Too Long", + 415: "Unsupported Media Type", + 416: "Requested Range Not Satisfiable", + 417: "Expectation Failed", + 422: "Unprocessable Entity", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported" + }; + + function makeApi(sinon) { + sinon.xhr = sinonXhr; + + sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { + async: true, + + open: function open(method, url, async, username, password) { + this.method = method; + this.url = url; + this.async = typeof async == "boolean" ? async : true; + this.username = username; + this.password = password; + this.responseText = null; + this.responseXML = null; + this.requestHeaders = {}; + this.sendFlag = false; + + if (FakeXMLHttpRequest.useFilters === true) { + var xhrArgs = arguments; + var defake = some(FakeXMLHttpRequest.filters, function (filter) { + return filter.apply(this, xhrArgs) + }); + if (defake) { + return FakeXMLHttpRequest.defake(this, arguments); + } + } + this.readyStateChange(FakeXMLHttpRequest.OPENED); + }, + + readyStateChange: function readyStateChange(state) { + this.readyState = state; + + if (typeof this.onreadystatechange == "function") { + try { + this.onreadystatechange(); + } catch (e) { + sinon.logError("Fake XHR onreadystatechange handler", e); + } + } + + this.dispatchEvent(new sinon.Event("readystatechange")); + + switch (this.readyState) { + case FakeXMLHttpRequest.DONE: + this.dispatchEvent(new sinon.Event("load", false, false, this)); + this.dispatchEvent(new sinon.Event("loadend", false, false, this)); + this.upload.dispatchEvent(new sinon.Event("load", false, false, this)); + if (supportsProgress) { + this.upload.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100})); + this.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100})); + } + break; + } + }, + + setRequestHeader: function setRequestHeader(header, value) { + verifyState(this); + + if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { + throw new Error("Refused to set unsafe header \"" + header + "\""); + } + + if (this.requestHeaders[header]) { + this.requestHeaders[header] += "," + value; + } else { + this.requestHeaders[header] = value; + } + }, + + // Helps testing + setResponseHeaders: function setResponseHeaders(headers) { + verifyRequestOpened(this); + this.responseHeaders = {}; + + for (var header in headers) { + if (headers.hasOwnProperty(header)) { + this.responseHeaders[header] = headers[header]; + } + } + + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); + } else { + this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED; + } + }, + + // Currently treats ALL data as a DOMString (i.e. no Document) + send: function send(data) { + verifyState(this); + + if (!/^(get|head)$/i.test(this.method)) { + var contentType = getHeader(this.requestHeaders, "Content-Type"); + if (this.requestHeaders[contentType]) { + var value = this.requestHeaders[contentType].split(";"); + this.requestHeaders[contentType] = value[0] + ";charset=utf-8"; + } else if (!(data instanceof FormData)) { + this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; + } + + this.requestBody = data; + } + + this.errorFlag = false; + this.sendFlag = this.async; + this.readyStateChange(FakeXMLHttpRequest.OPENED); + + if (typeof this.onSend == "function") { + this.onSend(this); + } + + this.dispatchEvent(new sinon.Event("loadstart", false, false, this)); + }, + + abort: function abort() { + this.aborted = true; + this.responseText = null; + this.errorFlag = true; + this.requestHeaders = {}; + + if (this.readyState > FakeXMLHttpRequest.UNSENT && this.sendFlag) { + this.readyStateChange(FakeXMLHttpRequest.DONE); + this.sendFlag = false; + } + + this.readyState = FakeXMLHttpRequest.UNSENT; + + this.dispatchEvent(new sinon.Event("abort", false, false, this)); + + this.upload.dispatchEvent(new sinon.Event("abort", false, false, this)); + + if (typeof this.onerror === "function") { + this.onerror(); + } + }, + + getResponseHeader: function getResponseHeader(header) { + if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { + return null; + } + + if (/^Set-Cookie2?$/i.test(header)) { + return null; + } + + header = getHeader(this.responseHeaders, header); + + return this.responseHeaders[header] || null; + }, + + getAllResponseHeaders: function getAllResponseHeaders() { + if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { + return ""; + } + + var headers = ""; + + for (var header in this.responseHeaders) { + if (this.responseHeaders.hasOwnProperty(header) && + !/^Set-Cookie2?$/i.test(header)) { + headers += header + ": " + this.responseHeaders[header] + "\r\n"; + } + } + + return headers; + }, + + setResponseBody: function setResponseBody(body) { + verifyRequestSent(this); + verifyHeadersReceived(this); + verifyResponseBodyType(body); + + var chunkSize = this.chunkSize || 10; + var index = 0; + this.responseText = ""; + + do { + if (this.async) { + this.readyStateChange(FakeXMLHttpRequest.LOADING); + } + + this.responseText += body.substring(index, index + chunkSize); + index += chunkSize; + } while (index < body.length); + + var type = this.getResponseHeader("Content-Type"); + + if (this.responseText && + (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) { + try { + this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); + } catch (e) { + // Unable to parse XML - no biggie + } + } + + this.readyStateChange(FakeXMLHttpRequest.DONE); + }, + + respond: function respond(status, headers, body) { + this.status = typeof status == "number" ? status : 200; + this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; + this.setResponseHeaders(headers || {}); + this.setResponseBody(body || ""); + }, + + uploadProgress: function uploadProgress(progressEventRaw) { + if (supportsProgress) { + this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); + } + }, + + downloadProgress: function downloadProgress(progressEventRaw) { + if (supportsProgress) { + this.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); + } + }, + + uploadError: function uploadError(error) { + if (supportsCustomEvent) { + this.upload.dispatchEvent(new sinon.CustomEvent("error", {detail: error})); + } + } + }); + + sinon.extend(FakeXMLHttpRequest, { + UNSENT: 0, + OPENED: 1, + HEADERS_RECEIVED: 2, + LOADING: 3, + DONE: 4 + }); + + sinon.useFakeXMLHttpRequest = function () { + FakeXMLHttpRequest.restore = function restore(keepOnCreate) { + if (sinonXhr.supportsXHR) { + global.XMLHttpRequest = sinonXhr.GlobalXMLHttpRequest; + } + + if (sinonXhr.supportsActiveX) { + global.ActiveXObject = sinonXhr.GlobalActiveXObject; + } + + delete FakeXMLHttpRequest.restore; + + if (keepOnCreate !== true) { + delete FakeXMLHttpRequest.onCreate; + } + }; + if (sinonXhr.supportsXHR) { + global.XMLHttpRequest = FakeXMLHttpRequest; + } + + if (sinonXhr.supportsActiveX) { + global.ActiveXObject = function ActiveXObject(objId) { + if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { + + return new FakeXMLHttpRequest(); + } + + return new sinonXhr.GlobalActiveXObject(objId); + }; + } + + return FakeXMLHttpRequest; + }; + + sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./core"); + require("../extend"); + require("./event"); + require("../log_error"); + makeApi(sinon); + module.exports = sinon; + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (typeof sinon === "undefined") { + return; + } else { + makeApi(sinon); + } + +})(typeof global !== "undefined" ? global : this); + +/** + * @depend fake_xdomain_request.js + * @depend fake_xml_http_request.js + * @depend ../format.js + * @depend ../log_error.js + */ +/** + * The Sinon "server" mimics a web server that receives requests from + * sinon.FakeXMLHttpRequest and provides an API to respond to those requests, + * both synchronously and asynchronously. To respond synchronuously, canned + * answers have to be provided upfront. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +if (typeof sinon == "undefined") { + var sinon = {}; +} + +(function () { + var push = [].push; + function F() {} + + function create(proto) { + F.prototype = proto; + return new F(); + } + + function responseArray(handler) { + var response = handler; + + if (Object.prototype.toString.call(handler) != "[object Array]") { + response = [200, {}, handler]; + } + + if (typeof response[2] != "string") { + throw new TypeError("Fake server response body should be string, but was " + + typeof response[2]); + } + + return response; + } + + var wloc = typeof window !== "undefined" ? window.location : {}; + var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); + + function matchOne(response, reqMethod, reqUrl) { + var rmeth = response.method; + var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase(); + var url = response.url; + var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl)); + + return matchMethod && matchUrl; + } + + function match(response, request) { + var requestUrl = request.url; + + if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { + requestUrl = requestUrl.replace(rCurrLoc, ""); + } + + if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { + if (typeof response.response == "function") { + var ru = response.url; + var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []); + return response.response.apply(response, args); + } + + return true; + } + + return false; + } + + function makeApi(sinon) { + sinon.fakeServer = { + create: function () { + var server = create(this); + if (!sinon.xhr.supportsCORS) { + this.xhr = sinon.useFakeXDomainRequest(); + } else { + this.xhr = sinon.useFakeXMLHttpRequest(); + } + server.requests = []; + + this.xhr.onCreate = function (xhrObj) { + server.addRequest(xhrObj); + }; + + return server; + }, + + addRequest: function addRequest(xhrObj) { + var server = this; + push.call(this.requests, xhrObj); + + xhrObj.onSend = function () { + server.handleRequest(this); + + if (server.respondImmediately) { + server.respond(); + } else if (server.autoRespond && !server.responding) { + setTimeout(function () { + server.responding = false; + server.respond(); + }, server.autoRespondAfter || 10); + + server.responding = true; + } + }; + }, + + getHTTPMethod: function getHTTPMethod(request) { + if (this.fakeHTTPMethods && /post/i.test(request.method)) { + var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); + return !!matches ? matches[1] : request.method; + } + + return request.method; + }, + + handleRequest: function handleRequest(xhr) { + if (xhr.async) { + if (!this.queue) { + this.queue = []; + } + + push.call(this.queue, xhr); + } else { + this.processRequest(xhr); + } + }, + + log: function log(response, request) { + var str; + + str = "Request:\n" + sinon.format(request) + "\n\n"; + str += "Response:\n" + sinon.format(response) + "\n\n"; + + sinon.log(str); + }, + + respondWith: function respondWith(method, url, body) { + if (arguments.length == 1 && typeof method != "function") { + this.response = responseArray(method); + return; + } + + if (!this.responses) { this.responses = []; } + + if (arguments.length == 1) { + body = method; + url = method = null; + } + + if (arguments.length == 2) { + body = url; + url = method; + method = null; + } + + push.call(this.responses, { + method: method, + url: url, + response: typeof body == "function" ? body : responseArray(body) + }); + }, + + respond: function respond() { + if (arguments.length > 0) { + this.respondWith.apply(this, arguments); + } + + var queue = this.queue || []; + var requests = queue.splice(0, queue.length); + var request; + + while (request = requests.shift()) { + this.processRequest(request); + } + }, + + processRequest: function processRequest(request) { + try { + if (request.aborted) { + return; + } + + var response = this.response || [404, {}, ""]; + + if (this.responses) { + for (var l = this.responses.length, i = l - 1; i >= 0; i--) { + if (match.call(this, this.responses[i], request)) { + response = this.responses[i].response; + break; + } + } + } + + if (request.readyState != 4) { + this.log(response, request); + + request.respond(response[0], response[1], response[2]); + } + } catch (e) { + sinon.logError("Fake server request processing", e); + } + }, + + restore: function restore() { + return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); + } + }; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./core"); + require("./fake_xdomain_request"); + require("./fake_xml_http_request"); + require("../format"); + makeApi(sinon); + module.exports = sinon; + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else { + makeApi(sinon); + } +}()); + +/** + * @depend fake_server.js + * @depend fake_timers.js + */ +/** + * Add-on for sinon.fakeServer that automatically handles a fake timer along with + * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery + * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, + * it polls the object for completion with setInterval. Dispite the direct + * motivation, there is nothing jQuery-specific in this file, so it can be used + * in any environment where the ajax implementation depends on setInterval or + * setTimeout. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function () { + function makeApi(sinon) { + function Server() {} + Server.prototype = sinon.fakeServer; + + sinon.fakeServerWithClock = new Server(); + + sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { + if (xhr.async) { + if (typeof setTimeout.clock == "object") { + this.clock = setTimeout.clock; + } else { + this.clock = sinon.useFakeTimers(); + this.resetClock = true; + } + + if (!this.longestTimeout) { + var clockSetTimeout = this.clock.setTimeout; + var clockSetInterval = this.clock.setInterval; + var server = this; + + this.clock.setTimeout = function (fn, timeout) { + server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); + + return clockSetTimeout.apply(this, arguments); + }; + + this.clock.setInterval = function (fn, timeout) { + server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); + + return clockSetInterval.apply(this, arguments); + }; + } + } + + return sinon.fakeServer.addRequest.call(this, xhr); + }; + + sinon.fakeServerWithClock.respond = function respond() { + var returnVal = sinon.fakeServer.respond.apply(this, arguments); + + if (this.clock) { + this.clock.tick(this.longestTimeout || 0); + this.longestTimeout = 0; + + if (this.resetClock) { + this.clock.restore(); + this.resetClock = false; + } + } + + return returnVal; + }; + + sinon.fakeServerWithClock.restore = function restore() { + if (this.clock) { + this.clock.restore(); + } + + return sinon.fakeServer.restore.apply(this, arguments); + }; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require) { + var sinon = require("./core"); + require("./fake_server"); + require("./fake_timers"); + makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require); + } else { + makeApi(sinon); + } +}()); + +/** + * @depend util/core.js + * @depend extend.js + * @depend collection.js + * @depend util/fake_timers.js + * @depend util/fake_server_with_clock.js + */ +/** + * Manages fake collections as well as fake utilities such as Sinon's + * timers and fake XHR implementation in one convenient object. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function () { + function makeApi(sinon) { + var push = [].push; + + function exposeValue(sandbox, config, key, value) { + if (!value) { + return; + } + + if (config.injectInto && !(key in config.injectInto)) { + config.injectInto[key] = value; + sandbox.injectedKeys.push(key); + } else { + push.call(sandbox.args, value); + } + } + + function prepareSandboxFromConfig(config) { + var sandbox = sinon.create(sinon.sandbox); + + if (config.useFakeServer) { + if (typeof config.useFakeServer == "object") { + sandbox.serverPrototype = config.useFakeServer; + } + + sandbox.useFakeServer(); + } + + if (config.useFakeTimers) { + if (typeof config.useFakeTimers == "object") { + sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); + } else { + sandbox.useFakeTimers(); + } + } + + return sandbox; + } + + sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { + useFakeTimers: function useFakeTimers() { + this.clock = sinon.useFakeTimers.apply(sinon, arguments); + + return this.add(this.clock); + }, + + serverPrototype: sinon.fakeServer, + + useFakeServer: function useFakeServer() { + var proto = this.serverPrototype || sinon.fakeServer; + + if (!proto || !proto.create) { + return null; + } + + this.server = proto.create(); + return this.add(this.server); + }, + + inject: function (obj) { + sinon.collection.inject.call(this, obj); + + if (this.clock) { + obj.clock = this.clock; + } + + if (this.server) { + obj.server = this.server; + obj.requests = this.server.requests; + } + + obj.match = sinon.match; + + return obj; + }, + + restore: function () { + sinon.collection.restore.apply(this, arguments); + this.restoreContext(); + }, + + restoreContext: function () { + if (this.injectedKeys) { + for (var i = 0, j = this.injectedKeys.length; i < j; i++) { + delete this.injectInto[this.injectedKeys[i]]; + } + this.injectedKeys = []; + } + }, + + create: function (config) { + if (!config) { + return sinon.create(sinon.sandbox); + } + + var sandbox = prepareSandboxFromConfig(config); + sandbox.args = sandbox.args || []; + sandbox.injectedKeys = []; + sandbox.injectInto = config.injectInto; + var prop, value, exposed = sandbox.inject({}); + + if (config.properties) { + for (var i = 0, l = config.properties.length; i < l; i++) { + prop = config.properties[i]; + value = exposed[prop] || prop == "sandbox" && sandbox; + exposeValue(sandbox, config, prop, value); + } + } else { + exposeValue(sandbox, config, "sandbox", value); + } + + return sandbox; + }, + + match: sinon.match + }); + + sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; + + return sinon.sandbox; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./extend"); + require("./util/fake_server_with_clock"); + require("./util/fake_timers"); + require("./collection"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}()); + +/** + * @depend util/core.js + * @depend sandbox.js + */ +/** + * Test function, sandboxes fakes + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + function makeApi(sinon) { + var slice = Array.prototype.slice; + + function test(callback) { + var type = typeof callback; + + if (type != "function") { + throw new TypeError("sinon.test needs to wrap a test function, got " + type); + } + + function sinonSandboxedTest() { + var config = sinon.getConfig(sinon.config); + config.injectInto = config.injectIntoThis && this || config.injectInto; + var sandbox = sinon.sandbox.create(config); + var args = slice.call(arguments); + var oldDone = args.length && args[args.length - 1]; + var exception, result; + + if (typeof oldDone == "function") { + args[args.length - 1] = function sinonDone(result) { + if (result) { + sandbox.restore(); + throw exception; + } else { + sandbox.verifyAndRestore(); + } + oldDone(result); + }; + } + + try { + result = callback.apply(this, args.concat(sandbox.args)); + } catch (e) { + exception = e; + } + + if (typeof oldDone != "function") { + if (typeof exception !== "undefined") { + sandbox.restore(); + throw exception; + } else { + sandbox.verifyAndRestore(); + } + } + + return result; + } + + if (callback.length) { + return function sinonAsyncSandboxedTest(callback) { + return sinonSandboxedTest.apply(this, arguments); + }; + } + + return sinonSandboxedTest; + } + + test.config = { + injectIntoThis: true, + injectInto: null, + properties: ["spy", "stub", "mock", "clock", "server", "requests"], + useFakeTimers: true, + useFakeServer: true + }; + + sinon.test = test; + return test; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./sandbox"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (sinon) { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend util/core.js + * @depend test.js + */ +/** + * Test case, sandboxes all test functions + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon) { + function createTest(property, setUp, tearDown) { + return function () { + if (setUp) { + setUp.apply(this, arguments); + } + + var exception, result; + + try { + result = property.apply(this, arguments); + } catch (e) { + exception = e; + } + + if (tearDown) { + tearDown.apply(this, arguments); + } + + if (exception) { + throw exception; + } + + return result; + }; + } + + function makeApi(sinon) { + function testCase(tests, prefix) { + /*jsl:ignore*/ + if (!tests || typeof tests != "object") { + throw new TypeError("sinon.testCase needs an object with test functions"); + } + /*jsl:end*/ + + prefix = prefix || "test"; + var rPrefix = new RegExp("^" + prefix); + var methods = {}, testName, property, method; + var setUp = tests.setUp; + var tearDown = tests.tearDown; + + for (testName in tests) { + if (tests.hasOwnProperty(testName)) { + property = tests[testName]; + + if (/^(setUp|tearDown)$/.test(testName)) { + continue; + } + + if (typeof property == "function" && rPrefix.test(testName)) { + method = property; + + if (setUp || tearDown) { + method = createTest(property, setUp, tearDown); + } + + methods[testName] = sinon.test(method); + } else { + methods[testName] = tests[testName]; + } + } + } + + return methods; + } + + sinon.testCase = testCase; + return testCase; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./test"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } +}(typeof sinon == "object" && sinon || null)); + +/** + * @depend times_in_words.js + * @depend util/core.js + * @depend match.js + * @depend format.js + */ +/** + * Assertions matching the test spy retrieval interface. + * + * @author Christian Johansen (christian@cjohansen.no) + * @license BSD + * + * Copyright (c) 2010-2013 Christian Johansen + */ + +(function (sinon, global) { + var slice = Array.prototype.slice; + + function makeApi(sinon) { + var assert; + + function verifyIsStub() { + var method; + + for (var i = 0, l = arguments.length; i < l; ++i) { + method = arguments[i]; + + if (!method) { + assert.fail("fake is not a spy"); + } + + if (method.proxy) { + verifyIsStub(method.proxy); + } else { + if (typeof method != "function") { + assert.fail(method + " is not a function"); + } + + if (typeof method.getCall != "function") { + assert.fail(method + " is not stubbed"); + } + } + + } + } + + function failAssertion(object, msg) { + object = object || global; + var failMethod = object.fail || assert.fail; + failMethod.call(object, msg); + } + + function mirrorPropAsAssertion(name, method, message) { + if (arguments.length == 2) { + message = method; + method = name; + } + + assert[name] = function (fake) { + verifyIsStub(fake); + + var args = slice.call(arguments, 1); + var failed = false; + + if (typeof method == "function") { + failed = !method(fake); + } else { + failed = typeof fake[method] == "function" ? + !fake[method].apply(fake, args) : !fake[method]; + } + + if (failed) { + failAssertion(this, (fake.printf || fake.proxy.printf).apply(fake, [message].concat(args))); + } else { + assert.pass(name); + } + }; + } + + function exposedName(prefix, prop) { + return !prefix || /^fail/.test(prop) ? prop : + prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1); + } + + assert = { + failException: "AssertError", + + fail: function fail(message) { + var error = new Error(message); + error.name = this.failException || assert.failException; + + throw error; + }, + + pass: function pass(assertion) {}, + + callOrder: function assertCallOrder() { + verifyIsStub.apply(null, arguments); + var expected = "", actual = ""; + + if (!sinon.calledInOrder(arguments)) { + try { + expected = [].join.call(arguments, ", "); + var calls = slice.call(arguments); + var i = calls.length; + while (i) { + if (!calls[--i].called) { + calls.splice(i, 1); + } + } + actual = sinon.orderByFirstCall(calls).join(", "); + } catch (e) { + // If this fails, we'll just fall back to the blank string + } + + failAssertion(this, "expected " + expected + " to be " + + "called in order but were called as " + actual); + } else { + assert.pass("callOrder"); + } + }, + + callCount: function assertCallCount(method, count) { + verifyIsStub(method); + + if (method.callCount != count) { + var msg = "expected %n to be called " + sinon.timesInWords(count) + + " but was called %c%C"; + failAssertion(this, method.printf(msg)); + } else { + assert.pass("callCount"); + } + }, + + expose: function expose(target, options) { + if (!target) { + throw new TypeError("target is null or undefined"); + } + + var o = options || {}; + var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix; + var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail; + + for (var method in this) { + if (method != "expose" && (includeFail || !/^(fail)/.test(method))) { + target[exposedName(prefix, method)] = this[method]; + } + } + + return target; + }, + + match: function match(actual, expectation) { + var matcher = sinon.match(expectation); + if (matcher.test(actual)) { + assert.pass("match"); + } else { + var formatted = [ + "expected value to match", + " expected = " + sinon.format(expectation), + " actual = " + sinon.format(actual) + ] + failAssertion(this, formatted.join("\n")); + } + } + }; + + mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); + mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; }, + "expected %n to not have been called but was called %c%C"); + mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); + mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); + mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); + mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); + mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t"); + mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new"); + mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new"); + mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); + mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C"); + mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); + mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C"); + mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); + mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); + mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); + mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); + mirrorPropAsAssertion("threw", "%n did not throw exception%C"); + mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); + + sinon.assert = assert; + return assert; + } + + var isNode = typeof module !== "undefined" && module.exports && typeof require == "function"; + var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; + + function loadDependencies(require, exports, module) { + var sinon = require("./util/core"); + require("./match"); + require("./format"); + module.exports = makeApi(sinon); + } + + if (isAMD) { + define(loadDependencies); + } else if (isNode) { + loadDependencies(require, module.exports, module); + } else if (!sinon) { + return; + } else { + makeApi(sinon); + } + +}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global)); + + return sinon; +})); diff --git a/src/effects/Tween.js b/src/effects/Tween.js index 478fed007b..d7cd8e606e 100644 --- a/src/effects/Tween.js +++ b/src/effects/Tween.js @@ -59,8 +59,10 @@ Tween.propHooks = { get: function( tween ) { var result; - if ( tween.elem[ tween.prop ] != null && - (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { return tween.elem[ tween.prop ]; } @@ -78,7 +80,7 @@ Tween.propHooks = { // Use .style if available and use plain properties where available. if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.style && + } else if ( tween.elem.nodeType === 1 && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); diff --git a/src/selector-native.js b/src/selector-native.js index 1b2dd185ba..5717918bcd 100644 --- a/src/selector-native.js +++ b/src/selector-native.js @@ -154,7 +154,8 @@ jQuery.extend({ expr: { attrHandle: {}, match: { - bool: /^(?:checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$/i, + bool: new RegExp( "^(?:checked|selected|async|autofocus|autoplay|controls|defer" + + "|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$", "i" ), needsContext: /^[\x20\t\r\n\f]*[>+~]/ } } diff --git a/test/data/testinit.js b/test/data/testinit.js index 468956d4df..e59d9db325 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -285,7 +285,8 @@ this.loadTests = function() { "unit/ajax.js", "unit/effects.js", "unit/offset.js", - "unit/dimensions.js" + "unit/dimensions.js", + "unit/tween.js" ]; // Ensure load order (to preserve test numbers) diff --git a/test/index.html b/test/index.html index d8ccdaa454..0285176d3d 100644 --- a/test/index.html +++ b/test/index.html @@ -13,9 +13,9 @@ + - diff --git a/test/unit/effects.js b/test/unit/effects.js index 571fda0316..7aff2242ab 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -10,13 +10,15 @@ var oldRaf = window.requestAnimationFrame; module("effects", { setup: function() { window.requestAnimationFrame = null; - this.clock = sinon.useFakeTimers( 505877050 ); + 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.clock.restore(); + this.sandbox.restore(); jQuery.now = Date.now; jQuery.fx.stop(); jQuery.fx.interval = this._oldInterval; diff --git a/test/unit/tween.js b/test/unit/tween.js new file mode 100644 index 0000000000..8b40d974e4 --- /dev/null +++ b/test/unit/tween.js @@ -0,0 +1,298 @@ +( function() { + +// Can't test what ain't there +if ( !jQuery.fx ) { + return; +} + +var oldRaf = window.requestAnimationFrame; + +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 ); + } +} ); + +test( "jQuery.Tween - Default propHooks on plain objects", function() { + expect( 8 ); + var propHooks, defaultHook, testObject, fakeTween, stepSpy; + + propHooks = jQuery.Tween.propHooks; + equal( typeof propHooks, "object", "jQuery.Tween.propHooks exists" ); + + defaultHook = propHooks._default; + ok( defaultHook, "_default propHook exists" ); + + testObject = { test: 0 }; + fakeTween = { elem: testObject, prop: "test", now: 10, unit: "px" }; + + equal( defaultHook.get( fakeTween ), 0, "Can get property of object" ); + + fakeTween.prop = "testMissing"; + equal( defaultHook.get( fakeTween ), undefined, "Can get missing property on object" ); + + defaultHook.set( fakeTween ); + equal( testObject.testMissing, 10, "Sets missing value properly on plain object" ); + + fakeTween.prop = "opacity"; + defaultHook.set( fakeTween ); + equal( testObject.opacity, 10, "Correctly set opacity on plain object" ); + + fakeTween.prop = "test"; + stepSpy = jQuery.fx.step.test = this.sandbox.spy(); + + defaultHook.set( fakeTween ); + ok( stepSpy.calledWith( fakeTween ), "Step function called with Tween" ); + equal( testObject.test, 0, "Because step didn't set, value is unchanged" ); +} ); + +test( "jQuery.Tween - Default propHooks on elements", function() { + expect( 19 ); + var propHooks, defaultHook, testElement, fakeTween, cssStub, styleStub, stepSpy; + + propHooks = jQuery.Tween.propHooks; + equal( typeof propHooks, "object", "jQuery.Tween.propHooks exists" ); + + defaultHook = propHooks._default; + 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 ); + + equal( defaultHook.get( fakeTween ), 10, "Gets expected style value" ); + ok( cssStub.calledWith( testElement, "height", "" ), "Calls jQuery.css correctly" ); + + fakeTween.prop = "testOpti"; + testElement.testOpti = 15; + cssStub.reset(); + + equal( defaultHook.get( fakeTween ), 15, "Gets expected value not defined on style" ); + equal( cssStub.callCount, 0, "Did not call jQuery.css" ); + + fakeTween.prop = "testMissing"; + equal( defaultHook.get( fakeTween ), 10, "Can get missing property on element" ); + ok( cssStub.calledWith( testElement, "testMissing", "" ), "...using jQuery.css" ); + + cssStub.returns( "" ); + equal( defaultHook.get( fakeTween ), 0, "Uses 0 for empty string" ); + + cssStub.returns( "auto" ); + equal( defaultHook.get( fakeTween ), 0, "Uses 0 for 'auto'" ); + + cssStub.returns( null ); + equal( defaultHook.get( fakeTween ), 0, "Uses 0 for null" ); + + cssStub.returns( undefined ); + equal( defaultHook.get( fakeTween ), 0, "Uses 0 for undefined" ); + + cssStub.reset(); + + // Setters + styleStub = this.sandbox.stub( jQuery, "style" ); + fakeTween.prop = "height"; + + defaultHook.set( fakeTween ); + ok( styleStub.calledWith( testElement, "height", "10px" ), + "Calls jQuery.style with elem, prop, now+unit" ); + + styleStub.reset(); + fakeTween.prop = "testMissing"; + + defaultHook.set( fakeTween ); + equal( styleStub.callCount, 0, "Did not call jQuery.style for non css property" ); + 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; + + ok( styleStub.calledWith( testElement, "testMissing", "11px" ), + "Presence of cssHooks causes jQuery.style with elem, prop, now+unit" ); + equal( testElement.testMissing, 10, "And value was unchanged" ); + + stepSpy = jQuery.fx.step.test = this.sandbox.spy(); + styleStub.reset(); + + fakeTween.prop = "test"; + defaultHook.set( fakeTween ); + ok( stepSpy.calledWith( fakeTween ), "Step function called with Tween" ); + equal( styleStub.callCount, 0, "Did not call jQuery.style" ); +} ); + +test( "jQuery.Tween - Plain Object", function() { + expect( 13 ); + var testObject = { test: 100 }, + testOptions = { duration: 100 }, + tween, easingSpy; + + tween = jQuery.Tween( testObject, testOptions, "test", 0, "linear" ); + equal( tween.elem, testObject, "Sets .element" ); + equal( tween.options, testOptions, "sets .options" ); + equal( tween.prop, "test", "sets .prop" ); + equal( tween.end, 0, "sets .end" ); + + equal( tween.easing, "linear", "sets .easing when provided" ); + + equal( tween.start, 100, "Reads .start value during construction" ); + equal( tween.now, 100, "Reads .now value during construction" ); + + easingSpy = this.sandbox.spy( jQuery.easing, "linear" ); + + equal( tween.run( 0.1 ), tween, ".run() returns this" ); + + equal( tween.now, 90, "Calculated tween" ); + + ok( easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ), + "...using jQuery.easing.linear with back-compat arguments" ); + equal( testObject.test, 90, "Set value" ); + + tween.run( 1 ); + equal( testObject.test, 0, "Checking another value" ); + + tween.run( 0 ); + equal( testObject.test, 100, "Can even go back in time" ); +} ); + +test( "jQuery.Tween - Element", function() { + expect( 15 ); + var testElement = jQuery( "
        " ).css( "height", 100 )[ 0 ], + testOptions = { duration: 100 }, + tween, easingSpy, eased; + + tween = jQuery.Tween( testElement, testOptions, "height", 0 ); + equal( tween.elem, testElement, "Sets .element" ); + equal( tween.options, testOptions, "sets .options" ); + equal( tween.prop, "height", "sets .prop" ); + equal( tween.end, 0, "sets .end" ); + + equal( tween.easing, jQuery.easing._default, "sets .easing to default when not provided" ); + equal( tween.unit, "px", "sets .unit to px when not provided" ); + + equal( tween.start, 100, "Reads .start value during construction" ); + equal( tween.now, 100, "Reads .now value during construction" ); + + easingSpy = this.sandbox.spy( jQuery.easing, "swing" ); + + equal( tween.run( 0.1 ), tween, ".run() returns this" ); + equal( tween.pos, jQuery.easing.swing( 0.1 ), "set .pos" ); + eased = 100 - ( jQuery.easing.swing( 0.1 ) * 100 ); + equal( tween.now, eased, "Calculated tween" ); + + ok( easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ), + "...using jQuery.easing.linear with back-compat arguments" ); + equal( parseFloat( testElement.style.height ).toFixed( 5 ), eased.toFixed( 5 ), "Set value" ); + + tween.run( 1 ); + equal( testElement.style.height, "0px", "Checking another value" ); + + tween.run( 0 ); + equal( testElement.style.height, "100px", "Can even go back in time" ); +} ); + +test( "jQuery.Tween - No duration", function() { + 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 ); + + equal( tween.pos, 0.5, "set .pos correctly" ); + equal( testObject.test, 50, "set value on object correctly" ); + equal( easingSpy.callCount, 0, "didn't ease the value" ); +} ); + +test( "jQuery.Tween - step function option", function() { + 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" ); + equal( testOptions.step.callCount, 0, "didn't call step on create" ); + + tween.run( 0.5 ); + ok( testOptions.step.calledOn( testObject ), + "Called step function in context of animated object" ); + ok( testOptions.step.calledWith( 50, tween ), "Called step function with correct parameters" ); + + ok( testOptions.step.calledBefore( propHookSpy ), + "Called step function before calling propHook.set" ); + +} ); + +test( "jQuery.Tween - custom propHooks", function() { + 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" ); + ok( propHook.get.calledWith( tween ), "called propHook.get on create" ); + equal( tween.now, 100, "Used return value from propHook.get" ); + + tween.run( 0.5 ); + ok( propHook.set.calledWith( tween ), "Called propHook.set function with correct parameters" ); + + delete jQuery.Tween.propHooks.testHooked; +} ); + +test( "jQuery.Tween - custom propHooks - advanced values", function() { + 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" ); + ok( propHook.get.calledWith( tween ), "called propHook.get on create" ); + 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? + ok( isNaN( tween.now ), "Used return value from propHook.get" ); + equal( tween.pos, 0.5, "But the eased percent is still avaliable" ); + ok( propHook.set.calledWith( tween ), "Called propHook.set function with correct parameters" ); + + delete jQuery.Tween.propHooks.testHooked; +} ); + +} )(); From b3b2d6c3dd51fbdc69e1942e9af75cc99a1834c2 Mon Sep 17 00:00:00 2001 From: Corey Frang Date: Tue, 19 May 2015 17:48:42 -0400 Subject: [PATCH 0343/1272] Effects: Adding unit tests for jQuery.Animation Closes gh-2326 --- Gruntfile.js | 5 +- src/effects.js | 44 ++++---- test/data/testinit.js | 1 + test/unit/animation.js | 230 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 260 insertions(+), 20 deletions(-) create mode 100644 test/unit/animation.js diff --git a/Gruntfile.js b/Gruntfile.js index 8c88370e49..1a6bdac1ac 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -103,14 +103,15 @@ module.exports = function( grunt ) { src: "src/**/*.js", gruntfile: "Gruntfile.js", - // Right now, check only test helpers - test: [ "test/data/testrunner.js", "test/unit/tween.js" ], + // Check parts of tests that pass + test: [ "test/data/testrunner.js", "test/unit/animation.js", "test/unit/tween.js" ], release: [ "build/*.js", "!build/release-notes.js" ], tasks: "build/tasks/*.js" }, testswarm: { tests: [ "ajax", + "animation", "attributes", "callbacks", "core", diff --git a/src/effects.js b/src/effects.js index 53b73fd848..40da887053 100644 --- a/src/effects.js +++ b/src/effects.js @@ -2,6 +2,7 @@ define([ "./core", "./var/document", "./var/rcssNum", + "./var/rnotwhite", "./css/var/cssExpand", "./css/var/isHidden", "./css/var/swap", @@ -16,20 +17,13 @@ define([ "./manipulation", "./css", "./effects/Tween" -], function( jQuery, document, rcssNum, cssExpand, isHidden, swap, adjustCSS, dataPriv, showHide ) { +], function( jQuery, document, rcssNum, rnotwhite, cssExpand, isHidden, swap, + adjustCSS, dataPriv, showHide ) { var fxNow, timerId, rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/, - animationPrefilters = [ defaultPrefilter ], - tweeners = { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }; + rrun = /queueHooks$/; function raf() { if ( timerId ) { @@ -69,7 +63,7 @@ function genFx( type, includeWidth ) { function createTween( value, prop, animation ) { var tween, - collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), index = 0, length = collection.length; for ( ; index < length; index++ ) { @@ -281,7 +275,7 @@ function Animation( elem, properties, options ) { var result, stopped, index = 0, - length = animationPrefilters.length, + length = Animation.prefilters.length, deferred = jQuery.Deferred().always( function() { // Don't match elem in the :animated selector delete tick.elem; @@ -357,8 +351,12 @@ function Animation( elem, properties, options ) { propFilter( props, animation.opts.specialEasing ); for ( ; index < length ; index++ ) { - result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); + 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; } } @@ -386,12 +384,20 @@ function Animation( elem, properties, options ) { jQuery.Animation = jQuery.extend( Animation, { + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + tweener: function( props, callback ) { if ( jQuery.isFunction( props ) ) { callback = props; props = [ "*" ]; } else { - props = props.split(" "); + props = props.match( rnotwhite ); } var prop, @@ -400,16 +406,18 @@ jQuery.Animation = jQuery.extend( Animation, { for ( ; index < length ; index++ ) { prop = props[ index ]; - tweeners[ prop ] = tweeners[ prop ] || []; - tweeners[ prop ].unshift( callback ); + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); } }, + prefilters: [ defaultPrefilter ], + prefilter: function( callback, prepend ) { if ( prepend ) { - animationPrefilters.unshift( callback ); + Animation.prefilters.unshift( callback ); } else { - animationPrefilters.push( callback ); + Animation.prefilters.push( callback ); } } }); diff --git a/test/data/testinit.js b/test/data/testinit.js index e59d9db325..ef90fe45c9 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -286,6 +286,7 @@ this.loadTests = function() { "unit/effects.js", "unit/offset.js", "unit/dimensions.js", + "unit/animation.js", "unit/tween.js" ]; diff --git a/test/unit/animation.js b/test/unit/animation.js new file mode 100644 index 0000000000..6bb070145e --- /dev/null +++ b/test/unit/animation.js @@ -0,0 +1,230 @@ +( 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 +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 ); + } +} ); + +test( "Animation( subject, props, opts ) - shape", function() { + expect( 20 ); + + var subject = { test: 0 }, + props = { test: 1 }, + opts = { queue: "fx", duration: 100 }, + animation = jQuery.Animation( subject, props, opts ); + + equal( animation.elem, subject, ".elem is set to the exact object passed" ); + equal( animation.originalOptions, opts, ".originalOptions is set to options passed" ); + equal( animation.originalProperties, props, ".originalProperties is set to props passed" ); + + notEqual( animation.props, props, ".props is not the original however" ); + deepEqual( animation.props, props, ".props is a copy of the original" ); + + deepEqual( animation.opts, { + duration: 100, + queue: "fx", + specialEasing: { test: undefined }, + easing: jQuery.easing._default + }, ".options is filled with default easing and specialEasing" ); + + equal( animation.startTime, startTime, "startTime was set" ); + equal( animation.duration, 100, ".duration is set" ); + + equal( animation.tweens.length, 1, ".tweens has one Tween" ); + equal( typeof animation.tweens[ 0 ].run, "function", "which has a .run function" ); + + equal( typeof animation.createTween, "function", ".createTween is a function" ); + equal( typeof animation.stop, "function", ".stop is a function" ); + + equal( typeof animation.done, "function", ".done is a function" ); + equal( typeof animation.fail, "function", ".fail is a function" ); + equal( typeof animation.always, "function", ".always is a function" ); + equal( typeof animation.progress, "function", ".progress is a function" ); + + equal( jQuery.timers.length, 1, "Added a timers function" ); + equal( jQuery.timers[ 0 ].elem, subject, "...with .elem as the subject" ); + equal( jQuery.timers[ 0 ].anim, animation, "...with .anim as the animation" ); + equal( jQuery.timers[ 0 ].queue, opts.queue, "...with .queue" ); + + // Cleanup after ourselves by ticking to the end + this.clock.tick( 100 ); +} ); + +test( "Animation.prefilter( fn ) - calls prefilter after defaultPrefilter", function() { + expect( 1 ); + + var prefilter = this.sandbox.stub(), + defaultSpy = this.sandbox.spy( jQuery.Animation.prefilters, 0 ); + + jQuery.Animation.prefilter( prefilter ); + + jQuery.Animation( {}, {}, {} ); + ok( prefilter.calledAfter( defaultSpy ), "our prefilter called after" ); +} ); + +test( "Animation.prefilter( fn, true ) - calls prefilter before defaultPrefilter", function() { + expect( 1 ); + + var prefilter = this.sandbox.stub(), + defaultSpy = this.sandbox.spy( jQuery.Animation.prefilters, 0 ); + + jQuery.Animation.prefilter( prefilter, true ); + + jQuery.Animation( {}, {}, {} ); + ok( prefilter.calledBefore( defaultSpy ), "our prefilter called before" ); +} ); + +test( "Animation.prefilter - prefilter return hooks", function() { + 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" ); + + deepEqual( realAnimation.originalProperties, props, "originalProperties" ); + equal( arguments[ 0 ], this.elem, "first param elem" ); + equal( arguments[ 1 ], this.props, "second param props" ); + 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 ); + + equal( prefilter.callCount, 1, "Called prefilter" ); + + equal( defaultSpy.callCount, 0, + "Returning something from a prefilter caused remaining prefilters to not run" ); + equal( jQuery.fx.timer.callCount, 0, "Returning something never queues a timer" ); + equal( animation, ourAnimation, "Returning something returned it from jQuery.Animation" ); + equal( realAnimation.createTween.callCount, 0, "Returning something never creates tweens" ); + 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 ); + + equal( prefilter.callCount, 1, "Called prefilter" ); + equal( queueSpy.callCount, 0, "Next function in queue not called" ); + + realAnimation.opts.complete.call( realAnimation.elem ); + equal( queueSpy.callCount, 1, "Next function in queue called after complete" ); + + equal( prefilter.callCount, 2, "Called prefilter again - animation #2" ); + equal( ourAnimation.stop.callCount, 0, ".stop() on our animation hasn't been called" ); + + element.stop(); + equal( ourAnimation.stop.callCount, 1, ".stop() called ourAnimation.stop()" ); + ok( !ourAnimation.stop.args[ 0 ][ 0 ], ".stop( falsy ) (undefined or false are both valid)" ); + + equal( queueSpy.callCount, 2, "Next queue function called" ); + ok( queueSpy.calledAfter( ourAnimation.stop ), "After our animation was told to stop" ); + + // ourAnimation.stop.reset(); + equal( prefilter.callCount, 3, "Got the next animation" ); + + ourAnimation.stop.reset(); + + // do not clear queue, gotoEnd + element.stop( false, true ); + ok( ourAnimation.stop.calledWith( true ), ".stop(true) calls .stop(true)" ); + ok( queueSpy.calledAfter( ourAnimation.stop ), + "and the next queue function ran after we were told" ); +} ); + +test( "Animation.tweener( fn ) - unshifts a * tweener", function() { + expect( 2 ); + var starTweeners = jQuery.Animation.tweeners[ "*" ]; + + jQuery.Animation.tweener( jQuery.noop ); + equal( starTweeners.length, 2 ); + deepEqual( starTweeners, [ jQuery.noop, defaultTweener ] ); +} ); + +test( "Animation.tweener( 'prop', fn ) - unshifts a 'prop' tweener", function() { + expect( 4 ); + var tweeners = jQuery.Animation.tweeners, + fn = function() {}; + + jQuery.Animation.tweener( "prop", jQuery.noop ); + equal( tweeners.prop.length, 1 ); + deepEqual( tweeners.prop, [ jQuery.noop ] ); + + jQuery.Animation.tweener( "prop", fn ); + equal( tweeners.prop.length, 2 ); + deepEqual( tweeners.prop, [ fn, jQuery.noop ] ); +} ); + +test( "Animation.tweener( 'list of props', fn ) - unshifts a tweener to each prop", function() { + expect( 2 ); + var tweeners = jQuery.Animation.tweeners, + fn = function() {}; + + jQuery.Animation.tweener( "list of props", jQuery.noop ); + 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 ); + deepEqual( tweeners, { + list: [ fn, jQuery.noop ], + of: [ fn, jQuery.noop ], + props: [ fn, jQuery.noop ], + "*": [ fn, defaultTweener ] + } ); +} ); + +} )(); From a44cfa00665d21c3197e25c2d63741dc15f6ffb9 Mon Sep 17 00:00:00 2001 From: Corey Frang Date: Fri, 26 Jun 2015 20:20:48 -0400 Subject: [PATCH 0344/1272] Tests: Lower the checks rounding error The CSS value rounding error was causig failures on FF and IE. --- test/unit/tween.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/tween.js b/test/unit/tween.js index 8b40d974e4..39894c5757 100644 --- a/test/unit/tween.js +++ b/test/unit/tween.js @@ -198,7 +198,7 @@ test( "jQuery.Tween - Element", function() { ok( easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ), "...using jQuery.easing.linear with back-compat arguments" ); - equal( parseFloat( testElement.style.height ).toFixed( 5 ), eased.toFixed( 5 ), "Set value" ); + equal( parseFloat( testElement.style.height ).toFixed( 2 ), eased.toFixed( 2 ), "Set value" ); tween.run( 1 ); equal( testElement.style.height, "0px", "Checking another value" ); From 8e4aac8cb03ffb88373ea99629165d82ff5eccdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Wed, 1 Jul 2015 23:20:32 +0200 Subject: [PATCH 0345/1272] CSS: Improve a comment explaining IE11 fullscreen bug --- src/css.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/css.js b/src/css.js index 922f44162c..373fdcb7e4 100644 --- a/src/css.js +++ b/src/css.js @@ -114,7 +114,8 @@ function getWidthOrHeight( elem, name, extra ) { isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; // Support: IE11 only - // Fix for edge case in IE 11. See gh-1764 + // 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 From 84ccf2606c6b97d5875774bf774f9f2aae950ae7 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 6 Jul 2015 10:13:01 -0400 Subject: [PATCH 0346/1272] Deferred: add .catch handler Fixes gh-2102 --- src/deferred.js | 3 +++ test/unit/deferred.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/deferred.js b/src/deferred.js index 188303c975..216baabb07 100644 --- a/src/deferred.js +++ b/src/deferred.js @@ -33,6 +33,9 @@ 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 */ ) { var fns = arguments; diff --git a/test/unit/deferred.js b/test/unit/deferred.js index 97f9111dd3..af91b36169 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -167,6 +167,42 @@ test( "jQuery.Deferred.then - filtering (fail)", function( assert ) { }); }); +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(); + }); +}); + test( "[PIPE ONLY] jQuery.Deferred.pipe - filtering (fail)", function( assert ) { assert.expect( 4 ); From b60b26e18477d21fa5ec9c6572e114fc5d441730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Thu, 2 Jul 2015 01:20:18 +0200 Subject: [PATCH 0347/1272] CSS: Make .css("width") & .css("height") return fractional values Fixes gh-1724 Closes gh-2439 --- src/css.js | 26 +++++++++++++++--------- test/unit/css.js | 45 +++++++++++++++++++++++++++++++++++++++++ test/unit/dimensions.js | 40 +++++++++++++++++++++--------------- 3 files changed, 86 insertions(+), 25 deletions(-) diff --git a/src/css.js b/src/css.js index 373fdcb7e4..859985f9d1 100644 --- a/src/css.js +++ b/src/css.js @@ -108,21 +108,23 @@ 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 valueIsBorderBox = true, - val = name === "width" ? elem.offsetWidth : elem.offsetHeight, + var val, + valueIsBorderBox = true, 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 ) { - // 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 ); - } + val *= 100; } // Some non-html elements return undefined for offsetWidth, so check for null/undefined @@ -309,7 +311,13 @@ 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" ) ) && - elem.offsetWidth === 0 ? + // 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 ) ? swap( elem, cssShow, function() { return getWidthOrHeight( elem, name, extra ); }) : diff --git a/test/unit/css.js b/test/unit/css.js index 22a3c76365..06de4acd9f 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -846,6 +846,51 @@ testIframeWithCallback( "css('width') should work correctly before document read } ); +( 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 ); + + test( "css('width') and css('height') should return fractional values for nodes in the document", function() { + if ( !supportsFractionalGBCR ) { + expect( 1 ); + ok( true, "This browser doesn't support fractional values in getBoundingClientRect()" ); + return; + } + + expect( 2 ); + + var el = jQuery( "
        " ).appendTo( "#qunit-fixture" ); + jQuery( "" ).appendTo( "#qunit-fixture" ); + + equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3", + "css('width') should return fractional values" ); + equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8", + "css('height') should return fractional values" ); + } ); + + test( "css('width') and css('height') should return fractional values for disconnected nodes", function() { + if ( !supportsFractionalGBCR ) { + expect( 1 ); + ok( true, "This browser doesn't support fractional values in getBoundingClientRect()" ); + return; + } + + expect( 2 ); + + var el = jQuery( "
        " ); + + equal( Number( el.css( "width" ).replace( /px$/, "" ) ).toFixed( 1 ), "33.3", + "css('width') should return fractional values" ); + equal( Number( el.css( "height" ).replace( /px$/, "" ) ).toFixed( 1 ), "88.8", + "css('height') should return fractional values" ); + } ); +} )(); + test("certain css values of 'normal' should be convertable to a number, see #8627", function() { expect ( 3 ); diff --git a/test/unit/dimensions.js b/test/unit/dimensions.js index 7e31771617..04810494a7 100644 --- a/test/unit/dimensions.js +++ b/test/unit/dimensions.js @@ -258,10 +258,12 @@ test("child of a hidden elem (or unconnected node) has accurate inner/outer/Widt equal( $divChild.outerWidth(), $divNormal.outerWidth(), "child of a hidden element outerWidth() is wrong see #9441" ); equal( $divChild.outerWidth(true), $divNormal.outerWidth( true ), "child of a hidden element outerWidth( true ) is wrong see #9300" ); - equal( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #9441" ); - equal( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #9441" ); - equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #9441" ); - equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #9300" ); + // Support: IE 10-11, Edge + // Child height is not always decimal + equal( $divChild.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "child of a hidden element height() is wrong see #9441" ); + equal( $divChild.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "child of a hidden element innerHeight() is wrong see #9441" ); + equal( $divChild.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "child of a hidden element outerHeight() is wrong see #9441" ); + equal( $divChild.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "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 equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #9441" ); @@ -269,10 +271,12 @@ test("child of a hidden elem (or unconnected node) has accurate inner/outer/Widt equal( $divUnconnected.outerWidth(), $divNormal.outerWidth(), "unconnected element outerWidth() is wrong see #9441" ); equal( $divUnconnected.outerWidth(true), $divNormal.outerWidth( true ), "unconnected element outerWidth( true ) is wrong see #9300" ); - equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #9441" ); - equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #9441" ); - equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #9441" ); - equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #9300" ); + // Support: IE 10-11, Edge + // Child height is not always decimal + equal( $divUnconnected.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "unconnected element height() is wrong see #9441" ); + equal( $divUnconnected.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "unconnected element innerHeight() is wrong see #9441" ); + equal( $divUnconnected.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "unconnected element outerHeight() is wrong see #9441" ); + equal( $divUnconnected.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "unconnected element outerHeight( true ) is wrong see #9300" ); // teardown html $divHiddenParent.remove(); @@ -329,10 +333,12 @@ test("box-sizing:border-box child of a hidden elem (or unconnected node) has acc equal( $divChild.outerWidth(), $divNormal.outerWidth(), "child of a hidden element outerWidth() is wrong see #10413" ); equal( $divChild.outerWidth(true), $divNormal.outerWidth( true ), "child of a hidden element outerWidth( true ) is wrong see #10413" ); - equal( $divChild.height(), $divNormal.height(), "child of a hidden element height() is wrong see #10413" ); - equal( $divChild.innerHeight(), $divNormal.innerHeight(), "child of a hidden element innerHeight() is wrong see #10413" ); - equal( $divChild.outerHeight(), $divNormal.outerHeight(), "child of a hidden element outerHeight() is wrong see #10413" ); - equal( $divChild.outerHeight(true), $divNormal.outerHeight( true ), "child of a hidden element outerHeight( true ) is wrong see #10413" ); + // Support: IE 10-11, Edge + // Child height is not always decimal + equal( $divChild.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "child of a hidden element height() is wrong see #10413" ); + equal( $divChild.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "child of a hidden element innerHeight() is wrong see #10413" ); + equal( $divChild.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "child of a hidden element outerHeight() is wrong see #10413" ); + equal( $divChild.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "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 equal( $divUnconnected.width(), $divNormal.width(), "unconnected element width() is wrong see #10413" ); @@ -340,10 +346,12 @@ test("box-sizing:border-box child of a hidden elem (or unconnected node) has acc equal( $divUnconnected.outerWidth(), $divNormal.outerWidth(), "unconnected element outerWidth() is wrong see #10413" ); equal( $divUnconnected.outerWidth(true), $divNormal.outerWidth( true ), "unconnected element outerWidth( true ) is wrong see #10413" ); - equal( $divUnconnected.height(), $divNormal.height(), "unconnected element height() is wrong see #10413" ); - equal( $divUnconnected.innerHeight(), $divNormal.innerHeight(), "unconnected element innerHeight() is wrong see #10413" ); - equal( $divUnconnected.outerHeight(), $divNormal.outerHeight(), "unconnected element outerHeight() is wrong see #10413" ); - equal( $divUnconnected.outerHeight(true), $divNormal.outerHeight( true ), "unconnected element outerHeight( true ) is wrong see #10413" ); + // Support: IE 10-11, Edge + // Child height is not always decimal + equal( $divUnconnected.height().toFixed( 3 ), $divNormal.height().toFixed( 3 ), "unconnected element height() is wrong see #10413" ); + equal( $divUnconnected.innerHeight().toFixed( 3 ), $divNormal.innerHeight().toFixed( 3 ), "unconnected element innerHeight() is wrong see #10413" ); + equal( $divUnconnected.outerHeight().toFixed( 3 ), $divNormal.outerHeight().toFixed( 3 ), "unconnected element outerHeight() is wrong see #10413" ); + equal( $divUnconnected.outerHeight( true ).toFixed( 3 ), $divNormal.outerHeight( true ).toFixed( 3 ), "unconnected element outerHeight( true ) is wrong see #10413" ); // teardown html $divHiddenParent.remove(); From 8887106702baa69ed80baa65c5a249786bffc77e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Tue, 23 Jun 2015 01:44:18 +0200 Subject: [PATCH 0348/1272] CSS: Add an integration test for issue gh-1764 Refs gh-1764 Refs gh-2401 Closes gh-2425 --- .../data/gh-1764-fullscreen-iframe.css | 18 ++++ .../data/gh-1764-fullscreen-iframe.html | 21 ++++ test/integration/data/gh-1764-fullscreen.js | 99 +++++++++++++++++++ test/integration/gh-1764-fullscreen.html | 34 +++++++ 4 files changed, 172 insertions(+) create mode 100644 test/integration/data/gh-1764-fullscreen-iframe.css create mode 100644 test/integration/data/gh-1764-fullscreen-iframe.html create mode 100644 test/integration/data/gh-1764-fullscreen.js create mode 100644 test/integration/gh-1764-fullscreen.html diff --git a/test/integration/data/gh-1764-fullscreen-iframe.css b/test/integration/data/gh-1764-fullscreen-iframe.css new file mode 100644 index 0000000000..ba4b4fa7d3 --- /dev/null +++ b/test/integration/data/gh-1764-fullscreen-iframe.css @@ -0,0 +1,18 @@ +.result { + font-size: 24px; + margin: 0.5em 0; + width: 700px; + height: 56px; +} + +.error { + background-color: red; +} + +.warn { + background-color: yellow; +} + +.success { + background-color: lightgreen; +} diff --git a/test/integration/data/gh-1764-fullscreen-iframe.html b/test/integration/data/gh-1764-fullscreen-iframe.html new file mode 100644 index 0000000000..bed56b8ecf --- /dev/null +++ b/test/integration/data/gh-1764-fullscreen-iframe.html @@ -0,0 +1,21 @@ + + + + + + Test for gh-1764 - test iframe + + + + +
        +
        + +
        + + + + + diff --git a/test/integration/data/gh-1764-fullscreen.js b/test/integration/data/gh-1764-fullscreen.js new file mode 100644 index 0000000000..e093c0dc78 --- /dev/null +++ b/test/integration/data/gh-1764-fullscreen.js @@ -0,0 +1,99 @@ +/* exported bootstrapFrom */ + +// `mode` may be "iframe" or not specified. +function bootstrapFrom( mainSelector, mode ) { + if ( mode === "iframe" && window.parent === window ) { + jQuery( mainSelector + " .result" ) + .attr( "class", "result warn" ) + .text( "This test should be run in an iframe. Open ../gh-1764-fullscreen.html." ); + jQuery( mainSelector + " .toggle-fullscreen" ).remove(); + return; + } + + var fullscreenSupported = document.exitFullscreen || + document.exitFullscreen || + document.msExitFullscreen || + document.mozCancelFullScreen || + document.webkitExitFullscreen; + + function isFullscreen() { + return !!(document.fullscreenElement || + document.mozFullScreenElement || + document.webkitFullscreenElement || + document.msFullscreenElement); + } + + function requestFullscreen( element ) { + if ( !isFullscreen() ) { + if ( element.requestFullscreen ) { + element.requestFullscreen(); + } else if ( element.msRequestFullscreen ) { + element.msRequestFullscreen(); + } else if ( element.mozRequestFullScreen ) { + element.mozRequestFullScreen(); + } else if ( element.webkitRequestFullscreen ) { + element.webkitRequestFullscreen(); + } + } + } + + function exitFullscreen() { + if ( document.exitFullscreen ) { + document.exitFullscreen(); + } else if ( document.msExitFullscreen ) { + document.msExitFullscreen(); + } else if ( document.mozCancelFullScreen ) { + document.mozCancelFullScreen(); + } else if ( document.webkitExitFullscreen ) { + document.webkitExitFullscreen(); + } + } + + function runTest() { + var dimensions; + if ( !fullscreenSupported ) { + jQuery( mainSelector + " .result" ) + .attr( "class", "result success" ) + .text( "Fullscreen mode is not supported in this browser. Test not run." ); + } else if ( !isFullscreen() ) { + jQuery( mainSelector + " .result" ) + .attr( "class", "result warn" ) + .text( "Enable fullscreen mode to fire the test." ); + } else { + dimensions = jQuery( mainSelector + " .result" ).css( [ "width", "height" ] ); + dimensions.width = parseFloat( dimensions.width ).toFixed( 3 ); + dimensions.height = parseFloat( dimensions.height ).toFixed( 3 ); + if ( dimensions.width === "700.000" && dimensions.height === "56.000" ) { + jQuery( mainSelector + " .result" ) + .attr( "class", "result success" ) + .text( "Dimensions in fullscreen mode are computed correctly." ); + } else { + jQuery( mainSelector + " .result" ) + .attr( "class", "result error" ) + .html( "Incorrect dimensions; " + + "expected: { width: '700.000', height: '56.000' };
        " + + "got: { width: '" + dimensions.width + "', height: '" + + dimensions.height + "' }." ); + } + } + } + + function toggleFullscreen() { + if ( isFullscreen() ) { + exitFullscreen(); + } else { + requestFullscreen( jQuery( mainSelector + " .container" )[0] ); + } + } + + $( mainSelector + " .toggle-fullscreen" ).on( "click", toggleFullscreen ); + + $( document ).on( [ + "webkitfullscreenchange", + "mozfullscreenchange", + "fullscreenchange", + "MSFullscreenChange", + ].join( " " ), runTest ); + + runTest(); +} diff --git a/test/integration/gh-1764-fullscreen.html b/test/integration/gh-1764-fullscreen.html new file mode 100644 index 0000000000..1cba659438 --- /dev/null +++ b/test/integration/gh-1764-fullscreen.html @@ -0,0 +1,34 @@ + + + + + + Test for gh-1764 + + + + + +
        +
        + +
        + + + + + + From dc8ba6af921f4c9650fb1e4cfc698b2a276fa53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Wed, 8 Jul 2015 13:00:38 +0200 Subject: [PATCH 0349/1272] Tests: Remove a trailing comma for compatibility with the compat branch --- test/integration/data/gh-1764-fullscreen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/data/gh-1764-fullscreen.js b/test/integration/data/gh-1764-fullscreen.js index e093c0dc78..c13c609f3b 100644 --- a/test/integration/data/gh-1764-fullscreen.js +++ b/test/integration/data/gh-1764-fullscreen.js @@ -92,7 +92,7 @@ function bootstrapFrom( mainSelector, mode ) { "webkitfullscreenchange", "mozfullscreenchange", "fullscreenchange", - "MSFullscreenChange", + "MSFullscreenChange" ].join( " " ), runTest ); runTest(); From 8f13997e89ca325a49f7581fad7e85fe37bad166 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Wed, 8 Jul 2015 13:41:48 -0400 Subject: [PATCH 0350/1272] Build: update AUTHORS.txt --- AUTHORS.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 48d68dcd4f..d8403cb731 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -245,3 +245,18 @@ Nicolas HENRY Anne-Gaelle Colom George Mauer Leonardo Braga +Stephen Edgar +Mr21 +Winston Howes +Jon Hester +Alexander O'Mara +Bastian Buchholz +Arthur Stolyar +Calvin Metcalf +Mu Haibao +Richard McDaniel +Chris Rebert +Gabriel Schulhof +Gilad Peleg +Martin Naumann +Thomas Tortorini From 3ec73efb26317239a4f22f0b023b0b99a4300a20 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Sat, 11 Jul 2015 11:41:06 -0400 Subject: [PATCH 0351/1272] Build: add mailmap entry --- .mailmap | 1 + AUTHORS.txt | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.mailmap b/.mailmap index 2ccdcb9ceb..2b3a980c08 100644 --- a/.mailmap +++ b/.mailmap @@ -85,6 +85,7 @@ Scott González Scott Jehl Sebastian Burkhard Senya Pugach +Thomas Tortorini Mr21 Timmy Willison Timmy Willison Timo Tijhof diff --git a/AUTHORS.txt b/AUTHORS.txt index d8403cb731..01e8686888 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -246,7 +246,7 @@ Anne-Gaelle Colom George Mauer Leonardo Braga Stephen Edgar -Mr21 +Thomas Tortorini Winston Howes Jon Hester Alexander O'Mara @@ -259,4 +259,3 @@ Chris Rebert Gabriel Schulhof Gilad Peleg Martin Naumann -Thomas Tortorini From a2ae215d999637e8d9d0906abcbf6b1ca35c8e6e Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Fri, 10 Jul 2015 20:58:43 +0300 Subject: [PATCH 0352/1272] Ajax: Remove jsonp callbacks through "jQuery#removeProp" method Fixes gh-2323 Closes gh-2464 --- src/ajax/jsonp.js | 10 ++++++++-- test/unit/ajax.js | 32 +++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/ajax/jsonp.js b/src/ajax/jsonp.js index a04898f67d..f469344e0b 100644 --- a/src/ajax/jsonp.js +++ b/src/ajax/jsonp.js @@ -64,8 +64,14 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { // Clean-up function (fires after converters) jqXHR.always(function() { - // Restore preexisting value - window[ callbackName ] = overwritten; + // If previous value didn't exist - remove it + if ( overwritten === undefined ) { + jQuery( window ).removeProp( callbackName ); + + // Otherwise restore preexisting value + } else { + window[ callbackName ] = overwritten; + } // Save back as free if ( s[ callbackName ] ) { diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 8a4ca7a657..359fa9d819 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1,12 +1,4 @@ module( "ajax", { - setup: function() { - var jsonpCallback = this.jsonpCallback = jQuery.ajaxSettings.jsonpCallback; - jQuery.ajaxSettings.jsonpCallback = function() { - var callback = jsonpCallback.apply( this, arguments ); - Globals.register( callback ); - return callback; - }; - }, teardown: function() { jQuery( document ).off( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxError ajaxSuccess" ); moduleTeardown.apply( this, arguments ); @@ -742,7 +734,7 @@ module( "ajax", { } ]); - ajaxTest( "jQuery.ajax() - JSONP - Explicit callback param" + label, 9, { + ajaxTest( "jQuery.ajax() - JSONP - Explicit callback param" + label, 10, { setup: function() { Globals.register("functionToCleanUp"); Globals.register("XXX"); @@ -765,6 +757,11 @@ module( "ajax", { crossDomain: crossDomain, jsonpCallback: "jsonpResults", success: function( data ) { + strictEqual( + typeof window[ "jsonpResults" ], + "function", + "should not rewrite original function" + ); ok( data.data, "JSON results returned (GET, custom callback name)" ); } }, { @@ -1356,16 +1353,29 @@ module( "ajax", { ]); jQuery.each( [ " - Same Domain", " - Cross Domain" ], function( crossDomain, label ) { - ajaxTest( "#8205 - jQuery.ajax() - JSONP - re-use callbacks name" + label, 2, { + ajaxTest( "#8205 - jQuery.ajax() - JSONP - re-use callbacks name" + label, 4, { url: "data/jsonp.php", dataType: "jsonp", crossDomain: crossDomain, beforeSend: function( jqXHR, s ) { s.callback = s.jsonpCallback; + + ok( this.callback in window, "JSONP callback name is in the window" ); }, success: function() { var previous = this; - strictEqual( previous.jsonpCallback, undefined, "jsonpCallback option is set back to default in callbacks" ); + + strictEqual( + previous.jsonpCallback, + undefined, + "jsonpCallback option is set back to default in callbacks" + ); + + ok( + !( this.callback in window ), + "JSONP callback name was removed from the window" + ); + jQuery.ajax({ url: "data/jsonp.php", dataType: "jsonp", From c44dd7775b387094d8c921c7e839e3c266e4f2c8 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 13 Jul 2015 15:01:33 -0400 Subject: [PATCH 0353/1272] Release: properly set the dist remote when it's a real release --- build/release/dist.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/release/dist.js b/build/release/dist.js index 7d134b429d..f17ea4ba70 100644 --- a/build/release/dist.js +++ b/build/release/dist.js @@ -4,7 +4,7 @@ module.exports = function( Release, complete ) { fs = require( "fs" ), shell = require( "shelljs" ), pkg = require( Release.dir.repo + "/package.json" ), - distRemote = Release.remote.replace( "jquery", "jquery-dist" ), + distRemote = Release.remote.replace( "jquery.git", "jquery-dist.git" ), // These files are included with the distrubtion files = [ "src", From bf591fb597a056bf2fc9bc474010374695b18d1a Mon Sep 17 00:00:00 2001 From: Marek Lewandowski Date: Mon, 13 Jul 2015 14:39:52 +0200 Subject: [PATCH 0354/1272] Selector: Define jQuery.uniqueSort in selector-native too Fixes gh-2466 Closes gh-2467 --- src/selector-native.js | 46 ++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/selector-native.js b/src/selector-native.js index 5717918bcd..2d5cb30263 100644 --- a/src/selector-native.js +++ b/src/selector-native.js @@ -67,6 +67,28 @@ var hasDuplicate, // Not directly comparable, sort on existence of method return a.compareDocumentPosition ? -1 : 1; + }, + uniqueSort = function( results ) { + var elem, + duplicates = [], + i = 0, + j = 0; + + hasDuplicate = false; + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + return results; }; jQuery.extend({ @@ -99,28 +121,8 @@ jQuery.extend({ return results; }, - unique: function( results ) { - var elem, - duplicates = [], - i = 0, - j = 0; - - hasDuplicate = false; - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - return results; - }, + uniqueSort: uniqueSort, + unique: uniqueSort, text: function( elem ) { var node, ret = "", From 1c59b308d201d6dd0f0aed2ad0256d01b9f68047 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 20 Jul 2015 00:55:48 +0200 Subject: [PATCH 0355/1272] Build: Acknowledge Android 2.3 is not ES5-compatible Android 2.3 chokes on unquoted reserved words being used as property names which was making Deferred tests not run. Acknowledge the sad fact that Android 2.3 is not ES5-compliant browser and enable the "es3" option in JSHint config. Fixes gh-2478 Closes gh-2481 --- src/.jshintrc | 3 +++ test/.jshintrc | 3 +++ test/unit/core.js | 2 +- test/unit/css.js | 2 +- test/unit/deferred.js | 8 ++++---- test/unit/effects.js | 2 +- 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/.jshintrc b/src/.jshintrc index 6144bf420e..281b683b90 100644 --- a/src/.jshintrc +++ b/src/.jshintrc @@ -12,8 +12,11 @@ "sub": true, + "es3": true, + "globals": { "window": true, + "JSON": false, "jQuery": true, "define": true, diff --git a/test/.jshintrc b/test/.jshintrc index 7aef665c68..6b380d6baf 100644 --- a/test/.jshintrc +++ b/test/.jshintrc @@ -10,6 +10,8 @@ "undef": true, "unused": true, + "es3": true, + "evil": true, "sub": true, @@ -21,6 +23,7 @@ "require": false, "define": false, "DOMParser": false, + "JSON": false, "Promise": false, "Symbol": false, "QUnit": false, diff --git a/test/unit/core.js b/test/unit/core.js index 5a87e2f0cf..8cfe98f838 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1400,7 +1400,7 @@ test("jQuery.parseJSON", function() { deepEqual( jQuery.parseJSON( "{ \"string\": \"\", \"number\": 4.2e+1, \"object\": {}," + "\"array\": [[]], \"boolean\": [ true, false ], \"null\": null }"), - { string: "", number: 42, object: {}, array: [[]], boolean: [ true, false ], "null": null }, + { string: "", number: 42, object: {}, array: [[]], "boolean": [ true, false ], "null": null }, "Dictionary of all data types" ); diff --git a/test/unit/css.js b/test/unit/css.js index 06de4acd9f..47db2c8f31 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1225,7 +1225,7 @@ test( "Do not throw on frame elements from css method (#15098)", 1, function() { if ( transformName ) { equal( elemStyle[ transformName ], transformVal, "setting properly-prefixed transform" ); } - equal( elemStyle.undefined, undefined, "Nothing writes to node.style.undefined" ); + equal( elemStyle[ "undefined" ], undefined, "Nothing writes to node.style.undefined" ); } ); test( "Don't detect fake set properties on a node when caching the prefixed version", function() { diff --git a/test/unit/deferred.js b/test/unit/deferred.js index af91b36169..1aa15435fe 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -172,7 +172,7 @@ test( "jQuery.Deferred.catch", function( assert ) { var value1, value2, value3, defer = jQuery.Deferred(), - piped = defer.catch(function( a, b ) { + piped = defer[ "catch" ](function( a, b ) { return a * b; }), done = jQuery.map( new Array( 3 ), function() { return assert.async(); } ); @@ -186,18 +186,18 @@ test( "jQuery.Deferred.catch", function( assert ) { value2 = b; }); - defer.reject( 2, 3 ).catch(function() { + 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() { + 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 ) { + jQuery.Deferred().reject()[ "catch" ]( jQuery.noop ).done(function( value ) { assert.strictEqual( value, undefined, "then fail callback can return undefined/null" ); done.pop().call(); }); diff --git a/test/unit/effects.js b/test/unit/effects.js index 7aff2242ab..47f8bdf0af 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -1579,7 +1579,7 @@ test("Initial step callback should show element as :animated (#14623)", 1, funct var foo = jQuery( "#foo" ); foo.animate({ - opacity: 0, + opacity: 0 }, { duration: 100, step: function() { From d24275372624bac897c4131fd1507a58c09a1483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 20 Jul 2015 20:22:34 +0200 Subject: [PATCH 0356/1272] Core: Add a support comment for Safari 8 Related issue: https://bugs.webkit.org/show_bug.cgi?id=137337 Thanks @phistuck! Refs cfe468f29c4cbe1a457d0feb17dec90dcfd7c280 --- src/core/support.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/support.js b/src/core/support.js index 4ef1dacab9..68d20e3538 100644 --- a/src/core/support.js +++ b/src/core/support.js @@ -3,6 +3,11 @@ define([ "../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 = "
        "; From bf48c21d225c31f0f9b5441d95f73615ca3dcfdb Mon Sep 17 00:00:00 2001 From: Thomas Tortorini Date: Thu, 25 Jun 2015 06:18:04 +0200 Subject: [PATCH 0357/1272] Core: .each/.map should accept an undefined/null value Fixes gh-2267 Closes gh-2363 --- src/core.js | 20 +++++++++----------- test/unit/core.js | 12 ++++++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/core.js b/src/core.js index ba6eeceb8f..e8024aaf10 100644 --- a/src/core.js +++ b/src/core.js @@ -268,11 +268,10 @@ jQuery.extend({ }, each: function( obj, callback ) { - var i = 0, - length = obj.length, - isArray = isArraylike( obj ); + var length, i = 0; - if ( isArray ) { + if ( isArrayLike( obj ) ) { + length = obj.length; for ( ; i < length; i++ ) { if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { break; @@ -301,7 +300,7 @@ jQuery.extend({ var ret = results || []; if ( arr != null ) { - if ( isArraylike( Object(arr) ) ) { + if ( isArrayLike( Object( arr ) ) ) { jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr @@ -355,14 +354,13 @@ jQuery.extend({ // arg is for internal usage only map: function( elems, callback, arg ) { - var value, + var length, value, i = 0, - length = elems.length, - isArray = isArraylike( elems ), ret = []; // Go through the array, translating each of the items to their new values - if ( isArray ) { + if ( isArrayLike( elems ) ) { + length = elems.length; for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); @@ -441,13 +439,13 @@ function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); -function isArraylike( obj ) { +function isArrayLike( obj ) { // Support: iOS 8.2 (not reproducible in simulator) // `in` check used to prevent JIT error (gh-2145) // hasOwn isn't used here due to false negatives // regarding Nodelist length in IE - var length = "length" in obj && obj.length, + var length = !!obj && "length" in obj && obj.length, type = jQuery.type( obj ); if ( type === "function" || jQuery.isWindow( obj ) ) { diff --git a/test/unit/core.js b/test/unit/core.js index 8cfe98f838..1ddf695a65 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -1198,6 +1198,18 @@ test("jQuery.each(Object,Function)", function() { equal( i, document.styleSheets.length, "Iteration over document.styleSheets" ); }); +test("jQuery.each/map(undefined/null,Function)", 1, function() { + try { + jQuery.each( undefined, jQuery.noop ); + jQuery.each( null, jQuery.noop ); + jQuery.map( undefined, jQuery.noop ); + jQuery.map( null, jQuery.noop ); + ok( true, "jQuery.each/map( undefined/null, function() {} );" ); + } catch ( e ) { + ok( false, "each/map must accept null and undefined values" ); + } +}); + test( "JIT compilation does not interfere with length retrieval (gh-2145)", function() { expect( 4 ); From 93bee4701d14202045a88aab156da0daf9418430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 27 Jul 2015 22:14:48 +0200 Subject: [PATCH 0358/1272] Core: Adjust comments & tests after dropping Safari 6 support Support comments that mentioned only Safari < 7 were checked & updated to account for bugs existing in newer versions as well; Safari 6 support test results were removed. Refs gh-2482 --- src/event.js | 2 +- src/offset.js | 2 +- test/unit/css.js | 2 +- test/unit/support.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/event.js b/src/event.js index 04ee403d5d..53cfcd5ee0 100644 --- a/src/event.js +++ b/src/event.js @@ -593,7 +593,7 @@ jQuery.event = { event[ prop ] = originalEvent[ prop ]; } - // Support: Safari 6.0+ + // Support: Safari 6-8+ // Target should not be a text node (#504, #13143) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; diff --git a/src/offset.js b/src/offset.js index f0139d5eff..23a4b2a181 100644 --- a/src/offset.js +++ b/src/offset.js @@ -203,7 +203,7 @@ jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( }; }); -// Support: Safari<7+, Chrome<37+ +// Support: Safari<7-8+, Chrome<37-44+ // Add the top/left cssHooks using jQuery.fn.position // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 // Blink bug: https://code.google.com/p/chromium/issues/detail?id=229280 diff --git a/test/unit/css.js b/test/unit/css.js index 47db2c8f31..181695b706 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1121,7 +1121,7 @@ test( "show() after hide() should always set display to initial value (#14750)", equal( div.css( "display" ), "list-item", "should get last set display value" ); }); -// Support: IE < 11, Safari < 7 +// Support: IE < 11 // We have to jump through the hoops here in order to test work with "order" CSS property, // that some browsers do not support. This test is not, strictly speaking, correct, // but it's the best that we can do. diff --git a/test/unit/support.js b/test/unit/support.js index 46f904efad..d62c8b988b 100644 --- a/test/unit/support.js +++ b/test/unit/support.js @@ -143,7 +143,7 @@ testIframeWithCallback( "Check CSP (https://developer.mozilla.org/en-US/docs/Sec "radioValue": true, "reliableMarginRight": true }; - } else if ( /(6|7)\.0(\.\d+|) safari/i.test( userAgent ) ) { + } else if ( /7\.0(\.\d+|) safari/i.test( userAgent ) ) { expected = { "ajax": true, "boxSizingReliable": true, From 2792845534e36c39dbb9c8369ed96aaefa560081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 27 Jul 2015 22:29:38 +0200 Subject: [PATCH 0359/1272] Event: Update support comments for mouseenter/mouseleave implementation Custom mouseenter/mouseleave implementation was needed because of: 1. Safari 6 not implementing mouseenter/mouseleave at all. 2. Chrome sending mouseenter too often. The second issue has been fixed in Chrome but exists now in Safari 7 (it's fixed in Safari 8) so we have to keep it for now, unfortunately. --- src/event.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/event.js b/src/event.js index 53cfcd5ee0..f0604503c2 100644 --- a/src/event.js +++ b/src/event.js @@ -772,13 +772,10 @@ jQuery.Event.prototype = { // so that event delegation works in jQuery. // Do the same for pointerenter/pointerleave and pointerover/pointerout // -// Support: Safari<7.0 -// Safari doesn't support mouseenter/mouseleave at all. -// -// Support: Chrome 34+ -// Mouseenter doesn't perform while left mouse button is pressed -// (and initiated outside the observed element) -// https://code.google.com/p/chromium/issues/detail?id=333868 +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://code.google.com/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout", From 6044fb6a7384aec85906949835ef9a58114896ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82e=CC=A8biowski?= Date: Mon, 5 May 2014 20:04:03 +0200 Subject: [PATCH 0360/1272] Ajax: Account for Android 2.3 not firing window.onerror on script errors Android 2.3 doesn't fire the window.onerror handler, just accept the reality there and skip the test. Refs gh-1573 Refs gh-1786 Refs jquery/jquery.com#108 Closes gh-2458 --- test/unit/ajax.js | 9 +++++++++ test/unit/manipulation.js | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 359fa9d819..e216f34a23 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1450,6 +1450,15 @@ module( "ajax", { }); asyncTest( "#11743 - jQuery.ajax() - script, throws exception", 1, function() { + // 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 ) ) { + ok( true, "Test skipped, Android 2.3 doesn't fire window.onerror for " + + "errors in dynamically included scripts" ); + start(); + return; + } + var onerror = window.onerror; window.onerror = function() { ok( true, "Exception thrown" ); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 5a84520118..c1dac6993f 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2241,6 +2241,17 @@ test( "Ensure oldIE creates a new set on appendTo (#8894)", function() { }); asyncTest( "html() - script exceptions bubble (#11743)", 2, function() { + // 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 ) ) { + ok( true, "Test skipped, Android 2.3 doesn't fire window.onerror for " + + "errors in dynamically included scripts" ); + ok( true, "Test skipped, Android 2.3 doesn't fire window.onerror for " + + "errors in dynamically included scripts" ); + start(); + return; + } + var onerror = window.onerror; setTimeout(function() { From 5fe76c663f8a4986af62edb434a1708c006d0b21 Mon Sep 17 00:00:00 2001 From: Jason Bedard Date: Sat, 18 Jul 2015 17:47:31 -0700 Subject: [PATCH 0361/1272] Data: remove user data in cleanData Fixes gh-2503 Closes gh-2480 --- src/manipulation.js | 25 +++++++++++++++---------- test/unit/manipulation.js | 24 +++++++++++++++++++++++- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/manipulation.js b/src/manipulation.js index 4bac1417fa..00d65de5a3 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -270,19 +270,24 @@ jQuery.extend({ i = 0; for ( ; (elem = elems[ i ]) !== undefined; i++ ) { - if ( jQuery.acceptData( elem ) && (data = elem[ dataPriv.expando ])) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); + if ( jQuery.acceptData( elem ) ) { + if ( (data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } } } + delete elem[ dataPriv.expando ]; + } + if ( elem[ dataUser.expando ] ) { + delete elem[ dataUser.expando ]; } - delete elem[ dataPriv.expando ]; } } } diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index c1dac6993f..fffbf38cea 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -2064,7 +2064,7 @@ test( "jQuery.cleanData", function() { }); test( "jQuery.cleanData eliminates all private data (gh-2127)", function() { - expect( 2 ); + expect( 3 ); var div = jQuery( "
        " ).appendTo( "#qunit-fixture" ); @@ -2074,12 +2074,34 @@ test( "jQuery.cleanData eliminates all private data (gh-2127)", function() { div.remove(); + ok( !jQuery.hasData( div[ 0 ] ), "Removed element hasData should return false" ); + ok( jQuery.isEmptyObject( jQuery._data( div[ 0 ] ) ), "Private data is empty after node is removed" ); div.remove(); }); +test( "jQuery.cleanData eliminates all public data", function() { + expect( 2 ); + + var key, + div = jQuery( "
        " ); + div.data( "some", "data" ); + ok( !jQuery.isEmptyObject( jQuery.data( div[ 0 ] ) ), "Ensure some public data exists" ); + + div.remove(); + + ok( !jQuery.hasData( div[ 0 ] ), "Removed element hasData should return false" ); + + // Make sure the expando is gone + for ( key in div[ 0 ] ) { + if ( /^jQuery/.test( key ) ) { + ok( false, "Expando was not removed when there was no more data" ); + } + } +}); + test( "domManip plain-text caching (trac-6779)", function() { expect( 1 ); From 360a4780339b7f412b75ad8a06dca7f39616f654 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pe=CC=81rel?= Date: Thu, 30 Jul 2015 15:34:34 +0200 Subject: [PATCH 0362/1272] Docs: Fix various spelling mistakes Closes gh-2487 --- build/release/dist.js | 2 +- test/data/support/csp.php | 2 +- test/unit/css.js | 2 +- test/unit/event.js | 2 +- test/unit/manipulation.js | 2 +- test/unit/tween.js | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/release/dist.js b/build/release/dist.js index f17ea4ba70..8ef6faf860 100644 --- a/build/release/dist.js +++ b/build/release/dist.js @@ -5,7 +5,7 @@ module.exports = function( Release, complete ) { shell = require( "shelljs" ), pkg = require( Release.dir.repo + "/package.json" ), distRemote = Release.remote.replace( "jquery.git", "jquery-dist.git" ), - // These files are included with the distrubtion + // These files are included with the distribution files = [ "src", "LICENSE.txt", diff --git a/test/data/support/csp.php b/test/data/support/csp.php index d01def783f..0783e1774b 100644 --- a/test/data/support/csp.php +++ b/test/data/support/csp.php @@ -1,5 +1,5 @@ diff --git a/test/unit/css.js b/test/unit/css.js index 181695b706..b4337a1eac 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -29,7 +29,7 @@ test("css(String|Hash)", function() { equal( div2.find("input").css("height"), "20px", "Height on hidden input." ); equal( div2.find("textarea").css("height"), "20px", "Height on hidden textarea." ); - equal( div2.find("div").css("height"), "20px", "Height on hidden textarea." ); + equal( div2.find("div").css("height"), "20px", "Height on hidden div." ); div2.remove(); diff --git a/test/unit/event.js b/test/unit/event.js index ba3d9481a7..46a9d72699 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -2725,7 +2725,7 @@ test( "Donor event interference", function( assert ) { jQuery( "#donor-input" )[ 0 ].click(); } ); -test( "originalEvent property for Chrome, Safari and FF of simualted event", function( assert ) { +test( "originalEvent property for Chrome, Safari and FF of simulated event", function( assert ) { var userAgent = window.navigator.userAgent; if ( !(/chrome/i.test( userAgent ) || diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index fffbf38cea..7befa29c4d 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -498,7 +498,7 @@ test( "html(String) tag-hyphenated elements (Bug #1987)", function() { var j = jQuery("text"); ok( jQuery.nodeName(j[0], "TR-MULTIPLE-HYPHENS"), "Tags with multiple hypens" ); ok( jQuery.nodeName(j.children()[0], "TD-WITH-HYPHEN"), "Tags with multiple hypens" ); - equal( j.children().text(), "text", "Tags with multple hypens behave normally" ); + equal( j.children().text(), "text", "Tags with multiple hypens behave normally" ); }); test( "IE8 serialization bug", function() { diff --git a/test/unit/tween.js b/test/unit/tween.js index 39894c5757..1386c2878b 100644 --- a/test/unit/tween.js +++ b/test/unit/tween.js @@ -289,7 +289,7 @@ test( "jQuery.Tween - custom propHooks - advanced values", function() { // Some day this NaN assumption might change - perhaps add a "calc" helper to the hooks? ok( isNaN( tween.now ), "Used return value from propHook.get" ); - equal( tween.pos, 0.5, "But the eased percent is still avaliable" ); + equal( tween.pos, 0.5, "But the eased percent is still available" ); ok( propHook.set.calledWith( tween ), "Called propHook.set function with correct parameters" ); delete jQuery.Tween.propHooks.testHooked; From aabe94edb4880c75eeebc5b5b5d66a9ad17008fe Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Wed, 29 Jul 2015 18:10:04 +0300 Subject: [PATCH 0363/1272] Tests: don't use deprecated argument in test declaration Closes gh-2507 --- test/unit/ajax.js | 20 ++++++-- test/unit/attributes.js | 7 ++- test/unit/core.js | 12 +++-- test/unit/css.js | 24 +++++++--- test/unit/data.js | 32 +++++++++---- test/unit/dimensions.js | 8 +++- test/unit/effects.js | 99 +++++++++++++++++++++++++++++---------- test/unit/event.js | 12 +++-- test/unit/manipulation.js | 28 ++++++++--- test/unit/queue.js | 8 +++- test/unit/wrap.js | 8 +++- 11 files changed, 193 insertions(+), 65 deletions(-) diff --git a/test/unit/ajax.js b/test/unit/ajax.js index e216f34a23..6eedc57842 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -6,7 +6,9 @@ module( "ajax", { }); (function() { - test("Unit Testing Environment", 2, function () { + test("Unit Testing Environment", function () { + expect( 2 ); + ok( hasPHP, "Running in an environment with PHP support. The AJAX tests only run if the environment supports PHP!" ); ok( !isLocal, "Unit tests are not ran from file:// (especially in Chrome. If you must test from file:// with Chrome, run it with the --allow-file-access-from-files flag!)" ); }); @@ -1288,7 +1290,9 @@ module( "ajax", { } }); - test( "#7531 - jQuery.ajax() - Location object as url", 1, function () { + test( "#7531 - jQuery.ajax() - Location object as url", function () { + expect( 1 ); + var xhr, success = false; try { @@ -1389,7 +1393,9 @@ module( "ajax", { }); }); - test( "#9887 - jQuery.ajax() - Context with circular references (#9887)", 2, function () { + test( "#9887 - jQuery.ajax() - Context with circular references (#9887)", function () { + expect( 2 ); + var success = false, context = {}; context.field = context; @@ -1699,7 +1705,9 @@ module( "ajax", { //----------- jQuery.domManip() - test( "#11264 - jQuery.domManip() - no side effect because of ajaxSetup or global events", 1, function() { + test( "#11264 - jQuery.domManip() - no side effect because of ajaxSetup or global events", function() { + expect( 1 ); + jQuery.ajaxSetup({ type: "POST" }); @@ -2086,7 +2094,9 @@ module( "ajax", { //----------- jQuery.active - test( "jQuery.active", 1, function() { + test( "jQuery.active", function() { + expect( 1 ); + ok( jQuery.active === 0, "ajax active counter should be zero: " + jQuery.active ); }); diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 526cfc99db..cec7b60558 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -734,7 +734,8 @@ test( "prop('tabindex')", function() { equal( jQuery("#linkWithNoHrefWithNegativeTabIndex").prop("tabindex"), -1, "anchor without href, no tabindex set" ); }); -test( "prop('tabindex', value)", 10, function() { +test( "prop('tabindex', value)", function() { + expect( 10 ); var clone, element = jQuery("#divWithNoTabIndex"); @@ -1452,7 +1453,9 @@ test( "coords returns correct values in IE6/IE7, see #10828", function() { equal( area.attr("coords"), "0,0,0,0", "did not retrieve coords correctly" ); }); -test( "should not throw at $(option).val() (#14686)", 1, function() { +test( "should not throw at $(option).val() (#14686)", function() { + expect( 1 ); + try { jQuery( "
        a
        a
        ").appendTo("#qunit-fixture"), tdElem = table.find("td").first(), colElem = table.find("col").first().width( 300 ); @@ -460,7 +462,9 @@ testIframe( "dimensions/documentLarge", "window vs. large document", function( j ok( jQuery( document ).width() > jQuery( window ).width(), "document width is larger than window width" ); }); -test( "allow modification of coordinates argument (gh-1848)", 1, function() { +test( "allow modification of coordinates argument (gh-1848)", function() { + expect( 1 ); + var offsetTop, element = jQuery( "
        " ).appendTo( "#qunit-fixture" ); diff --git a/test/unit/effects.js b/test/unit/effects.js index 47f8bdf0af..b5f45bf6d2 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -32,7 +32,9 @@ test("sanity check", function() { equal( jQuery("#dl:visible, #qunit-fixture:visible, #foo:visible").length, 3, "QUnit state is correct for testing effects" ); }); -test("show() basic", 1, function() { +test("show() basic", function() { + expect( 1 ); + var div = jQuery("
        ").hide().appendTo("#qunit-fixture").show(); equal( div.css("display"), "block", "Make sure pre-hidden divs show" ); @@ -41,7 +43,9 @@ test("show() basic", 1, function() { div.remove(); }); -test("show()", 27, function () { +test("show()", function () { + expect( 27 ); + var div, speeds, old, test, hiddendiv = jQuery("div.hidden"); @@ -781,7 +785,9 @@ test("toggle()", function() { ok( x.is(":visible"), "is visible again" ); }); -test( "jQuery.fx.prototype.cur() - <1.8 Back Compat", 7, function() { +test( "jQuery.fx.prototype.cur() - <1.8 Back Compat", function() { + expect( 7 ); + var div = jQuery( "
        " ).appendTo( "#qunit-fixture" ).css({ color: "#ABC", border: "5px solid black", @@ -1253,7 +1259,9 @@ test("hide hidden elements, with animation (bug #7141)", function() { this.clock.tick( 10 ); }); -test("animate unit-less properties (#4966)", 2, function() { +test("animate unit-less properties (#4966)", function() { + expect( 2 ); + var div = jQuery( "
        " ).appendTo( "#qunit-fixture" ); equal( div.css( "z-index" ), "0", "z-index is 0" ); div.animate({ zIndex: 2 }, function() { @@ -1262,8 +1270,9 @@ test("animate unit-less properties (#4966)", 2, function() { this.clock.tick( 400 ); }); -test( "animate properties missing px w/ opacity as last (#9074)", 2, function() { +test( "animate properties missing px w/ opacity as last (#9074)", function() { expect( 6 ); + var ml, l, div = jQuery( "
        " ) .appendTo( "#qunit-fixture" ); @@ -1360,7 +1369,9 @@ test("animate will scale margin properties individually", function() { }); }); -test("Do not append px to 'fill-opacity' #9548", 1, function() { +test("Do not append px to 'fill-opacity' #9548", function() { + expect( 1 ); + var $div = jQuery("
        ").appendTo("#qunit-fixture"); $div.css("fill-opacity", 0).animate({ "fill-opacity": 1.0 }, 0, function () { @@ -1374,7 +1385,9 @@ test("Do not append px to 'fill-opacity' #9548", 1, function() { }); }); -test("line-height animates correctly (#13855)", 12, function() { +test("line-height animates correctly (#13855)", function() { + expect( 12 ); + var t0, clock = this.clock, longDuration = 2000, @@ -1436,7 +1449,9 @@ clock.tick( 50 ); }); // Start 1.8 Animation tests -test( "jQuery.Animation( object, props, opts )", 4, function() { +test( "jQuery.Animation( object, props, opts )", function() { + expect( 4 ); + var animation, testObject = { "foo": 0, @@ -1461,7 +1476,9 @@ test( "jQuery.Animation( object, props, opts )", 4, function() { this.clock.tick( 10 ); }); -test( "Animate Option: step: function( percent, tween )", 1, function() { +test( "Animate Option: step: function( percent, tween )", function() { + expect( 1 ); + var counter = {}; jQuery( "#foo" ).animate({ prop1: 1, @@ -1486,7 +1503,9 @@ test( "Animate Option: step: function( percent, tween )", 1, function() { this.clock.tick( 10 ); }); -test( "Animate callbacks have correct context", 2, function() { +test( "Animate callbacks have correct context", function() { + expect( 2 ); + var foo = jQuery( "#foo" ); foo.animate({ height: 10 @@ -1501,7 +1520,9 @@ test( "Animate callbacks have correct context", 2, function() { this.clock.tick( 10 ); }); -test( "User supplied callback called after show when fx off (#8892)", 2, function() { +test( "User supplied callback called after show when fx off (#8892)", function() { + expect( 2 ); + var foo = jQuery( "#foo" ); jQuery.fx.off = true; foo.hide(); @@ -1564,7 +1585,9 @@ test( "animate should set display for disconnected nodes", function() { clock.tick( 400 ); }); -test("Animation callback should not show animated element as :animated (#7157)", 1, function() { +test("Animation callback should not show animated element as :animated (#7157)", function() { + expect( 1 ); + var foo = jQuery( "#foo" ); foo.animate({ @@ -1575,7 +1598,9 @@ test("Animation callback should not show animated element as :animated (#7157)", this.clock.tick( 100 ); }); -test("Initial step callback should show element as :animated (#14623)", 1, function() { +test("Initial step callback should show element as :animated (#14623)", function() { + expect( 1 ); + var foo = jQuery( "#foo" ); foo.animate({ @@ -1590,7 +1615,9 @@ test("Initial step callback should show element as :animated (#14623)", 1, funct foo.stop(); }); -test( "hide called on element within hidden parent should set display to none (#10045)", 3, function() { +test( "hide called on element within hidden parent should set display to none (#10045)", function() { + expect( 3 ); + var hidden = jQuery(".hidden"), elems = jQuery("
        hide
        hide0
        hide1
        "); @@ -1610,7 +1637,9 @@ test( "hide called on element within hidden parent should set display to none (# this.clock.tick( 10 ); }); -test( "hide, fadeOut and slideUp called on element width height and width = 0 should set display to none", 5, function() { +test( "hide, fadeOut and slideUp called on element width height and width = 0 should set display to none", function() { + expect( 5 ); + var foo = jQuery("#foo"), i = 0, elems = jQuery(); @@ -1639,7 +1668,9 @@ test( "hide, fadeOut and slideUp called on element width height and width = 0 sh this.clock.tick( 400 ); }); -test( "hide should not leave hidden inline elements visible (#14848)", 2, function() { +test( "hide should not leave hidden inline elements visible (#14848)", function() { + expect( 2 ); + var el = jQuery("#simon1"); el.hide( 1, function() { @@ -1652,7 +1683,9 @@ test( "hide should not leave hidden inline elements visible (#14848)", 2, functi this.clock.tick( 100 ); }); -test( "Handle queue:false promises", 10, function() { +test( "Handle queue:false promises", function() { + expect( 10 ); + var foo = jQuery( "#foo" ).clone().addBack(), step = 1; @@ -1703,7 +1736,9 @@ test( "Handle queue:false promises", 10, function() { this.clock.tick( 10 ); }); -test( "multiple unqueued and promise", 4, function() { +test( "multiple unqueued and promise", function() { + expect( 4 ); + var foo = jQuery( "#foo" ), step = 1; foo.animate({ @@ -1735,7 +1770,9 @@ test( "multiple unqueued and promise", 4, function() { this.clock.tick( 1000 ); }); -test( "animate does not change start value for non-px animation (#7109)", 1, function() { +test( "animate does not change start value for non-px animation (#7109)", function() { + expect( 1 ); + var parent = jQuery( "
        " ).css({ width: 284, height: 1 }).appendTo( "#qunit-fixture" ), child = parent.children().css({ fontSize: "98.6in", width: "0.01em", height: 1 }), actual = parseFloat( child.css( "width" ) ), @@ -1755,7 +1792,9 @@ test( "animate does not change start value for non-px animation (#7109)", 1, fun this.clock.tick( 10 ); }); -test( "non-px animation handles non-numeric start (#11971)", 2, function() { +test( "non-px animation handles non-numeric start (#11971)", function() { + expect( 2 ); + var foo = jQuery("#foo"), initial = foo.css("backgroundPositionX"); @@ -1785,7 +1824,9 @@ test( "non-px animation handles non-numeric start (#11971)", 2, function() { this.clock.tick( 10 ); }); -test("Animation callbacks (#11797)", 15, function() { +test("Animation callbacks (#11797)", function() { + expect( 15 ); + var targets = jQuery("#foo").children(), done = false, expectedProgress = 0; @@ -1866,7 +1907,9 @@ test("Animation callbacks (#11797)", 15, function() { this.clock.tick( 10 ); }); -test( "Animate properly sets overflow hidden when animating width/height (#12117)", 8, function() { +test( "Animate properly sets overflow hidden when animating width/height (#12117)", function() { + expect( 8 ); + jQuery.each( [ "height", "width" ], function( _, prop ) { jQuery.each( [ 100, 0 ], function( _, value ) { var div = jQuery("
        ").css( "overflow", "auto" ), @@ -1907,7 +1950,9 @@ test( "Each tick of the timer loop uses a fresh time (#12837)", function() { tmp.stop(); }); -test( "Animations with 0 duration don't ease (#12273)", 1, function() { +test( "Animations with 0 duration don't ease (#12273)", function() { + expect( 1 ); + jQuery.easing.test = function() { ok( false, "Called easing" ); }; @@ -2146,7 +2191,9 @@ test( ".finish() is applied correctly when multiple elements were animated (#139 this.clock.tick( 1500 ); }); -test( "slideDown() after stop() (#13483)", 2, function() { +test( "slideDown() after stop() (#13483)", function() { + expect( 2 ); + var ul = jQuery( "
          " ) .appendTo("#qunit-fixture"), origHeight = ul.height(), @@ -2177,7 +2224,9 @@ test( "slideDown() after stop() (#13483)", 2, function() { clock.tick( 10 ); }); -test( "Respect display value on inline elements (#14824)", 2, function() { +test( "Respect display value on inline elements (#14824)", function() { + expect( 2 ); + var clock = this.clock, fromStyleSheet = jQuery( "" ), fromStyleAttr = jQuery( "" ); diff --git a/test/unit/event.js b/test/unit/event.js index 46a9d72699..2e86eb78d6 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -443,7 +443,9 @@ test("on(), trigger change on select", function() { }).trigger("change"); }); -test("on(), namespaced events, cloned events", 18, function() { +test("on(), namespaced events, cloned events", function() { + expect( 18 ); + var firstp = jQuery( "#firstp" ); firstp.on("custom.test",function(){ @@ -2576,7 +2578,9 @@ test( "Namespace preserved when passed an Event (#12739)", function() { equal( triggered, 3, "foo.bar triggered" ); }); -test( "make sure events cloned correctly", 18, function() { +test( "make sure events cloned correctly", function() { + expect( 18 ); + var clone, fixture = jQuery("#qunit-fixture"), checkbox = jQuery("#check1"), @@ -2760,7 +2764,9 @@ test( "originalEvent property for Chrome, Safari and FF of simulated event", fun // This tests are unreliable in Firefox if ( !(/firefox/i.test( window.navigator.userAgent )) ) { - test( "Check order of focusin/focusout events", 2, function() { + test( "Check order of focusin/focusout events", function() { + expect( 2 ); + var focus, blur, input = jQuery( "#name" ); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 7befa29c4d..8b0f9040b7 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -1870,7 +1870,9 @@ test( "remove() with filters", function() { equal( jQuery("#nonnodes").contents().length, 0, "Check node,textnode,comment remove works" ); }); -test( "remove() event cleaning ", 1, function() { +test( "remove() event cleaning ", function() { + expect( 1 ); + var count, first, cleanUp; count = 0; @@ -1885,7 +1887,9 @@ test( "remove() event cleaning ", 1, function() { cleanUp.remove(); }); -test( "remove() in document order #13779", 1, function() { +test( "remove() in document order #13779", function() { + expect( 1 ); + var last, cleanData = jQuery.cleanData; @@ -1957,7 +1961,9 @@ test("detach() with filters", function () { equal(jQuery("#nonnodes").contents().length, 0, "Check node,textnode,comment remove works"); }); -test( "detach() event cleaning ", 1, function() { +test( "detach() event cleaning ", function() { + expect( 1 ); + var count, first, cleanUp; count = 0; @@ -2487,7 +2493,9 @@ test( "insertAfter, insertBefore, etc do not work when destination is original e }); }); -test( "Index for function argument should be received (#13094)", 2, function() { +test( "Index for function argument should be received (#13094)", function() { + expect( 2 ); + var i = 0; jQuery("
          ").before(function( index ) { @@ -2496,7 +2504,9 @@ test( "Index for function argument should be received (#13094)", 2, function() { }); -test( "Make sure jQuery.fn.remove can work on elements in documentFragment", 1, function() { +test( "Make sure jQuery.fn.remove can work on elements in documentFragment", function() { + expect( 1 ); + var fragment = document.createDocumentFragment(), div = fragment.appendChild( document.createElement("div") ); @@ -2505,7 +2515,9 @@ test( "Make sure jQuery.fn.remove can work on elements in documentFragment", 1, equal( fragment.childNodes.length, 0, "div element was removed from documentFragment" ); }); -test( "Make sure specific elements with content created correctly (#13232)", 20, function() { +test( "Make sure specific elements with content created correctly (#13232)", function() { + expect( 20 ); + var results = [], args = [], elems = { @@ -2534,7 +2546,9 @@ test( "Make sure specific elements with content created correctly (#13232)", 20, }); }); -test( "Validate creation of multiple quantities of certain elements (#13818)", 44, function() { +test( "Validate creation of multiple quantities of certain elements (#13818)", function() { + expect( 44 ); + var tags = [ "thead", "tbody", "tfoot", "colgroup", "col", "caption", "tr", "th", "td", "optgroup", "option" ]; jQuery.each( tags, function( index, tag ) { diff --git a/test/unit/queue.js b/test/unit/queue.js index 5cc84f913d..761f17b17b 100644 --- a/test/unit/queue.js +++ b/test/unit/queue.js @@ -1,6 +1,8 @@ module( "queue", { teardown: moduleTeardown }); -test( "queue() with other types", 14, function() { +test( "queue() with other types", function() { + expect( 14 ); + stop(); var $div = jQuery({}), @@ -121,7 +123,9 @@ test("callbacks keep their place in the queue", function() { }); }); -test( "jQuery.queue should return array while manipulating the queue", 1, function() { +test( "jQuery.queue should return array while manipulating the queue", function() { + expect( 1 ); + var div = document.createElement("div"); ok( jQuery.isArray( jQuery.queue( div, "fx", jQuery.noop ) ), "jQuery.queue should return an array while manipulating the queue" ); diff --git a/test/unit/wrap.js b/test/unit/wrap.js index dcec277d2a..4907b7bc98 100644 --- a/test/unit/wrap.js +++ b/test/unit/wrap.js @@ -148,7 +148,9 @@ test( "wrapAll(String)", function() { }); -test( "wrapAll(Function)", 5, function() { +test( "wrapAll(Function)", function() { + expect( 5 ); + var prev = jQuery( "#firstp" )[ 0 ].previousSibling, p = jQuery( "#firstp,#first" )[ 0 ].parentNode, result = jQuery( "#firstp,#first" ).wrapAll(function() { @@ -162,7 +164,9 @@ test( "wrapAll(Function)", 5, function() { strictEqual( jQuery( "#first" ).parent().parent()[ 0 ].previousSibling, prev, "Correct Previous Sibling" ); }); -test( "wrapAll(Function) check execution characteristics", 3, function() { +test( "wrapAll(Function) check execution characteristics", function() { + expect( 3 ); + var i = 0; jQuery( "non-existent" ).wrapAll(function() { From 669cb16d763cb5486dadd56ec15a17b2b0303571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Sun, 2 Aug 2015 01:48:54 +0200 Subject: [PATCH 0364/1272] Build: Add a comment explaining why the es3 option is needed It might not be obvious to everyone that IE 9 & Android 4.0 are not ES5-compliant browsers (by a large margin) so it's better to add a support comment. This requires slight changes in parsing the config file as it's not a pure JSON anymore. JSHint understands such files without problems. Closes gh-2520 --- Gruntfile.js | 8 ++++++-- package.json | 1 + src/.jshintrc | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 1a6bdac1ac..0fe64d7e6f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -4,12 +4,16 @@ module.exports = function( grunt ) { function readOptionalJSON( filepath ) { var data = {}; try { - data = grunt.file.readJSON( filepath ); + data = JSON.parse( stripJSONComments( + fs.readFileSync( filepath, { encoding: "utf8" } ) + ) ); } catch ( e ) {} return data; } - var gzip = require( "gzip-js" ), + var fs = require( "fs" ), + stripJSONComments = require( "strip-json-comments" ), + gzip = require( "gzip-js" ), srcHintOptions = readOptionalJSON( "src/.jshintrc" ); // The concatenated file won't pass onevar diff --git a/package.json b/package.json index 5d82995343..43d24ba5d4 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "requirejs": "2.1.17", "sinon": "1.10.3", "sizzle": "2.2.0", + "strip-json-comments": "1.0.3", "testswarm": "1.1.0", "win-spawn": "2.0.0" }, diff --git a/src/.jshintrc b/src/.jshintrc index 281b683b90..ea3549d5c6 100644 --- a/src/.jshintrc +++ b/src/.jshintrc @@ -12,6 +12,9 @@ "sub": true, + // Support: IE < 10, Android < 4.1 + // The above browsers are failing a lot of tests in the ES5 + // test suite at http://test262.ecmascript.org. "es3": true, "globals": { From 9adfad19865837f5dffedb1eb41e407f196ca515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski?= Date: Mon, 3 Aug 2015 19:31:25 +0200 Subject: [PATCH 0365/1272] Core: Don't expose jQuery.access jQuery.access was never documented, there is no need to keep it exposed. Fixes gh-2513 Closes gh-2524 --- src/core/access.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/access.js b/src/core/access.js index 396c9e8dcb..a006ed919e 100644 --- a/src/core/access.js +++ b/src/core/access.js @@ -4,7 +4,7 @@ define([ // Multifunctional method to get and set values of a collection // The value/s can optionally be executed if it's a function -var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) { +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, len = elems.length, bulk = key == null; From 9d820fbde6d89bc7a06e2704be61cf6c0b4d6e3c Mon Sep 17 00:00:00 2001 From: Richard Gibson Date: Wed, 16 Jan 2013 00:14:57 -0500 Subject: [PATCH 0366/1272] Event: Only check elements for delegation matches Closes gh-2529 Ref trac-13208 (cherry picked from commit fc2ba2e1361126c39f955437ee025cfca3bffa65) --- src/event.js | 3 ++- test/unit/event.js | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/event.js b/src/event.js index f0604503c2..156bc016a8 100644 --- a/src/event.js +++ b/src/event.js @@ -483,8 +483,9 @@ jQuery.event = { for ( ; cur !== this; cur = cur.parentNode || this ) { + // Don't check non-elements (#13208) // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.disabled !== true || event.type !== "click" ) { + if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { matches = []; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; diff --git a/test/unit/event.js b/test/unit/event.js index 2e86eb78d6..c53690abb2 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -1834,6 +1834,17 @@ test( "delegated event with selector matching Object.prototype property (#13203) equal( matched, 0, "Nothing matched 'toString'" ); }); +test( "delegated event with intermediate DOM manipulation (#13208)", function() { + expect(1); + + jQuery("#foo").on( "click", "[id=sap]", function() {}); + jQuery("#sap").on( "click", "[id=anchor2]", function() { + document.createDocumentFragment().appendChild( this.parentNode ); + ok( true, "Element removed" ); + }); + jQuery("#anchor2").trigger("click"); +}); + test("stopPropagation() stops directly-bound events on delegated target", function() { expect(1); From b930d14ce64937e9478405eee2828d4da091d2cb Mon Sep 17 00:00:00 2001 From: Oleg Gaidarenko Date: Sun, 16 Aug 2015 06:45:28 +0300 Subject: [PATCH 0367/1272] Tests: partially use new qunit interface http://qunitjs.com/upgrade-guide-2.x/ For most of the boring work was used https://github.com/apsdehal/qunit-migrate package However, it can't update local qunit helpers, plus in some places old QUnit.asyncTest signature is still used Fixes gh-2540 --- test/data/testinit.js | 49 +- test/unit/ajax.js | 2382 ++++++++++++++++++++----------------- test/unit/animation.js | 231 ++-- test/unit/attributes.js | 982 +++++++-------- test/unit/callbacks.js | 130 +- test/unit/core.js | 1072 ++++++++--------- test/unit/css.js | 569 ++++----- test/unit/data.js | 517 ++++---- test/unit/deferred.js | 196 +-- test/unit/deprecated.js | 2 +- test/unit/dimensions.js | 356 +++--- test/unit/effects.js | 905 +++++++------- test/unit/event.js | 1160 +++++++++--------- test/unit/exports.js | 8 +- test/unit/manipulation.js | 1342 ++++++++++----------- test/unit/offset.js | 322 ++--- test/unit/queue.js | 180 +-- test/unit/ready.js | 30 +- test/unit/selector.js | 340 +++--- test/unit/serialize.js | 78 +- test/unit/support.js | 45 +- test/unit/traversing.js | 816 ++++++------- test/unit/tween.js | 203 ++-- test/unit/wrap.js | 224 ++-- 24 files changed, 6198 insertions(+), 5941 deletions(-) diff --git a/test/data/testinit.js b/test/data/testinit.js index ef90fe45c9..0dcb4f8713 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -137,16 +137,20 @@ function url( value ) { // Ajax testing helper this.ajaxTest = function( title, expect, options ) { - var requestOptions; - if ( jQuery.isFunction( options ) ) { - options = options(); - } - options = options || []; - requestOptions = options.requests || options.request || options; - if ( !jQuery.isArray( requestOptions ) ) { - requestOptions = [ requestOptions ]; - } - asyncTest( title, expect, function() { + QUnit.test( title, expect, function( assert ) { + var requestOptions; + + if ( jQuery.isFunction( options ) ) { + options = options( assert ); + } + options = options || []; + requestOptions = options.requests || options.request || options; + if ( !jQuery.isArray( requestOptions ) ) { + requestOptions = [ requestOptions ]; + } + + var done = assert.async(); + if ( options.setup ) { options.setup(); } @@ -160,7 +164,9 @@ this.ajaxTest = function( title, expect, options ) { if ( options.teardown ) { options.teardown(); } - start(); + + // Make sure all events will be called before done() + setTimeout(done); } }, requests = jQuery.map( requestOptions, function( options ) { @@ -170,7 +176,7 @@ this.ajaxTest = function( title, expect, options ) { return function( _, status ) { if ( !completed ) { if ( !handler ) { - ok( false, "unexpected " + status ); + assert.ok( false, "unexpected " + status ); } else if ( jQuery.isFunction( handler ) ) { handler.apply( this, arguments ); } @@ -179,7 +185,7 @@ this.ajaxTest = function( title, expect, options ) { }; if ( options.afterSend ) { - options.afterSend( request ); + options.afterSend( request, assert ); } return request @@ -202,7 +208,8 @@ this.ajaxTest = function( title, expect, options ) { }; this.testIframe = function( fileName, name, fn ) { - asyncTest(name, function() { + QUnit.test(name, function( assert ) { + var done = assert.async(); // load fixture in iframe var iframe = loadFixture(), @@ -211,10 +218,9 @@ this.testIframe = function( fileName, name, fn ) { if ( win && win.jQuery && win.jQuery.isReady ) { clearInterval( interval ); - start(); - // call actual tests passing the correct jQuery instance to use - fn.call( this, win.jQuery, win, win.document ); + fn.call( this, win.jQuery, win, win.document, assert ); + done(); document.body.removeChild( iframe ); iframe = null; } @@ -233,11 +239,14 @@ this.testIframe = function( fileName, name, fn ) { }; this.testIframeWithCallback = function( title, fileName, func ) { - asyncTest( title, 1, function() { + QUnit.test( title, 1, function( assert ) { var iframe; + var done = assert.async(); window.iframeCallback = function() { - var args = arguments; + var args = Array.prototype.slice.call( arguments ); + + args.push( assert ); setTimeout(function() { this.iframeCallback = undefined; @@ -246,7 +255,7 @@ this.testIframeWithCallback = function( title, fileName, func ) { func.apply( this, args ); func = function() {}; - start(); + done(); }); }; iframe = jQuery( "
          " ).css({ position: "absolute", width: "500px", left: "-600px" }) diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 6eedc57842..2f83341470 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1,4 +1,4 @@ -module( "ajax", { +QUnit.module( "ajax", { teardown: function() { jQuery( document ).off( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxError ajaxSuccess" ); moduleTeardown.apply( this, arguments ); @@ -6,122 +6,136 @@ module( "ajax", { }); (function() { - test("Unit Testing Environment", function () { - expect( 2 ); + QUnit.test("Unit Testing Environment", function( assert ) { + assert.expect( 2 ); - ok( hasPHP, "Running in an environment with PHP support. The AJAX tests only run if the environment supports PHP!" ); - ok( !isLocal, "Unit tests are not ran from file:// (especially in Chrome. If you must test from file:// with Chrome, run it with the --allow-file-access-from-files flag!)" ); + assert.ok( hasPHP, "Running in an environment with PHP support. The AJAX tests only run if the environment supports PHP!" ); + assert.ok( !isLocal, "Unit tests are not ran from file:// (especially in Chrome. If you must test from file:// with Chrome, run it with the --allow-file-access-from-files flag!)" ); }); if ( !jQuery.ajax || ( isLocal && !hasPHP ) ) { return; } - function addGlobalEvents( expected ) { + function addGlobalEvents( expected, assert ) { return function() { expected = expected || ""; jQuery( document ).on( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxError ajaxSuccess", function( e ) { - ok( expected.indexOf(e.type) !== -1, e.type ); + assert.ok( expected.indexOf(e.type) !== -1, e.type ); }); }; } //----------- jQuery.ajax() - testIframeWithCallback( "XMLHttpRequest - Attempt to block tests because of dangling XHR requests (IE)", "ajax/unreleasedXHR.html", function() { - expect( 1 ); - ok( true, "done" ); - }); - - ajaxTest( "jQuery.ajax() - success callbacks", 8, { - setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess"), - url: url("data/name.html"), - beforeSend: function() { - ok( true, "beforeSend" ); - }, - success: function() { - ok( true, "success" ); - }, - complete: function() { - ok( true, "complete"); + testIframeWithCallback( + "XMLHttpRequest - Attempt to block tests because of dangling XHR requests (IE)", + "ajax/unreleasedXHR.html", + function( assert ) { + assert.expect( 1 ); + assert.ok( true, "done" ); } + ); + + ajaxTest( "jQuery.ajax() - success callbacks", 8, function( assert ) { + return { + setup: addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), + url: url("data/name.html"), + beforeSend: function() { + assert.ok( true, "beforeSend" ); + }, + success: function() { + assert.ok( true, "success" ); + }, + complete: function() { + assert.ok( true, "complete"); + } + }; }); - ajaxTest( "jQuery.ajax() - success callbacks - (url, options) syntax", 8, { - setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess"), - create: function( options ) { - return jQuery.ajax( url("data/name.html"), options ); - }, - beforeSend: function() { - ok( true, "beforeSend" ); - }, - success: function() { - ok( true, "success" ); - }, - complete: function() { - ok( true, "complete" ); - } + ajaxTest( "jQuery.ajax() - success callbacks - (url, options) syntax", 8, function( assert ) { + return { + setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), + create: function( options ) { + return jQuery.ajax( url("data/name.html"), options ); + }, + beforeSend: function() { + assert.ok( true, "beforeSend" ); + }, + success: function() { + assert.ok( true, "success" ); + }, + complete: function() { + assert.ok( true, "complete" ); + } + }; }); - ajaxTest( "jQuery.ajax() - success callbacks (late binding)", 8, { - setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess"), - url: url("data/name.html"), - beforeSend: function() { - ok( true, "beforeSend" ); - }, - success: true, - afterSend: function( request ) { - request.always(function() { - ok( true, "complete" ); - }).done(function() { - ok( true, "success" ); - }).fail(function() { - ok( false, "error" ); - }); - } + ajaxTest( "jQuery.ajax() - success callbacks (late binding)", 8, function( assert ) { + return { + setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), + url: url("data/name.html"), + beforeSend: function() { + assert.ok( true, "beforeSend" ); + }, + success: true, + afterSend: function( request ) { + request.always(function() { + assert.ok( true, "complete" ); + }).done(function() { + assert.ok( true, "success" ); + }).fail(function() { + assert.ok( false, "error" ); + }); + } + }; }); - ajaxTest( "jQuery.ajax() - success callbacks (oncomplete binding)", 8, { - setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess"), - url: url("data/name.html"), - beforeSend: function() { - ok( true, "beforeSend" ); - }, - success: true, - complete: function( xhr ) { - xhr.always(function() { - ok( true, "complete" ); - }).done(function() { - ok( true, "success" ); - }).fail(function() { - ok( false, "error" ); - }); - } + ajaxTest( "jQuery.ajax() - success callbacks (oncomplete binding)", 8, function( assert ) { + return { + setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxSuccess", assert ), + url: url("data/name.html"), + beforeSend: function() { + assert.ok( true, "beforeSend" ); + }, + success: true, + complete: function( xhr ) { + xhr.always(function() { + assert.ok( true, "complete" ); + }).done(function() { + assert.ok( true, "success" ); + }).fail(function() { + assert.ok( false, "error" ); + }); + } + }; }); - ajaxTest( "jQuery.ajax() - error callbacks", 8, { - setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxError"), - url: url("data/name.php?wait=5"), - beforeSend: function() { - ok( true, "beforeSend" ); - }, - afterSend: function( request ) { - request.abort(); - }, - error: function() { - ok( true, "error" ); - }, - complete: function() { - ok( true, "complete" ); - } + ajaxTest( "jQuery.ajax() - error callbacks", 8, function( assert ) { + return { + setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxError", assert ), + url: url("data/name.php?wait=5"), + beforeSend: function() { + assert.ok( true, "beforeSend" ); + }, + afterSend: function( request ) { + request.abort(); + }, + error: function() { + assert.ok( true, "error" ); + }, + complete: function() { + assert.ok( true, "complete" ); + } + }; }); - ajaxTest( "jQuery.ajax() - textStatus and errorThrown values", 4, [ - { + ajaxTest( "jQuery.ajax() - textStatus and errorThrown values", 4, function( assert ) { + return [{ url: url("data/name.php?wait=5"), error: function( _, textStatus, errorThrown ) { - strictEqual( textStatus, "abort", "textStatus is 'abort' for abort" ); - strictEqual( errorThrown, "abort", "errorThrown is 'abort' for abort" ); + assert.strictEqual( textStatus, "abort", "textStatus is 'abort' for abort" ); + assert.strictEqual( errorThrown, "abort", "errorThrown is 'abort' for abort" ); }, afterSend: function( request ) { request.abort(); @@ -130,23 +144,25 @@ module( "ajax", { { url: url("data/name.php?wait=5"), error: function( _, textStatus, errorThrown ) { - strictEqual( textStatus, "mystatus", "textStatus is 'mystatus' for abort('mystatus')" ); - strictEqual( errorThrown, "mystatus", "errorThrown is 'mystatus' for abort('mystatus')" ); + assert.strictEqual( textStatus, "mystatus", "textStatus is 'mystatus' for abort('mystatus')" ); + assert.strictEqual( errorThrown, "mystatus", "errorThrown is 'mystatus' for abort('mystatus')" ); }, afterSend: function( request ) { request.abort("mystatus"); } - } - ]); + }]; + }); - ajaxTest( "jQuery.ajax() - responseText on error", 1, { - url: url("data/errorWithText.php"), - error: function( xhr ) { - strictEqual( xhr.responseText, "plain text message", "Test jqXHR.responseText is filled for HTTP errors" ); - } + ajaxTest( "jQuery.ajax() - responseText on error", 1, function( assert ) { + return { + url: url("data/errorWithText.php"), + error: function( xhr ) { + assert.strictEqual( xhr.responseText, "plain text message", "Test jqXHR.responseText is filled for HTTP errors" ); + } + }; }); - asyncTest( "jQuery.ajax() - retry with jQuery.ajax( this )", 2, function() { + QUnit.asyncTest( "jQuery.ajax() - retry with jQuery.ajax( this )", 2, function( assert ) { var previousUrl, firstTime = true; jQuery.ajax({ @@ -166,8 +182,8 @@ module( "ajax", { if ( !previousUrl ) { previousUrl = this.url; } else { - strictEqual( this.url, previousUrl, "url parameters are not re-appended" ); - start(); + assert.strictEqual( this.url, previousUrl, "url parameters are not re-appended" ); + QUnit.start(); return false; } }, @@ -180,128 +196,138 @@ module( "ajax", { }); }); - ajaxTest( "jQuery.ajax() - headers", 5, { - setup: function() { - jQuery( document ).ajaxSend(function( evt, xhr ) { - xhr.setRequestHeader( "ajax-send", "test" ); - }); - }, - url: url("data/headers.php?keys=siMPle_SometHing-elsE_OthEr_Nullable_undefined_Empty_ajax-send"), - headers: { - "siMPle": "value", - "SometHing-elsE": "other value", - "OthEr": "something else", - "Nullable": null, - "undefined": undefined - - // Support: Firefox - // Not all browsers allow empty-string headers - // https://bugzilla.mozilla.org/show_bug.cgi?id=815299 - //"Empty": "" - }, - success: function( data, _, xhr ) { - var i, emptyHeader, - requestHeaders = jQuery.extend( this.headers, { - "ajax-send": "test" - }), - tmp = []; - for ( i in requestHeaders ) { - tmp.push( i, ": ", requestHeaders[ i ] + "", "\n" ); - } - tmp = tmp.join(""); + ajaxTest( "jQuery.ajax() - headers", 5, function( assert ) { + return { + setup: function() { + jQuery( document ).ajaxSend(function( evt, xhr ) { + xhr.setRequestHeader( "ajax-send", "test" ); + }); + }, + url: url("data/headers.php?keys=siMPle_SometHing-elsE_OthEr_Nullable_undefined_Empty_ajax-send"), + headers: { + "siMPle": "value", + "SometHing-elsE": "other value", + "OthEr": "something else", + "Nullable": null, + "undefined": undefined + + // Support: Firefox + // Not all browsers allow empty-string headers + // https://bugzilla.mozilla.org/show_bug.cgi?id=815299 + //"Empty": "" + }, + success: function( data, _, xhr ) { + var i, emptyHeader, + requestHeaders = jQuery.extend( this.headers, { + "ajax-send": "test" + }), + tmp = []; + for ( i in requestHeaders ) { + tmp.push( i, ": ", requestHeaders[ i ] + "", "\n" ); + } + tmp = tmp.join(""); - strictEqual( data, tmp, "Headers were sent" ); - strictEqual( xhr.getResponseHeader("Sample-Header"), "Hello World", "Sample header received" ); - ok( data.indexOf( "undefined" ) < 0 , "Undefined header value was not sent" ); + assert.strictEqual( data, tmp, "Headers were sent" ); + assert.strictEqual( xhr.getResponseHeader("Sample-Header"), "Hello World", "Sample header received" ); + assert.ok( data.indexOf( "undefined" ) < 0 , "Undefined header value was not sent" ); - emptyHeader = xhr.getResponseHeader("Empty-Header"); - if ( emptyHeader === null ) { - ok( true, "Firefox doesn't support empty headers" ); - } else { - strictEqual( emptyHeader, "", "Empty header received" ); + emptyHeader = xhr.getResponseHeader("Empty-Header"); + if ( emptyHeader === null ) { + assert.ok( true, "Firefox doesn't support empty headers" ); + } else { + assert.strictEqual( emptyHeader, "", "Empty header received" ); + } + assert.strictEqual( xhr.getResponseHeader("Sample-Header2"), "Hello World 2", "Second sample header received" ); } - strictEqual( xhr.getResponseHeader("Sample-Header2"), "Hello World 2", "Second sample header received" ); - } - }); - - ajaxTest( "jQuery.ajax() - Accept header", 1, { - url: url("data/headers.php?keys=accept"), - headers: { - Accept: "very wrong accept value" - }, - beforeSend: function( xhr ) { - xhr.setRequestHeader("Accept", "*/*"); - }, - success: function( data ) { - strictEqual( data, "accept: */*\n", "Test Accept header is set to last value provided" ); - } + }; }); - ajaxTest( "jQuery.ajax() - contentType", 2, [ - { - url: url("data/headers.php?keys=content-type"), - contentType: "test", - success: function( data ) { - strictEqual( data, "content-type: test\n", "Test content-type is sent when options.contentType is set" ); - } - }, - { - url: url("data/headers.php?keys=content-type"), - contentType: false, + ajaxTest( "jQuery.ajax() - Accept header", 1, function( assert ) { + return { + url: url("data/headers.php?keys=accept"), + headers: { + Accept: "very wrong accept value" + }, + beforeSend: function( xhr ) { + xhr.setRequestHeader("Accept", "*/*"); + }, success: function( data ) { - // Some server/interpreter combinations always supply a Content-Type to scripts - data = data || "content-type: \n"; - strictEqual( data, "content-type: \n", "Test content-type is not set when options.contentType===false" ); + assert.strictEqual( data, "accept: */*\n", "Test Accept header is set to last value provided" ); } - } - ]); - - ajaxTest( "jQuery.ajax() - protocol-less urls", 1, { - url: "//somedomain.com", - beforeSend: function( xhr, settings ) { - equal( settings.url, location.protocol + "//somedomain.com", "Make sure that the protocol is added." ); - return false; - }, - error: true + }; }); - ajaxTest( "jQuery.ajax() - hash", 3, [ - { - url: "data/name.html#foo", - beforeSend: function( xhr, settings ) { - equal( settings.url, "data/name.html", "Make sure that the URL is trimmed." ); - return false; + ajaxTest( "jQuery.ajax() - contentType", 2, function( assert ) { + return [ + { + url: url("data/headers.php?keys=content-type"), + contentType: "test", + success: function( data ) { + assert.strictEqual( data, "content-type: test\n", "Test content-type is sent when options.contentType is set" ); + } }, - error: true - }, - { - url: "data/name.html?abc#foo", + { + url: url("data/headers.php?keys=content-type"), + contentType: false, + success: function( data ) { + // Some server/interpreter combinations always supply a Content-Type to scripts + data = data || "content-type: \n"; + assert.strictEqual( data, "content-type: \n", "Test content-type is not set when options.contentType===false" ); + } + } + ]; + }); + + ajaxTest( "jQuery.ajax() - protocol-less urls", 1, function( assert ) { + return { + url: "//somedomain.com", beforeSend: function( xhr, settings ) { - equal( settings.url, "data/name.html?abc", "Make sure that the URL is trimmed." ); + assert.equal( settings.url, location.protocol + "//somedomain.com", "Make sure that the protocol is added." ); return false; }, error: true - }, - { - url: "data/name.html?abc#foo", - data: { - "test": 123 + }; + }); + + ajaxTest( "jQuery.ajax() - hash", 3, function( assert ) { + return [ + { + url: "data/name.html#foo", + beforeSend: function( xhr, settings ) { + assert.equal( settings.url, "data/name.html", "Make sure that the URL is trimmed." ); + return false; + }, + error: true }, - beforeSend: function( xhr, settings ) { - equal( settings.url, "data/name.html?abc&test=123", "Make sure that the URL is trimmed." ); - return false; + { + url: "data/name.html?abc#foo", + beforeSend: function( xhr, settings ) { + assert.equal( settings.url, "data/name.html?abc", "Make sure that the URL is trimmed." ); + return false; + }, + error: true }, - error: true - } - ]); + { + url: "data/name.html?abc#foo", + data: { + "test": 123 + }, + beforeSend: function( xhr, settings ) { + assert.equal( settings.url, "data/name.html?abc&test=123", "Make sure that the URL is trimmed." ); + return false; + }, + error: true + } + ]; + }); - ajaxTest( "jQuery.ajax() - cross-domain detection", 8, function() { + ajaxTest( "jQuery.ajax() - cross-domain detection", 8, function( assert ) { function request( url, title, crossDomainOrOptions ) { return jQuery.extend( { dataType: "jsonp", url: url, beforeSend: function( _, s ) { - ok( crossDomainOrOptions === false ? !s.crossDomain : s.crossDomain, title ); + assert.ok( crossDomainOrOptions === false ? !s.crossDomain : s.crossDomain, title ); return false; }, error: true @@ -353,34 +379,35 @@ module( "ajax", { ]; }); - ajaxTest( "jQuery.ajax() - abort", 9, { - setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxError ajaxComplete"), - url: url("data/name.php?wait=5"), - beforeSend: function() { - ok( true, "beforeSend" ); - }, - afterSend: function( xhr ) { - strictEqual( xhr.readyState, 1, "XHR readyState indicates successful dispatch" ); - xhr.abort(); - strictEqual( xhr.readyState, 0, "XHR readyState indicates successful abortion" ); - }, - error: true, - complete: function() { - ok( true, "complete" ); - } + ajaxTest( "jQuery.ajax() - abort", 9, function( assert ) { + return { + setup: addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxError ajaxComplete", assert ), + url: url("data/name.php?wait=5"), + beforeSend: function() { + assert.ok( true, "beforeSend" ); + }, + afterSend: function( xhr ) { + assert.strictEqual( xhr.readyState, 1, "XHR readyState indicates successful dispatch" ); + xhr.abort(); + assert.strictEqual( xhr.readyState, 0, "XHR readyState indicates successful abortion" ); + }, + error: true, + complete: function() { + assert.ok( true, "complete" ); + } + }; }); - ajaxTest( "jQuery.ajax() - events with context", 12, function() { - + ajaxTest( "jQuery.ajax() - events with context", 12, function( assert ) { var context = document.createElement("div"); function event( e ) { - equal( this, context, e.type ); + assert.equal( this, context, e.type ); } function callback( msg ) { return function() { - equal( this, context, "context is preserved on callback " + msg ); + assert.equal( this, context, "context is preserved on callback " + msg ); }; } @@ -408,10 +435,10 @@ module( "ajax", { }; }); - ajaxTest( "jQuery.ajax() - events without context", 3, function() { + ajaxTest( "jQuery.ajax() - events without context", 3, function( assert ) { function nocallback( msg ) { return function() { - equal( typeof this.url, "string", "context is settings on callback " + msg ); + assert.equal( typeof this.url, "string", "context is settings on callback " + msg ); }; } return { @@ -422,7 +449,7 @@ module( "ajax", { }; }); - ajaxTest( "#15118 - jQuery.ajax() - function without jQuery.event", 1, function() { + ajaxTest( "#15118 - jQuery.ajax() - function without jQuery.event", 1, function( assert ) { var holder; return { url: url( "data/json.php" ), @@ -431,200 +458,222 @@ module( "ajax", { delete jQuery.event; }, complete: function() { - ok( true, "Call can be made without jQuery.event" ); + assert.ok( true, "Call can be made without jQuery.event" ); jQuery.event = holder; }, success: true }; }); - ajaxTest( "#15160 - jQuery.ajax() - request manually aborted in ajaxSend", 3, { - setup: function() { - jQuery( document ).on( "ajaxSend", function( e, jqXHR ) { - jqXHR.abort(); - }); + ajaxTest( "#15160 - jQuery.ajax() - request manually aborted in ajaxSend", 3, function( assert ) { + return { + setup: function() { + jQuery( document ).on( "ajaxSend", function( e, jqXHR ) { + jqXHR.abort(); + }); - jQuery( document ).on( "ajaxError ajaxComplete", function( e, jqXHR ) { - equal( jqXHR.statusText, "abort", "jqXHR.statusText equals abort on global ajaxComplete and ajaxError events" ); - }); - }, - url: url("data/name.html"), - error: true, - complete: function() { - ok( true, "complete" ); - } + jQuery( document ).on( "ajaxError ajaxComplete", function( e, jqXHR ) { + assert.equal( jqXHR.statusText, "abort", "jqXHR.statusText equals abort on global ajaxComplete and ajaxError events" ); + }); + }, + url: url("data/name.html"), + error: true, + complete: function() { + assert.ok( true, "complete" ); + } + }; }); - ajaxTest( "jQuery.ajax() - context modification", 1, { - url: url("data/name.html"), - context: {}, - beforeSend: function() { - this.test = "foo"; - }, - afterSend: function() { - strictEqual( this.context.test, "foo", "Make sure the original object is maintained." ); - }, - success: true + ajaxTest( "jQuery.ajax() - context modification", 1, function( assert ) { + return { + url: url("data/name.html"), + context: {}, + beforeSend: function() { + this.test = "foo"; + }, + afterSend: function() { + assert.strictEqual( this.context.test, "foo", "Make sure the original object is maintained." ); + }, + success: true + }; }); - ajaxTest( "jQuery.ajax() - context modification through ajaxSetup", 3, function() { + ajaxTest( "jQuery.ajax() - context modification through ajaxSetup", 3, function( assert ) { var obj = {}; return { setup: function() { jQuery.ajaxSetup({ context: obj }); - strictEqual( jQuery.ajaxSettings.context, obj, "Make sure the context is properly set in ajaxSettings." ); + assert.strictEqual( jQuery.ajaxSettings.context, obj, "Make sure the context is properly set in ajaxSettings." ); }, requests: [{ url: url("data/name.html"), success: function() { - strictEqual( this, obj, "Make sure the original object is maintained." ); + assert.strictEqual( this, obj, "Make sure the original object is maintained." ); } }, { url: url("data/name.html"), context: {}, success: function() { - ok( this !== obj, "Make sure overriding context is possible." ); + assert.ok( this !== obj, "Make sure overriding context is possible." ); } }] }; }); - ajaxTest( "jQuery.ajax() - disabled globals", 3, { - setup: addGlobalEvents(""), - global: false, - url: url("data/name.html"), - beforeSend: function() { - ok( true, "beforeSend" ); - }, - success: function() { - ok( true, "success" ); - }, - complete: function() { - ok( true, "complete" ); - } - }); - - ajaxTest( "jQuery.ajax() - xml: non-namespace elements inside namespaced elements", 3, { - url: url("data/with_fries.xml"), - dataType: "xml", - success: function( resp ) { - equal( jQuery( "properties", resp ).length, 1, "properties in responseXML" ); - equal( jQuery( "jsconf", resp ).length, 1, "jsconf in responseXML" ); - equal( jQuery( "thing", resp ).length, 2, "things in responseXML" ); - } + ajaxTest( "jQuery.ajax() - disabled globals", 3, function( assert ) { + return { + setup: addGlobalEvents( "", assert ), + global: false, + url: url("data/name.html"), + beforeSend: function() { + assert.ok( true, "beforeSend" ); + }, + success: function() { + assert.ok( true, "success" ); + }, + complete: function() { + assert.ok( true, "complete" ); + } + }; }); - ajaxTest( "jQuery.ajax() - xml: non-namespace elements inside namespaced elements (over JSONP)", 3, { - url: url("data/with_fries_over_jsonp.php"), - dataType: "jsonp xml", - success: function( resp ) { - equal( jQuery( "properties", resp ).length, 1, "properties in responseXML" ); - equal( jQuery( "jsconf", resp ).length, 1, "jsconf in responseXML" ); - equal( jQuery( "thing", resp ).length, 2, "things in responseXML" ); - } + ajaxTest( "jQuery.ajax() - xml: non-namespace elements inside namespaced elements", 3, function( assert ) { + return { + url: url("data/with_fries.xml"), + dataType: "xml", + success: function( resp ) { + assert.equal( jQuery( "properties", resp ).length, 1, "properties in responseXML" ); + assert.equal( jQuery( "jsconf", resp ).length, 1, "jsconf in responseXML" ); + assert.equal( jQuery( "thing", resp ).length, 2, "things in responseXML" ); + } + }; }); - ajaxTest( "jQuery.ajax() - HEAD requests", 2, [ - { - url: url("data/name.html"), - type: "HEAD", - success: function( data, status, xhr ) { - ok( /Date/i.test( xhr.getAllResponseHeaders() ), "No Date in HEAD response" ); - } - }, - { - url: url("data/name.html"), - data: { - "whip_it": "good" - }, - type: "HEAD", - success: function( data, status, xhr ) { - ok( /Date/i.test( xhr.getAllResponseHeaders() ), "No Date in HEAD response with data" ); + ajaxTest( "jQuery.ajax() - xml: non-namespace elements inside namespaced elements (over JSONP)", 3, function( assert ) { + return { + url: url("data/with_fries_over_jsonp.php"), + dataType: "jsonp xml", + success: function( resp ) { + assert.equal( jQuery( "properties", resp ).length, 1, "properties in responseXML" ); + assert.equal( jQuery( "jsconf", resp ).length, 1, "jsconf in responseXML" ); + assert.equal( jQuery( "thing", resp ).length, 2, "things in responseXML" ); } - } - ]); - - ajaxTest( "jQuery.ajax() - beforeSend", 1, { - url: url("data/name.html"), - beforeSend: function() { - this.check = true; - }, - success: function() { - ok( this.check, "check beforeSend was executed" ); - } + }; }); - ajaxTest( "jQuery.ajax() - beforeSend, cancel request manually", 2, { - create: function() { - return jQuery.ajax({ + ajaxTest( "jQuery.ajax() - HEAD requests", 2, function( assert ) { + return [ + { url: url("data/name.html"), - beforeSend: function( xhr ) { - ok( true, "beforeSend got called, canceling" ); - xhr.abort(); - }, - success: function() { - ok( false, "request didn't get canceled" ); - }, - complete: function() { - ok( false, "request didn't get canceled" ); + type: "HEAD", + success: function( data, status, xhr ) { + assert.ok( /Date/i.test( xhr.getAllResponseHeaders() ), "No Date in HEAD response" ); + } + }, + { + url: url("data/name.html"), + data: { + "whip_it": "good" }, - error: function() { - ok( false, "request didn't get canceled" ); + type: "HEAD", + success: function( data, status, xhr ) { + assert.ok( /Date/i.test( xhr.getAllResponseHeaders() ), "No Date in HEAD response with data" ); } - }); - }, - fail: function( _, reason ) { - strictEqual( reason, "canceled", "canceled request must fail with 'canceled' status text" ); - } - }); - - ajaxTest( "jQuery.ajax() - dataType html", 5, { - setup: function() { - Globals.register("testFoo"); - Globals.register("testBar"); - }, - dataType: "html", - url: url("data/test.html"), - success: function( data ) { - ok( data.match( /^html text/ ), "Check content for datatype html" ); - jQuery("#ap").html( data ); - strictEqual( window["testFoo"], "foo", "Check if script was evaluated for datatype html" ); - strictEqual( window["testBar"], "bar", "Check if script src was evaluated for datatype html" ); - } - }); - - ajaxTest( "jQuery.ajax() - synchronous request", 1, { - url: url("data/json_obj.js"), - dataType: "text", - async: false, - success: true, - afterSend: function( xhr ) { - ok( /^\{ "data"/.test( xhr.responseText ), "check returned text" ); - } + } + ]; }); - ajaxTest( "jQuery.ajax() - synchronous request with callbacks", 2, { - url: url("data/json_obj.js"), - async: false, - dataType: "text", - success: true, - afterSend: function( xhr ) { - var result; - xhr.done(function( data ) { - ok( true, "success callback executed" ); - result = data; - }); - ok( /^\{ "data"/.test( result ), "check returned text" ); - } + ajaxTest( "jQuery.ajax() - beforeSend", 1, function( assert ) { + return { + url: url("data/name.html"), + beforeSend: function() { + this.check = true; + }, + success: function() { + assert.ok( this.check, "check beforeSend was executed" ); + } + }; }); - asyncTest( "jQuery.ajax(), jQuery.get[Script|JSON](), jQuery.post(), pass-through request object", 8, function() { - var target = "data/name.html", - successCount = 0, - errorCount = 0, - errorEx = "", + ajaxTest( "jQuery.ajax() - beforeSend, cancel request manually", 2, function( assert ) { + return { + create: function() { + return jQuery.ajax({ + url: url("data/name.html"), + beforeSend: function( xhr ) { + assert.ok( true, "beforeSend got called, canceling" ); + xhr.abort(); + }, + success: function() { + assert.ok( false, "request didn't get canceled" ); + }, + complete: function() { + assert.ok( false, "request didn't get canceled" ); + }, + error: function() { + assert.ok( false, "request didn't get canceled" ); + } + }); + }, + fail: function( _, reason ) { + assert.strictEqual( reason, "canceled", "canceled request must fail with 'canceled' status text" ); + } + }; + }); + + ajaxTest( "jQuery.ajax() - dataType html", 5, function( assert ) { + return { + setup: function() { + Globals.register("testFoo"); + Globals.register("testBar"); + }, + dataType: "html", + url: url("data/test.html"), + success: function( data ) { + assert.ok( data.match( /^html text/ ), "Check content for datatype html" ); + jQuery("#ap").html( data ); + assert.strictEqual( window["testFoo"], "foo", "Check if script was evaluated for datatype html" ); + assert.strictEqual( window["testBar"], "bar", "Check if script src was evaluated for datatype html" ); + } + }; + }); + + ajaxTest( "jQuery.ajax() - synchronous request", 1, function( assert ) { + return { + url: url("data/json_obj.js"), + dataType: "text", + async: false, + success: true, + afterSend: function( xhr ) { + assert.ok( /^\{ "data"/.test( xhr.responseText ), "check returned text" ); + } + }; + }); + + ajaxTest( "jQuery.ajax() - synchronous request with callbacks", 2, function( assert ) { + return { + url: url("data/json_obj.js"), + async: false, + dataType: "text", + success: true, + afterSend: function( xhr ) { + var result; + xhr.done(function( data ) { + assert.ok( true, "success callback executed" ); + result = data; + }); + assert.ok( /^\{ "data"/.test( result ), "check returned text" ); + } + }; + }); + + QUnit.asyncTest( "jQuery.ajax(), jQuery.get[Script|JSON](), jQuery.post(), pass-through request object", 8, function( assert ) { + var target = "data/name.html", + successCount = 0, + errorCount = 0, + errorEx = "", success = function() { successCount++; }; @@ -633,25 +682,24 @@ module( "ajax", { errorEx += ": " + xml.status; }); jQuery( document ).one( "ajaxStop", function() { - equal( successCount, 5, "Check all ajax calls successful" ); - equal( errorCount, 0, "Check no ajax errors (status" + errorEx + ")" ); + assert.equal( successCount, 5, "Check all ajax calls successful" ); + assert.equal( errorCount, 0, "Check no ajax errors (status" + errorEx + ")" ); jQuery( document ).off("ajaxError.passthru"); - start(); + QUnit.start(); }); Globals.register("testBar"); - ok( jQuery.get( url(target), success ), "get" ); - ok( jQuery.post( url(target), success ), "post" ); - ok( jQuery.getScript( url("data/testbar.php"), success ), "script" ); - ok( jQuery.getJSON( url("data/json_obj.js"), success ), "json" ); - ok( jQuery.ajax({ + assert.ok( jQuery.get( url(target), success ), "get" ); + assert.ok( jQuery.post( url(target), success ), "post" ); + assert.ok( jQuery.getScript( url("data/testbar.php"), success ), "script" ); + assert.ok( jQuery.getJSON( url("data/json_obj.js"), success ), "json" ); + assert.ok( jQuery.ajax({ url: url( target ), success: success }), "generic" ); }); - ajaxTest( "jQuery.ajax() - cache", 12, function() { - + ajaxTest( "jQuery.ajax() - cache", 12, function( assert ) { var re = /_=(.*?)(&|$)/g; function request( url, title ) { @@ -661,9 +709,9 @@ module( "ajax", { beforeSend: function() { var parameter, tmp; while(( tmp = re.exec( this.url ) )) { - strictEqual( parameter, undefined, title + ": only one 'no-cache' parameter" ); + assert.strictEqual( parameter, undefined, title + ": only one 'no-cache' parameter" ); parameter = tmp[ 1 ]; - notStrictEqual( parameter, "tobereplaced555", title + ": parameter (if it was there) was replaced" ); + assert.notStrictEqual( parameter, "tobereplaced555", title + ": parameter (if it was there) was replaced" ); } return false; }, @@ -701,316 +749,346 @@ module( "ajax", { jQuery.each( [ " - Same Domain", " - Cross Domain" ], function( crossDomain, label ) { - ajaxTest( "jQuery.ajax() - JSONP - Query String (?n)" + label, 4, [ - { - url: "data/jsonp.php?callback=?", - dataType: "jsonp", - crossDomain: crossDomain, - success: function( data ) { - ok( data.data, "JSON results returned (GET, url callback)" ); - } - }, - { - url: "data/jsonp.php?callback=??", - dataType: "jsonp", - crossDomain: crossDomain, - success: function( data ) { - ok( data.data, "JSON results returned (GET, url context-free callback)" ); - } - }, - { - url: "data/jsonp.php/??", - dataType: "jsonp", - crossDomain: crossDomain, - success: function( data ) { - ok( data.data, "JSON results returned (GET, REST-like)" ); - } - }, - { - url: "data/jsonp.php/???json=1", - dataType: "jsonp", - crossDomain: crossDomain, - success: function( data ) { - strictEqual( jQuery.type( data ), "array", "JSON results returned (GET, REST-like with param)" ); + ajaxTest( "jQuery.ajax() - JSONP - Query String (?n)" + label, 4, function( assert ) { + return [ + { + url: "data/jsonp.php?callback=?", + dataType: "jsonp", + crossDomain: crossDomain, + success: function( data ) { + assert.ok( data.data, "JSON results returned (GET, url callback)" ); + } + }, + { + url: "data/jsonp.php?callback=??", + dataType: "jsonp", + crossDomain: crossDomain, + success: function( data ) { + assert.ok( data.data, "JSON results returned (GET, url context-free callback)" ); + } + }, + { + url: "data/jsonp.php/??", + dataType: "jsonp", + crossDomain: crossDomain, + success: function( data ) { + assert.ok( data.data, "JSON results returned (GET, REST-like)" ); + } + }, + { + url: "data/jsonp.php/???json=1", + dataType: "jsonp", + crossDomain: crossDomain, + success: function( data ) { + assert.strictEqual( jQuery.type( data ), "array", "JSON results returned (GET, REST-like with param)" ); + } } - } - ]); + ]; + }); - ajaxTest( "jQuery.ajax() - JSONP - Explicit callback param" + label, 10, { - setup: function() { - Globals.register("functionToCleanUp"); - Globals.register("XXX"); - Globals.register("jsonpResults"); - window["jsonpResults"] = function( data ) { - ok( data["data"], "JSON results returned (GET, custom callback function)" ); - }; - }, - requests: [{ - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - jsonp: "callback", - success: function( data ) { - ok( data["data"], "JSON results returned (GET, data obj callback)" ); - } - }, { - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - jsonpCallback: "jsonpResults", - success: function( data ) { - strictEqual( - typeof window[ "jsonpResults" ], - "function", - "should not rewrite original function" - ); - ok( data.data, "JSON results returned (GET, custom callback name)" ); - } - }, { - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - jsonpCallback: "functionToCleanUp", - success: function( data ) { - ok( data["data"], "JSON results returned (GET, custom callback name to be cleaned up)" ); - strictEqual( window["functionToCleanUp"], true, "Callback was removed (GET, custom callback name to be cleaned up)" ); - var xhr; - jQuery.ajax({ - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - jsonpCallback: "functionToCleanUp", - beforeSend: function( jqXHR ) { - xhr = jqXHR; - return false; - } - }); - xhr.fail(function() { - ok( true, "Ajax error JSON (GET, custom callback name to be cleaned up)" ); - strictEqual( window["functionToCleanUp"], true, "Callback was removed after early abort (GET, custom callback name to be cleaned up)" ); - }); - } - }, { - url: "data/jsonp.php?callback=XXX", - dataType: "jsonp", - jsonp: false, - jsonpCallback: "XXX", - crossDomain: crossDomain, - beforeSend: function() { - ok( /^data\/jsonp.php\?callback=XXX&_=\d+$/.test( this.url ), "The URL wasn't messed with (GET, custom callback name with no url manipulation)" ); + ajaxTest( "jQuery.ajax() - JSONP - Explicit callback param" + label, 10, function( assert ) { + return { + setup: function() { + Globals.register("functionToCleanUp"); + Globals.register("XXX"); + Globals.register("jsonpResults"); + window["jsonpResults"] = function( data ) { + assert.ok( data["data"], "JSON results returned (GET, custom callback function)" ); + }; }, - success: function( data ) { - ok( data["data"], "JSON results returned (GET, custom callback name with no url manipulation)" ); - } - }] + requests: [{ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + jsonp: "callback", + success: function( data ) { + assert.ok( data["data"], "JSON results returned (GET, data obj callback)" ); + } + }, { + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + jsonpCallback: "jsonpResults", + success: function( data ) { + assert.strictEqual( + typeof window[ "jsonpResults" ], + "function", + "should not rewrite original function" + ); + assert.ok( data.data, "JSON results returned (GET, custom callback name)" ); + } + }, { + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + jsonpCallback: "functionToCleanUp", + success: function( data ) { + assert.ok( data["data"], "JSON results returned (GET, custom callback name to be cleaned up)" ); + assert.strictEqual( window["functionToCleanUp"], true, "Callback was removed (GET, custom callback name to be cleaned up)" ); + var xhr; + jQuery.ajax({ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + jsonpCallback: "functionToCleanUp", + beforeSend: function( jqXHR ) { + xhr = jqXHR; + return false; + } + }); + xhr.fail(function() { + assert.ok( true, "Ajax error JSON (GET, custom callback name to be cleaned up)" ); + assert.strictEqual( window["functionToCleanUp"], true, "Callback was removed after early abort (GET, custom callback name to be cleaned up)" ); + }); + } + }, { + url: "data/jsonp.php?callback=XXX", + dataType: "jsonp", + jsonp: false, + jsonpCallback: "XXX", + crossDomain: crossDomain, + beforeSend: function() { + assert.ok( /^data\/jsonp.php\?callback=XXX&_=\d+$/.test( this.url ), "The URL wasn't messed with (GET, custom callback name with no url manipulation)" ); + }, + success: function( data ) { + assert.ok( data["data"], "JSON results returned (GET, custom callback name with no url manipulation)" ); + } + }] + }; }); - ajaxTest( "jQuery.ajax() - JSONP - Callback in data" + label, 2, [ - { - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - data: "callback=?", - success: function( data ) { - ok( data.data, "JSON results returned (GET, data callback)" ); - } - }, - { - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - data: "callback=??", - success: function( data ) { - ok( data.data, "JSON results returned (GET, data context-free callback)" ); + ajaxTest( "jQuery.ajax() - JSONP - Callback in data" + label, 2, function( assert ) { + return [ + { + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + data: "callback=?", + success: function( data ) { + assert.ok( data.data, "JSON results returned (GET, data callback)" ); + } + }, + { + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + data: "callback=??", + success: function( data ) { + assert.ok( data.data, "JSON results returned (GET, data context-free callback)" ); + } } - } - ]); + ]; + }); - ajaxTest( "jQuery.ajax() - JSONP - POST" + label, 3, [ - { - type: "POST", - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - success: function( data ) { - ok( data["data"], "JSON results returned (POST, no callback)" ); + ajaxTest( "jQuery.ajax() - JSONP - POST" + label, 3, function( assert ) { + return [ + { + type: "POST", + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + success: function( data ) { + assert.ok( data["data"], "JSON results returned (POST, no callback)" ); + } + }, + { + type: "POST", + url: "data/jsonp.php", + data: "callback=?", + dataType: "jsonp", + crossDomain: crossDomain, + success: function( data ) { + assert.ok( data["data"], "JSON results returned (POST, data callback)" ); + } + }, + { + type: "POST", + url: "data/jsonp.php", + jsonp: "callback", + dataType: "jsonp", + crossDomain: crossDomain, + success: function( data ) { + assert.ok( data["data"], "JSON results returned (POST, data obj callback)" ); + } } - }, - { - type: "POST", - url: "data/jsonp.php", - data: "callback=?", - dataType: "jsonp", - crossDomain: crossDomain, - success: function( data ) { - ok( data["data"], "JSON results returned (POST, data callback)" ); + ]; + }); + + ajaxTest( "jQuery.ajax() - JSONP" + label, 3, function( assert ) { + return [ + { + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + success: function( data ) { + assert.ok( data.data, "JSON results returned (GET, no callback)" ); + } + }, + { + create: function( options ) { + var request = jQuery.ajax( options ), + promise = request.then(function( data ) { + assert.ok( data.data, "first request: JSON results returned (GET, no callback)" ); + request = jQuery.ajax( this ).done(function( data ) { + assert.ok( data.data, "this re-used: JSON results returned (GET, no callback)" ); + }); + promise.abort = request.abort; + return request; + }); + promise.abort = request.abort; + return promise; + }, + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + success: true } + ]; + }); + + }); + + ajaxTest( "jQuery.ajax() - script, Remote", 2, function( assert ) { + return { + setup: function() { + Globals.register("testBar"); }, - { - type: "POST", - url: "data/jsonp.php", - jsonp: "callback", - dataType: "jsonp", - crossDomain: crossDomain, - success: function( data ) { - ok( data["data"], "JSON results returned (POST, data obj callback)" ); - } + url: window.location.href.replace( /[^\/]*$/, "" ) + "data/testbar.php", + dataType: "script", + success: function() { + assert.strictEqual( window["testBar"], "bar", "Script results returned (GET, no callback)" ); } - ]); + }; + }); - ajaxTest( "jQuery.ajax() - JSONP" + label, 3, [ - { - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - success: function( data ) { - ok( data.data, "JSON results returned (GET, no callback)" ); - } + ajaxTest( "jQuery.ajax() - script, Remote with POST", 3, function( assert ) { + return { + setup: function() { + Globals.register("testBar"); }, - { - create: function( options ) { - var request = jQuery.ajax( options ), - promise = request.then(function( data ) { - ok( data.data, "first request: JSON results returned (GET, no callback)" ); - request = jQuery.ajax( this ).done(function( data ) { - ok( data.data, "this re-used: JSON results returned (GET, no callback)" ); - }); - promise.abort = request.abort; - return request; - }); - promise.abort = request.abort; - return promise; - }, - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - success: true + url: window.location.href.replace( /[^\/]*$/, "" ) + "data/testbar.php", + type: "POST", + dataType: "script", + success: function( data, status ) { + assert.strictEqual( window["testBar"], "bar", "Script results returned (POST, no callback)" ); + assert.strictEqual( status, "success", "Script results returned (POST, no callback)" ); } - ]); - + }; }); - ajaxTest( "jQuery.ajax() - script, Remote", 2, { - setup: function() { - Globals.register("testBar"); - }, - url: window.location.href.replace( /[^\/]*$/, "" ) + "data/testbar.php", - dataType: "script", - success: function() { - strictEqual( window["testBar"], "bar", "Script results returned (GET, no callback)" ); - } + ajaxTest( "jQuery.ajax() - script, Remote with scheme-less URL", 2, function( assert ) { + return { + setup: function() { + Globals.register("testBar"); + }, + url: window.location.href.replace( /[^\/]*$/, "" ).replace( /^.*?\/\//, "//" ) + "data/testbar.php", + dataType: "script", + success: function() { + assert.strictEqual( window["testBar"], "bar", "Script results returned (GET, no callback)" ); + } + }; }); - ajaxTest( "jQuery.ajax() - script, Remote with POST", 3, { - setup: function() { - Globals.register("testBar"); - }, - url: window.location.href.replace( /[^\/]*$/, "" ) + "data/testbar.php", - type: "POST", - dataType: "script", - success: function( data, status ) { - strictEqual( window["testBar"], "bar", "Script results returned (POST, no callback)" ); - strictEqual( status, "success", "Script results returned (POST, no callback)" ); - } + ajaxTest( "jQuery.ajax() - malformed JSON", 2, function( assert ) { + return { + url: "data/badjson.js", + dataType: "json", + error: function( xhr, msg, detailedMsg ) { + assert.strictEqual( msg, "parsererror", "A parse error occurred." ); + assert.ok( /(invalid|error|exception)/i.test( detailedMsg ), "Detailed parsererror message provided" ); + } + }; }); - ajaxTest( "jQuery.ajax() - script, Remote with scheme-less URL", 2, { - setup: function() { - Globals.register("testBar"); - }, - url: window.location.href.replace( /[^\/]*$/, "" ).replace( /^.*?\/\//, "//" ) + "data/testbar.php", - dataType: "script", - success: function() { - strictEqual( window["testBar"], "bar", "Script results returned (GET, no callback)" ); - } + ajaxTest( "jQuery.ajax() - script by content-type", 2, function() { + return [ + { + url: "data/script.php", + data: { + "header": "script" + }, + success: true + }, + { + url: "data/script.php", + data: { + "header": "ecma" + }, + success: true + } + ]; }); - ajaxTest( "jQuery.ajax() - malformed JSON", 2, { - url: "data/badjson.js", - dataType: "json", - error: function( xhr, msg, detailedMsg ) { - strictEqual( msg, "parsererror", "A parse error occurred." ); - ok( /(invalid|error|exception)/i.test( detailedMsg ), "Detailed parsererror message provided" ); - } + ajaxTest( "jQuery.ajax() - JSON by content-type", 5, function( assert ) { + return { + url: "data/json.php", + data: { + "header": "json", + "json": "array" + }, + success: function( json ) { + assert.ok( json.length >= 2, "Check length" ); + assert.strictEqual( json[ 0 ]["name"], "John", "Check JSON: first, name" ); + assert.strictEqual( json[ 0 ]["age"], 21, "Check JSON: first, age" ); + assert.strictEqual( json[ 1 ]["name"], "Peter", "Check JSON: second, name" ); + assert.strictEqual( json[ 1 ]["age"], 25, "Check JSON: second, age" ); + } + }; }); - ajaxTest( "jQuery.ajax() - script by content-type", 2, [ - { - url: "data/script.php", + ajaxTest( "jQuery.ajax() - JSON by content-type disabled with options", 6, function( assert ) { + return { + url: url("data/json.php"), data: { - "header": "script" + "header": "json", + "json": "array" }, - success: true - }, - { - url: "data/script.php", - data: { - "header": "ecma" + contents: { + "json": false }, - success: true - } - ]); - - ajaxTest( "jQuery.ajax() - JSON by content-type", 5, { - url: "data/json.php", - data: { - "header": "json", - "json": "array" - }, - success: function( json ) { - ok( json.length >= 2, "Check length" ); - strictEqual( json[ 0 ]["name"], "John", "Check JSON: first, name" ); - strictEqual( json[ 0 ]["age"], 21, "Check JSON: first, age" ); - strictEqual( json[ 1 ]["name"], "Peter", "Check JSON: second, name" ); - strictEqual( json[ 1 ]["age"], 25, "Check JSON: second, age" ); - } - }); - - ajaxTest( "jQuery.ajax() - JSON by content-type disabled with options", 6, { - url: url("data/json.php"), - data: { - "header": "json", - "json": "array" - }, - contents: { - "json": false - }, - success: function( text ) { - strictEqual( typeof text, "string", "json wasn't auto-determined" ); - var json = jQuery.parseJSON( text ); - ok( json.length >= 2, "Check length"); - strictEqual( json[ 0 ]["name"], "John", "Check JSON: first, name" ); - strictEqual( json[ 0 ]["age"], 21, "Check JSON: first, age" ); - strictEqual( json[ 1 ]["name"], "Peter", "Check JSON: second, name" ); - strictEqual( json[ 1 ]["age"], 25, "Check JSON: second, age" ); - } + success: function( text ) { + assert.strictEqual( typeof text, "string", "json wasn't auto-determined" ); + var json = jQuery.parseJSON( text ); + assert.ok( json.length >= 2, "Check length"); + assert.strictEqual( json[ 0 ]["name"], "John", "Check JSON: first, name" ); + assert.strictEqual( json[ 0 ]["age"], 21, "Check JSON: first, age" ); + assert.strictEqual( json[ 1 ]["name"], "Peter", "Check JSON: second, name" ); + assert.strictEqual( json[ 1 ]["age"], 25, "Check JSON: second, age" ); + } + }; }); - ajaxTest( "jQuery.ajax() - simple get", 1, { - type: "GET", - url: url("data/name.php?name=foo"), - success: function( msg ) { - strictEqual( msg, "bar", "Check for GET" ); - } + ajaxTest( "jQuery.ajax() - simple get", 1, function( assert ) { + return { + type: "GET", + url: url("data/name.php?name=foo"), + success: function( msg ) { + assert.strictEqual( msg, "bar", "Check for GET" ); + } + }; }); - ajaxTest( "jQuery.ajax() - simple post", 1, { - type: "POST", - url: url("data/name.php"), - data: "name=peter", - success: function( msg ) { - strictEqual( msg, "pan", "Check for POST" ); - } + ajaxTest( "jQuery.ajax() - simple post", 1, function( assert ) { + return { + type: "POST", + url: url("data/name.php"), + data: "name=peter", + success: function( msg ) { + assert.strictEqual( msg, "pan", "Check for POST" ); + } + }; }); - ajaxTest( "jQuery.ajax() - data option - empty bodies for non-GET requests", 1, { - url: "data/echoData.php", - data: undefined, - type: "post", - success: function( result ) { - strictEqual( result, "" ); - } + ajaxTest( "jQuery.ajax() - data option - empty bodies for non-GET requests", 1, function( assert ) { + return { + url: "data/echoData.php", + data: undefined, + type: "post", + success: function( result ) { + assert.strictEqual( result, "" ); + } + }; }); var ifModifiedNow = new Date(); @@ -1029,24 +1107,24 @@ module( "ajax", { }, function( type, url ) { url = "data/" + url + "?ts=" + ifModifiedNow++; - asyncTest( "jQuery.ajax() - " + type + " support" + label, 4, function() { + QUnit.asyncTest( "jQuery.ajax() - " + type + " support" + label, 4, function( assert ) { jQuery.ajax({ url: url, ifModified: true, cache: cache, success: function( _, status ) { - strictEqual( status, "success", "Initial status is 'success'" ); + assert.strictEqual( status, "success", "Initial status is 'success'" ); jQuery.ajax({ url: url, ifModified: true, cache: cache, success: function( data, status, jqXHR ) { - strictEqual( status, "notmodified", "Following status is 'notmodified'" ); - strictEqual( jqXHR.status, 304, "XHR status is 304" ); - equal( data, null, "no response body is given" ); + assert.strictEqual( status, "notmodified", "Following status is 'notmodified'" ); + assert.strictEqual( jqXHR.status, 304, "XHR status is 304" ); + assert.equal( data, null, "no response body is given" ); }, complete: function() { - start(); + QUnit.start(); } }); } @@ -1058,46 +1136,52 @@ module( "ajax", { /* jQuery.each arguments end */ ); - ajaxTest( "jQuery.ajax() - failing cross-domain (non-existing)", 1, { - // see RFC 2606 - url: "http://example.invalid", - error: function( xhr, _, e ) { - ok( true, "file not found: " + xhr.status + " => " + e ); - } + ajaxTest( "jQuery.ajax() - failing cross-domain (non-existing)", 1, function( assert ) { + return { + // see RFC 2606 + url: "http://example.invalid", + error: function( xhr, _, e ) { + assert.ok( true, "file not found: " + xhr.status + " => " + e ); + } + }; }); - ajaxTest( "jQuery.ajax() - failing cross-domain", 1, { - url: "http://" + externalHost, - error: function( xhr, _, e ) { - ok( true, "access denied: " + xhr.status + " => " + e ); - } + ajaxTest( "jQuery.ajax() - failing cross-domain", 1, function( assert ) { + return { + url: "http://" + externalHost, + error: function( xhr, _, e ) { + assert.ok( true, "access denied: " + xhr.status + " => " + e ); + } + }; }); - ajaxTest( "jQuery.ajax() - atom+xml", 1, { - url: url("data/atom+xml.php"), - success: function() { - ok( true, "success" ); - } + ajaxTest( "jQuery.ajax() - atom+xml", 1, function( assert ) { + return { + url: url("data/atom+xml.php"), + success: function() { + assert.ok( true, "success" ); + } + }; }); - asyncTest( "jQuery.ajax() - statusText", 3, function() { + QUnit.asyncTest( "jQuery.ajax() - statusText", 3, function( assert ) { jQuery.ajax( url("data/statusText.php?status=200&text=Hello") ).done(function( _, statusText, jqXHR ) { - strictEqual( statusText, "success", "callback status text ok for success" ); - ok( jqXHR.statusText === "Hello" || jqXHR.statusText === "OK", "jqXHR status text ok for success (" + jqXHR.statusText + ")" ); + assert.strictEqual( statusText, "success", "callback status text ok for success" ); + assert.ok( jqXHR.statusText === "Hello" || jqXHR.statusText === "OK", "jqXHR status text ok for success (" + jqXHR.statusText + ")" ); jQuery.ajax( url("data/statusText.php?status=404&text=World") ).fail(function( jqXHR, statusText ) { - strictEqual( statusText, "error", "callback status text ok for error" ); - start(); + assert.strictEqual( statusText, "error", "callback status text ok for error" ); + QUnit.start(); }); }); }); - asyncTest( "jQuery.ajax() - statusCode", 20, function() { + QUnit.asyncTest( "jQuery.ajax() - statusCode", 20, function( assert ) { var count = 12; function countComplete() { if ( ! --count ) { - start(); + QUnit.start(); } } @@ -1105,10 +1189,10 @@ module( "ajax", { name = "Test " + name + " " + ( isSuccess ? "success" : "error" ); return { 200: function() { - ok( isSuccess, name ); + assert.ok( isSuccess, name ); }, 404: function() { - ok( !isSuccess, name ); + assert.ok( !isSuccess, name ); } }; } @@ -1161,7 +1245,7 @@ module( "ajax", { jQuery.ajax( url(uri), { success: function( a, b, jqXHR ) { - ok( isSuccess, "success" ); + assert.ok( isSuccess, "success" ); var statusCode = {}; statusCode[ jqXHR.status ] = function() { testString += "B"; @@ -1170,7 +1254,7 @@ module( "ajax", { testString += "A"; }, error: function( jqXHR ) { - ok( !isSuccess, "error" ); + assert.ok( !isSuccess, "error" ); var statusCode = {}; statusCode[ jqXHR.status ] = function() { testString += "B"; @@ -1179,7 +1263,7 @@ module( "ajax", { testString += "A"; }, complete: function() { - strictEqual( + assert.strictEqual( testString, "AB", "Test statusCode callbacks are ordered like " + ( isSuccess ? "success" : "error" ) + " callbacks" @@ -1193,105 +1277,115 @@ module( "ajax", { ); }); - ajaxTest( "jQuery.ajax() - transitive conversions", 8, [ - { - url: url("data/json.php"), - converters: { - "json myJson": function( data ) { - ok( true, "converter called" ); - return data; + ajaxTest( "jQuery.ajax() - transitive conversions", 8, function( assert ) { + return [ + { + url: url("data/json.php"), + converters: { + "json myJson": function( data ) { + assert.ok( true, "converter called" ); + return data; + } + }, + dataType: "myJson", + success: function() { + assert.ok( true, "Transitive conversion worked" ); + assert.strictEqual( this.dataTypes[ 0 ], "text", "response was retrieved as text" ); + assert.strictEqual( this.dataTypes[ 1 ], "myjson", "request expected myjson dataType" ); } }, - dataType: "myJson", - success: function() { - ok( true, "Transitive conversion worked" ); - strictEqual( this.dataTypes[ 0 ], "text", "response was retrieved as text" ); - strictEqual( this.dataTypes[ 1 ], "myjson", "request expected myjson dataType" ); - } - }, - { - url: url("data/json.php"), - converters: { - "json myJson": function( data ) { - ok( true, "converter called (*)" ); - return data; + { + url: url("data/json.php"), + converters: { + "json myJson": function( data ) { + assert.ok( true, "converter called (*)" ); + return data; + } + }, + contents: false, /* headers are wrong so we ignore them */ + dataType: "* myJson", + success: function() { + assert.ok( true, "Transitive conversion worked (*)" ); + assert.strictEqual( this.dataTypes[ 0 ], "text", "response was retrieved as text (*)" ); + assert.strictEqual( this.dataTypes[ 1 ], "myjson", "request expected myjson dataType (*)" ); } - }, - contents: false, /* headers are wrong so we ignore them */ - dataType: "* myJson", - success: function() { - ok( true, "Transitive conversion worked (*)" ); - strictEqual( this.dataTypes[ 0 ], "text", "response was retrieved as text (*)" ); - strictEqual( this.dataTypes[ 1 ], "myjson", "request expected myjson dataType (*)" ); } - } - ]); + ]; + }); - ajaxTest( "jQuery.ajax() - overrideMimeType", 2, [ - { - url: url("data/json.php"), - beforeSend: function( xhr ) { - xhr.overrideMimeType( "application/json" ); + ajaxTest( "jQuery.ajax() - overrideMimeType", 2, function( assert ) { + return [ + { + url: url("data/json.php"), + beforeSend: function( xhr ) { + xhr.overrideMimeType( "application/json" ); + }, + success: function( json ) { + assert.ok( json.data, "Mimetype overridden using beforeSend" ); + } }, - success: function( json ) { - ok( json.data, "Mimetype overridden using beforeSend" ); - } - }, - { - url: url("data/json.php"), - mimeType: "application/json", - success: function( json ) { - ok( json.data, "Mimetype overridden using mimeType option" ); + { + url: url("data/json.php"), + mimeType: "application/json", + success: function( json ) { + assert.ok( json.data, "Mimetype overridden using mimeType option" ); + } } - } - ]); + ]; + }); - ajaxTest( "jQuery.ajax() - empty json gets to error callback instead of success callback.", 1, { - url: url("data/echoData.php"), - error: function( _, __, error ) { - equal( typeof error === "object", true, "Didn't get back error object for empty json response" ); - }, - dataType: "json" + ajaxTest( "jQuery.ajax() - empty json gets to error callback instead of success callback.", 1, function( assert ) { + return { + url: url("data/echoData.php"), + error: function( _, __, error ) { + assert.equal( typeof error === "object", true, "Didn't get back error object for empty json response" ); + }, + dataType: "json" + }; }); - ajaxTest( "#2688 - jQuery.ajax() - beforeSend, cancel request", 2, { - create: function() { - return jQuery.ajax({ - url: url("data/name.html"), - beforeSend: function() { - ok( true, "beforeSend got called, canceling" ); - return false; - }, - success: function() { - ok( false, "request didn't get canceled" ); - }, - complete: function() { - ok( false, "request didn't get canceled" ); - }, - error: function() { - ok( false, "request didn't get canceled" ); - } - }); - }, - fail: function( _, reason ) { - strictEqual( reason, "canceled", "canceled request must fail with 'canceled' status text" ); - } + ajaxTest( "#2688 - jQuery.ajax() - beforeSend, cancel request", 2, function( assert ) { + return { + create: function() { + return jQuery.ajax({ + url: url("data/name.html"), + beforeSend: function() { + assert.ok( true, "beforeSend got called, canceling" ); + return false; + }, + success: function() { + assert.ok( false, "request didn't get canceled" ); + }, + complete: function() { + assert.ok( false, "request didn't get canceled" ); + }, + error: function() { + assert.ok( false, "request didn't get canceled" ); + } + }); + }, + fail: function( _, reason ) { + assert.strictEqual( reason, "canceled", "canceled request must fail with 'canceled' status text" ); + } + }; }); - ajaxTest( "#2806 - jQuery.ajax() - data option - evaluate function values", 1, { - url: "data/echoQuery.php", - data: { - key: function() { - return "value"; + ajaxTest( "#2806 - jQuery.ajax() - data option - evaluate function values", 1, function( assert ) { + return { + url: "data/echoQuery.php", + data: { + key: function() { + return "value"; + } + }, + success: function( result ) { + assert.strictEqual( result, "key=value" ); } - }, - success: function( result ) { - strictEqual( result, "key=value" ); - } + }; }); - test( "#7531 - jQuery.ajax() - Location object as url", function () { - expect( 1 ); + QUnit.test( "#7531 - jQuery.ajax() - Location object as url", function( assert ) { + assert.expect( 1 ); var xhr, success = false; @@ -1304,97 +1398,103 @@ module( "ajax", { } catch (e) { } - ok( success, "document.location did not generate exception" ); + assert.ok( success, "document.location did not generate exception" ); }); jQuery.each( [ " - Same Domain", " - Cross Domain" ], function( crossDomain, label ) { - ajaxTest( "#7578 - jQuery.ajax() - JSONP - default for cache option" + label, 1, { - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - beforeSend: function() { - strictEqual( this.cache, false, "cache must be false on JSON request" ); - return false; - }, - error: true + ajaxTest( "#7578 - jQuery.ajax() - JSONP - default for cache option" + label, 1, function( assert ) { + return { + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + beforeSend: function() { + assert.strictEqual( this.cache, false, "cache must be false on JSON request" ); + return false; + }, + error: true + }; }); }); - ajaxTest( "#8107 - jQuery.ajax() - multiple method signatures introduced in 1.5", 4, [ - { - create: function() { - return jQuery.ajax(); - }, - done: function() { - ok( true, "With no arguments" ); - } - }, - { - create: function() { - return jQuery.ajax("data/name.html"); + ajaxTest( "#8107 - jQuery.ajax() - multiple method signatures introduced in 1.5", 4, function( assert ) { + return [ + { + create: function() { + return jQuery.ajax(); + }, + done: function() { + assert.ok( true, "With no arguments" ); + } }, - done: function() { - ok( true, "With only string URL argument" ); - } - }, - { - create: function() { - return jQuery.ajax( "data/name.html", {}); + { + create: function() { + return jQuery.ajax("data/name.html"); + }, + done: function() { + assert.ok( true, "With only string URL argument" ); + } }, - done: function() { - ok( true, "With string URL param and map" ); - } - }, - { - create: function( options ) { - return jQuery.ajax( options ); + { + create: function() { + return jQuery.ajax( "data/name.html", {}); + }, + done: function() { + assert.ok( true, "With string URL param and map" ); + } }, - url: "data/name.html", - success: function() { - ok( true, "With only map" ); + { + create: function( options ) { + return jQuery.ajax( options ); + }, + url: "data/name.html", + success: function() { + assert.ok( true, "With only map" ); + } } - } - ]); + ]; + }); jQuery.each( [ " - Same Domain", " - Cross Domain" ], function( crossDomain, label ) { - ajaxTest( "#8205 - jQuery.ajax() - JSONP - re-use callbacks name" + label, 4, { - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - beforeSend: function( jqXHR, s ) { - s.callback = s.jsonpCallback; + ajaxTest( "#8205 - jQuery.ajax() - JSONP - re-use callbacks name" + label, 4, function( assert ) { + return { + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + beforeSend: function( jqXHR, s ) { + s.callback = s.jsonpCallback; - ok( this.callback in window, "JSONP callback name is in the window" ); - }, - success: function() { - var previous = this; + assert.ok( this.callback in window, "JSONP callback name is in the window" ); + }, + success: function() { + var previous = this; - strictEqual( - previous.jsonpCallback, - undefined, - "jsonpCallback option is set back to default in callbacks" - ); + assert.strictEqual( + previous.jsonpCallback, + undefined, + "jsonpCallback option is set back to default in callbacks" + ); - ok( - !( this.callback in window ), - "JSONP callback name was removed from the window" - ); + assert.ok( + !( this.callback in window ), + "JSONP callback name was removed from the window" + ); - jQuery.ajax({ - url: "data/jsonp.php", - dataType: "jsonp", - crossDomain: crossDomain, - beforeSend: function() { - strictEqual( this.jsonpCallback, previous.callback, "JSONP callback name is re-used" ); - return false; - } - }); - } + jQuery.ajax({ + url: "data/jsonp.php", + dataType: "jsonp", + crossDomain: crossDomain, + beforeSend: function() { + assert.strictEqual( this.jsonpCallback, previous.callback, "JSONP callback name is re-used" ); + return false; + } + }); + } + }; }); }); - test( "#9887 - jQuery.ajax() - Context with circular references (#9887)", function () { - expect( 2 ); + QUnit.test( "#9887 - jQuery.ajax() - Context with circular references (#9887)", function( assert ) { + assert.expect( 2 ); var success = false, context = {}; @@ -1403,7 +1503,7 @@ module( "ajax", { jQuery.ajax( "non-existing", { context: context, beforeSend: function() { - ok( this === context, "context was not deep extended" ); + assert.ok( this === context, "context was not deep extended" ); return false; } }); @@ -1411,65 +1511,70 @@ module( "ajax", { } catch ( e ) { console.log( e ); } - ok( success, "context with circular reference did not generate an exception" ); + assert.ok( success, "context with circular reference did not generate an exception" ); }); jQuery.each( [ "as argument", "in settings object" ], function( inSetting, title ) { - function request( url, test ) { + function request( assert, url, test ) { return { create: function() { return jQuery.ajax( inSetting ? { url: url } : url ); }, done: function() { - ok( true, ( test || url ) + " " + title ); + assert.ok( true, ( test || url ) + " " + title ); } }; } - ajaxTest( "#10093 - jQuery.ajax() - falsy url " + title, 4, [ - request( "", "empty string" ), - request( false ), - request( null ), - request( undefined ) - ]); - + ajaxTest( "#10093 - jQuery.ajax() - falsy url " + title, 4, function( assert ) { + return [ + request( assert, "", "empty string" ), + request( assert, false ), + request( assert, null ), + request( assert, undefined ) + ]; + }); }); - ajaxTest( "#11151 - jQuery.ajax() - parse error body", 2, { - url: url("data/errorWithJSON.php"), - dataFilter: function( string ) { - ok( false, "dataFilter called" ); - return string; - }, - error: function( jqXHR ) { - strictEqual( jqXHR.responseText, "{ \"code\": 40, \"message\": \"Bad Request\" }", "Error body properly set" ); - deepEqual( jqXHR.responseJSON, { code: 40, message: "Bad Request" }, "Error body properly parsed" ); - } + ajaxTest( "#11151 - jQuery.ajax() - parse error body", 2, function( assert ) { + return { + url: url("data/errorWithJSON.php"), + dataFilter: function( string ) { + assert.ok( false, "dataFilter called" ); + return string; + }, + error: function( jqXHR ) { + assert.strictEqual( jqXHR.responseText, "{ \"code\": 40, \"message\": \"Bad Request\" }", "Error body properly set" ); + assert.deepEqual( jqXHR.responseJSON, { code: 40, message: "Bad Request" }, "Error body properly parsed" ); + } + }; }); - ajaxTest( "#11426 - jQuery.ajax() - loading binary data shouldn't throw an exception in IE", 1, { - url: url("data/1x1.jpg"), - success: function( data ) { - ok( data === undefined || /JFIF/.test( data ), "success callback reached" ); - } + ajaxTest( "#11426 - jQuery.ajax() - loading binary data shouldn't throw an exception in IE", 1, function( assert ) { + return { + url: url("data/1x1.jpg"), + success: function( data ) { + assert.ok( data === undefined || /JFIF/.test( data ), "success callback reached" ); + } + }; }); - asyncTest( "#11743 - jQuery.ajax() - script, throws exception", 1, function() { + QUnit.asyncTest( "#11743 - jQuery.ajax() - script, throws exception", 1, function( assert ) { // 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 ) ) { - ok( true, "Test skipped, Android 2.3 doesn't fire window.onerror for " + + assert.ok( true, "Test skipped, Android 2.3 doesn't fire window.onerror for " + "errors in dynamically included scripts" ); - start(); + QUnit.start(); return; } var onerror = window.onerror; window.onerror = function() { - ok( true, "Exception thrown" ); + assert.ok( true, "Exception thrown" ); window.onerror = onerror; - start(); + QUnit.start(); }; jQuery.ajax({ url: "data/badjson.js", @@ -1479,121 +1584,137 @@ module( "ajax", { }); jQuery.each( [ "method", "type" ], function( _, globalOption ) { - - function request( option ) { + function request( assert, option ) { var options = { url: url("data/echoData.php"), data: "hello", success: function( msg ) { - strictEqual( msg, "hello", "Check for POST (no override)" ); + assert.strictEqual( msg, "hello", "Check for POST (no override)" ); } }; if ( option ) { options[ option ] = "GET"; options.success = function( msg ) { - strictEqual( msg, "", "Check for no POST (overriding with " + option + ")" ); + assert.strictEqual( msg, "", "Check for no POST (overriding with " + option + ")" ); }; } return options; } - ajaxTest( "#12004 - jQuery.ajax() - method is an alias of type - " + globalOption + " set globally", 3, { - setup: function() { - var options = {}; - options[ globalOption ] = "POST"; - jQuery.ajaxSetup( options ); - }, - requests: [ - request("type"), - request("method"), - request() - ] - }); - + ajaxTest( + "#12004 - jQuery.ajax() - method is an alias of type - " + + globalOption + " set globally", 3, + function( assert ) { + return { + setup: function() { + var options = {}; + options[ globalOption ] = "POST"; + jQuery.ajaxSetup( options ); + }, + requests: [ + request(assert, "type"), + request(assert, "method"), + request(assert ) + ] + }; + } + ); }); - ajaxTest( "#13276 - jQuery.ajax() - compatibility between XML documents from ajax requests and parsed string", 1, { - url: "data/dashboard.xml", - dataType: "xml", - success: function( ajaxXML ) { - var parsedXML = jQuery( jQuery.parseXML("blibli") ).find("tab"); - ajaxXML = jQuery( ajaxXML ); - try { - // Android 2.3 doesn't automatically adopt nodes from foreign documents. - // (see the comment in test/manipulation.js) - // Support: Android 2.3 - if ( /android 2\.3/i.test( navigator.userAgent ) ) { - parsedXML = jQuery( ajaxXML[ 0 ].adoptNode( parsedXML[ 0 ] ) ); + ajaxTest( "#13276 - jQuery.ajax() - compatibility between XML documents from ajax requests and parsed string", 1, function( assert ) { + return { + url: "data/dashboard.xml", + dataType: "xml", + success: function( ajaxXML ) { + var parsedXML = jQuery( jQuery.parseXML("blibli") ).find("tab"); + ajaxXML = jQuery( ajaxXML ); + try { + // Android 2.3 doesn't automatically adopt nodes from foreign documents. + // (see the comment in test/manipulation.js) + // Support: Android 2.3 + if ( /android 2\.3/i.test( navigator.userAgent ) ) { + parsedXML = jQuery( ajaxXML[ 0 ].adoptNode( parsedXML[ 0 ] ) ); + } + ajaxXML.find("infowindowtab").append( parsedXML ); + } catch( e ) { + assert.strictEqual( e, undefined, "error" ); + return; } - ajaxXML.find("infowindowtab").append( parsedXML ); - } catch( e ) { - strictEqual( e, undefined, "error" ); - return; + assert.strictEqual( ajaxXML.find("tab").length, 3, "Parsed node was added properly" ); } - strictEqual( ajaxXML.find("tab").length, 3, "Parsed node was added properly" ); - } + }; }); - ajaxTest( "#13292 - jQuery.ajax() - converter is bypassed for 204 requests", 3, { - url: "data/nocontent.php", - dataType: "testing", - converters: { - "* testing": function() { - throw "converter was called"; + ajaxTest( "#13292 - jQuery.ajax() - converter is bypassed for 204 requests", 3, function( assert ) { + return { + url: "data/nocontent.php", + dataType: "testing", + converters: { + "* testing": function() { + throw "converter was called"; + } + }, + success: function( data, status, jqXHR ) { + assert.strictEqual( jqXHR.status, 204, "status code is 204" ); + assert.strictEqual( status, "nocontent", "status text is 'nocontent'" ); + assert.strictEqual( data, undefined, "data is undefined" ); + }, + error: function( _, status, error ) { + assert.ok( false, "error" ); + assert.strictEqual( status, "parsererror", "Parser Error" ); + assert.strictEqual( error, "converter was called", "Converter was called" ); } - }, - success: function( data, status, jqXHR ) { - strictEqual( jqXHR.status, 204, "status code is 204" ); - strictEqual( status, "nocontent", "status text is 'nocontent'" ); - strictEqual( data, undefined, "data is undefined" ); - }, - error: function( _, status, error ) { - ok( false, "error" ); - strictEqual( status, "parsererror", "Parser Error" ); - strictEqual( error, "converter was called", "Converter was called" ); - } + }; }); - ajaxTest( "#13388 - jQuery.ajax() - responseXML", 3, { - url: url("data/with_fries.xml"), - dataType: "xml", - success: function( resp, _, jqXHR ) { - notStrictEqual( resp, undefined, "XML document exists" ); - ok( "responseXML" in jqXHR, "jqXHR.responseXML exists" ); - strictEqual( resp, jqXHR.responseXML, "jqXHR.responseXML is set correctly" ); - } + ajaxTest( "#13388 - jQuery.ajax() - responseXML", 3, function( assert ) { + return { + url: url("data/with_fries.xml"), + dataType: "xml", + success: function( resp, _, jqXHR ) { + assert.notStrictEqual( resp, undefined, "XML document exists" ); + assert.ok( "responseXML" in jqXHR, "jqXHR.responseXML exists" ); + assert.strictEqual( resp, jqXHR.responseXML, "jqXHR.responseXML is set correctly" ); + } + }; }); - ajaxTest( "#13922 - jQuery.ajax() - converter is bypassed for HEAD requests", 3, { - url: "data/json.php", - method: "HEAD", - data: { - header: "yes" - }, - converters: { - "text json": function() { - throw "converter was called"; + ajaxTest( "#13922 - jQuery.ajax() - converter is bypassed for HEAD requests", 3, function( assert ) { + return { + url: "data/json.php", + method: "HEAD", + data: { + header: "yes" + }, + converters: { + "text json": function() { + throw "converter was called"; + } + }, + success: function( data, status ) { + assert.ok( true, "success" ); + assert.strictEqual( status, "nocontent", "data is undefined" ); + assert.strictEqual( data, undefined, "data is undefined" ); + }, + error: function( _, status, error ) { + assert.ok( false, "error" ); + assert.strictEqual( status, "parsererror", "Parser Error" ); + assert.strictEqual( error, "converter was called", "Converter was called" ); } - }, - success: function( data, status ) { - ok( true, "success" ); - strictEqual( status, "nocontent", "data is undefined" ); - strictEqual( data, undefined, "data is undefined" ); - }, - error: function( _, status, error ) { - ok( false, "error" ); - strictEqual( status, "parsererror", "Parser Error" ); - strictEqual( error, "converter was called", "Converter was called" ); - } - } ); - - testIframeWithCallback( "#14379 - jQuery.ajax() on unload", "ajax/onunload.html", function( status ) { - expect( 1 ); - strictEqual( status, "success", "Request completed" ); + }; }); - ajaxTest( "#14683 - jQuery.ajax() - Exceptions thrown synchronously by xhr.send should be caught", 4, [ - { + testIframeWithCallback( + "#14379 - jQuery.ajax() on unload", + "ajax/onunload.html", + function( status, assert ) { + assert.expect( 1 ); + assert.strictEqual( status, "success", "Request completed" ); + } + ); + + ajaxTest( "#14683 - jQuery.ajax() - Exceptions thrown synchronously by xhr.send should be caught", 4, function( assert ) { + return [{ url: "data/params_html.php", method: "POST", data: { @@ -1603,71 +1724,73 @@ module( "ajax", { }, processData: false, done: function( data ) { - ok( false, "done: " + data ); - }, - fail: function( jqXHR, status, error ) { - ok( true, "exception caught: " + error ); - strictEqual( jqXHR.status, 0, "proper status code" ); - strictEqual( status, "error", "proper status" ); - } - }, - { - url: "http://domain.org:80d", - done: function( data ) { - ok( false, "done: " + data ); + assert.ok( false, "done: " + data ); }, - fail: function( _, status, error ) { - 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 ); + } + }]; } - ]); + ); -//----------- jQuery.ajaxPrefilter() +// //----------- jQuery.ajaxPrefilter() - ajaxTest( "jQuery.ajaxPrefilter() - abort", 1, { - dataType: "prefix", - setup: function() { - // Ensure prefix does not throw an error - jQuery.ajaxPrefilter("+prefix", function( options, _, jqXHR ) { - if ( options.abortInPrefilter ) { - jqXHR.abort(); - } - }); - }, - abortInPrefilter: true, - error: function() { - ok( false, "error callback called" ); - }, - fail: function( _, reason ) { - strictEqual( reason, "canceled", "Request aborted by the prefilter must fail with 'canceled' status text" ); - } + ajaxTest( "jQuery.ajaxPrefilter() - abort", 1, function( assert ) { + return { + dataType: "prefix", + setup: function() { + // Ensure prefix does not throw an error + jQuery.ajaxPrefilter("+prefix", function( options, _, jqXHR ) { + if ( options.abortInPrefilter ) { + jqXHR.abort(); + } + }); + }, + abortInPrefilter: true, + error: function() { + assert.ok( false, "error callback called" ); + }, + fail: function( _, reason ) { + assert.strictEqual( reason, "canceled", "Request aborted by the prefilter must fail with 'canceled' status text" ); + } + }; }); //----------- jQuery.ajaxSetup() - asyncTest( "jQuery.ajaxSetup()", 1, function() { + QUnit.asyncTest( "jQuery.ajaxSetup()", 1, function( assert ) { jQuery.ajaxSetup({ url: url("data/name.php?name=foo"), success: function( msg ) { - strictEqual( msg, "bar", "Check for GET" ); - start(); + assert.strictEqual( msg, "bar", "Check for GET" ); + QUnit.start(); } }); jQuery.ajax(); }); - asyncTest( "jQuery.ajaxSetup({ timeout: Number }) - with global timeout", 2, function() { + QUnit.asyncTest( "jQuery.ajaxSetup({ timeout: Number }) - with global timeout", 2, function( assert ) { var passed = 0, pass = function() { - ok( passed++ < 2, "Error callback executed" ); + assert.ok( passed++ < 2, "Error callback executed" ); if ( passed === 2 ) { jQuery( document ).off("ajaxError.setupTest"); - start(); + QUnit.start(); } }, fail = function( a, b ) { - ok( false, "Check for timeout failed " + a + " " + b ); - start(); + assert.ok( false, "Check for timeout failed " + a + " " + b ); + QUnit.start(); }; jQuery( document ).on( "ajaxError.setupTest", pass ); @@ -1684,7 +1807,7 @@ module( "ajax", { }); }); - asyncTest( "jQuery.ajaxSetup({ timeout: Number }) with localtimeout", 1, function() { + QUnit.asyncTest( "jQuery.ajaxSetup({ timeout: Number }) with localtimeout", 1, function( assert ) { jQuery.ajaxSetup({ timeout: 50 }); @@ -1693,27 +1816,27 @@ module( "ajax", { timeout: 15000, url: url("data/name.php?wait=1"), error: function() { - ok( false, "Check for local timeout failed" ); - start(); + assert.ok( false, "Check for local timeout failed" ); + QUnit.start(); }, success: function() { - ok( true, "Check for local timeout" ); - start(); + assert.ok( true, "Check for local timeout" ); + QUnit.start(); } }); }); //----------- jQuery.domManip() - test( "#11264 - jQuery.domManip() - no side effect because of ajaxSetup or global events", function() { - expect( 1 ); + QUnit.test( "#11264 - jQuery.domManip() - no side effect because of ajaxSetup or global events", function( assert ) { + assert.expect( 1 ); jQuery.ajaxSetup({ type: "POST" }); jQuery( document ).on( "ajaxStart ajaxStop", function() { - ok( false, "Global event triggered" ); + assert.ok( false, "Global event triggered" ); }); jQuery("#qunit-fixture").append(""); @@ -1721,232 +1844,238 @@ module( "ajax", { jQuery( document ).off("ajaxStart ajaxStop"); }); - asyncTest( "jQuery#load() - always use GET method even if it overrided through ajaxSetup (#11264)", 1, function() { + QUnit.asyncTest( "jQuery#load() - always use GET method even if it overrided through ajaxSetup (#11264)", 1, function( assert ) { jQuery.ajaxSetup({ type: "POST" }); jQuery( "#qunit-fixture" ).load( "data/ajax/method.php", function( method ) { - equal( method, "GET" ); - start(); + assert.equal( method, "GET" ); + QUnit.start(); }); }); - asyncTest( "#11402 - jQuery.domManip() - script in comments are properly evaluated", 2, function() { + QUnit.asyncTest( "#11402 - jQuery.domManip() - script in comments are properly evaluated", 2, function() { jQuery("#qunit-fixture").load( "data/cleanScript.html", start ); }); //----------- jQuery.get() - asyncTest( "jQuery.get( String, Hash, Function ) - parse xml and use text() on nodes", 2, function() { + QUnit.asyncTest( "jQuery.get( String, Hash, Function ) - parse xml and use text() on nodes", 2, function( assert ) { jQuery.get( url("data/dashboard.xml"), function( xml ) { var content = []; jQuery( "tab", xml ).each(function() { content.push( jQuery( this ).text() ); }); - strictEqual( content[ 0 ], "blabla", "Check first tab" ); - strictEqual( content[ 1 ], "blublu", "Check second tab" ); - start(); + assert.strictEqual( content[ 0 ], "blabla", "Check first tab" ); + assert.strictEqual( content[ 1 ], "blublu", "Check second tab" ); + QUnit.start(); }); }); - asyncTest( "#8277 - jQuery.get( String, Function ) - data in ajaxSettings", 1, function() { + QUnit.asyncTest( "#8277 - jQuery.get( String, Function ) - data in ajaxSettings", 1, function( assert ) { jQuery.ajaxSetup({ data: "helloworld" }); jQuery.get( url("data/echoQuery.php"), function( data ) { - ok( /helloworld$/.test( data ), "Data from ajaxSettings was used" ); - start(); + assert.ok( /helloworld$/.test( data ), "Data from ajaxSettings was used" ); + QUnit.start(); }); }); //----------- jQuery.getJSON() - asyncTest( "jQuery.getJSON( String, Hash, Function ) - JSON array", 5, function() { + QUnit.asyncTest( "jQuery.getJSON( String, Hash, Function ) - JSON array", 5, function( assert ) { jQuery.getJSON( url("data/json.php"), { "json": "array" }, function( json ) { - ok( json.length >= 2, "Check length" ); - strictEqual( json[ 0 ]["name"], "John", "Check JSON: first, name" ); - strictEqual( json[ 0 ]["age"], 21, "Check JSON: first, age" ); - strictEqual( json[ 1 ]["name"], "Peter", "Check JSON: second, name" ); - strictEqual( json[ 1 ]["age"], 25, "Check JSON: second, age" ); - start(); + assert.ok( json.length >= 2, "Check length" ); + assert.strictEqual( json[ 0 ]["name"], "John", "Check JSON: first, name" ); + assert.strictEqual( json[ 0 ]["age"], 21, "Check JSON: first, age" ); + assert.strictEqual( json[ 1 ]["name"], "Peter", "Check JSON: second, name" ); + assert.strictEqual( json[ 1 ]["age"], 25, "Check JSON: second, age" ); + QUnit.start(); } ); }); - asyncTest( "jQuery.getJSON( String, Function ) - JSON object", 2, function() { + QUnit.asyncTest( "jQuery.getJSON( String, Function ) - JSON object", 2, function( assert ) { jQuery.getJSON( url("data/json.php"), function( json ) { if ( json && json["data"] ) { - strictEqual( json["data"]["lang"], "en", "Check JSON: lang" ); - strictEqual( json["data"].length, 25, "Check JSON: length" ); - start(); + assert.strictEqual( json["data"]["lang"], "en", "Check JSON: lang" ); + assert.strictEqual( json["data"].length, 25, "Check JSON: length" ); + QUnit.start(); } }); }); - asyncTest( "jQuery.getJSON( String, Function ) - JSON object with absolute url to local content", 2, function() { + QUnit.asyncTest( "jQuery.getJSON( String, Function ) - JSON object with absolute url to local content", 2, function( assert ) { jQuery.getJSON( url( window.location.href.replace( /[^\/]*$/, "" ) + "data/json.php" ), function( json ) { - strictEqual( json.data.lang, "en", "Check JSON: lang" ); - strictEqual( json.data.length, 25, "Check JSON: length" ); - start(); + assert.strictEqual( json.data.lang, "en", "Check JSON: lang" ); + assert.strictEqual( json.data.length, 25, "Check JSON: length" ); + QUnit.start(); }); }); //----------- jQuery.getScript() - asyncTest( "jQuery.getScript( String, Function ) - with callback", 2, function() { + QUnit.asyncTest( "jQuery.getScript( String, Function ) - with callback", 2, function( assert ) { Globals.register("testBar"); jQuery.getScript( url("data/testbar.php"), function() { - strictEqual( window["testBar"], "bar", "Check if script was evaluated" ); - start(); + assert.strictEqual( window["testBar"], "bar", "Check if script was evaluated" ); + QUnit.start(); }); }); - asyncTest( "jQuery.getScript( String, Function ) - no callback", 1, function() { + QUnit.asyncTest( "jQuery.getScript( String, Function ) - no callback", 1, function() { Globals.register("testBar"); jQuery.getScript( url("data/testbar.php") ).done( start ); }); - asyncTest( "#8082 - jQuery.getScript( String, Function ) - source as responseText", 2, function() { + QUnit.asyncTest( "#8082 - jQuery.getScript( String, Function ) - source as responseText", 2, function( assert ) { Globals.register("testBar"); jQuery.getScript( url("data/testbar.php"), function( data, _, jqXHR ) { - strictEqual( data, jqXHR.responseText, "Same-domain script requests returns the source of the script" ); - start(); + assert.strictEqual( data, jqXHR.responseText, "Same-domain script requests returns the source of the script" ); + QUnit.start(); }); }); -//----------- jQuery.fn.load() +// //----------- jQuery.fn.load() // check if load can be called with only url - asyncTest( "jQuery.fn.load( String )", 2, function() { + QUnit.asyncTest( "jQuery.fn.load( String )", 2, function( assert ) { jQuery.ajaxSetup({ beforeSend: function() { - strictEqual( this.type, "GET", "no data means GET request" ); + assert.strictEqual( this.type, "GET", "no data means GET request" ); } }); jQuery("#first").load( "data/name.html", start ); }); - asyncTest( "jQuery.fn.load() - 404 error callbacks", 6, function() { - addGlobalEvents("ajaxStart ajaxStop ajaxSend ajaxComplete ajaxError")(); - jQuery( document ).ajaxStop( start ); + QUnit.test( "jQuery.fn.load() - 404 error callbacks", function( assert ) { + assert.expect( 6 ); + var done = assert.async(); + + addGlobalEvents( "ajaxStart ajaxStop ajaxSend ajaxComplete ajaxError", assert )(); + jQuery( document ).ajaxStop( done ); jQuery("
          ").load( "data/404.html", function() { - ok( true, "complete" ); + assert.ok( true, "complete" ); }); }); // check if load can be called with url and null data - asyncTest( "jQuery.fn.load( String, null )", 2, function() { + QUnit.asyncTest( "jQuery.fn.load( String, null )", 2, function( assert ) { jQuery.ajaxSetup({ beforeSend: function() { - strictEqual( this.type, "GET", "no data means GET request" ); + assert.strictEqual( this.type, "GET", "no data means GET request" ); } }); jQuery("#first").load( "data/name.html", null, start ); }); // check if load can be called with url and undefined data - asyncTest( "jQuery.fn.load( String, undefined )", 2, function() { + QUnit.asyncTest( "jQuery.fn.load( String, undefined )", 2, function( assert ) { jQuery.ajaxSetup({ beforeSend: function() { - strictEqual( this.type, "GET", "no data means GET request" ); + assert.strictEqual( this.type, "GET", "no data means GET request" ); } }); jQuery("#first").load( "data/name.html", undefined, start ); }); // check if load can be called with only url - asyncTest( "jQuery.fn.load( URL_SELECTOR )", 1, function() { + QUnit.asyncTest( "jQuery.fn.load( URL_SELECTOR )", 1, function( assert ) { jQuery("#first").load( "data/test3.html div.user", function() { - strictEqual( jQuery( this ).children("div").length, 2, "Verify that specific elements were injected" ); - start(); + assert.strictEqual( jQuery( this ).children("div").length, 2, "Verify that specific elements were injected" ); + QUnit.start(); }); }); // Selector should be trimmed to avoid leading spaces (#14773) - asyncTest( "jQuery.fn.load( URL_SELECTOR with spaces )", 1, function() { + QUnit.asyncTest( "jQuery.fn.load( URL_SELECTOR with spaces )", 1, function( assert ) { jQuery("#first").load( "data/test3.html #superuser ", function() { - strictEqual( jQuery( this ).children("div").length, 1, "Verify that specific elements were injected" ); - start(); + assert.strictEqual( jQuery( this ).children("div").length, 1, "Verify that specific elements were injected" ); + QUnit.start(); }); }); - asyncTest( "jQuery.fn.load( String, Function ) - simple: inject text into DOM", 2, function() { + QUnit.asyncTest( "jQuery.fn.load( String, Function ) - simple: inject text into DOM", 2, function( assert ) { jQuery("#first").load( url("data/name.html"), function() { - ok( /^ERROR/.test(jQuery("#first").text()), "Check if content was injected into the DOM" ); - start(); + assert.ok( /^ERROR/.test(jQuery("#first").text()), "Check if content was injected into the DOM" ); + QUnit.start(); }); }); - asyncTest( "jQuery.fn.load( String, Function ) - check scripts", 7, function() { + QUnit.asyncTest( "jQuery.fn.load( String, Function ) - check scripts", 7, function( assert ) { var verifyEvaluation = function() { - strictEqual( window["testBar"], "bar", "Check if script src was evaluated after load" ); - strictEqual( jQuery("#ap").html(), "bar", "Check if script evaluation has modified DOM"); - start(); + assert.strictEqual( window["testBar"], "bar", "Check if script src was evaluated after load" ); + assert.strictEqual( jQuery("#ap").html(), "bar", "Check if script evaluation has modified DOM"); + QUnit.start(); }; Globals.register("testFoo"); Globals.register("testBar"); jQuery("#first").load( url("data/test.html"), function() { - ok( jQuery("#first").html().match( /^html text/ ), "Check content after loading html" ); - strictEqual( jQuery("#foo").html(), "foo", "Check if script evaluation has modified DOM" ); - strictEqual( window["testFoo"], "foo", "Check if script was evaluated after load" ); + assert.ok( jQuery("#first").html().match( /^html text/ ), "Check content after loading html" ); + assert.strictEqual( jQuery("#foo").html(), "foo", "Check if script evaluation has modified DOM" ); + assert.strictEqual( window["testFoo"], "foo", "Check if script was evaluated after load" ); setTimeout( verifyEvaluation, 600 ); }); }); - asyncTest( "jQuery.fn.load( String, Function ) - check file with only a script tag", 3, function() { + QUnit.asyncTest( "jQuery.fn.load( String, Function ) - check file with only a script tag", 3, function( assert ) { Globals.register("testFoo"); jQuery("#first").load( url("data/test2.html"), function() { - strictEqual( jQuery("#foo").html(), "foo", "Check if script evaluation has modified DOM"); - strictEqual( window["testFoo"], "foo", "Check if script was evaluated after load" ); - start(); + assert.strictEqual( jQuery("#foo").html(), "foo", "Check if script evaluation has modified DOM"); + assert.strictEqual( window["testFoo"], "foo", "Check if script was evaluated after load" ); + QUnit.start(); }); }); - asyncTest( "jQuery.fn.load( String, Function ) - dataFilter in ajaxSettings", 2, function() { + QUnit.asyncTest( "jQuery.fn.load( String, Function ) - dataFilter in ajaxSettings", 2, function( assert ) { jQuery.ajaxSetup({ dataFilter: function() { return "Hello World"; } }); jQuery("
          ").load( url("data/name.html"), function( responseText ) { - strictEqual( jQuery( this ).html(), "Hello World", "Test div was filled with filtered data" ); - strictEqual( responseText, "Hello World", "Test callback receives filtered data" ); - start(); + assert.strictEqual( jQuery( this ).html(), "Hello World", "Test div was filled with filtered data" ); + assert.strictEqual( responseText, "Hello World", "Test callback receives filtered data" ); + QUnit.start(); }); }); - asyncTest( "jQuery.fn.load( String, Object, Function )", 2, function() { + QUnit.asyncTest( "jQuery.fn.load( String, Object, Function )", 2, function( assert ) { jQuery("
          ").load( url("data/params_html.php"), { "foo": 3, "bar": "ok" }, function() { var $post = jQuery( this ).find("#post"); - strictEqual( $post.find("#foo").text(), "3", "Check if a hash of data is passed correctly" ); - strictEqual( $post.find("#bar").text(), "ok", "Check if a hash of data is passed correctly" ); - start(); + assert.strictEqual( $post.find("#foo").text(), "3", "Check if a hash of data is passed correctly" ); + assert.strictEqual( $post.find("#bar").text(), "ok", "Check if a hash of data is passed correctly" ); + QUnit.start(); }); }); - asyncTest( "jQuery.fn.load( String, String, Function )", 2, function() { + QUnit.test( "jQuery.fn.load( String, String, Function )", 2, function( assert ) { + var done = assert.async(); + jQuery("
          ").load( url("data/params_html.php"), "foo=3&bar=ok", function() { var $get = jQuery( this ).find("#get"); - strictEqual( $get.find("#foo").text(), "3", "Check if a string of data is passed correctly" ); - strictEqual( $get.find("#bar").text(), "ok", "Check if a of data is passed correctly" ); - start(); + assert.strictEqual( $get.find("#foo").text(), "3", "Check if a string of data is passed correctly" ); + assert.strictEqual( $get.find("#bar").text(), "ok", "Check if a of data is passed correctly" ); + done(); }); }); - asyncTest( "jQuery.fn.load() - callbacks get the correct parameters", 8, function() { + QUnit.test( "jQuery.fn.load() - callbacks get the correct parameters", 8, function( assert ) { var completeArgs = {}; + var done = assert.async(); jQuery.ajaxSetup({ success: function( _, status, jqXHR ) { @@ -1973,30 +2102,34 @@ module( "ajax", { return jQuery.Deferred(function( defer ) { jQuery("#foo").load( options.url, function() { var args = arguments; - strictEqual( completeArgs[ options.url ].length, args.length, "same number of arguments (" + options.type + ")" ); + assert.strictEqual( completeArgs[ options.url ].length, args.length, "same number of arguments (" + options.type + ")" ); jQuery.each( completeArgs[ options.url ], function( i, value ) { - strictEqual( args[ i ], value, "argument #" + i + " is the same (" + options.type + ")" ); + assert.strictEqual( args[ i ], value, "argument #" + i + " is the same (" + options.type + ")" ); }); defer.resolve(); }); }); }) - ).always( start ); + ).always( done ); }); - asyncTest( "#2046 - jQuery.fn.load( String, Function ) with ajaxSetup on dataType json", 1, function() { + QUnit.test( "#2046 - jQuery.fn.load( String, Function ) with ajaxSetup on dataType json", 1, function( assert ) { + var done = assert.async(); + jQuery.ajaxSetup({ dataType: "json" }); jQuery( document ).ajaxComplete(function( e, xml, s ) { - strictEqual( s.dataType, "html", "Verify the load() dataType was html" ); + assert.strictEqual( s.dataType, "html", "Verify the load() dataType was html" ); jQuery( document ).off("ajaxComplete"); - start(); + done(); }); jQuery("#first").load("data/test3.html"); }); - asyncTest( "#10524 - jQuery.fn.load() - data specified in ajaxSettings is merged in", 1, function() { + QUnit.test( "#10524 - jQuery.fn.load() - data specified in ajaxSettings is merged in", 1, function( assert ) { + var done = assert.async(); + var data = { "baz": 1 }; @@ -2007,14 +2140,16 @@ module( "ajax", { }); jQuery("#foo").load( "data/echoQuery.php", data ); jQuery( document ).ajaxComplete(function( event, jqXHR, options ) { - ok( ~options.data.indexOf("foo=bar"), "Data from ajaxSettings was used" ); - start(); + assert.ok( ~options.data.indexOf("foo=bar"), "Data from ajaxSettings was used" ); + done(); }); }); -//----------- jQuery.post() +// //----------- jQuery.post() + + QUnit.test( "jQuery.post() - data", 3, function( assert ) { + var done = assert.async(); - asyncTest( "jQuery.post() - data", 3, function() { jQuery.when( jQuery.post( url("data/name.php"), @@ -2024,8 +2159,8 @@ module( "ajax", { }, function( xml ) { jQuery( "math", xml ).each(function() { - strictEqual( jQuery( "calculation", this ).text(), "5-2", "Check for XML" ); - strictEqual( jQuery( "result", this ).text(), "3", "Check for XML" ); + assert.strictEqual( jQuery( "calculation", this ).text(), "5-2", "Check for XML" ); + assert.strictEqual( jQuery( "result", this ).text(), "3", "Check for XML" ); }); } ), @@ -2039,15 +2174,17 @@ module( "ajax", { } }, success: function( data ) { - strictEqual( data, "test%5Blength%5D=7&test%5Bfoo%5D=bar", "Check if a sub-object with a length param is serialized correctly" ); + assert.strictEqual( data, "test%5Blength%5D=7&test%5Bfoo%5D=bar", "Check if a sub-object with a length param is serialized correctly" ); } }) ).always(function() { - start(); + done(); }); }); - asyncTest( "jQuery.post( String, Hash, Function ) - simple with xml", 4, function() { + QUnit.test( "jQuery.post( String, Hash, Function ) - simple with xml", 4, function( assert ) { + var done = assert.async(); + jQuery.when( jQuery.post( url("data/name.php"), @@ -2056,23 +2193,25 @@ module( "ajax", { }, function( xml ) { jQuery( "math", xml ).each(function() { - strictEqual( jQuery( "calculation", this ).text(), "5-2", "Check for XML" ); - strictEqual( jQuery( "result", this ).text(), "3", "Check for XML" ); + assert.strictEqual( jQuery( "calculation", this ).text(), "5-2", "Check for XML" ); + assert.strictEqual( jQuery( "result", this ).text(), "3", "Check for XML" ); }); } ), jQuery.post( url("data/name.php?xml=5-2"), {}, function( xml ) { jQuery( "math", xml ).each(function() { - strictEqual( jQuery( "calculation", this ).text(), "5-2", "Check for XML" ); - strictEqual( jQuery( "result", this ).text(), "3", "Check for XML" ); + assert.strictEqual( jQuery( "calculation", this ).text(), "5-2", "Check for XML" ); + assert.strictEqual( jQuery( "result", this ).text(), "3", "Check for XML" ); }); }) ).always(function() { - start(); + done(); }); }); - asyncTest( "jQuery[get|post]( options ) - simple with xml", 2, function() { + QUnit.test( "jQuery[get|post]( options ) - simple with xml", 2, function( assert ) { + var done = assert.async(); + jQuery.when.apply( jQuery, jQuery.map( [ "get", "post" ] , function( method ) { return jQuery[ method ]({ @@ -2082,22 +2221,21 @@ module( "ajax", { }, success: function( xml ) { jQuery( "math", xml ).each(function() { - strictEqual( jQuery( "result", this ).text(), "3", "Check for XML" ); + assert.strictEqual( jQuery( "result", this ).text(), "3", "Check for XML" ); }); } }); }) ).always(function() { - start(); + done(); }); }); //----------- jQuery.active - test( "jQuery.active", function() { - expect( 1 ); - - ok( jQuery.active === 0, "ajax active counter should be zero: " + jQuery.active ); + QUnit.test( "jQuery.active", function( assert ) { + assert.expect( 1 ); + assert.ok( jQuery.active === 0, "ajax active counter should be zero: " + jQuery.active ); }); })(); diff --git a/test/unit/animation.js b/test/unit/animation.js index 6bb070145e..3b1479432c 100644 --- a/test/unit/animation.js +++ b/test/unit/animation.js @@ -11,7 +11,7 @@ var oldRaf = window.requestAnimationFrame, startTime = 505877050; // This module tests jQuery.Animation and the corresponding 1.8+ effects APIs -module( "animation", { +QUnit.module( "animation", { setup: function() { window.requestAnimationFrame = null; this.sandbox = sinon.sandbox.create(); @@ -33,77 +33,93 @@ module( "animation", { } } ); -test( "Animation( subject, props, opts ) - shape", function() { - expect( 20 ); +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 ); - equal( animation.elem, subject, ".elem is set to the exact object passed" ); - equal( animation.originalOptions, opts, ".originalOptions is set to options passed" ); - equal( animation.originalProperties, props, ".originalProperties is set to props passed" ); - - notEqual( animation.props, props, ".props is not the original however" ); - deepEqual( animation.props, props, ".props is a copy of the original" ); - - deepEqual( animation.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" ); - equal( animation.startTime, startTime, "startTime was set" ); - equal( animation.duration, 100, ".duration is set" ); + assert.equal( animation.startTime, startTime, "startTime was set" ); + assert.equal( animation.duration, 100, ".duration is set" ); - equal( animation.tweens.length, 1, ".tweens has one Tween" ); - equal( typeof animation.tweens[ 0 ].run, "function", "which has a .run function" ); + assert.equal( animation.tweens.length, 1, ".tweens has one Tween" ); + assert.equal( typeof animation.tweens[ 0 ].run, "function", "which has a .run function" ); - equal( typeof animation.createTween, "function", ".createTween is a function" ); - equal( typeof animation.stop, "function", ".stop is a function" ); + assert.equal( typeof animation.createTween, "function", ".createTween is a function" ); + assert.equal( typeof animation.stop, "function", ".stop is a function" ); - equal( typeof animation.done, "function", ".done is a function" ); - equal( typeof animation.fail, "function", ".fail is a function" ); - equal( typeof animation.always, "function", ".always is a function" ); - equal( typeof animation.progress, "function", ".progress 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" ); - equal( jQuery.timers.length, 1, "Added a timers function" ); - equal( jQuery.timers[ 0 ].elem, subject, "...with .elem as the subject" ); - equal( jQuery.timers[ 0 ].anim, animation, "...with .anim as the animation" ); - equal( jQuery.timers[ 0 ].queue, opts.queue, "...with .queue" ); + 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 ); } ); -test( "Animation.prefilter( fn ) - calls prefilter after defaultPrefilter", function() { - expect( 1 ); +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 ); + var prefilter = this.sandbox.stub(), + defaultSpy = this.sandbox.spy( jQuery.Animation.prefilters, 0 ); - jQuery.Animation.prefilter( prefilter ); + jQuery.Animation.prefilter( prefilter ); - jQuery.Animation( {}, {}, {} ); - ok( prefilter.calledAfter( defaultSpy ), "our prefilter called after" ); -} ); + jQuery.Animation( {}, {}, {} ); + assert.ok( prefilter.calledAfter( defaultSpy ), "our prefilter called after" ); + } +); -test( "Animation.prefilter( fn, true ) - calls prefilter before defaultPrefilter", function() { - expect( 1 ); +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 ); + var prefilter = this.sandbox.stub(), + defaultSpy = this.sandbox.spy( jQuery.Animation.prefilters, 0 ); - jQuery.Animation.prefilter( prefilter, true ); + jQuery.Animation.prefilter( prefilter, true ); - jQuery.Animation( {}, {}, {} ); - ok( prefilter.calledBefore( defaultSpy ), "our prefilter called before" ); -} ); + jQuery.Animation( {}, {}, {} ); + assert.ok( prefilter.calledBefore( defaultSpy ), "our prefilter called before" ); + } +); -test( "Animation.prefilter - prefilter return hooks", function() { - expect( 34 ); +QUnit.test( "Animation.prefilter - prefilter return hooks", function( assert ) { + assert.expect( 34 ); var animation, realAnimation, element, sandbox = this.sandbox, @@ -115,10 +131,10 @@ test( "Animation.prefilter - prefilter return hooks", function() { realAnimation = this; sandbox.spy( realAnimation, "createTween" ); - deepEqual( realAnimation.originalProperties, props, "originalProperties" ); - equal( arguments[ 0 ], this.elem, "first param elem" ); - equal( arguments[ 1 ], this.props, "second param props" ); - equal( arguments[ 2 ], this.opts, "third param opts" ); + 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 ), @@ -133,14 +149,25 @@ test( "Animation.prefilter - prefilter return hooks", function() { animation = jQuery.Animation( target, props, opts ); - equal( prefilter.callCount, 1, "Called prefilter" ); - - equal( defaultSpy.callCount, 0, - "Returning something from a prefilter caused remaining prefilters to not run" ); - equal( jQuery.fx.timer.callCount, 0, "Returning something never queues a timer" ); - equal( animation, ourAnimation, "Returning something returned it from jQuery.Animation" ); - equal( realAnimation.createTween.callCount, 0, "Returning something never creates tweens" ); - equal( TweenSpy.callCount, 0, "Returning something never creates tweens" ); + 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(); @@ -153,78 +180,84 @@ test( "Animation.prefilter - prefilter return hooks", function() { .animate( props, 100 ) .queue( queueSpy ); - equal( prefilter.callCount, 1, "Called prefilter" ); - equal( queueSpy.callCount, 0, "Next function in queue not called" ); + assert.equal( prefilter.callCount, 1, "Called prefilter" ); + assert.equal( queueSpy.callCount, 0, "Next function in queue not called" ); realAnimation.opts.complete.call( realAnimation.elem ); - equal( queueSpy.callCount, 1, "Next function in queue called after complete" ); + assert.equal( queueSpy.callCount, 1, "Next function in queue called after complete" ); - equal( prefilter.callCount, 2, "Called prefilter again - animation #2" ); - equal( ourAnimation.stop.callCount, 0, ".stop() on our animation hasn't been called" ); + 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(); - equal( ourAnimation.stop.callCount, 1, ".stop() called ourAnimation.stop()" ); - ok( !ourAnimation.stop.args[ 0 ][ 0 ], ".stop( falsy ) (undefined or false are both valid)" ); + 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)" + ); - equal( queueSpy.callCount, 2, "Next queue function called" ); - ok( queueSpy.calledAfter( ourAnimation.stop ), "After our animation was told to stop" ); + 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(); - equal( prefilter.callCount, 3, "Got the next animation" ); + assert.equal( prefilter.callCount, 3, "Got the next animation" ); ourAnimation.stop.reset(); // do not clear queue, gotoEnd element.stop( false, true ); - ok( ourAnimation.stop.calledWith( true ), ".stop(true) calls .stop(true)" ); - ok( queueSpy.calledAfter( ourAnimation.stop ), + 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" ); } ); -test( "Animation.tweener( fn ) - unshifts a * tweener", function() { - expect( 2 ); +QUnit.test( "Animation.tweener( fn ) - unshifts a * tweener", function( assert ) { + assert.expect( 2 ); var starTweeners = jQuery.Animation.tweeners[ "*" ]; jQuery.Animation.tweener( jQuery.noop ); - equal( starTweeners.length, 2 ); - deepEqual( starTweeners, [ jQuery.noop, defaultTweener ] ); + assert.equal( starTweeners.length, 2 ); + assert.deepEqual( starTweeners, [ jQuery.noop, defaultTweener ] ); } ); -test( "Animation.tweener( 'prop', fn ) - unshifts a 'prop' tweener", function() { - expect( 4 ); +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 ); - equal( tweeners.prop.length, 1 ); - deepEqual( tweeners.prop, [ jQuery.noop ] ); + assert.equal( tweeners.prop.length, 1 ); + assert.deepEqual( tweeners.prop, [ jQuery.noop ] ); jQuery.Animation.tweener( "prop", fn ); - equal( tweeners.prop.length, 2 ); - deepEqual( tweeners.prop, [ fn, jQuery.noop ] ); + assert.equal( tweeners.prop.length, 2 ); + assert.deepEqual( tweeners.prop, [ fn, jQuery.noop ] ); } ); -test( "Animation.tweener( 'list of props', fn ) - unshifts a tweener to each prop", function() { - expect( 2 ); - var tweeners = jQuery.Animation.tweeners, - fn = function() {}; - - jQuery.Animation.tweener( "list of props", jQuery.noop ); - 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 ); - deepEqual( tweeners, { - list: [ fn, jQuery.noop ], - of: [ fn, jQuery.noop ], - props: [ fn, jQuery.noop ], - "*": [ fn, defaultTweener ] - } ); -} ); +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/attributes.js b/test/unit/attributes.js index cec7b60558..6d8848a3ea 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -1,4 +1,4 @@ -module( "attributes", { +QUnit.module( "attributes", { teardown: moduleTeardown }); @@ -24,8 +24,8 @@ function functionReturningObj( value ) { Returns a function that returns the value */ -test( "jQuery.propFix integrity test", function() { - expect( 1 ); +QUnit.test( "jQuery.propFix integrity test", function( assert ) { + assert.expect( 1 ); // This must be maintained and equal jQuery.attrFix when appropriate // Ensure that accidental or erroneous property @@ -46,74 +46,74 @@ test( "jQuery.propFix integrity test", function() { "contenteditable": "contentEditable" }; - deepEqual( props, jQuery.propFix, "jQuery.propFix passes integrity check" ); + assert.deepEqual( props, jQuery.propFix, "jQuery.propFix passes integrity check" ); }); -test( "attr(String)", function() { - expect( 50 ); +QUnit.test( "attr(String)", function( assert ) { + assert.expect( 50 ); var extras, body, $body, select, optgroup, option, $img, styleElem, $button, $form, $a; - equal( jQuery("#text1").attr("type"), "text", "Check for type attribute" ); - equal( jQuery("#radio1").attr("type"), "radio", "Check for type attribute" ); - equal( jQuery("#check1").attr("type"), "checkbox", "Check for type attribute" ); - equal( jQuery("#simon1").attr("rel"), "bookmark", "Check for rel attribute" ); - equal( jQuery("#google").attr("title"), "Google!", "Check for title attribute" ); - equal( jQuery("#mark").attr("hreflang"), "en", "Check for hreflang attribute" ); - equal( jQuery("#en").attr("lang"), "en", "Check for lang attribute" ); - equal( jQuery("#simon").attr("class"), "blog link", "Check for class attribute" ); - equal( jQuery("#name").attr("name"), "name", "Check for name attribute" ); - equal( jQuery("#text1").attr("name"), "action", "Check for name attribute" ); - ok( jQuery("#form").attr("action").indexOf("formaction") >= 0, "Check for action attribute" ); - equal( jQuery("#text1").attr("value", "t").attr("value"), "t", "Check setting the value attribute" ); - equal( jQuery("#text1").attr("value", "").attr("value"), "", "Check setting the value attribute to empty string" ); - equal( jQuery("
          ").attr("value"), "t", "Check setting custom attr named 'value' on a div" ); - equal( jQuery("#form").attr("blah", "blah").attr("blah"), "blah", "Set non-existent attribute on a form" ); - equal( jQuery("#foo").attr("height"), undefined, "Non existent height attribute should return undefined" ); + assert.equal( jQuery("#text1").attr("type"), "text", "Check for type attribute" ); + assert.equal( jQuery("#radio1").attr("type"), "radio", "Check for type attribute" ); + assert.equal( jQuery("#check1").attr("type"), "checkbox", "Check for type attribute" ); + assert.equal( jQuery("#simon1").attr("rel"), "bookmark", "Check for rel attribute" ); + assert.equal( jQuery("#google").attr("title"), "Google!", "Check for title attribute" ); + assert.equal( jQuery("#mark").attr("hreflang"), "en", "Check for hreflang attribute" ); + assert.equal( jQuery("#en").attr("lang"), "en", "Check for lang attribute" ); + assert.equal( jQuery("#simon").attr("class"), "blog link", "Check for class attribute" ); + assert.equal( jQuery("#name").attr("name"), "name", "Check for name attribute" ); + assert.equal( jQuery("#text1").attr("name"), "action", "Check for name attribute" ); + assert.ok( jQuery("#form").attr("action").indexOf("formaction") >= 0, "Check for action attribute" ); + assert.equal( jQuery("#text1").attr("value", "t").attr("value"), "t", "Check setting the value attribute" ); + assert.equal( jQuery("#text1").attr("value", "").attr("value"), "", "Check setting the value attribute to empty string" ); + assert.equal( jQuery("
          ").attr("value"), "t", "Check setting custom attr named 'value' on a div" ); + assert.equal( jQuery("#form").attr("blah", "blah").attr("blah"), "blah", "Set non-existent attribute on a form" ); + assert.equal( jQuery("#foo").attr("height"), undefined, "Non existent height attribute should return undefined" ); // [7472] & [3113] (form contains an input with name="action" or name="id") extras = jQuery("").appendTo("#testForm"); - equal( jQuery("#form").attr("action","newformaction").attr("action"), "newformaction", "Check that action attribute was changed" ); - equal( jQuery("#testForm").attr("target"), undefined, "Retrieving target does not equal the input with name=target" ); - equal( jQuery("#testForm").attr("target", "newTarget").attr("target"), "newTarget", "Set target successfully on a form" ); - equal( jQuery("#testForm").removeAttr("id").attr("id"), undefined, "Retrieving id does not equal the input with name=id after id is removed [#7472]" ); + assert.equal( jQuery("#form").attr("action","newformaction").attr("action"), "newformaction", "Check that action attribute was changed" ); + assert.equal( jQuery("#testForm").attr("target"), undefined, "Retrieving target does not equal the input with name=target" ); + assert.equal( jQuery("#testForm").attr("target", "newTarget").attr("target"), "newTarget", "Set target successfully on a form" ); + assert.equal( jQuery("#testForm").removeAttr("id").attr("id"), undefined, "Retrieving id does not equal the input with name=id after id is removed [#7472]" ); // Bug #3685 (form contains input with name="name") - equal( jQuery("#testForm").attr("name"), undefined, "Retrieving name does not retrieve input with name=name" ); + assert.equal( jQuery("#testForm").attr("name"), undefined, "Retrieving name does not retrieve input with name=name" ); extras.remove(); - equal( jQuery("#text1").attr("maxlength"), "30", "Check for maxlength attribute" ); - equal( jQuery("#text1").attr("maxLength"), "30", "Check for maxLength attribute" ); - equal( jQuery("#area1").attr("maxLength"), "30", "Check for maxLength attribute" ); + assert.equal( jQuery("#text1").attr("maxlength"), "30", "Check for maxlength attribute" ); + assert.equal( jQuery("#text1").attr("maxLength"), "30", "Check for maxLength attribute" ); + assert.equal( jQuery("#area1").attr("maxLength"), "30", "Check for maxLength attribute" ); // using innerHTML in IE causes href attribute to be serialized to the full path jQuery("").attr({ "id": "tAnchor5", "href": "#5" }).appendTo("#qunit-fixture"); - equal( jQuery("#tAnchor5").attr("href"), "#5", "Check for non-absolute href (an anchor)" ); + assert.equal( jQuery("#tAnchor5").attr("href"), "#5", "Check for non-absolute href (an anchor)" ); jQuery("").appendTo("#qunit-fixture"); - equal( jQuery("#tAnchor5").prop("href"), jQuery("#tAnchor6").prop("href"), "Check for absolute href prop on an anchor" ); + assert.equal( jQuery("#tAnchor5").prop("href"), jQuery("#tAnchor6").prop("href"), "Check for absolute href prop on an anchor" ); jQuery("").appendTo("#qunit-fixture"); - equal( jQuery("#tAnchor5").prop("href"), jQuery("#scriptSrc").prop("src"), "Check for absolute src prop on a script" ); + assert.equal( jQuery("#tAnchor5").prop("href"), jQuery("#scriptSrc").prop("src"), "Check for absolute src prop on a script" ); // list attribute is readonly by default in browsers that support it jQuery("#list-test").attr( "list", "datalist" ); - equal( jQuery("#list-test").attr("list"), "datalist", "Check setting list attribute" ); + assert.equal( jQuery("#list-test").attr("list"), "datalist", "Check setting list attribute" ); // Related to [5574] and [5683] body = document.body; $body = jQuery( body ); - strictEqual( $body.attr("foo"), undefined, "Make sure that a non existent attribute returns undefined" ); + assert.strictEqual( $body.attr("foo"), undefined, "Make sure that a non existent attribute returns undefined" ); body.setAttribute( "foo", "baz" ); - equal( $body.attr("foo"), "baz", "Make sure the dom attribute is retrieved when no expando is found" ); + assert.equal( $body.attr("foo"), "baz", "Make sure the dom attribute is retrieved when no expando is found" ); $body.attr( "foo","cool" ); - equal( $body.attr("foo"), "cool", "Make sure that setting works well when both expando and dom attribute are available" ); + assert.equal( $body.attr("foo"), "cool", "Make sure that setting works well when both expando and dom attribute are available" ); body.removeAttribute("foo"); // Cleanup @@ -124,82 +124,82 @@ test( "attr(String)", function() { optgroup.appendChild( option ); select.appendChild( optgroup ); - equal( jQuery( option ).prop("selected"), true, "Make sure that a single option is selected, even when in an optgroup." ); + assert.equal( jQuery( option ).prop("selected"), true, "Make sure that a single option is selected, even when in an optgroup." ); $img = jQuery("").appendTo("body"); - equal( $img.attr("width"), "215", "Retrieve width attribute an an element with display:none." ); - equal( $img.attr("height"), "53", "Retrieve height attribute an an element with display:none." ); + assert.equal( $img.attr("width"), "215", "Retrieve width attribute an an element with display:none." ); + assert.equal( $img.attr("height"), "53", "Retrieve height attribute an an element with display:none." ); // Check for style support styleElem = jQuery("
          ").appendTo("#qunit-fixture").css({ background: "url(UPPERlower.gif)" }); - ok( !!~styleElem.attr("style").indexOf("UPPERlower.gif"), "Check style attribute getter" ); - ok( !!~styleElem.attr("style", "position:absolute;").attr("style").indexOf("absolute"), "Check style setter" ); + assert.ok( !!~styleElem.attr("style").indexOf("UPPERlower.gif"), "Check style attribute getter" ); + assert.ok( !!~styleElem.attr("style", "position:absolute;").attr("style").indexOf("absolute"), "Check style setter" ); // Check value on button element (#1954) $button = jQuery("").insertAfter("#button"); - strictEqual( $button.attr("value"), undefined, "Absence of value attribute on a button" ); - equal( $button.attr( "value", "foobar" ).attr("value"), "foobar", "Value attribute on a button does not return innerHTML" ); - equal( $button.attr("value", "baz").html(), "text", "Setting the value attribute does not change innerHTML" ); + assert.strictEqual( $button.attr("value"), undefined, "Absence of value attribute on a button" ); + assert.equal( $button.attr( "value", "foobar" ).attr("value"), "foobar", "Value attribute on a button does not return innerHTML" ); + assert.equal( $button.attr("value", "baz").html(), "text", "Setting the value attribute does not change innerHTML" ); // Attributes with a colon on a table element (#1591) - equal( jQuery("#table").attr("test:attrib"), undefined, "Retrieving a non-existent attribute on a table with a colon does not throw an error." ); - equal( jQuery("#table").attr( "test:attrib", "foobar" ).attr("test:attrib"), "foobar", "Setting an attribute on a table with a colon does not throw an error." ); + assert.equal( jQuery("#table").attr("test:attrib"), undefined, "Retrieving a non-existent attribute on a table with a colon does not throw an error." ); + assert.equal( jQuery("#table").attr( "test:attrib", "foobar" ).attr("test:attrib"), "foobar", "Setting an attribute on a table with a colon does not throw an error." ); $form = jQuery("
          ").appendTo("#qunit-fixture"); - equal( $form.attr("class"), "something", "Retrieve the class attribute on a form." ); + assert.equal( $form.attr("class"), "something", "Retrieve the class attribute on a form." ); $a = jQuery("
          Click").appendTo("#qunit-fixture"); - equal( $a.attr("onclick"), "something()", "Retrieve ^on attribute without anonymous function wrapper." ); + assert.equal( $a.attr("onclick"), "something()", "Retrieve ^on attribute without anonymous function wrapper." ); - ok( jQuery("
          ").attr("doesntexist") === undefined, "Make sure undefined is returned when no attribute is found." ); - ok( jQuery("
          ").attr("title") === undefined, "Make sure undefined is returned when no attribute is found." ); - equal( jQuery("
          ").attr( "title", "something" ).attr("title"), "something", "Set the title attribute." ); - ok( jQuery().attr("doesntexist") === undefined, "Make sure undefined is returned when no element is there." ); - equal( jQuery("
          ").attr("value"), undefined, "An unset value on a div returns undefined." ); - strictEqual( jQuery("").attr("value"), undefined, "An unset value on a select returns undefined." ); + assert.ok( jQuery("
          ").attr("doesntexist") === undefined, "Make sure undefined is returned when no attribute is found." ); + assert.ok( jQuery("
          ").attr("title") === undefined, "Make sure undefined is returned when no attribute is found." ); + assert.equal( jQuery("
          ").attr( "title", "something" ).attr("title"), "something", "Set the title attribute." ); + assert.ok( jQuery().attr("doesntexist") === undefined, "Make sure undefined is returned when no element is there." ); + assert.equal( jQuery("
          ").attr("value"), undefined, "An unset value on a div returns undefined." ); + assert.strictEqual( jQuery("").attr("value"), undefined, "An unset value on a select returns undefined." ); $form = jQuery("#form").attr( "enctype", "multipart/form-data" ); - equal( $form.prop("enctype"), "multipart/form-data", "Set the enctype of a form (encoding in IE6/7 #6743)" ); + assert.equal( $form.prop("enctype"), "multipart/form-data", "Set the enctype of a form (encoding in IE6/7 #6743)" ); }); -test( "attr(String) on cloned elements, #9646", function() { - expect( 4 ); +QUnit.test( "attr(String) on cloned elements, #9646", function( assert ) { + assert.expect( 4 ); var div, input = jQuery(""); input.attr("name"); - strictEqual( input.clone( true ).attr( "name", "test" )[ 0 ].name, "test", "Name attribute should be changed on cloned element" ); + assert.strictEqual( input.clone( true ).attr( "name", "test" )[ 0 ].name, "test", "Name attribute should be changed on cloned element" ); div = jQuery("
          "); div.attr("id"); - strictEqual( div.clone( true ).attr( "id", "test" )[ 0 ].id, "test", "Id attribute should be changed on cloned element" ); + assert.strictEqual( div.clone( true ).attr( "id", "test" )[ 0 ].id, "test", "Id attribute should be changed on cloned element" ); input = jQuery(""); input.attr("value"); - strictEqual( input.clone( true ).attr( "value", "test" )[ 0 ].value, "test", "Value attribute should be changed on cloned element" ); + assert.strictEqual( input.clone( true ).attr( "value", "test" )[ 0 ].value, "test", "Value attribute should be changed on cloned element" ); - strictEqual( input.clone( true ).attr( "value", 42 )[ 0 ].value, "42", "Value attribute should be changed on cloned element" ); + assert.strictEqual( input.clone( true ).attr( "value", 42 )[ 0 ].value, "42", "Value attribute should be changed on cloned element" ); }); -test( "attr(String) in XML Files", function() { - expect( 3 ); +QUnit.test( "attr(String) in XML Files", function( assert ) { + assert.expect( 3 ); var xml = createDashboardXML(); - equal( jQuery( "locations", xml ).attr("class"), "foo", "Check class attribute in XML document" ); - equal( jQuery( "location", xml ).attr("for"), "bar", "Check for attribute in XML document" ); - equal( jQuery( "location", xml ).attr("checked"), "different", "Check that hooks are not attached in XML document" ); + assert.equal( jQuery( "locations", xml ).attr("class"), "foo", "Check class attribute in XML document" ); + assert.equal( jQuery( "location", xml ).attr("for"), "bar", "Check for attribute in XML document" ); + assert.equal( jQuery( "location", xml ).attr("checked"), "different", "Check that hooks are not attached in XML document" ); }); -test( "attr(String, Function)", function() { - expect( 2 ); +QUnit.test( "attr(String, Function)", function( assert ) { + assert.expect( 2 ); - equal( + assert.equal( jQuery("#text1").attr( "value", function() { return this.id; }).attr("value"), @@ -207,7 +207,7 @@ test( "attr(String, Function)", function() { "Set value from id" ); - equal( + assert.equal( jQuery("#text1").attr( "title", function(i) { return i; }).attr("title"), @@ -216,8 +216,8 @@ test( "attr(String, Function)", function() { ); }); -test( "attr(Hash)", function() { - expect( 3 ); +QUnit.test( "attr(Hash)", function( assert ) { + assert.expect( 3 ); var pass = true; jQuery("div").attr({ "foo": "baz", @@ -228,9 +228,9 @@ test( "attr(Hash)", function() { } }); - ok( pass, "Set Multiple Attributes" ); + assert.ok( pass, "Set Multiple Attributes" ); - equal( + assert.equal( jQuery("#text1").attr({ "value": function() { return this["id"]; @@ -239,7 +239,7 @@ test( "attr(Hash)", function() { "Set attribute to computed value #1" ); - equal( + assert.equal( jQuery("#text1").attr({ "title": function(i) { return i; @@ -250,8 +250,8 @@ test( "attr(Hash)", function() { ); }); -test( "attr(String, Object)", function() { - expect( 71 ); +QUnit.test( "attr(String, Object)", function( assert ) { + assert.expect( 71 ); var $input, $text, $details, attributeNode, commentNode, textNode, obj, @@ -268,9 +268,9 @@ test( "attr(String, Object)", function() { } } - equal( fail, false, "Set Attribute, the #" + fail + " element didn't get the attribute 'foo'" ); + assert.equal( fail, false, "Set Attribute, the #" + fail + " element didn't get the attribute 'foo'" ); - ok( + assert.ok( jQuery("#foo").attr({ "width": null }), @@ -278,90 +278,90 @@ test( "attr(String, Object)", function() { ); jQuery("#name").attr( "name", "something" ); - equal( jQuery("#name").attr("name"), "something", "Set name attribute" ); + assert.equal( jQuery("#name").attr("name"), "something", "Set name attribute" ); jQuery("#name").attr( "name", null ); - equal( jQuery("#name").attr("name"), undefined, "Remove name attribute" ); + assert.equal( jQuery("#name").attr("name"), undefined, "Remove name attribute" ); $input = jQuery( "", { name: "something", id: "specified" }); - equal( $input.attr("name"), "something", "Check element creation gets/sets the name attribute." ); - equal( $input.attr("id"), "specified", "Check element creation gets/sets the id attribute." ); + assert.equal( $input.attr("name"), "something", "Check element creation gets/sets the name attribute." ); + assert.equal( $input.attr("id"), "specified", "Check element creation gets/sets the id attribute." ); // As of fixing #11115, we only guarantee boolean property update for checked and selected $input = jQuery("").attr( "checked", true ); - equal( $input.prop("checked"), true, "Setting checked updates property (verified by .prop)" ); - equal( $input[0].checked, true, "Setting checked updates property (verified by native property)" ); + assert.equal( $input.prop("checked"), true, "Setting checked updates property (verified by .prop)" ); + assert.equal( $input[0].checked, true, "Setting checked updates property (verified by native property)" ); $input = jQuery("