From df7dfc2404807dce2f97c21782eb3a14ced86d6b Mon Sep 17 00:00:00 2001 From: rjgotten Date: Sun, 17 Oct 2010 08:30:05 -0700 Subject: [PATCH 001/372] Check against the type attribute of script elements retrieved through getElementsByTagName() so that only those elements of type "text/javascript" are handled by 'clean'. Fixes #6180: jQuery.clean should not touch script tags that are not of type text/javascript --- src/manipulation.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/manipulation.js b/src/manipulation.js index 325f303a..2cd95ce9 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -146,7 +146,7 @@ jQuery.fn.extend({ return set; } }, - + // keepData is for internal use only--do not document remove: function( selector, keepData ) { for ( var i = 0, elem; (elem = this[i]) != null; i++ ) { @@ -161,7 +161,7 @@ jQuery.fn.extend({ } } } - + return this; }, @@ -177,7 +177,7 @@ jQuery.fn.extend({ elem.removeChild( elem.firstChild ); } } - + return this; }, @@ -322,9 +322,9 @@ jQuery.fn.extend({ } else { results = jQuery.buildFragment( args, this, scripts ); } - + fragment = results.fragment; - + if ( fragment.childNodes.length === 1 ) { first = fragment = fragment.firstChild; } else { @@ -429,18 +429,18 @@ jQuery.each({ jQuery.fn[ name ] = function( selector ) { var ret = [], insert = jQuery( selector ), parent = this.length === 1 && this[0].parentNode; - + if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) { insert[ original ]( this[0] ); return this; - + } else { for ( var i = 0, l = insert.length; i < l; i++ ) { var elems = (i > 0 ? this.clone(true) : this).get(); jQuery( insert[i] )[ original ]( elems ); ret = ret.concat( elems ); } - + return this.pushStack( ret, name, insert.selector ); } }; @@ -528,10 +528,12 @@ jQuery.extend({ for ( i = 0; ret[i]; i++ ) { if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) { scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] ); - + } else { if ( ret[i].nodeType === 1 ) { - ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) ); + var jsTags = jQuery.makeArray( ret[i].getElementsByTagName( "script" )), + jsTags = jQuery.grep(jsTags, function(n, i) { return ( !n.type || n.type.toLowerCase() === "text/javascript" ) }); + ret.splice.apply( ret, [i + 1, 0].concat( jsTags )); } fragment.appendChild( ret[i] ); } @@ -540,22 +542,22 @@ jQuery.extend({ return ret; }, - + cleanData: function( elems ) { var data, id, cache = jQuery.cache, special = jQuery.event.special, deleteExpando = jQuery.support.deleteExpando; - + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { continue; } id = elem[ jQuery.expando ]; - + if ( id ) { data = cache[ id ]; - + if ( data && data.events ) { for ( var type in data.events ) { if ( special[ type ] ) { @@ -566,14 +568,14 @@ jQuery.extend({ } } } - + if ( deleteExpando ) { delete elem[ jQuery.expando ]; } else if ( elem.removeAttribute ) { elem.removeAttribute( jQuery.expando ); } - + delete cache[ id ]; } } From 689d63f4871d96300d492fa5ab9d25301070efba Mon Sep 17 00:00:00 2001 From: Jephte CLAIN Date: Tue, 19 Oct 2010 09:29:20 +0400 Subject: [PATCH 002/372] Return control of $ and jQuery only if it is really necessary. This make jQuery.noConflict() callable anytime. --- src/core.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core.js b/src/core.js index 99521d91..f701a20c 100644 --- a/src/core.js +++ b/src/core.js @@ -373,9 +373,9 @@ jQuery.extend = jQuery.fn.extend = function() { jQuery.extend({ noConflict: function( deep ) { - window.$ = _$; + if ( window.$ === jQuery ) window.$ = _$; - if ( deep ) { + if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } From 1ac7b459a4defb8238309ae47afb3637719cf8be Mon Sep 17 00:00:00 2001 From: Jephte CLAIN Date: Mon, 22 Nov 2010 08:12:12 +0400 Subject: [PATCH 003/372] respect source guidelines --- src/core.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core.js b/src/core.js index f701a20c..4cc5eea1 100644 --- a/src/core.js +++ b/src/core.js @@ -373,7 +373,9 @@ jQuery.extend = jQuery.fn.extend = function() { jQuery.extend({ noConflict: function( deep ) { - if ( window.$ === jQuery ) window.$ = _$; + if ( window.$ === jQuery ) { + window.$ = _$; + } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; From dd79199a08b9b69d139606619b818c429e0540c3 Mon Sep 17 00:00:00 2001 From: Jephte CLAIN Date: Mon, 22 Nov 2010 08:12:12 +0400 Subject: [PATCH 004/372] fix to follow current source style --- src/core.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core.js b/src/core.js index f701a20c..4cc5eea1 100644 --- a/src/core.js +++ b/src/core.js @@ -373,7 +373,9 @@ jQuery.extend = jQuery.fn.extend = function() { jQuery.extend({ noConflict: function( deep ) { - if ( window.$ === jQuery ) window.$ = _$; + if ( window.$ === jQuery ) { + window.$ = _$; + } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; From 9f8cd6c499844451468257140e71f611abb3a040 Mon Sep 17 00:00:00 2001 From: Gianni Chiappetta Date: Tue, 14 Dec 2010 21:53:04 -0500 Subject: [PATCH 005/372] Fixing $.proxy to work like (and use) Function.prototype.bind (ticket #7783) http://bugs.jquery.com/ticket/7783 --- src/core.js | 49 +++++++++++++++++++++++++++++------------------ src/event.js | 44 ++++++++++++++++++++++++++---------------- test/unit/core.js | 11 ++++++++--- 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/src/core.js b/src/core.js index 346e52d7..74ec4ea0 100644 --- a/src/core.js +++ b/src/core.js @@ -740,31 +740,42 @@ jQuery.extend({ // 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; + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var args, proxy; - } else if ( proxy && !jQuery.isFunction( proxy ) ) { - thisObject = proxy; - proxy = undefined; + // 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; + } + + if ( jQuery.isFunction( Function.prototype.bind ) ) { + // Native bind + args = slice.call( arguments, 1 ); + proxy = Function.prototype.bind.apply( fn, args ); + } else { + // Simulated bind + args = slice.call( arguments, 2 ); + if ( args.length ) { + proxy = function() { + return arguments.length ? + fn.apply( context, args.concat( slice.call( arguments ) ) ) : + fn.apply( context, args ); + }; + } else { + proxy = function() { + return arguments.length ? + fn.apply( context, arguments ) : + fn.call( context ); + }; } } - 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++; - } + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; - // So proxy can be declared as an argument return proxy; }, diff --git a/src/event.js b/src/event.js index fd470e71..82e9b52d 100644 --- a/src/event.js +++ b/src/event.js @@ -891,6 +891,8 @@ if ( document.addEventListener ) { jQuery.each(["bind", "one"], function( i, name ) { jQuery.fn[ name ] = function( type, data, fn ) { + var handler; + // Handle object literals if ( typeof type === "object" ) { for ( var key in type ) { @@ -904,10 +906,15 @@ jQuery.each(["bind", "one"], function( i, name ) { data = undefined; } - var handler = name === "one" ? jQuery.proxy( fn, function( event ) { - jQuery( this ).unbind( event, handler ); - return fn.apply( this, arguments ); - }) : fn; + if ( name === "one" ) { + handler = function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }; + handler.guid = fn.guid || jQuery.guid++; + } else { + handler = fn; + } if ( type === "unload" && name !== "one" ) { this.one( type, data, fn ); @@ -971,24 +978,27 @@ jQuery.fn.extend({ toggle: function( fn ) { // Save reference to arguments for access in closure var args = arguments, - i = 1; + guid = fn.guid || jQuery.guid++, + i = 0, + toggler = 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; + }; // link all the functions, so any of them can unbind this click handler + toggler.guid = guid; while ( i < args.length ) { - jQuery.proxy( fn, args[ i++ ] ); + args[ i++ ].guid = guid; } - 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; - })); + return this.click( toggler ); }, hover: function( fnOver, fnOut ) { diff --git a/test/unit/core.js b/test/unit/core.js index 70577837..9f9078a4 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -858,7 +858,7 @@ test("jQuery.isEmptyObject", function(){ }); test("jQuery.proxy", function(){ - expect(4); + expect(5); var test = function(){ equals( this, thisObject, "Make sure that scope is set properly." ); }; var thisObject = { foo: "bar", method: test }; @@ -872,8 +872,13 @@ test("jQuery.proxy", function(){ // Make sure it doesn't freak out equals( jQuery.proxy( null, thisObject ), undefined, "Make sure no function was returned." ); - // Use the string shortcut - jQuery.proxy( thisObject, "method" )(); + // Partial application + var test2 = function( a ){ equals( a, "pre-applied", "Ensure arguments can be pre-applied." ); }; + jQuery.proxy( test2, null, "pre-applied" )(); + + // Partial application w/ normal arguments + var test3 = function( a, b ){ equals( b, "normal", "Ensure arguments can be pre-applied and passed as usual." ); }; + jQuery.proxy( test3, null, "pre-applied" )( "normal" ); }); test("jQuery.parseJSON", function(){ From 5b1b57850cfd4c92a4f9231581dff7faac489566 Mon Sep 17 00:00:00 2001 From: Gianni Chiappetta Date: Wed, 15 Dec 2010 18:31:10 -0500 Subject: [PATCH 006/372] Add a quick test to $.support for native bind. As per the suggestion by ajpiano: https://github.com/gf3/jquery/commit/9f8cd6c499844451468257140e71f611abb3a040#commitcomment-218658 --- src/core.js | 2 +- src/support.js | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core.js b/src/core.js index 74ec4ea0..a6e2a46f 100644 --- a/src/core.js +++ b/src/core.js @@ -751,7 +751,7 @@ jQuery.extend({ return undefined; } - if ( jQuery.isFunction( Function.prototype.bind ) ) { + if ( jQuery.support.nativeBind ) { // Native bind args = slice.call( arguments, 1 ); proxy = Function.prototype.bind.apply( fn, args ); diff --git a/src/support.js b/src/support.js index 67b41c4a..2913d217 100644 --- a/src/support.js +++ b/src/support.js @@ -60,6 +60,9 @@ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, + // Test for native Function#bind. + nativeBind: jQuery.isFunction( Function.prototype.bind ), + // Will be defined later deleteExpando: true, optDisabled: false, From 1ebb5ab3e1c670e04024cd949fa6f341e93c4487 Mon Sep 17 00:00:00 2001 From: Gianni Chiappetta Date: Thu, 16 Dec 2010 16:04:23 -0500 Subject: [PATCH 007/372] Added list of browsers that currently support Function#bind. --- src/support.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/support.js b/src/support.js index 2913d217..1fd1c2a6 100644 --- a/src/support.js +++ b/src/support.js @@ -60,7 +60,8 @@ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, - // Test for native Function#bind. + // Test for presence of native Function#bind. + // Currently in: Chrome 7, FireFox 4 nativeBind: jQuery.isFunction( Function.prototype.bind ), // Will be defined later From 6bc9fc7c10a6dd2c8c7132307e63323a1f59d35f Mon Sep 17 00:00:00 2001 From: Gianni Chiappetta Date: Sat, 18 Dec 2010 19:17:37 -0500 Subject: [PATCH 008/372] Perf. improvement based on fearphage's suggestion (direct vs call vs apply). --- src/core.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core.js b/src/core.js index a6e2a46f..2ffcb911 100644 --- a/src/core.js +++ b/src/core.js @@ -754,7 +754,11 @@ jQuery.extend({ if ( jQuery.support.nativeBind ) { // Native bind args = slice.call( arguments, 1 ); - proxy = Function.prototype.bind.apply( fn, args ); + if ( args.length ) { + proxy = Function.prototype.bind.apply( fn, args ); + } else { + proxy = fn.bind( context ); + } } else { // Simulated bind args = slice.call( arguments, 2 ); From ade531cfaa194eb13fa6307368d1e715f3be8326 Mon Sep 17 00:00:00 2001 From: Gianni Chiappetta Date: Sat, 18 Dec 2010 19:26:36 -0500 Subject: [PATCH 009/372] Noted which browsers don't support Function#bind. --- src/support.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/support.js b/src/support.js index 1fd1c2a6..55c19d80 100644 --- a/src/support.js +++ b/src/support.js @@ -61,7 +61,7 @@ optSelected: opt.selected, // Test for presence of native Function#bind. - // Currently in: Chrome 7, FireFox 4 + // Not in: >= Chrome 6, >= FireFox 3, Safari 5?, IE 9?, Opera 11? nativeBind: jQuery.isFunction( Function.prototype.bind ), // Will be defined later From 612a908514b6ad6ec35754b0193887b01ce2c9f2 Mon Sep 17 00:00:00 2001 From: rwldrn Date: Sat, 1 Jan 2011 13:49:59 -0500 Subject: [PATCH 010/372] #7883 .delegate and .live should accept false as the fn arg, like bind --- src/event.js | 7 ++++++- test/unit/event.js | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/event.js b/src/event.js index 675e5fff..4d908b92 100644 --- a/src/event.js +++ b/src/event.js @@ -1023,10 +1023,15 @@ jQuery.each(["live", "die"], function( i, name ) { return this; } - if ( jQuery.isFunction( data ) ) { + if ( jQuery.isFunction( data ) || data === false ) { fn = data; data = undefined; } + + if ( fn === false ) { + fn = returnFalse; + } + types = (types || "").split(" "); diff --git a/test/unit/event.js b/test/unit/event.js index b4672a8b..01fbac57 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -527,6 +527,45 @@ test("bind(name, false), unbind(name, false)", function() { equals( main, 1, "Verify that the trigger happened correctly." ); }); +test("live(name, false), die(name, false)", function() { + expect(3); + + var main = 0; + jQuery("#main").live("click", function(e){ main++; }); + jQuery("#ap").trigger("click"); + equals( main, 1, "Verify that the trigger happened correctly." ); + + main = 0; + jQuery("#ap").live("click", false); + jQuery("#ap").trigger("click"); + equals( main, 0, "Verify that no bubble happened." ); + + main = 0; + jQuery("#ap").die("click", false); + jQuery("#ap").trigger("click"); + equals( main, 1, "Verify that the trigger happened correctly." ); +}); + +test("delegate(selector, name, false), undelegate(selector, name, false)", function() { + expect(3); + + var main = 0; + + jQuery("#main").delegate("#ap", "click", function(e){ main++; }); + jQuery("#ap").trigger("click"); + equals( main, 1, "Verify that the trigger happened correctly." ); + + main = 0; + jQuery("#ap").delegate("#groups", "click", false); + jQuery("#groups").trigger("click"); + equals( main, 0, "Verify that no bubble happened." ); + + main = 0; + jQuery("#ap").undelegate("#groups", "click", false); + jQuery("#groups").trigger("click"); + equals( main, 1, "Verify that the trigger happened correctly." ); +}); + test("bind()/trigger()/unbind() on plain object", function() { expect( 8 ); From 037d6bd5c33cea91974bbfeaaa30d26e9dc94d48 Mon Sep 17 00:00:00 2001 From: rwldrn Date: Sat, 1 Jan 2011 17:13:04 -0500 Subject: [PATCH 011/372] 4321 returns empty jquery object --- src/core.js | 3 ++- test/unit/core.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core.js b/src/core.js index 0211808c..fcbd1c35 100644 --- a/src/core.js +++ b/src/core.js @@ -17,7 +17,8 @@ var jQuery = function( selector, context ) { // A simple way to check for HTML strings or ID strings // (both of which we optimize for) - quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/, + quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, + // Is it a simple selector isSimple = /^.[^:#\[\.,]*$/, diff --git a/test/unit/core.js b/test/unit/core.js index 9367ab10..2563f17c 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -12,7 +12,7 @@ test("Basic requirements", function() { }); test("jQuery()", function() { - expect(24); + expect(25); strictEqual( commonJSDefined, jQuery, "CommonJS registered (Bug #7102)" ); @@ -22,6 +22,7 @@ test("jQuery()", function() { equals( jQuery(undefined).length, 0, "jQuery(undefined) === jQuery([])" ); equals( jQuery(null).length, 0, "jQuery(null) === jQuery([])" ); equals( jQuery("").length, 0, "jQuery('') === jQuery([])" ); + equals( jQuery("#").length, 0, "jQuery('#') === jQuery([])" ); var obj = jQuery("div") equals( jQuery(obj).selector, "div", "jQuery(jQueryObj) == jQueryObj" ); From 5f52e61d74678786e2f40d4edbeb2396661bb9bc Mon Sep 17 00:00:00 2001 From: rwldrn Date: Sat, 1 Jan 2011 17:18:47 -0500 Subject: [PATCH 012/372] 4321 jQuery('#') returns empty jquery object --- src/core.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core.js b/src/core.js index fcbd1c35..3a4d9e66 100644 --- a/src/core.js +++ b/src/core.js @@ -19,7 +19,6 @@ var jQuery = function( selector, context ) { // (both of which we optimize for) quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/, - // Is it a simple selector isSimple = /^.[^:#\[\.,]*$/, From d03d2e9f26f85366ad2e91b9e2c76a249d7bf7be Mon Sep 17 00:00:00 2001 From: Xavi Date: Sun, 9 Jan 2011 19:11:05 -0500 Subject: [PATCH 013/372] Bug 7931; Fixed bug that caused scrollTop and scrollLeft setters to return null when called on an empty jquery object --- src/offset.js | 28 ++++++++++++++-------------- test/unit/offset.js | 8 +++++++- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/offset.js b/src/offset.js index 2040c9d8..d53a8813 100644 --- a/src/offset.js +++ b/src/offset.js @@ -261,13 +261,9 @@ jQuery.each( ["Left", "Top"], function( i, name ) { var method = "scroll" + name; jQuery.fn[ method ] = function(val) { - var elem = this[0], win; + var elem, win; - if ( !elem ) { - return null; - } - - if ( val !== undefined ) { + if ( val != undefined ) { // Set the scroll offset return this.each(function() { win = getWindow( this ); @@ -282,15 +278,19 @@ jQuery.each( ["Left", "Top"], function( i, name ) { this[ method ] = val; } }); - } else { - win = getWindow( elem ); - - // Return the scroll offset - return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] : - jQuery.support.boxModel && win.document.documentElement[ method ] || - win.document.body[ method ] : - elem[ method ]; } + + elem = this[0]; + if( !elem ) { + return null + } + + win = getWindow( elem ); + // Return the scroll offset + return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] : + jQuery.support.boxModel && win.document.documentElement[ method ] || + win.document.body[ method ] : + elem[ method ]; }; }); diff --git a/test/unit/offset.js b/test/unit/offset.js index cfa14449..66676def 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -333,7 +333,7 @@ testoffset("table", function( jQuery ) { }); testoffset("scroll", function( jQuery, win ) { - expect(16); + expect(20); var ie = jQuery.browser.msie && parseInt( jQuery.browser.version, 10 ) < 8; @@ -379,6 +379,12 @@ testoffset("scroll", function( jQuery, win ) { equals( jQuery(window).scrollLeft(), 0, "jQuery(window).scrollLeft() other window" ); equals( jQuery(document).scrollTop(), 0, "jQuery(window).scrollTop() other document" ); equals( jQuery(document).scrollLeft(), 0, "jQuery(window).scrollLeft() other document" ); + + // Tests scrollTop/Left with empty jquery objects + ok( jQuery().scrollTop(100) != null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); + ok( jQuery().scrollLeft(100) != null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); + ok( jQuery().scrollTop() === null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); + ok( jQuery().scrollLeft() === null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); }); testoffset("body", function( jQuery ) { From 628bacc3ce26a7a0e0462c2a2e0d764edf859c97 Mon Sep 17 00:00:00 2001 From: Xavi Date: Sun, 9 Jan 2011 20:12:29 -0500 Subject: [PATCH 014/372] Bug 7931; Added missing semicolon and replaced '!=' with '!==' to allow null through --- src/offset.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/offset.js b/src/offset.js index d53a8813..02f067eb 100644 --- a/src/offset.js +++ b/src/offset.js @@ -263,7 +263,7 @@ jQuery.each( ["Left", "Top"], function( i, name ) { jQuery.fn[ method ] = function(val) { var elem, win; - if ( val != undefined ) { + if ( val !== undefined ) { // Set the scroll offset return this.each(function() { win = getWindow( this ); @@ -282,7 +282,7 @@ jQuery.each( ["Left", "Top"], function( i, name ) { elem = this[0]; if( !elem ) { - return null + return null; } win = getWindow( elem ); From 8d28f41f669168ebd436599f8b187c783fec4ba9 Mon Sep 17 00:00:00 2001 From: Xavi Date: Sun, 9 Jan 2011 20:34:15 -0500 Subject: [PATCH 015/372] Bug 7931; Replaced with and --- test/unit/offset.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/offset.js b/test/unit/offset.js index 66676def..20bd7079 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -381,10 +381,10 @@ testoffset("scroll", function( jQuery, win ) { equals( jQuery(document).scrollLeft(), 0, "jQuery(window).scrollLeft() other document" ); // Tests scrollTop/Left with empty jquery objects - ok( jQuery().scrollTop(100) != null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); - ok( jQuery().scrollLeft(100) != null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); - ok( jQuery().scrollTop() === null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); - ok( jQuery().scrollLeft() === null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); + notEqual( jQuery().scrollTop(100), null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); + notEqual( jQuery().scrollLeft(100), null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); + strictEqual( jQuery().scrollTop(), null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); + strictEqual( jQuery().scrollLeft(), null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); }); testoffset("body", function( jQuery ) { From bed64e65cc658409961a7127b715643390919e6c Mon Sep 17 00:00:00 2001 From: Xavi Date: Sun, 9 Jan 2011 20:39:23 -0500 Subject: [PATCH 016/372] Bug 7931; Added unit tests for scrollTop/Left. --- test/unit/offset.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit/offset.js b/test/unit/offset.js index 20bd7079..69bf6d5d 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -333,7 +333,7 @@ testoffset("table", function( jQuery ) { }); testoffset("scroll", function( jQuery, win ) { - expect(20); + expect(22); var ie = jQuery.browser.msie && parseInt( jQuery.browser.version, 10 ) < 8; @@ -383,6 +383,8 @@ testoffset("scroll", function( jQuery, win ) { // Tests scrollTop/Left with empty jquery objects notEqual( jQuery().scrollTop(100), null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); notEqual( jQuery().scrollLeft(100), null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); + notEqual( jQuery().scrollTop(null), null, "jQuery().scrollTop(null) testing setter on empty jquery object" ); + notEqual( jQuery().scrollLeft(null), null, "jQuery().scrollLeft(null) testing setter on empty jquery object" ); strictEqual( jQuery().scrollTop(), null, "jQuery().scrollTop(100) testing setter on empty jquery object" ); strictEqual( jQuery().scrollLeft(), null, "jQuery().scrollLeft(100) testing setter on empty jquery object" ); }); From b78e3fc39f96d63a60ea66e3d066815626e633d8 Mon Sep 17 00:00:00 2001 From: Xavi Date: Sun, 9 Jan 2011 20:51:20 -0500 Subject: [PATCH 017/372] Bug 7931; Inverted logic in scrollTop/Left (i.e. made --- src/offset.js | 52 +++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/offset.js b/src/offset.js index 02f067eb..660efa23 100644 --- a/src/offset.js +++ b/src/offset.js @@ -263,34 +263,34 @@ jQuery.each( ["Left", "Top"], function( i, name ) { jQuery.fn[ method ] = function(val) { var elem, win; - if ( val !== undefined ) { - // Set the scroll offset - return this.each(function() { - win = getWindow( this ); - - if ( win ) { - win.scrollTo( - !i ? val : jQuery(win).scrollLeft(), - i ? val : jQuery(win).scrollTop() - ); - - } else { - this[ method ] = val; - } - }); + if(val === undefined) { + elem = this[0]; + if( !elem ) { + return null; + } + + win = getWindow( elem ); + // Return the scroll offset + return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] : + jQuery.support.boxModel && win.document.documentElement[ method ] || + win.document.body[ method ] : + elem[ method ]; } - elem = this[0]; - if( !elem ) { - return null; - } - - win = getWindow( elem ); - // Return the scroll offset - return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] : - jQuery.support.boxModel && win.document.documentElement[ method ] || - win.document.body[ method ] : - elem[ method ]; + // Set the scroll offset + return this.each(function() { + win = getWindow( this ); + + if ( win ) { + win.scrollTo( + !i ? val : jQuery(win).scrollLeft(), + i ? val : jQuery(win).scrollTop() + ); + + } else { + this[ method ] = val; + } + }); }; }); From 75655e5758bc786989f26a98b09aabbfb88f66fd Mon Sep 17 00:00:00 2001 From: Sylvester Keil Date: Sat, 15 Jan 2011 13:56:20 +0100 Subject: [PATCH 018/372] Use parseFloat instead of parseInt to read CSS values. This fixes #7730 and #7885. --- src/offset.js | 8 +++++--- test/unit/offset.js | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/offset.js b/src/offset.js index 2040c9d8..94b67c77 100644 --- a/src/offset.js +++ b/src/offset.js @@ -187,11 +187,13 @@ jQuery.offset = { // need to be able to calculate position if either top or left is auto and position is absolute if ( calculatePosition ) { curPosition = curElem.position(); + curTop = curPosition.top; + curLeft = curPosition.left; + } else { + curTop = parseFloat( curCSSTop ) || 0; + curLeft = parseFloat( curCSSLeft ) || 0; } - curTop = calculatePosition ? curPosition.top : parseInt( curCSSTop, 10 ) || 0; - curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0; - if ( jQuery.isFunction( options ) ) { options = options.call( elem, i, curOffset ); } diff --git a/test/unit/offset.js b/test/unit/offset.js index cfa14449..1f8c3b15 100644 --- a/test/unit/offset.js +++ b/test/unit/offset.js @@ -422,6 +422,32 @@ test("offsetParent", function(){ equals( div[1], jQuery("#nothiddendiv")[0], "The div is the offsetParent." ); }); +test("fractions (see #7730 and #7885)", function() { + expect(2); + + jQuery('body').append('
'); + + var expected = { top: 1000, left: 1000 }; + var div = jQuery('#fractions'); + + div.css({ + position: 'absolute', + left: '1000.7432222px', + top: '1000.532325px', + width: 100, + height: 100 + }); + + div.offset(expected); + + var result = div.offset(); + + equals( result.top, expected.top, "Check top" ); + equals( result.left, expected.left, "Check left" ); + + div.remove(); +}); + function testoffset(name, fn) { test(name, function() { From 135a384cf3e4cc3671de4cfcced20f294a5667a8 Mon Sep 17 00:00:00 2001 From: Xavi Date: Tue, 18 Jan 2011 12:40:07 -0500 Subject: [PATCH 019/372] Bug 7931; cleaned up white space in accordance to style guide --- src/offset.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/offset.js b/src/offset.js index 660efa23..8696c205 100644 --- a/src/offset.js +++ b/src/offset.js @@ -260,15 +260,15 @@ jQuery.fn.extend({ jQuery.each( ["Left", "Top"], function( i, name ) { var method = "scroll" + name; - jQuery.fn[ method ] = function(val) { + jQuery.fn[ method ] = function( val ) { var elem, win; - if(val === undefined) { - elem = this[0]; + if( val === undefined ) { + elem = this[ 0 ]; if( !elem ) { return null; } - + win = getWindow( elem ); // Return the scroll offset return win ? ("pageXOffset" in win) ? win[ i ? "pageYOffset" : "pageXOffset" ] : @@ -276,17 +276,16 @@ jQuery.each( ["Left", "Top"], function( i, name ) { win.document.body[ method ] : elem[ method ]; } - + // Set the scroll offset return this.each(function() { win = getWindow( this ); if ( win ) { win.scrollTo( - !i ? val : jQuery(win).scrollLeft(), - i ? val : jQuery(win).scrollTop() + !i ? val : jQuery( win ).scrollLeft(), + i ? val : jQuery( win ).scrollTop() ); - } else { this[ method ] = val; } From 574ae3b1be555dbd5242532739cd8e0a34e0569c Mon Sep 17 00:00:00 2001 From: Gianni Chiappetta Date: Fri, 21 Jan 2011 10:33:50 -0500 Subject: [PATCH 020/372] added: Backcompatibility with old proxy syntax. --- src/core.js | 6 ++++++ test/unit/core.js | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core.js b/src/core.js index 3bdedf53..ea3506a6 100644 --- a/src/core.js +++ b/src/core.js @@ -739,6 +739,12 @@ jQuery.extend({ proxy: function( fn, context ) { var args, proxy; + // XXX BACKCOMPAT: Support old string method. + if ( typeof context === "string" ) { + fn = fn[ context ]; + context = arguments[0]; + } + // 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 ) ) { diff --git a/test/unit/core.js b/test/unit/core.js index 7638554a..332fc51e 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -869,7 +869,7 @@ test("jQuery.isEmptyObject", function(){ }); test("jQuery.proxy", function(){ - expect(5); + expect(6); var test = function(){ equals( this, thisObject, "Make sure that scope is set properly." ); }; var thisObject = { foo: "bar", method: test }; @@ -890,6 +890,10 @@ test("jQuery.proxy", function(){ // Partial application w/ normal arguments var test3 = function( a, b ){ equals( b, "normal", "Ensure arguments can be pre-applied and passed as usual." ); }; jQuery.proxy( test3, null, "pre-applied" )( "normal" ); + + // Test old syntax + var test4 = { meth: function( a ){ equals( a, "boom", "Ensure old syntax works." ); } }; + jQuery.proxy( test4, "meth" )( "boom" ); }); test("jQuery.parseJSON", function(){ From ed48787ec58c12917faf47e3b95e043b2b6ded10 Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Mon, 24 Jan 2011 16:18:19 -0500 Subject: [PATCH 021/372] Fix bug #2773, jQuery.fn.is to accept JQuery and node objects, and a small fix for winnow getting an undefined selector --- src/traversing.js | 5 ++-- test/unit/traversing.js | 60 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/traversing.js b/src/traversing.js index 90601df5..f8d08fa9 100644 --- a/src/traversing.js +++ b/src/traversing.js @@ -60,7 +60,8 @@ jQuery.fn.extend({ }, is: function( selector ) { - return !!selector && jQuery.filter( selector, this ).length > 0; + return !!selector && (typeof selector === "string" ? jQuery.filter( selector, this ).length > 0 : + this.filter( selector ).length > 0); }, closest: function( selectors, context ) { @@ -286,7 +287,7 @@ function winnow( elements, qualifier, keep ) { return retVal === keep; }); - } else if ( qualifier.nodeType ) { + } else if ( qualifier && qualifier.nodeType ) { return jQuery.grep(elements, function( elem, i ) { return (elem === qualifier) === keep; }); diff --git a/test/unit/traversing.js b/test/unit/traversing.js index 56fed220..a74ee08b 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -13,8 +13,8 @@ test("find(String)", function() { same( jQuery("#main").find("> #foo > p").get(), q("sndp", "en", "sap"), "find child elements" ); }); -test("is(String)", function() { - expect(26); +test("is(String|undefined)", function() { + expect(27); ok( jQuery('#form').is('form'), 'Check for element: A form must be a form' ); ok( !jQuery('#form').is('div'), 'Check for element: A form is not a div' ); ok( jQuery('#mark').is('.blog'), 'Check for class: Expected class "blog"' ); @@ -33,11 +33,13 @@ test("is(String)", function() { ok( !jQuery('#foo').is(':has(ul)'), 'Check for child: Did not expect "ul" element' ); ok( jQuery('#foo').is(':has(p):has(a):has(code)'), 'Check for childs: Expected "p", "a" and "code" child elements' ); ok( !jQuery('#foo').is(':has(p):has(a):has(code):has(ol)'), 'Check for childs: Expected "p", "a" and "code" child elements, but no "ol"' ); + ok( !jQuery('#foo').is(0), 'Expected false for an invalid expression - 0' ); ok( !jQuery('#foo').is(null), 'Expected false for an invalid expression - null' ); ok( !jQuery('#foo').is(''), 'Expected false for an invalid expression - ""' ); ok( !jQuery('#foo').is(undefined), 'Expected false for an invalid expression - undefined' ); - + ok( !jQuery('#foo').is({ plain: "object" }), 'Check passing invalid object' ); + // test is() with comma-seperated expressions ok( jQuery('#en').is('[lang="en"],[lang="de"]'), 'Comma-seperated; Check for lang attribute: Expect en or de' ); ok( jQuery('#en').is('[lang="de"],[lang="en"]'), 'Comma-seperated; Check for lang attribute: Expect en or de' ); @@ -45,6 +47,49 @@ test("is(String)", function() { ok( jQuery('#en').is('[lang="de"] , [lang="en"]'), 'Comma-seperated; Check for lang attribute: Expect en or de' ); }); +test("is(Object)", function() { + expect(18); + ok( jQuery('#form').is( jQuery('form') ), 'Check for element: A form is a form' ); + ok( !jQuery('#form').is( jQuery('div') ), 'Check for element: A form is not a div' ); + ok( jQuery('#mark').is( jQuery('.blog') ), 'Check for class: Expected class "blog"' ); + ok( !jQuery('#mark').is( jQuery('.link') ), 'Check for class: Did not expect class "link"' ); + ok( jQuery('#simon').is( jQuery('.blog.link') ), 'Check for multiple classes: Expected classes "blog" and "link"' ); + ok( !jQuery('#simon').is( jQuery('.blogTest') ), 'Check for multiple classes: Expected classes "blog" and "link", but not "blogTest"' ); + ok( jQuery('#en').is( jQuery('[lang="en"]') ), 'Check for attribute: Expected attribute lang to be "en"' ); + ok( !jQuery('#en').is( jQuery('[lang="de"]') ), 'Check for attribute: Expected attribute lang to be "en", not "de"' ); + ok( jQuery('#text1').is( jQuery('[type="text"]') ), 'Check for attribute: Expected attribute type to be "text"' ); + ok( !jQuery('#text1').is( jQuery('[type="radio"]') ), 'Check for attribute: Expected attribute type to be "text", not "radio"' ); + ok( jQuery('#text2').is( jQuery(':disabled') ), 'Check for pseudoclass: Expected to be disabled' ); + ok( !jQuery('#text1').is( jQuery(':disabled') ), 'Check for pseudoclass: Expected not disabled' ); + ok( jQuery('#radio2').is( jQuery(':checked') ), 'Check for pseudoclass: Expected to be checked' ); + ok( !jQuery('#radio1').is( jQuery(':checked') ), 'Check for pseudoclass: Expected not checked' ); + ok( jQuery('#foo').is( jQuery(':has(p)') ), 'Check for child: Expected a child "p" element' ); + ok( !jQuery('#foo').is( jQuery(':has(ul)') ), 'Check for child: Did not expect "ul" element' ); + ok( jQuery('#foo').is( jQuery(':has(p):has(a):has(code)') ), 'Check for childs: Expected "p", "a" and "code" child elements' ); + ok( !jQuery('#foo').is( jQuery(':has(p):has(a):has(code):has(ol)') ), 'Check for childs: Expected "p", "a" and "code" child elements, but no "ol"' ); +}); + +test("is(node Object)", function() { + expect(17); + ok( jQuery('#form').is( jQuery('form')[0] ), 'Check for element: A form is a form' ); + ok( !jQuery('#form').is( jQuery('div')[0] ), 'Check for element: A form is not a div' ); + ok( jQuery('#mark').is( jQuery('.blog')[0] ), 'Check for class: Expected class "blog"' ); + ok( !jQuery('#mark').is( jQuery('.link')[0] ), 'Check for class: Did not expect class "link"' ); + ok( jQuery('#simon').is( jQuery('.blog.link')[0] ), 'Check for multiple classes: Expected classes "blog" and "link"' ); + ok( !jQuery('#simon').is( jQuery('.blogTest')[0] ), 'Check for multiple classes: Expected classes "blog" and "link", but not "blogTest"' ); + ok( jQuery('#en').is( jQuery('[lang="en"]')[1] ), 'Check for attribute: Expected attribute lang to be "en"' ); + ok( !jQuery('#en').is( jQuery('[lang="de"]')[0] ), 'Check for attribute: Expected attribute lang to be "en", not "de"' ); + ok( jQuery('#text1').is( jQuery('[type="text"]')[0] ), 'Check for attribute: Expected attribute type to be "text"' ); + ok( !jQuery('#text1').is( jQuery('[type="radio"]')[0] ), 'Check for attribute: Expected attribute type to be "text", not "radio"' ); + ok( jQuery('#text2').is( jQuery(':disabled')[0] ), 'Check for pseudoclass: Expected to be disabled' ); + ok( !jQuery('#text1').is( jQuery(':disabled')[0] ), 'Check for pseudoclass: Expected not disabled' ); + ok( !jQuery('#radio1').is( jQuery(':checked')[0] ), 'Check for pseudoclass: Expected not checked' ); + ok( jQuery('#foo').is( jQuery(':has(p)')[4] ), 'Check for child: Expected a child "p" element' ); + ok( !jQuery('#foo').is( jQuery(':has(ul)')[0] ), 'Check for child: Did not expect "ul" element' ); + ok( jQuery('#foo').is( jQuery(':has(p):has(a):has(code)')[4] ), 'Check for childs: Expected "p", "a" and "code" child elements' ); + ok( !jQuery('#foo').is( jQuery(':has(p):has(a):has(code):has(ol)')[0] ), 'Check for childs: Expected "p", "a" and "code" child elements, but no "ol"' ); +}); + test("index()", function() { expect(1); @@ -82,11 +127,16 @@ test("index(Object|String|undefined)", function() { equals( jQuery('#radio2').index('#form :text') , -1, "Check for index not found within a selector" ); }); -test("filter(Selector)", function() { - expect(5); +test("filter(Selector|undefined)", function() { + expect(9); same( jQuery("#form input").filter(":checked").get(), q("radio2", "check1"), "filter(String)" ); same( jQuery("p").filter("#ap, #sndp").get(), q("ap", "sndp"), "filter('String, String')" ); same( jQuery("p").filter("#ap,#sndp").get(), q("ap", "sndp"), "filter('String,String')" ); + + same( jQuery('p').filter(null).get(), [], "filter(null) should return an empty jQuery object"); + same( jQuery('p').filter(undefined).get(), [], "filter(undefined) should return an empty jQuery object"); + same( jQuery('p').filter(0).get(), [], "filter(0) should return an empty jQuery object"); + same( jQuery('p').filter('').get(), [], "filter('') should return an empty jQuery object"); // using contents will get comments regular, text, and comment nodes var j = jQuery("#nonnodes").contents(); From 82626799cacef94a1b35d0a0b4d284b38104704b Mon Sep 17 00:00:00 2001 From: Timmy Willison Date: Sun, 6 Feb 2011 19:34:57 -0500 Subject: [PATCH 022/372] Changed $.sub internals to match sub naming, added some more spacing in some areas for readability --- src/core.js | 36 ++++++++++++++++++------------------ src/css.js | 14 +++++++------- src/event.js | 6 ++---- 3 files changed, 27 insertions(+), 29 deletions(-) diff --git a/src/core.js b/src/core.js index 2e634723..1bc4c1cf 100644 --- a/src/core.js +++ b/src/core.js @@ -441,7 +441,7 @@ jQuery.extend({ } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes - document.attachEvent("onreadystatechange", DOMContentLoaded); + document.attachEvent( "onreadystatechange", DOMContentLoaded ); // A fallback to window.onload, that will always work window.attachEvent( "onload", jQuery.ready ); @@ -598,7 +598,7 @@ jQuery.extend({ each: function( object, callback, args ) { var name, i = 0, length = object.length, - isObj = length === undefined || jQuery.isFunction(object); + isObj = length === undefined || jQuery.isFunction( object ); if ( args ) { if ( isObj ) { @@ -625,7 +625,7 @@ jQuery.extend({ } } else { for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + i < length && callback.call( value, i, value ) !== false; value = object[ ++i ] ) {} } } @@ -656,7 +656,7 @@ jQuery.extend({ // The extra typeof function check is to prevent crashes // in Safari 2 (See: #3039) // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930 - var type = jQuery.type(array); + var type = jQuery.type( array ); if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) { push.call( ret, array ); @@ -982,24 +982,24 @@ jQuery.extend({ }, sub: function() { - function jQuerySubclass( selector, context ) { - return new jQuerySubclass.fn.init( selector, context ); + function jQuerySub( selector, context ) { + return new jQuerySub.fn.init( selector, context ); } - jQuery.extend( true, jQuerySubclass, this ); - jQuerySubclass.superclass = this; - jQuerySubclass.fn = jQuerySubclass.prototype = this(); - jQuerySubclass.fn.constructor = jQuerySubclass; - jQuerySubclass.subclass = this.subclass; - jQuerySubclass.fn.init = function init( selector, context ) { - if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) { - context = jQuerySubclass(context); + jQuery.extend( true, jQuerySub, this ); + jQuerySub.superclass = this; + jQuerySub.fn = jQuerySub.prototype = this(); + jQuerySub.fn.constructor = jQuerySub; + jQuerySub.sub = this.sub; + jQuerySub.fn.init = function init( selector, context ) { + if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) { + context = jQuerySub( context ); } - return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass ); + return jQuery.fn.init.call( this, selector, context, rootjQuerySub ); }; - jQuerySubclass.fn.init.prototype = jQuerySubclass.fn; - var rootjQuerySubclass = jQuerySubclass(document); - return jQuerySubclass; + jQuerySub.fn.init.prototype = jQuerySub.fn; + var rootjQuerySub = jQuerySub(document); + return jQuerySub; }, browser: {} diff --git a/src/css.js b/src/css.js index 19c6342d..968188d6 100644 --- a/src/css.js +++ b/src/css.js @@ -215,8 +215,8 @@ if ( !jQuery.support.opacity ) { jQuery.cssHooks.opacity = { get: function( elem, computed ) { // IE uses filters for opacity - return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "") ? - (parseFloat(RegExp.$1) / 100) + "" : + return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? + ( parseFloat( RegExp.$1 ) / 100 ) + "" : computed ? "1" : ""; }, @@ -228,13 +228,13 @@ if ( !jQuery.support.opacity ) { style.zoom = 1; // Set the alpha filter to set the opacity - var opacity = jQuery.isNaN(value) ? - "" : - "alpha(opacity=" + value * 100 + ")", + var opacity = jQuery.isNaN( value ) ? + "" : + "alpha(opacity=" + value * 100 + ")", filter = style.filter || ""; - style.filter = ralpha.test(filter) ? - filter.replace(ralpha, opacity) : + style.filter = ralpha.test( filter ) ? + filter.replace( ralpha, opacity ) : style.filter + ' ' + opacity; } }; diff --git a/src/event.js b/src/event.js index 2d53562a..01b05149 100644 --- a/src/event.js +++ b/src/event.js @@ -294,11 +294,9 @@ jQuery.event = { } }, - // bubbling is internal - trigger: function( event, data, elem /*, bubbling */ ) { + trigger: function( event, data, elem, bubbling /* For Internal Use Only */ ) { // Event object or event type - var type = event.type || event, - bubbling = arguments[3]; + var type = event.type || event; if ( !bubbling ) { event = typeof event === "object" ? From c8a887af066a62840ec1910604ddb7e0c38728e8 Mon Sep 17 00:00:00 2001 From: Jordan Boesch Date: Sun, 27 Feb 2011 12:47:35 -0600 Subject: [PATCH 023/372] Bug 2616; Adding object support to jQuery.map --- src/core.js | 28 +++++++++++++++++++++------- test/unit/core.js | 12 +++++------- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/core.js b/src/core.js index 036b2db6..3ff12085 100644 --- a/src/core.js +++ b/src/core.js @@ -712,15 +712,29 @@ jQuery.extend({ // arg is for internal usage only map: function( elems, callback, arg ) { - var ret = [], value; + var ret = [], + value, + length = elems.length, + // same object detection used in jQuery.each, not full-proof but very speedy. + isObj = length === undefined; - // 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 ( isObj ) { + for ( key in elems ) { + value = callback( elems[ key ], key, arg ); - if ( value != null ) { - ret[ ret.length ] = value; + if ( value != null ) { + ret[ ret.length ] = value; + } + } + } else { + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } } } diff --git a/test/unit/core.js b/test/unit/core.js index bce0de0f..d77e6a97 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -608,7 +608,7 @@ test("first()/last()", function() { }); test("map()", function() { - expect(2);//expect(6); + expect(6); same( jQuery("#ap").map(function(){ @@ -625,26 +625,24 @@ test("map()", function() { q("ap","ap","ap"), "Single Map" ); - - return;//these haven't been accepted yet - + //for #2616 var keys = jQuery.map( {a:1,b:2}, function( v, k ){ return k; - }, [ ] ); + }); equals( keys.join(""), "ab", "Map the keys from a hash to an array" ); var values = jQuery.map( {a:1,b:2}, function( v, k ){ return v; - }, [ ] ); + }); equals( values.join(""), "12", "Map the values from a hash to an array" ); var scripts = document.getElementsByTagName("script"); var mapped = jQuery.map( scripts, function( v, k ){ return v; - }, {length:0} ); + }); equals( mapped.length, scripts.length, "Map an array(-like) to a hash" ); From 025f2c63e487e069215b2a03ded2b98198904af9 Mon Sep 17 00:00:00 2001 From: louisremi Date: Tue, 1 Mar 2011 00:54:15 +0100 Subject: [PATCH 024/372] fixing both #8403 and #8401: jQuery \"bulldozes\" other IE filters when setting opacity --- src/css.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/css.js b/src/css.js index 8a982312..9fdba3b7 100644 --- a/src/css.js +++ b/src/css.js @@ -221,7 +221,8 @@ if ( !jQuery.support.opacity ) { }, set: function( elem, value ) { - var style = elem.style; + var style = elem.style, + currentStyle = elem.currentStyle; // IE has trouble with opacity if it does not have layout // Force it by setting the zoom level @@ -231,11 +232,11 @@ if ( !jQuery.support.opacity ) { var opacity = jQuery.isNaN(value) ? "" : "alpha(opacity=" + value * 100 + ")", - filter = style.filter || ""; + filter = currentStyle && currentStyle.filter || style.filter || ""; style.filter = ralpha.test(filter) ? filter.replace(ralpha, opacity) : - style.filter + ' ' + opacity; + filter + ' ' + opacity; } }; } From d4e4414451e15d23d7174e8eeddaa952ed0e4d73 Mon Sep 17 00:00:00 2001 From: jeresig Date: Sun, 6 Mar 2011 22:47:40 -0500 Subject: [PATCH 025/372] Very crude first pass at splitting apart the attr/prop logic. Also adding in attrHooks/propHooks. All of it is completely untested. --- src/attributes.js | 274 ++++++++++++++++++++++++++++------------------ 1 file changed, 168 insertions(+), 106 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 59972105..e5425a05 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -3,38 +3,37 @@ var rclass = /[\n\t\r]/g, rspaces = /\s+/, rreturn = /\r/g, - rspecialurl = /^(?:href|src|style)$/, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, rradiocheck = /^(?:radio|checkbox)$/i; -jQuery.props = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" -}; - jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.attr ); }, - removeAttr: function( name, fn ) { - return this.each(function(){ - jQuery.attr( this, name, "" ); + removeAttr: function( name ) { + return this.each(function() { if ( this.nodeType === 1 ) { this.removeAttribute( name ); } }); }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( 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 ) { if ( jQuery.isFunction(value) ) { @@ -275,6 +274,21 @@ jQuery.extend({ height: true, offset: true }, + + // TODO: Check to see if any of these are needed anymore? + // If not, it may be good to standardize on all-lowercase names instead + attrFix: { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" + }, attr: function( elem, name, value, pass ) { // don't get/set attributes on text, comment and attribute nodes @@ -286,104 +300,152 @@ jQuery.extend({ return jQuery(elem)[name](value); } - var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), - // Whether we are setting (or getting) - set = value !== undefined; - + var ret, + notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + hooks; + // Try to normalize/fix the name - name = notxml && jQuery.props[ name ] || name; + name = notxml && jQuery.attrFix[ name ] || name; + + hooks = jQuery.attrHooks[ name ]; + + if ( value !== undefined ) { + + if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value )) !== undefined ) { + return ret; + + } else { + // convert the value to a string (all browsers do this but IE) see #1070 + value = "" + value; + + elem.setAttribute( name, value ); + + return value; + } + + } else { + + if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem )) !== undefined ) { + return ret; + + } else { + + if ( !jQuery.hasAttr( elem, name ) ) { + return undefined; + } - // 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 ); + var attr = elem.getAttribute( 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; - } + // Non-existent attributes return null, we normalize to undefined + return attr === null ? + undefined : + attr; + } + } + }, + + hasAttr: function( elem, name ) { + // Blackberry 4.7 returns "" from getAttribute #6938 + return elem.attributes[ name ] || (elem.hasAttribute && elem.hasAttribute( name )); + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); } } + }, + + // 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/ + tabIndex: { + get: function( elem ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); - // If applicable, access the attribute via the DOM 0 way - // 'in' checks fail in Blackberry 4.7 #6931 - if ( (name in elem || elem[ name ] !== undefined) && 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" ); - } - - if ( value === null ) { - if ( elem.nodeType === 1 ) { - elem.removeAttribute( name ); - } - - } else { - 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 attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + }, + + // TODO: Check to see if we really need any here. + propFix: {}, + + prop: function( elem, name, value ) { + var ret, hooks; + + // Try to normalize/fix the name + name = notxml && jQuery.propFix[ name ] || name; + + hooks = jQuery.propHooks[ name ]; + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value )) !== undefined ) { + return ret; + + } else { + return (elem[ name ] = value); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem )) !== undefined ) { + return ret; + + } else { 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 ); - } - - // Ensure that missing attributes return undefined - // Blackberry 4.7 returns "" from getAttribute #6938 - if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { - return undefined; - } - - 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; } - // Handle everything which isn't a DOM element node - if ( set ) { - elem[ name ] = value; - } - return elem[ name ]; - } + }, + + propHooks: {} }); +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "style" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + return elem.getAttribute( name, 2 ); + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + return elem.style.cssText; + }, + + 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.attrHooks.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; + } + } + } + }; +} + })( jQuery ); From c6b891fb1c909a2791ba7a4d745940858bd7b94f Mon Sep 17 00:00:00 2001 From: louisremi Date: Mon, 7 Mar 2011 14:43:08 +0100 Subject: [PATCH 026/372] Adding unit tests for #8403 --- test/data/testsuite.css | 2 +- test/unit/css.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/data/testsuite.css b/test/data/testsuite.css index cffaaa46..02900681 100644 --- a/test/data/testsuite.css +++ b/test/data/testsuite.css @@ -1,5 +1,5 @@ /* for testing opacity set in styles in IE */ -ol#empty { opacity: 0; filter:Alpha(opacity=0); } +ol#empty { opacity: 0; filter:Alpha(opacity=0) progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffff0000', EndColorStr='#ffffffff'); } div#fx-tests h4 { background: red; diff --git a/test/unit/css.js b/test/unit/css.js index 555f1357..87466187 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -1,7 +1,7 @@ module("css", { teardown: moduleTeardown }); test("css(String|Hash)", function() { - expect(41); + expect(42); equals( jQuery('#main').css("display"), 'block', 'Check for css property "display"'); @@ -58,6 +58,7 @@ test("css(String|Hash)", function() { equals( jQuery('#empty').css('opacity'), '0', "Assert opacity is accessible via filter property set in stylesheet in IE" ); jQuery('#empty').css({ opacity: '1' }); equals( jQuery('#empty').css('opacity'), '1', "Assert opacity is taken from style attribute when set vs stylesheet in IE with filters" ); + ok( ~jQuery('#empty')[0].currentStyle.filter.indexOf('gradient'), "Assert setting opacity doesn't overwrite other filters of the stylesheet in IE" ); var div = jQuery('#nothiddendiv'), child = jQuery('#nothiddendivchild'); From 8246347b7191e79ed09bf1fc4c4a0a58211cf345 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 13 Mar 2011 21:12:10 -0400 Subject: [PATCH 027/372] Starting with adding the test --- test/unit/traversing.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/unit/traversing.js b/test/unit/traversing.js index f5108bde..9216bb5e 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -13,6 +13,15 @@ test("find(String)", function() { same( jQuery("#main").find("> #foo > p").get(), q("sndp", "en", "sap"), "find child elements" ); }); +test("find(node|jQuery object)", function() { + expect( 2 ); + + var $blog = jQuery('.blogTest'), + blog = $blog[0]; + equals( jQuery('#foo').find( $blog ).text(), 'Yahoo', 'Find with blog jQuery object' ); + equals( jQuery('#foo').find( blog ).text(), 'Yahoo', 'Find with blog node' ); +}); + test("is(String)", function() { expect(26); ok( jQuery('#form').is('form'), 'Check for element: A form must be a form' ); From 7a69e34a5cd4df37762cbee9c9468c96c0ac3017 Mon Sep 17 00:00:00 2001 From: timmywil Date: Wed, 16 Mar 2011 01:16:32 -0400 Subject: [PATCH 028/372] 2773: first pass adding node/jQuery object support to jQuery.fn.find; unit tests added --- src/core.js | 2 +- src/traversing.js | 23 ++++++++++++++++++----- test/unit/traversing.js | 25 ++++++++++++++++++++----- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/src/core.js b/src/core.js index 9312ee28..812ecde5 100644 --- a/src/core.js +++ b/src/core.js @@ -88,7 +88,7 @@ jQuery.fn = jQuery.prototype = { if ( selector === "body" && !context && document.body ) { this.context = document; this[0] = document.body; - this.selector = "body"; + this.selector = selector; this.length = 1; return this; } diff --git a/src/traversing.js b/src/traversing.js index fe2e33d8..fa6aae2f 100644 --- a/src/traversing.js +++ b/src/traversing.js @@ -17,17 +17,30 @@ var runtil = /Until$/, jQuery.fn.extend({ find: function( selector ) { - var ret = this.pushStack( "", "find", selector ), - length = 0; + var self = this, + ret, i, l; - for ( var i = 0, l = this.length; i < l; i++ ) { + if ( typeof selector !== "string" ) { + return jQuery( selector ).filter(function() { + for ( i = 0, l = self.length; i < l; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + }); + } + + ret = this.pushStack( "", "find", selector ); + + var length, n, r; + for ( 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++ ) { + for ( n = length; n < ret.length; n++ ) { + for ( r = 0; r < length; r++ ) { if ( ret[r] === ret[n] ) { ret.splice(n--, 1); break; diff --git a/test/unit/traversing.js b/test/unit/traversing.js index 9216bb5e..76b93d84 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -14,12 +14,27 @@ test("find(String)", function() { }); test("find(node|jQuery object)", function() { - expect( 2 ); + expect( 11 ); + + var $foo = jQuery('#foo'), + $blog = jQuery('.blogTest'), + $first = jQuery('#first'), + $two = $blog.add( $first ), + $fooTwo = $foo.add( $blog ); + + equals( $foo.find( $blog ).text(), 'Yahoo', 'Find with blog jQuery object' ); + equals( $foo.find( $blog[0] ).text(), 'Yahoo', 'Find with blog node' ); + equals( $foo.find( $first ).length, 0, '#first is not in #foo' ); + equals( $foo.find( $first[0]).length, 0, '#first not in #foo (node)' ); + ok( $foo.find( $two ).is('.blogTest'), 'Find returns only nodes within #foo' ); + ok( $fooTwo.find( $blog ).is('.blogTest'), 'Blog is part of the collection, but also within foo' ); + ok( $fooTwo.find( $blog[0] ).is('.blogTest'), 'Blog is part of the collection, but also within foo(node)' ); + + equals( $two.find( $foo ).length, 0, 'Foo is not in two elements' ); + equals( $two.find( $foo[0] ).length, 0, 'Foo is not in two elements(node)' ); + equals( $two.find( $first ).length, 0, 'first is in the collection and not within two' ); + equals( $two.find( $first ).length, 0, 'first is in the collection and not within two(node)' ); - var $blog = jQuery('.blogTest'), - blog = $blog[0]; - equals( jQuery('#foo').find( $blog ).text(), 'Yahoo', 'Find with blog jQuery object' ); - equals( jQuery('#foo').find( blog ).text(), 'Yahoo', 'Find with blog node' ); }); test("is(String)", function() { From 929792834f77e075e4b5397fb4b25b1a2dcbd49a Mon Sep 17 00:00:00 2001 From: timmywil Date: Wed, 16 Mar 2011 14:41:26 -0400 Subject: [PATCH 029/372] Organizing vars --- src/traversing.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/traversing.js b/src/traversing.js index fa6aae2f..30d60435 100644 --- a/src/traversing.js +++ b/src/traversing.js @@ -18,7 +18,7 @@ var runtil = /Until$/, jQuery.fn.extend({ find: function( selector ) { var self = this, - ret, i, l; + i, l; if ( typeof selector !== "string" ) { return jQuery( selector ).filter(function() { @@ -30,9 +30,8 @@ jQuery.fn.extend({ }); } - ret = this.pushStack( "", "find", selector ); - - var length, n, r; + var ret = this.pushStack( "", "find", selector ), + length, n, r; for ( i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); From 2407690ef9b3ec59920917935dc1a312f6c2b56e Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Mon, 21 Mar 2011 08:10:27 -0700 Subject: [PATCH 030/372] Fixes 2616; Pull in #252 by jboesch: jQuery.map with object support --- test/qunit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/qunit b/test/qunit index d404faf8..cc8460c7 160000 --- a/test/qunit +++ b/test/qunit @@ -1 +1 @@ -Subproject commit d404faf8f587fcbe6b8907943022e6318dd51e0c +Subproject commit cc8460c7b44f023c4f84ab1810b72bf6c6ee4542 From e38f074d14fd65b3f8b0e1bd7956cd75b3dafe2b Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Mon, 21 Mar 2011 08:39:53 -0700 Subject: [PATCH 031/372] jQuery.map to conform with style guidelines - improved size/DRY code --- src/core.js | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/core.js b/src/core.js index 1077d38c..a0dd7b5b 100644 --- a/src/core.js +++ b/src/core.js @@ -706,29 +706,31 @@ jQuery.extend({ // arg is for internal usage only map: function( elems, callback, arg ) { - var ret = [], - value, + var ret = [], value, i = 0, length = elems.length, // same object detection used in jQuery.each, not full-proof but very speedy. isObj = length === undefined; - - if ( isObj ) { - for ( key in elems ) { - value = callback( elems[ key ], key, arg ); - + + // the work for the loops - run elems[x] through callback + inLoop = function( key ) { + value = callback( elems[ key ], key, arg ); + if ( value != null ) { ret[ ret.length ] = value; } } - } else { - // Go through the array, translating each of the items to their - // new value (or values). - for ( var i = 0; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - if ( value != null ) { - ret[ ret.length ] = value; - } + // Go thorugh every key on the object + if ( isObj ) { + for ( key in elems ) { + inLoop( key ); + } + + // Go through the array, translating each of the items to their + // new value (or values). + } else { + for ( ; i < length; i++ ) { + inLoop( i ); } } From d832f4f71ec51e67d4cae2557221ef582818f607 Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Mon, 21 Mar 2011 12:12:31 -0700 Subject: [PATCH 032/372] jQuery.map to iterate over objects with a .length property --- src/core.js | 40 ++++++++++++++++++++-------------------- test/unit/core.js | 12 +++++++----- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/core.js b/src/core.js index a0dd7b5b..951f1b55 100644 --- a/src/core.js +++ b/src/core.js @@ -704,33 +704,33 @@ jQuery.extend({ return ret; }, - // arg is for internal usage only + // arg is for internal usage only map: function( elems, callback, arg ) { - var ret = [], value, i = 0, - length = elems.length, - // same object detection used in jQuery.each, not full-proof but very speedy. - isObj = length === undefined; - - // the work for the loops - run elems[x] through callback - inLoop = function( key ) { - value = callback( elems[ key ], key, arg ); - + var value, ret = [], + i = 0, + length = elems.length, + // process .length if it's just an object member + isArray = length !== undefined && ( elems[ length - 1 ] || jQuery.isArray( elems ) ); + + // Go through the array, translating each of the items to their + // new value (or values). + if ( isArray ) { + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + if ( value != null ) { ret[ ret.length ] = value; } } - // Go thorugh every key on the object - if ( isObj ) { + // Go thorugh every key on the object, + } else { for ( key in elems ) { - inLoop( key ); - } - - // Go through the array, translating each of the items to their - // new value (or values). - } else { - for ( ; i < length; i++ ) { - inLoop( i ); + value = callback( elems[ key ], key, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } } } diff --git a/test/unit/core.js b/test/unit/core.js index c1ffe10b..08d80400 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -608,7 +608,7 @@ test("first()/last()", function() { }); test("map()", function() { - expect(6); + expect(7); same( jQuery("#ap").map(function(){ @@ -630,26 +630,28 @@ test("map()", function() { var keys = jQuery.map( {a:1,b:2}, function( v, k ){ return k; }); - equals( keys.join(""), "ab", "Map the keys from a hash to an array" ); var values = jQuery.map( {a:1,b:2}, function( v, k ){ return v; }); - equals( values.join(""), "12", "Map the values from a hash to an array" ); + + // object with length prop + var values = jQuery.map( {a:1,b:2, length:3}, function( v, k ){ + return v; + }); + equals( values.join(""), "123", "Map the values from a hash with a length property to an array" ); var scripts = document.getElementsByTagName("script"); var mapped = jQuery.map( scripts, function( v, k ){ return v; }); - equals( mapped.length, scripts.length, "Map an array(-like) to a hash" ); var flat = jQuery.map( Array(4), function( v, k ){ return k % 2 ? k : [k,k,k];//try mixing array and regular returns }); - equals( flat.join(""), "00012223", "try the new flatten technique(#2616)" ); }); From 00dd6013b6b53455ef7b788801a5dc0616651580 Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Mon, 21 Mar 2011 12:24:53 -0700 Subject: [PATCH 033/372] Clean up tab spacing --- src/core.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core.js b/src/core.js index 951f1b55..49c191b9 100644 --- a/src/core.js +++ b/src/core.js @@ -707,10 +707,10 @@ jQuery.extend({ // arg is for internal usage only map: function( elems, callback, arg ) { var value, ret = [], - i = 0, - length = elems.length, - // process .length if it's just an object member - isArray = length !== undefined && ( elems[ length - 1 ] || jQuery.isArray( elems ) ); + i = 0, + length = elems.length, + // process .length if it's just an object member + isArray = length !== undefined && ( elems[ length - 1 ] || jQuery.isArray( elems ) ); // Go through the array, translating each of the items to their // new value (or values). From e09d8898d8a8df27bb72ebc64a4cd08c11f21ddd Mon Sep 17 00:00:00 2001 From: timmywil Date: Mon, 21 Mar 2011 20:59:20 -0400 Subject: [PATCH 034/372] Add node and jQuery object support to $.fn.closest --- src/traversing.js | 20 ++++++++++++-------- test/unit/traversing.js | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/traversing.js b/src/traversing.js index 30d60435..49197c1f 100644 --- a/src/traversing.js +++ b/src/traversing.js @@ -32,6 +32,7 @@ jQuery.fn.extend({ var ret = this.pushStack( "", "find", selector ), length, n, r; + for ( i = 0, l = this.length; i < l; i++ ) { length = ret.length; jQuery.find( selector, this[i], ret ); @@ -77,7 +78,8 @@ jQuery.fn.extend({ closest: function( selectors, context ) { var ret = [], i, l, cur = this[0]; - + + // Array if ( jQuery.isArray( selectors ) ) { var match, selector, matches = {}, @@ -87,8 +89,8 @@ jQuery.fn.extend({ for ( i = 0, l = selectors.length; i < l; i++ ) { selector = selectors[i]; - if ( !matches[selector] ) { - matches[selector] = jQuery.expr.match.POS.test( selector ) ? + if ( !matches[ selector ] ) { + matches[ selector ] = POS.test( selector ) ? jQuery( selector, context || this.context ) : selector; } @@ -96,9 +98,9 @@ jQuery.fn.extend({ while ( cur && cur.ownerDocument && cur !== context ) { for ( selector in matches ) { - match = matches[selector]; + match = matches[ selector ]; - if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + if ( match.jquery ? match.index( cur ) > -1 : jQuery( cur ).is( match ) ) { ret.push({ selector: selector, elem: cur, level: level }); } } @@ -110,9 +112,11 @@ jQuery.fn.extend({ return ret; } - - var pos = POS.test( selectors ) ? - jQuery( selectors, context || this.context ) : null; + + // String + var pos = POS.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; for ( i = 0, l = this.length; i < l; i++ ) { cur = this[i]; diff --git a/test/unit/traversing.js b/test/unit/traversing.js index 76b93d84..bd05f470 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -182,6 +182,20 @@ test("closest(Array)", function() { same( jQuery("body").closest(["span","html"]), [{selector:"html", elem:document.documentElement, level:2}], "closest([body, html])" ); }); +test("closest(jQuery)", function() { + expect(7); + var $child = jQuery("#nothiddendivchild"), + $parent = jQuery("#nothiddendiv"), + $main = jQuery("#main"); + ok( $child.closest( $parent ).is('#nothiddendiv'), "closest( jQuery('#nothiddendiv') )" ); + ok( $child.closest( $parent[0] ).is('#nothiddendiv'), "closest( jQuery('#nothiddendiv') ) :: node" ); + ok( $child.closest( $child ).is('#nothiddendivchild'), "child is included" ); + ok( $child.closest( $child[0] ).is('#nothiddendivchild'), "child is included :: node" ); + equals( $child.closest( document.createElement('div') ).length, 0, "created element is not related" ); + equals( $child.closest( $main ).length, 0, "Main not a parent of child" ); + equals( $child.closest( $main[0] ).length, 0, "Main not a parent of child :: node" ); +}); + test("not(Selector)", function() { expect(7); equals( jQuery("#main > p#ap > a").not("#google").length, 2, "not('selector')" ); From 50e8837207bbfb251af33280b8ef333f16c18e72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carl=20F=C3=BCrstenberg?= Date: Tue, 22 Mar 2011 23:18:15 +0100 Subject: [PATCH 035/372] Makefile: pull_submodules cleaning Empirical testing confirms that pulling the url again is enough --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2c7bb808..b9fa6188 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,7 @@ update_submodules: # update the submodules to the latest at the most logical branch pull_submodules: - @@git submodule foreach "git pull origin \$$(git branch --no-color --contains \$$(git rev-parse HEAD) | grep -v \( | head -1)" + @@git submodule foreach "git pull \$$(git config remote.origin.url)" @@git submodule summary pull: pull_submodules From b8013581ced78fb6c2005e76b44211e01fc2e466 Mon Sep 17 00:00:00 2001 From: timmywil Date: Wed, 23 Mar 2011 15:56:05 -0400 Subject: [PATCH 036/372] Closest unit tests: add one for passing a jQuery collection with multiple elements --- test/unit/traversing.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/unit/traversing.js b/test/unit/traversing.js index bd05f470..adca5f40 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -183,10 +183,11 @@ test("closest(Array)", function() { }); test("closest(jQuery)", function() { - expect(7); + expect(8); var $child = jQuery("#nothiddendivchild"), $parent = jQuery("#nothiddendiv"), - $main = jQuery("#main"); + $main = jQuery("#main"), + $body = jQuery("body"); ok( $child.closest( $parent ).is('#nothiddendiv'), "closest( jQuery('#nothiddendiv') )" ); ok( $child.closest( $parent[0] ).is('#nothiddendiv'), "closest( jQuery('#nothiddendiv') ) :: node" ); ok( $child.closest( $child ).is('#nothiddendivchild'), "child is included" ); @@ -194,6 +195,7 @@ test("closest(jQuery)", function() { equals( $child.closest( document.createElement('div') ).length, 0, "created element is not related" ); equals( $child.closest( $main ).length, 0, "Main not a parent of child" ); equals( $child.closest( $main[0] ).length, 0, "Main not a parent of child :: node" ); + ok( $child.closest( $body.add($parent) ).is('#nothiddendiv'), "Closest ancestor retrieved." ); }); test("not(Selector)", function() { From 85232c97bf1f129b2bc246cf674dc3d5582aaecb Mon Sep 17 00:00:00 2001 From: timmywil Date: Wed, 23 Mar 2011 16:04:12 -0400 Subject: [PATCH 037/372] Traversing unit tests: added tests for passing invalid arguments to $.fn.not (should have no effect on existing object rather than return an empty object as filter does) --- test/unit/traversing.js | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/test/unit/traversing.js b/test/unit/traversing.js index 9eb0d78b..7d15f4c1 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -47,8 +47,8 @@ test("is(String|undefined)", function() { ok( jQuery('#en').is('[lang="de"] , [lang="en"]'), 'Comma-seperated; Check for lang attribute: Expect en or de' ); }); -test("is(Object)", function() { - expect(18); +test("is(jQuery)", function() { + expect(24); ok( jQuery('#form').is( jQuery('form') ), 'Check for element: A form is a form' ); ok( !jQuery('#form').is( jQuery('div') ), 'Check for element: A form is not a div' ); ok( jQuery('#mark').is( jQuery('.blog') ), 'Check for class: Expected class "blog"' ); @@ -67,27 +67,14 @@ test("is(Object)", function() { ok( !jQuery('#foo').is( jQuery(':has(ul)') ), 'Check for child: Did not expect "ul" element' ); ok( jQuery('#foo').is( jQuery(':has(p):has(a):has(code)') ), 'Check for childs: Expected "p", "a" and "code" child elements' ); ok( !jQuery('#foo').is( jQuery(':has(p):has(a):has(code):has(ol)') ), 'Check for childs: Expected "p", "a" and "code" child elements, but no "ol"' ); -}); - -test("is(node Object)", function() { - expect(17); + + // Some raw elements ok( jQuery('#form').is( jQuery('form')[0] ), 'Check for element: A form is a form' ); ok( !jQuery('#form').is( jQuery('div')[0] ), 'Check for element: A form is not a div' ); ok( jQuery('#mark').is( jQuery('.blog')[0] ), 'Check for class: Expected class "blog"' ); ok( !jQuery('#mark').is( jQuery('.link')[0] ), 'Check for class: Did not expect class "link"' ); ok( jQuery('#simon').is( jQuery('.blog.link')[0] ), 'Check for multiple classes: Expected classes "blog" and "link"' ); ok( !jQuery('#simon').is( jQuery('.blogTest')[0] ), 'Check for multiple classes: Expected classes "blog" and "link", but not "blogTest"' ); - ok( jQuery('#en').is( jQuery('[lang="en"]')[1] ), 'Check for attribute: Expected attribute lang to be "en"' ); - ok( !jQuery('#en').is( jQuery('[lang="de"]')[0] ), 'Check for attribute: Expected attribute lang to be "en", not "de"' ); - ok( jQuery('#text1').is( jQuery('[type="text"]')[0] ), 'Check for attribute: Expected attribute type to be "text"' ); - ok( !jQuery('#text1').is( jQuery('[type="radio"]')[0] ), 'Check for attribute: Expected attribute type to be "text", not "radio"' ); - ok( jQuery('#text2').is( jQuery(':disabled')[0] ), 'Check for pseudoclass: Expected to be disabled' ); - ok( !jQuery('#text1').is( jQuery(':disabled')[0] ), 'Check for pseudoclass: Expected not disabled' ); - ok( !jQuery('#radio1').is( jQuery(':checked')[0] ), 'Check for pseudoclass: Expected not checked' ); - ok( jQuery('#foo').is( jQuery(':has(p)')[4] ), 'Check for child: Expected a child "p" element' ); - ok( !jQuery('#foo').is( jQuery(':has(ul)')[0] ), 'Check for child: Did not expect "ul" element' ); - ok( jQuery('#foo').is( jQuery(':has(p):has(a):has(code)')[4] ), 'Check for childs: Expected "p", "a" and "code" child elements' ); - ok( !jQuery('#foo').is( jQuery(':has(p):has(a):has(code):has(ol)')[0] ), 'Check for childs: Expected "p", "a" and "code" child elements, but no "ol"' ); }); test("index()", function() { @@ -208,8 +195,8 @@ test("closest(Array)", function() { same( jQuery("body").closest(["span","html"]), [{selector:"html", elem:document.documentElement, level:2}], "closest([body, html])" ); }); -test("not(Selector)", function() { - expect(7); +test("not(Selector|undefined)", function() { + expect(11); equals( jQuery("#main > p#ap > a").not("#google").length, 2, "not('selector')" ); same( jQuery("p").not(".result").get(), q("firstp", "ap", "sndp", "en", "sap", "first"), "not('.class')" ); same( jQuery("p").not("#ap, #sndp, .result").get(), q("firstp", "en", "sap", "first"), "not('selector, selector')" ); @@ -218,6 +205,12 @@ test("not(Selector)", function() { same( jQuery('#ap *').not('code').get(), q("google", "groups", "anchor1", "mark"), "not('tag selector')" ); same( jQuery('#ap *').not('code, #mark').get(), q("google", "groups", "anchor1"), "not('tag, ID selector')" ); same( jQuery('#ap *').not('#mark, code').get(), q("google", "groups", "anchor1"), "not('ID, tag selector')"); + + var all = jQuery('p').get(); + same( jQuery('p').not(null).get(), all, "not(null) should have no effect"); + same( jQuery('p').not(undefined).get(), all, "not(undefined) should have no effect"); + same( jQuery('p').not(0).get(), all, "not(0) should have no effect"); + same( jQuery('p').not('').get(), all, "not('') should have no effect"); }); test("not(Element)", function() { From e6da0fa6a96c9b4314303e251fd6efac98813ab8 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 23:46:29 -0400 Subject: [PATCH 038/372] Bug #7369: Add test for disconnected node in closest when passing attribute selector; this was recently fixed in 1.5.2rc --- test/unit/traversing.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit/traversing.js b/test/unit/traversing.js index adca5f40..f5cd8aac 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -148,7 +148,7 @@ test("filter(jQuery)", function() { }) test("closest()", function() { - expect(11); + expect(12); same( jQuery("body").closest("body").get(), q("body"), "closest(body)" ); same( jQuery("body").closest("html").get(), q("html"), "closest(html)" ); same( jQuery("body").closest("div").get(), [], "closest(div)" ); @@ -168,6 +168,8 @@ test("closest()", function() { // Test on disconnected node equals( jQuery("

").find("p").closest("table").length, 0, "Make sure disconnected closest work." ); + // Bug #7369 + equals( jQuery('
').closest('[foo]').length, 1, "Disconnected nodes with attribute selector" ); }); test("closest(Array)", function() { From e93ca40aa7ec4337a57fcdbc699d900e01b4c67e Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 23:52:36 -0400 Subject: [PATCH 039/372] Bug #7369: Check non-existent attribute as well to be sure --- test/unit/traversing.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/traversing.js b/test/unit/traversing.js index f5cd8aac..43a9f22a 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -148,7 +148,7 @@ test("filter(jQuery)", function() { }) test("closest()", function() { - expect(12); + expect(13); same( jQuery("body").closest("body").get(), q("body"), "closest(body)" ); same( jQuery("body").closest("html").get(), q("html"), "closest(html)" ); same( jQuery("body").closest("div").get(), [], "closest(div)" ); @@ -170,6 +170,7 @@ test("closest()", function() { equals( jQuery("

").find("p").closest("table").length, 0, "Make sure disconnected closest work." ); // Bug #7369 equals( jQuery('
').closest('[foo]').length, 1, "Disconnected nodes with attribute selector" ); + equals( jQuery('
').closest('[lang]').length, 0, "Disconnected nodes with non-existent attribute selector" ); }); test("closest(Array)", function() { From 3296116041ea0eb89e123c24cf092e34ccb3f380 Mon Sep 17 00:00:00 2001 From: Jordan Boesch Date: Wed, 30 Mar 2011 11:17:48 -0600 Subject: [PATCH 040/372] Bug 4366; fixing $.each(document.styleSheets) from throwing errors in IE --- src/core.js | 7 +++++-- test/unit/core.js | 9 ++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/core.js b/src/core.js index 9312ee28..1b06913c 100644 --- a/src/core.js +++ b/src/core.js @@ -610,8 +610,11 @@ jQuery.extend({ } } } else { - for ( var value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + for ( ; i < length; ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + break; + } + } } } diff --git a/test/unit/core.js b/test/unit/core.js index 6ee8724d..39b7d275 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -784,7 +784,7 @@ test("jQuery.extend(Object, Object)", function() { }); test("jQuery.each(Object,Function)", function() { - expect(13); + expect(14); jQuery.each( [0,1,2], function(i, n){ equals( i, n, "Check array iteration" ); }); @@ -816,6 +816,13 @@ test("jQuery.each(Object,Function)", function() { f[i] = 'baz'; }); equals( "baz", f.foo, "Loop over a function" ); + + var stylesheet_count = 0; + jQuery.each(document.styleSheets, function(i){ + stylesheet_count++; + }); + equals(stylesheet_count, 2, "should not throw an error in IE while looping over document.styleSheets and return proper amount"); + }); test("jQuery.makeArray", function(){ From 926884bf1f071b6dd92f0611d905b2cbffa16a19 Mon Sep 17 00:00:00 2001 From: Jordan Boesch Date: Wed, 30 Mar 2011 11:26:20 -0600 Subject: [PATCH 041/372] Bug 4366; removing extra space --- src/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core.js b/src/core.js index 1b06913c..7cf99372 100644 --- a/src/core.js +++ b/src/core.js @@ -611,7 +611,7 @@ jQuery.extend({ } } else { for ( ; i < length; ) { - if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { + if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) { break; } } From 1a167767305202797cf4c839eb64bd7adfb00182 Mon Sep 17 00:00:00 2001 From: timmywil Date: Wed, 30 Mar 2011 23:23:38 -0400 Subject: [PATCH 042/372] Remove test for bug #7369 to move the fix to a separate branch for a sooner pull --- src/traversing.js | 4 ++-- test/unit/traversing.js | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/traversing.js b/src/traversing.js index 49197c1f..91bc017e 100644 --- a/src/traversing.js +++ b/src/traversing.js @@ -112,7 +112,7 @@ jQuery.fn.extend({ return ret; } - + // String var pos = POS.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : @@ -135,7 +135,7 @@ jQuery.fn.extend({ } } - ret = ret.length > 1 ? jQuery.unique(ret) : ret; + ret = ret.length > 1 ? jQuery.unique( ret ) : ret; return this.pushStack( ret, "closest", selectors ); }, diff --git a/test/unit/traversing.js b/test/unit/traversing.js index 43a9f22a..117e4600 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -168,9 +168,6 @@ test("closest()", function() { // Test on disconnected node equals( jQuery("

").find("p").closest("table").length, 0, "Make sure disconnected closest work." ); - // Bug #7369 - equals( jQuery('
').closest('[foo]').length, 1, "Disconnected nodes with attribute selector" ); - equals( jQuery('
').closest('[lang]').length, 0, "Disconnected nodes with non-existent attribute selector" ); }); test("closest(Array)", function() { From a807451a23577ad04140a32f7888e6c7b26a8838 Mon Sep 17 00:00:00 2001 From: timmywil Date: Wed, 30 Mar 2011 23:39:19 -0400 Subject: [PATCH 043/372] Fixes #7369 - Using an attribute selector for a non-existent attribute raised an exception on disconnected nodes --- src/traversing.js | 2 +- test/unit/traversing.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/traversing.js b/src/traversing.js index fe2e33d8..468aa097 100644 --- a/src/traversing.js +++ b/src/traversing.js @@ -112,7 +112,7 @@ jQuery.fn.extend({ } else { cur = cur.parentNode; - if ( !cur || !cur.ownerDocument || cur === context ) { + if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) { break; } } diff --git a/test/unit/traversing.js b/test/unit/traversing.js index f5108bde..4cccd650 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -124,7 +124,7 @@ test("filter(jQuery)", function() { }) test("closest()", function() { - expect(11); + expect(13); same( jQuery("body").closest("body").get(), q("body"), "closest(body)" ); same( jQuery("body").closest("html").get(), q("html"), "closest(html)" ); same( jQuery("body").closest("div").get(), [], "closest(div)" ); @@ -144,6 +144,10 @@ test("closest()", function() { // Test on disconnected node equals( jQuery("

").find("p").closest("table").length, 0, "Make sure disconnected closest work." ); + + // Bug #7369 + equals( jQuery('
').closest('[foo]').length, 1, "Disconnected nodes with attribute selector" ); + equals( jQuery('
text
').closest('[lang]').length, 0, "Disconnected nodes with text and non-existent attribute selector" ); }); test("closest(Array)", function() { From 368bfc0fe0628e10ebf9873b123253c2a8dbf844 Mon Sep 17 00:00:00 2001 From: Ben Alman Date: Thu, 31 Mar 2011 11:37:48 -0400 Subject: [PATCH 044/372] DOM Ready unit tests (but not the supporting fixed code). --- test/unit/event.js | 95 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 14 deletions(-) diff --git a/test/unit/event.js b/test/unit/event.js index 2a6d8a66..00fad6e5 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -685,7 +685,7 @@ test("hover()", function() { test("mouseover triggers mouseenter", function() { expect(1); - + var count = 0, elem = jQuery(""); elem.mouseenter(function () { @@ -693,7 +693,7 @@ test("mouseover triggers mouseenter", function() { }); elem.trigger('mouseover'); equals(count, 1, "make sure mouseover triggers a mouseenter" ); - + elem.remove(); }); @@ -1982,8 +1982,8 @@ test("window resize", function() { test("focusin bubbles", function() { expect(5); - - var input = jQuery( '' ).prependTo( "body" ), + + var input = jQuery( '' ).prependTo( "body" ), order = 0; jQuery( "body" ).bind( "focusin.focusinBubblesTest", function(){ @@ -1996,12 +1996,12 @@ test("focusin bubbles", function() { // DOM focus method input[0].focus(); - + // To make the next focus test work, we need to take focus off the input. // This will fire another focusin event, so set order to reflect that. order = 1; jQuery("#text1")[0].focus(); - + // jQuery trigger, which calls DOM focus order = 0; input.trigger( "focus" ); @@ -2010,15 +2010,82 @@ test("focusin bubbles", function() { jQuery( "body" ).unbind( "focusin.focusinBubblesTest" ); }); -/* -test("jQuery(function($) {})", function() { - stop(); - jQuery(function($) { - equals(jQuery, $, "ready doesn't provide an event object, instead it provides a reference to the jQuery function, see http://docs.jquery.com/Events/ready#fn"); - start(); - }); -}); +(function(){ + // This code must be run before DOM ready! + var notYetReady, noEarlyExecution, + order = [], + args = {}; + + notYetReady = !jQuery.isReady; + + test("jQuery.isReady", function() { + expect(2); + + equals(notYetReady, true, "jQuery.isReady should not be true before DOM ready"); + equals(jQuery.isReady, true, "jQuery.isReady should be true once DOM is ready"); + }); + + // Create an event handler. + function makeHandler( testId ) { + // When returned function is executed, push testId onto `order` array + // to ensure execution order. Also, store event handler arg to ensure + // the correct arg is being passed into the event handler. + return function( arg ) { + order.push(testId); + args[testId] = arg; + }; + } + + // Bind to the ready event in every possible way. + jQuery(makeHandler("a")); + jQuery(document).ready(makeHandler("b")); + jQuery(document).bind("ready.readytest", makeHandler("c")); + + // Do it twice, just to be sure. + jQuery(makeHandler("d")); + jQuery(document).ready(makeHandler("e")); + jQuery(document).bind("ready.readytest", makeHandler("f")); + + noEarlyExecution = order.length == 0; + + // This assumes that QUnit tests are run on DOM ready! + test("jQuery ready", function() { + expect(11); + + ok(noEarlyExecution, "Handlers bound to DOM ready should not execute before DOM ready"); + + // Ensure execution order. + same(order, ["a", "b", "c", "d", "e", "f"], "All bound DOM ready handlers should have executed in bind-order"); + + // Ensure handler argument is correct. + equals(args.a, jQuery, "Argument passed to fn in jQuery( fn ) should be jQuery"); + equals(args.b, jQuery, "Argument passed to fn in jQuery(document).ready( fn ) should be jQuery"); + ok(args.c instanceof jQuery.Event, "Argument passed to fn in jQuery(document).bind( 'ready', fn ) should be an event object"); + + order = []; + + // Now that the ready event has fired, again bind to the ready event + // in every possible way. These event handlers should execute immediately. + jQuery(makeHandler("g")); + equals(order.pop(), "g", "Event handler should execute immediately"); + equals(args.g, jQuery, "Argument passed to fn in jQuery( fn ) should be jQuery"); + + jQuery(document).ready(makeHandler("h")); + equals(order.pop(), "h", "Event handler should execute immediately"); + equals(args.h, jQuery, "Argument passed to fn in jQuery(document).ready( fn ) should be jQuery"); + + jQuery(document).bind("ready.readytest", makeHandler("i")); + equals(order.pop(), "i", "Event handler should execute immediately"); + ok(args.i instanceof jQuery.Event, "Argument passed to fn in jQuery(document).bind( 'ready', fn ) should be an event object"); + + // Cleanup. + jQuery(document).unbind("ready.readytest"); + }); + +})(); + +/* test("event properties", function() { stop(); jQuery("#simon1").click(function(event) { From de0c25bef485bab8c2d1e642947311596a9b5e87 Mon Sep 17 00:00:00 2001 From: Ben Alman Date: Thu, 31 Mar 2011 13:36:16 -0400 Subject: [PATCH 045/372] Updated DOM ready unit tests. --- test/unit/event.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/unit/event.js b/test/unit/event.js index 00fad6e5..0acab543 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -2051,12 +2051,12 @@ test("focusin bubbles", function() { // This assumes that QUnit tests are run on DOM ready! test("jQuery ready", function() { - expect(11); + expect(10); ok(noEarlyExecution, "Handlers bound to DOM ready should not execute before DOM ready"); // Ensure execution order. - same(order, ["a", "b", "c", "d", "e", "f"], "All bound DOM ready handlers should have executed in bind-order"); + same(order, ["a", "b", "d", "e", "c", "f"], "Bound DOM ready handlers should execute in bind-order, but those bound with jQuery(document).bind( 'ready', fn ) will always execute last"); // Ensure handler argument is correct. equals(args.a, jQuery, "Argument passed to fn in jQuery( fn ) should be jQuery"); @@ -2075,9 +2075,8 @@ test("focusin bubbles", function() { equals(order.pop(), "h", "Event handler should execute immediately"); equals(args.h, jQuery, "Argument passed to fn in jQuery(document).ready( fn ) should be jQuery"); - jQuery(document).bind("ready.readytest", makeHandler("i")); - equals(order.pop(), "i", "Event handler should execute immediately"); - ok(args.i instanceof jQuery.Event, "Argument passed to fn in jQuery(document).bind( 'ready', fn ) should be an event object"); + jQuery(document).bind("ready.readytest", makeHandler("never")); + equals(order.length, 0, "Event handler should never execute since DOM ready has already passed"); // Cleanup. jQuery(document).unbind("ready.readytest"); From fcc112f4062cd58113b28bd6eca4ab2eb80ac11d Mon Sep 17 00:00:00 2001 From: John Resig Date: Thu, 31 Mar 2011 15:28:33 -0400 Subject: [PATCH 046/372] Updating the source version to 1.6pre. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index a73b4325..0a0196e2 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.5.2 \ No newline at end of file +1.6pre \ No newline at end of file From 64a0005a3b5a168a421efa1d8b253de234620229 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sat, 2 Apr 2011 17:05:04 -0400 Subject: [PATCH 047/372] A more modest valHooks proposal - The main difference is that this does not allow arbitrarily adding hooks to any collection of elements. - Modularizes val into a set of easily maintainable and conditional hooks. - valHooks is placed at jQuery.valHooks + This could technically be extended, but I do not see it being used except in very rare cases since you can only apply valHooks to nodeNames and input types, and not a collection of elements as before. We could theoretically privatize valHooks taking it off of jQuery and only use it internally for our own convenience, but again, I do not believe this patch carries with it the dangers of the first proposal. - Slightly improved performance of val on radios and checkboxes for browsers that support checkOn, given the conditional attachment of its hook. --- src/attributes.js | 178 +++++++++++++++++++++++++++------------------- 1 file changed, 103 insertions(+), 75 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 59972105..4c59a675 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -154,82 +154,35 @@ jQuery.fn.extend({ }, val: function( value ) { + var hooks, val, + elem = this[0]; + if ( !arguments.length ) { - var elem = this[0]; - if ( elem ) { - if ( jQuery.nodeName( elem, "option" ) ) { - // 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; + hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; + + if ( hooks && "get" in hooks && (val = hooks.get( elem )) !== undefined ) { + return val; } - // 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 ]; - - // Don't return options that are disabled or in a disabled optgroup - if ( option.selected && (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 ); - } - } - - // Fixes Bug #2551 -- select.val() broken in IE after form.reset() - if ( one && !values.length && options.length ) { - return jQuery( options[ index ] ).val(); - } - - 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); + var isFunction = jQuery.isFunction( value ); - return this.each(function(i) { - var self = jQuery(this), val = value; + return this.each(function( i ) { + var self = jQuery(this); if ( this.nodeType !== 1 ) { return; } + val = value; if ( isFunction ) { - val = value.call(this, i, self.val()); + val = value.call( this, i, self.val() ); } // Treat null/undefined as ""; convert numbers to string @@ -237,27 +190,16 @@ jQuery.fn.extend({ val = ""; } else if ( typeof val === "number" ) { val += ""; - } else if ( jQuery.isArray(val) ) { - val = jQuery.map(val, function (value) { + } else if ( jQuery.isArray( val ) ) { + val = jQuery.map(val, function ( value ) { return value == null ? "" : value + ""; }); } - if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { - this.checked = jQuery.inArray( self.val(), val ) >= 0; + hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; - } 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 { + // If set returns undefined, fall back to normal setting + if ( !hooks || ("set" in hooks && hooks.set( this, val ) === undefined) ) { this.value = val; } }); @@ -265,6 +207,71 @@ jQuery.fn.extend({ }); 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 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 ]; + + // Don't return options that are disabled or in a disabled optgroup + if ( option.selected && (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 ); + } + } + + // Fixes Bug #2551 -- select.val() broken in IE after form.reset() + if ( one && !values.length && options.length ) { + return jQuery( options[ index ] ).val(); + } + + 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; + } + } + }, + attrFn: { val: true, css: true, @@ -386,4 +393,25 @@ jQuery.extend({ } }); +// 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); + } + } + }); +}); + })( jQuery ); From ab4e300919c5b3335e6d6c99ce9b1c314d116f19 Mon Sep 17 00:00:00 2001 From: jeresig Date: Sun, 6 Mar 2011 22:47:40 -0500 Subject: [PATCH 048/372] Very crude first pass at splitting apart the attr/prop logic. Also adding in attrHooks/propHooks. All of it is completely untested. --- src/attributes.js | 274 ++++++++++++++++++++++++++++------------------ 1 file changed, 168 insertions(+), 106 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 59972105..e5425a05 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -3,38 +3,37 @@ var rclass = /[\n\t\r]/g, rspaces = /\s+/, rreturn = /\r/g, - rspecialurl = /^(?:href|src|style)$/, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, rradiocheck = /^(?:radio|checkbox)$/i; -jQuery.props = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" -}; - jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, name, value, true, jQuery.attr ); }, - removeAttr: function( name, fn ) { - return this.each(function(){ - jQuery.attr( this, name, "" ); + removeAttr: function( name ) { + return this.each(function() { if ( this.nodeType === 1 ) { this.removeAttribute( name ); } }); }, + + prop: function( name, value ) { + return jQuery.access( this, name, value, true, jQuery.prop ); + }, + + removeProp: function( 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 ) { if ( jQuery.isFunction(value) ) { @@ -275,6 +274,21 @@ jQuery.extend({ height: true, offset: true }, + + // TODO: Check to see if any of these are needed anymore? + // If not, it may be good to standardize on all-lowercase names instead + attrFix: { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" + }, attr: function( elem, name, value, pass ) { // don't get/set attributes on text, comment and attribute nodes @@ -286,104 +300,152 @@ jQuery.extend({ return jQuery(elem)[name](value); } - var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), - // Whether we are setting (or getting) - set = value !== undefined; - + var ret, + notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + hooks; + // Try to normalize/fix the name - name = notxml && jQuery.props[ name ] || name; + name = notxml && jQuery.attrFix[ name ] || name; + + hooks = jQuery.attrHooks[ name ]; + + if ( value !== undefined ) { + + if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value )) !== undefined ) { + return ret; + + } else { + // convert the value to a string (all browsers do this but IE) see #1070 + value = "" + value; + + elem.setAttribute( name, value ); + + return value; + } + + } else { + + if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem )) !== undefined ) { + return ret; + + } else { + + if ( !jQuery.hasAttr( elem, name ) ) { + return undefined; + } - // 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 ); + var attr = elem.getAttribute( 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; - } + // Non-existent attributes return null, we normalize to undefined + return attr === null ? + undefined : + attr; + } + } + }, + + hasAttr: function( elem, name ) { + // Blackberry 4.7 returns "" from getAttribute #6938 + return elem.attributes[ name ] || (elem.hasAttribute && elem.hasAttribute( name )); + }, + + attrHooks: { + type: { + set: function( elem, value ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); } } + }, + + // 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/ + tabIndex: { + get: function( elem ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); - // If applicable, access the attribute via the DOM 0 way - // 'in' checks fail in Blackberry 4.7 #6931 - if ( (name in elem || elem[ name ] !== undefined) && 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" ); - } - - if ( value === null ) { - if ( elem.nodeType === 1 ) { - elem.removeAttribute( name ); - } - - } else { - 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 attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + } + }, + + // TODO: Check to see if we really need any here. + propFix: {}, + + prop: function( elem, name, value ) { + var ret, hooks; + + // Try to normalize/fix the name + name = notxml && jQuery.propFix[ name ] || name; + + hooks = jQuery.propHooks[ name ]; + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value )) !== undefined ) { + return ret; + + } else { + return (elem[ name ] = value); + } + + } else { + if ( hooks && "get" in hooks && (ret = hooks.get( elem )) !== undefined ) { + return ret; + + } else { 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 ); - } - - // Ensure that missing attributes return undefined - // Blackberry 4.7 returns "" from getAttribute #6938 - if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) { - return undefined; - } - - 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; } - // Handle everything which isn't a DOM element node - if ( set ) { - elem[ name ] = value; - } - return elem[ name ]; - } + }, + + propHooks: {} }); +// Some attributes require a special call on IE +if ( !jQuery.support.hrefNormalized ) { + jQuery.each([ "href", "src", "style" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + return elem.getAttribute( name, 2 ); + } + }); + }); +} + +if ( !jQuery.support.style ) { + jQuery.attrHooks.style = { + get: function( elem ) { + return elem.style.cssText; + }, + + 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.attrHooks.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; + } + } + } + }; +} + })( jQuery ); From de79e8c7e0d1d2243447d59c70a9058eabf56bc3 Mon Sep 17 00:00:00 2001 From: timmywil Date: Tue, 8 Mar 2011 12:07:05 -0500 Subject: [PATCH 049/372] Make the new attr/prop changes pass the test suite (in Webkit). There are still errors in IE. + Added hooks for selected, checked, readonly, disabled to removeAttr if set to falsey + Removed all attrs from attrFix, these aren't needed for setAttribute + If prop is used for class, do we want a propFix for class? - We could just assume the user should know to use className with prop. I've done the latter for now. + Created tests for $.fn.prop and $.fn.removeProp - Actually all I did was change broken attr tests to prop where it made sense. --- src/attributes.js | 48 ++++++----- src/manipulation.js | 2 +- test/unit/attributes.js | 177 ++++++++++++++++++++------------------ test/unit/manipulation.js | 6 +- 4 files changed, 124 insertions(+), 109 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index e5425a05..cb8128d2 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -36,10 +36,10 @@ jQuery.fn.extend({ }, addClass: function( value ) { - if ( jQuery.isFunction(value) ) { + if ( jQuery.isFunction( value ) ) { return this.each(function(i) { var self = jQuery(this); - self.addClass( value.call(this, i, self.attr("class")) ); + self.addClass( value.call(this, i, self.attr("class") || "") ); }); } @@ -278,19 +278,10 @@ jQuery.extend({ // TODO: Check to see if any of these are needed anymore? // If not, it may be good to standardize on all-lowercase names instead attrFix: { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" }, attr: function( elem, name, value, pass ) { + // don't get/set attributes on text, comment and attribute nodes if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { return undefined; @@ -314,6 +305,10 @@ jQuery.extend({ if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value )) !== undefined ) { return ret; + } else if ( value === null ) { + elem.removeAttribute( name ); + return undefined; + } else { // convert the value to a string (all browsers do this but IE) see #1070 value = "" + value; @@ -329,7 +324,7 @@ jQuery.extend({ return ret; } else { - + if ( !jQuery.hasAttr( elem, name ) ) { return undefined; } @@ -337,16 +332,14 @@ jQuery.extend({ var attr = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - return attr === null ? - undefined : - attr; + return attr === null ? undefined : attr; } } }, hasAttr: function( elem, name ) { // Blackberry 4.7 returns "" from getAttribute #6938 - return elem.attributes[ name ] || (elem.hasAttribute && elem.hasAttribute( name )); + return elem && elem.attributes[ name ] || (elem.hasAttribute && elem.hasAttribute( name )); }, attrHooks: { @@ -361,7 +354,7 @@ jQuery.extend({ // 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/ - tabIndex: { + tabindex: { get: function( elem ) { var attributeNode = elem.getAttributeNode( "tabIndex" ); @@ -375,10 +368,11 @@ jQuery.extend({ }, // TODO: Check to see if we really need any here. - propFix: {}, + propFix: { + }, prop: function( elem, name, value ) { - var ret, hooks; + var ret, hooks, notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ); // Try to normalize/fix the name name = notxml && jQuery.propFix[ name ] || name; @@ -406,6 +400,20 @@ jQuery.extend({ propHooks: {} }); +// Remove certain attrs if set to false +jQuery.each([ "selected", "checked", "readonly", "disabled" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + set: function( elem, value ) { + if ( !value ) { // '', undefined, false, null will remove attr + elem.removeAttribute( name ); + return false; + } + elem.setAttribute( name, value ); + return value; + } + }); +}); + // Some attributes require a special call on IE if ( !jQuery.support.hrefNormalized ) { jQuery.each([ "href", "src", "style" ], function( i, name ) { diff --git a/src/manipulation.js b/src/manipulation.js index 27f81cc2..81a55cb8 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -377,7 +377,7 @@ function cloneCopyEvent( src, dest ) { } } -function cloneFixAttributes(src, dest) { +function cloneFixAttributes( src, dest ) { // We do not need to do anything for non-Elements if ( dest.nodeType !== 1 ) { return; diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 8cf47bed..d4284556 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -3,38 +3,64 @@ module("attributes", { teardown: moduleTeardown }); var bareObj = function(value) { return value; }; var functionReturningObj = function(value) { return (function() { return value; }); }; -test("jQuery.props: itegrity test", function() { - - expect(1); - - // This must be maintained and equal jQuery.props - // Ensure that accidental or erroneous property - // overwrites don't occur - // This is simply for better code coverage and future proofing. - var propsShouldBe = { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" - }; - - same(propsShouldBe, jQuery.props, "jQuery.props passes integrity check"); +// test("jQuery.props: integrity test", function() { +// +// expect(1); +// +// // This must be maintained and equal jQuery.props +// // Ensure that accidental or erroneous property +// // overwrites don't occur +// // This is simply for better code coverage and future proofing. +// var propsShouldBe = { +// "for": "htmlFor", +// "class": "className", +// readonly: "readOnly", +// maxlength: "maxLength", +// cellspacing: "cellSpacing", +// rowspan: "rowSpan", +// colspan: "colSpan", +// tabindex: "tabIndex", +// usemap: "useMap", +// frameborder: "frameBorder" +// }; +// +// same(propsShouldBe, jQuery.props, "jQuery.props passes integrity check"); +// +// }); +test("prop", function() { + equals( jQuery('#text1').prop('value'), "Test", 'Check for value attribute' ); + equals( jQuery('#text1').prop('value', "Test2").prop('defaultValue'), "Test", 'Check for defaultValue attribute' ); + equals( jQuery('#select2').prop('selectedIndex'), 3, 'Check for selectedIndex attribute' ); + equals( jQuery('#foo').prop('nodeName').toUpperCase(), 'DIV', 'Check for nodeName attribute' ); + equals( jQuery('#foo').prop('tagName').toUpperCase(), 'DIV', 'Check for tagName attribute' ); + equals( jQuery("').attr({ 'id': 'tAnchor5', 'href': '#5' }).appendTo('#main'); equals( jQuery('#tAnchor5').attr('href'), "#5", 'Check for non-absolute href (an anchor)' ); - equals( jQuery("
").attr("doesntexist") === undefined, "Make sure undefined is returned when no attribute is found." ); ok( jQuery().attr("doesntexist") === undefined, "Make sure undefined is returned when no element is there." ); - equals( jQuery(document).attr("nodeName"), "#document", "attr works correctly on document nodes (bug #7451)." ); - - var attributeNode = document.createAttribute("irrelevant"), - commentNode = document.createComment("some comment"), - textNode = document.createTextNode("some text"), - obj = {}; - jQuery.each( [document, attributeNode, commentNode, textNode, obj, "#firstp"], function( i, ele ) { - strictEqual( jQuery(ele).attr("nonexisting"), undefined, "attr works correctly for non existing attributes (bug #7500)." ); - }); }); if ( !isLocal ) { @@ -133,7 +135,7 @@ test("attr(Hash)", function() { }); test("attr(String, Object)", function() { - expect(30); + expect(24); var div = jQuery("div").attr("foo", "bar"), fail = false; @@ -153,7 +155,7 @@ test("attr(String, Object)", function() { jQuery("#name").attr('name', 'something'); equals( jQuery("#name").attr('name'), 'something', 'Set name attribute' ); jQuery("#name").attr('name', null); - equals( jQuery("#name").attr('title'), '', 'Remove name attribute' ); + equals( jQuery("#name").attr('name'), undefined, 'Remove name attribute' ); jQuery("#check2").attr('checked', true); equals( document.getElementById('check2').checked, true, 'Set checked attribute' ); jQuery("#check2").attr('checked', false); @@ -163,28 +165,28 @@ test("attr(String, Object)", function() { jQuery("#text1").attr('readonly', false); equals( document.getElementById('text1').readOnly, false, 'Set readonly attribute' ); jQuery("#name").attr('maxlength', '5'); - equals( document.getElementById('name').maxLength, '5', 'Set maxlength attribute' ); + equals( document.getElementById('name').maxLength, 5, 'Set maxlength attribute' ); jQuery("#name").attr('maxLength', '10'); - equals( document.getElementById('name').maxLength, '10', 'Set maxlength attribute' ); + equals( document.getElementById('name').maxLength, 10, 'Set maxlength attribute' ); - var attributeNode = document.createAttribute("irrelevant"), - commentNode = document.createComment("some comment"), - textNode = document.createTextNode("some text"), - obj = {}; - jQuery.each( [document, obj, "#firstp"], function( i, ele ) { - var $ele = jQuery( ele ); - $ele.attr( "nonexisting", "foo" ); - equal( $ele.attr("nonexisting"), "foo", "attr(name, value) works correctly for non existing attributes (bug #7500)." ); - }); - jQuery.each( [commentNode, textNode, attributeNode], function( i, ele ) { - var $ele = jQuery( ele ); - $ele.attr( "nonexisting", "foo" ); - strictEqual( $ele.attr("nonexisting"), undefined, "attr(name, value) works correctly on comment and text nodes (bug #7500)." ); - }); - //cleanup - jQuery.each( [document, "#firstp"], function( i, ele ) { - jQuery( ele ).removeAttr("nonexisting"); - }); + // var attributeNode = document.createAttribute("irrelevant"), + // commentNode = document.createComment("some comment"), + // textNode = document.createTextNode("some text"), + // obj = {}; + // jQuery.each( [document, obj, "#firstp"], function( i, ele ) { + // var $ele = jQuery( ele ); + // $ele.attr( "nonexisting", "foo" ); + // equal( $ele.attr("nonexisting"), "foo", "attr(name, value) works correctly for non existing attributes (bug #7500)." ); + // }); + // jQuery.each( [commentNode, textNode, attributeNode], function( i, ele ) { + // var $ele = jQuery( ele ); + // $ele.attr( "nonexisting", "foo" ); + // strictEqual( $ele.attr("nonexisting"), undefined, "attr(name, value) works correctly on comment and text nodes (bug #7500)." ); + // }); + // //cleanup + // jQuery.each( [document, "#firstp"], function( i, ele ) { + // jQuery( ele ).removeAttr("nonexisting"); + // }); var table = jQuery('#table').append("cellcellcellcellcell"), td = table.find('td:first'); @@ -356,25 +358,29 @@ test("attr('tabindex', value)", function() { }); test("removeAttr(String)", function() { - expect(7); + expect(1); equals( jQuery('#mark').removeAttr( "class" )[0].className, "", "remove class" ); +}); + +test("removeProp(String)", function() { + expect(6); var attributeNode = document.createAttribute("irrelevant"), commentNode = document.createComment("some comment"), textNode = document.createTextNode("some text"), obj = {}; - //removeAttr only really removes on DOM element nodes handle all other seperatyl - strictEqual( jQuery( "#firstp" ).attr( "nonexisting", "foo" ).removeAttr( "nonexisting" )[0].nonexisting, undefined, "removeAttr works correctly on DOM element nodes" ); + + strictEqual( jQuery( "#firstp" ).prop( "nonexisting", "foo" ).removeProp( "nonexisting" )[0].nonexisting, undefined, "removeprop works correctly on DOM element nodes" ); jQuery.each( [document, obj], function( i, ele ) { var $ele = jQuery( ele ); - $ele.attr( "nonexisting", "foo" ).removeAttr( "nonexisting" ); - strictEqual( ele.nonexisting, "", "removeAttr works correctly on non DOM element nodes (bug #7500)." ); + $ele.prop( "nonexisting", "foo" ).removeProp( "nonexisting" ); + strictEqual( ele.nonexisting, undefined, "removeProp works correctly on non DOM element nodes (bug #7500)." ); }); jQuery.each( [commentNode, textNode, attributeNode], function( i, ele ) { $ele = jQuery( ele ); - $ele.attr( "nonexisting", "foo" ).removeAttr( "nonexisting" ); - strictEqual( ele.nonexisting, undefined, "removeAttr works correctly on non DOM element nodes (bug #7500)." ); + $ele.prop( "nonexisting", "foo" ).removeProp( "nonexisting" ); + strictEqual( ele.nonexisting, undefined, "removeProp works correctly on non DOM element nodes (bug #7500)." ); }); }); @@ -604,21 +610,20 @@ test("addClass(Function)", function() { test("addClass(Function) with incoming value", function() { expect(45); - var div = jQuery("div"), old = div.map(function(){ - return jQuery(this).attr("class"); + return jQuery(this).attr("class") || ""; }); - + div.addClass(function(i, val) { - if ( this.id !== "_firebugConsole" ) { + if ( this.id !== "_firebugConsole") { equals( val, old[i], "Make sure the incoming value is correct." ); return "test"; } }); var pass = true; - for ( var i = 0; i < div.size(); i++ ) { - if ( div.get(i).className.indexOf("test") == -1 ) pass = false; + for ( var i = 0; i < div.length; i++ ) { + if ( div.get(i).className.indexOf("test") == -1 ) pass = false; } ok( pass, "Add Class" ); }); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index ff3dff16..e972a479 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -1009,7 +1009,7 @@ test("clone()", function() { }); test("clone(form element) (Bug #3879, #6655)", function() { - expect(6); + expect(5); var element = jQuery(""); equals( element.clone().find("option:selected").val(), element.find("option:selected").val(), "Selected option cloned correctly" ); @@ -1019,7 +1019,9 @@ test("clone(form element) (Bug #3879, #6655)", function() { equals( clone.is(":checked"), element.is(":checked"), "Checked input cloned correctly" ); equals( clone[0].defaultValue, "foo", "Checked input defaultValue cloned correctly" ); - equals( clone[0].defaultChecked, !jQuery.support.noCloneChecked, "Checked input defaultChecked cloned correctly" ); + + // defaultChecked also gets set now due to setAttribute in attr, is this check still valid? + // equals( clone[0].defaultChecked, !jQuery.support.noCloneChecked, "Checked input defaultChecked cloned correctly" ); element = jQuery(""); clone = element.clone(); From 5eecb13fa3391870e904548f03d8a509117984f3 Mon Sep 17 00:00:00 2001 From: timmywil Date: Wed, 9 Mar 2011 20:20:53 -0500 Subject: [PATCH 050/372] Now passes in IE8, changed around $.hasAttr and switched the attrHook for selected to be a propHook --- src/attributes.js | 39 ++++++++++++++++++++++++++++----------- test/unit/attributes.js | 34 +++++----------------------------- 2 files changed, 33 insertions(+), 40 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index cb8128d2..8de5cf80 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -278,10 +278,11 @@ jQuery.extend({ // TODO: Check to see if any of these are needed anymore? // If not, it may be good to standardize on all-lowercase names instead attrFix: { + }, attr: function( elem, name, value, pass ) { - + // don't get/set attributes on text, comment and attribute nodes if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { return undefined; @@ -294,9 +295,6 @@ jQuery.extend({ var ret, notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), hooks; - - // Try to normalize/fix the name - name = notxml && jQuery.attrFix[ name ] || name; hooks = jQuery.attrHooks[ name ]; @@ -312,9 +310,7 @@ jQuery.extend({ } else { // convert the value to a string (all browsers do this but IE) see #1070 value = "" + value; - elem.setAttribute( name, value ); - return value; } @@ -332,14 +328,24 @@ jQuery.extend({ var attr = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - return attr === null ? undefined : attr; + return attr === null || attr === "undefined" ? undefined : attr; } } }, hasAttr: function( elem, name ) { - // Blackberry 4.7 returns "" from getAttribute #6938 - return elem && elem.attributes[ name ] || (elem.hasAttribute && elem.hasAttribute( name )); + var inAttrs, attrs = elem.attributes; + + if ( elem.hasAttribute ) { + return elem.hasAttribute( name ); + } else { + // Browsers do not understand the associative indexes, look for the name in elem.attributes.name + for ( var i = 0, l = attrs.length; i < l; i++ ) { + if ( attrs[i]["name"] === name ) { + return true; + } + } + } }, attrHooks: { @@ -369,9 +375,16 @@ jQuery.extend({ // TODO: Check to see if we really need any here. propFix: { + }, prop: function( elem, name, value ) { + + // don't get/set properties on text, comment and attribute nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { + return undefined; + } + var ret, hooks, notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ); // Try to normalize/fix the name @@ -440,13 +453,17 @@ if ( !jQuery.support.style ) { // Safari mis-reports the default selected property of an option // Accessing the parent's selectedIndex property fixes it if ( !jQuery.support.optSelected ) { - jQuery.attrHooks.selected = { + + jQuery.propHooks.selected = { get: function( elem ) { var parent = elem.parentNode; if ( parent ) { parent.selectedIndex; - + + // TODO: We may need an attrHook for selected that simply defers to prop? + // The attr is undefined if the option is created with createElement and not on the DOM + // Make sure that it also works with optgroups, see #5701 if ( parent.parentNode ) { parent.parentNode.selectedIndex; diff --git a/test/unit/attributes.js b/test/unit/attributes.js index d4284556..af423e34 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -3,31 +3,6 @@ module("attributes", { teardown: moduleTeardown }); var bareObj = function(value) { return value; }; var functionReturningObj = function(value) { return (function() { return value; }); }; -// test("jQuery.props: integrity test", function() { -// -// expect(1); -// -// // This must be maintained and equal jQuery.props -// // Ensure that accidental or erroneous property -// // overwrites don't occur -// // This is simply for better code coverage and future proofing. -// var propsShouldBe = { -// "for": "htmlFor", -// "class": "className", -// readonly: "readOnly", -// maxlength: "maxLength", -// cellspacing: "cellSpacing", -// rowspan: "rowSpan", -// colspan: "colSpan", -// tabindex: "tabIndex", -// usemap: "useMap", -// frameborder: "frameBorder" -// }; -// -// same(propsShouldBe, jQuery.props, "jQuery.props passes integrity check"); -// -// }); - test("prop", function() { equals( jQuery('#text1').prop('value'), "Test", 'Check for value attribute' ); equals( jQuery('#text1').prop('value', "Test2").prop('defaultValue'), "Test", 'Check for defaultValue attribute' ); @@ -41,11 +16,12 @@ test("prop", function() { body.foo = 'bar'; equals( $body.prop('foo'), 'bar', 'Make sure the expando is preferred over the dom attribute' ); body.foo = undefined; - ok( $body.attr('foo') === undefined, 'Make sure the expando is preferred over the dom attribute, even if undefined' ); + ok( $body.prop('foo') === undefined, 'Make sure the expando is preferred over the dom attribute, even if undefined' ); var select = document.createElement("select"), optgroup = document.createElement("optgroup"), option = document.createElement("option"); optgroup.appendChild( option ); select.appendChild( optgroup ); + equals( jQuery(option).prop("selected"), true, "Make sure that a single option is selected, even when in an optgroup." ); equals( jQuery(document).prop("nodeName"), "#document", "prop works correctly on document nodes (bug #7451)." ); @@ -85,7 +61,7 @@ test("attr(String)", function() { // Related to [5574] and [5683] var body = document.body, $body = jQuery(body); - ok( $body.attr('foo') === undefined, 'Make sure that a non existent attribute returns undefined' ); + strictEqual( $body.attr('foo'), undefined, 'Make sure that a non existent attribute returns undefined' ); body.setAttribute('foo', 'baz'); equals( $body.attr('foo'), 'baz', 'Make sure the dom attribute is retrieved when no expando is found' ); @@ -118,8 +94,8 @@ if ( !isLocal ) { test("attr(String, Function)", function() { expect(2); - equals( jQuery('#text1').attr('value', function() { return this.id ;})[0].value, "text1", "Set value from id" ); - equals( jQuery('#text1').attr('title', function(i) { return i }).attr('title'), "0", "Set value with an index"); + equals( jQuery('#text1').attr('value', function() { return this.id; })[0].value, "text1", "Set value from id" ); + equals( jQuery('#text1').attr('title', function(i) { return i; }).attr('title'), "0", "Set value with an index"); }); test("attr(Hash)", function() { From 607210e01068224ac613558c0a314ad4a8fba247 Mon Sep 17 00:00:00 2001 From: timmywil Date: Thu, 10 Mar 2011 18:34:15 -0500 Subject: [PATCH 051/372] Speed up hasAttr a little --- src/attributes.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 8de5cf80..83d02e21 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -334,18 +334,20 @@ jQuery.extend({ }, hasAttr: function( elem, name ) { - var inAttrs, attrs = elem.attributes; - - if ( elem.hasAttribute ) { - return elem.hasAttribute( name ); - } else { - // Browsers do not understand the associative indexes, look for the name in elem.attributes.name - for ( var i = 0, l = attrs.length; i < l; i++ ) { - if ( attrs[i]["name"] === name ) { - return true; + + return elem.hasAttribute ? + elem.hasAttribute( name ) : + (function() { + // Some browsers do not understand the associative indexes + // Look for the name in elem.attributes.name + var attrs = elem.attributes, i = 0, len = attrs.length; + for ( ; i < len; i++ ) { + if ( attrs[i]["name"] === name ) { + return true; + } } - } - } + return false; + })(); }, attrHooks: { From 4baa213d881a71ffd8557bc587f81d0bc606d63c Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 11 Mar 2011 14:51:57 -0500 Subject: [PATCH 052/372] First proposed solution for IE6/7 get/setAttribute quirks. Needs more testing, but solves some issues --- src/attributes.js | 39 ++++++++++++++++++++++++++++++--------- src/support.js | 5 ++++- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 83d02e21..ee4dc1ba 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -275,12 +275,6 @@ jQuery.extend({ offset: true }, - // TODO: Check to see if any of these are needed anymore? - // If not, it may be good to standardize on all-lowercase names instead - attrFix: { - - }, - attr: function( elem, name, value, pass ) { // don't get/set attributes on text, comment and attribute nodes @@ -342,7 +336,7 @@ jQuery.extend({ // Look for the name in elem.attributes.name var attrs = elem.attributes, i = 0, len = attrs.length; for ( ; i < len; i++ ) { - if ( attrs[i]["name"] === name ) { + if ( attrs[i].name === name ) { return true; } } @@ -455,7 +449,7 @@ if ( !jQuery.support.style ) { // 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 = { get: function( elem ) { var parent = elem.parentNode; @@ -475,4 +469,31 @@ if ( !jQuery.support.optSelected ) { }; } -})( jQuery ); +// IE6/7 do not support getting/setting some attributes with get/setAttribute + +if ( jQuery.support.attrFix ) { + var attrFix = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" + }; + + jQuery.each(attrFix, function( key, name ) { + jQuery.attrHooks[ key ] = jQuery.extend( jQuery.attrHooks[ key ], { + get: function( elem ) { + return elem.getAttribute( name ); + }, + set: function( elem, value ) { + elem.setAttribute( name, value ); + return value; + } + }); + }); +} \ No newline at end of file diff --git a/src/support.js b/src/support.js index 4c309562..3ca28d20 100644 --- a/src/support.js +++ b/src/support.js @@ -7,8 +7,9 @@ var div = document.createElement("div"); div.style.display = "none"; + div.setAttribute("className", "t"); div.innerHTML = "
a"; - + var all = div.getElementsByTagName("*"), a = div.getElementsByTagName("a")[0], select = document.createElement("select"), @@ -58,6 +59,8 @@ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, + attrFix: div.getAttribute("className") === "t", + // Will be defined later deleteExpando: true, optDisabled: false, From 00abeaee17a0eed8422a15ff5d48f4011490953b Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 11 Mar 2011 14:57:37 -0500 Subject: [PATCH 053/372] Didn't actually need the hooks anymore --- src/attributes.js | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index ee4dc1ba..d6179a12 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -275,6 +275,8 @@ jQuery.extend({ offset: true }, + attrFix: {}, + attr: function( elem, name, value, pass ) { // don't get/set attributes on text, comment and attribute nodes @@ -285,11 +287,14 @@ jQuery.extend({ if ( pass && name in jQuery.attrFn ) { return jQuery(elem)[name](value); } - + var ret, notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), hooks; + // Normalize the name if needed + name = notxml && jQuery.attrFix[ name ] || name; + hooks = jQuery.attrHooks[ name ]; if ( value !== undefined ) { @@ -472,8 +477,8 @@ if ( !jQuery.support.optSelected ) { // IE6/7 do not support getting/setting some attributes with get/setAttribute if ( jQuery.support.attrFix ) { - var attrFix = { - "for": "htmlFor", + jQuery.extend(jQuery.attrFix, { + "for": "htmlFor", "class": "className", readonly: "readOnly", maxlength: "maxLength", @@ -483,17 +488,5 @@ if ( jQuery.support.attrFix ) { tabindex: "tabIndex", usemap: "useMap", frameborder: "frameBorder" - }; - - jQuery.each(attrFix, function( key, name ) { - jQuery.attrHooks[ key ] = jQuery.extend( jQuery.attrHooks[ key ], { - get: function( elem ) { - return elem.getAttribute( name ); - }, - set: function( elem, value ) { - elem.setAttribute( name, value ); - return value; - } - }); - }); + }); } \ No newline at end of file From ebb8e8e300be5da2671f62e939551bd3c859e81e Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 11 Mar 2011 15:59:34 -0500 Subject: [PATCH 054/372] Fix feature test, accidentally got rid of closure end --- src/attributes.js | 11 ++++++----- src/support.js | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index d6179a12..82ebe727 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -475,10 +475,9 @@ if ( !jQuery.support.optSelected ) { } // IE6/7 do not support getting/setting some attributes with get/setAttribute - if ( jQuery.support.attrFix ) { - jQuery.extend(jQuery.attrFix, { - "for": "htmlFor", + jQuery.extend( jQuery.attrFix, { + "for": "htmlFor", "class": "className", readonly: "readOnly", maxlength: "maxLength", @@ -488,5 +487,7 @@ if ( jQuery.support.attrFix ) { tabindex: "tabIndex", usemap: "useMap", frameborder: "frameBorder" - }); -} \ No newline at end of file + }); +} + +})( jQuery ); \ No newline at end of file diff --git a/src/support.js b/src/support.js index 3ca28d20..ebda569f 100644 --- a/src/support.js +++ b/src/support.js @@ -59,7 +59,7 @@ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, - attrFix: div.getAttribute("className") === "t", + attrFix: div.className === "t", // Will be defined later deleteExpando: true, From 8cd30c62d813af68ccd91cc41adf43b8907f41cf Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 11 Mar 2011 21:28:42 -0500 Subject: [PATCH 055/372] Continuing IE7 testing, conditional attr fixes and hooks with feature testing. Will figure out a way to shorten after the test suite passes. --- src/attributes.js | 132 ++++++++++++++++++++-------------------- src/core.js | 2 +- src/support.js | 2 +- test/unit/attributes.js | 2 +- 4 files changed, 68 insertions(+), 70 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 82ebe727..ad75a001 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -16,7 +16,7 @@ jQuery.fn.extend({ removeAttr: function( name ) { return this.each(function() { if ( this.nodeType === 1 ) { - this.removeAttribute( name ); + jQuery.removeAttr( this, name ); } }); }, @@ -287,68 +287,52 @@ jQuery.extend({ if ( pass && name in jQuery.attrFn ) { return jQuery(elem)[name](value); } - + var ret, notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), hooks; - + // Normalize the name if needed name = notxml && jQuery.attrFix[ name ] || name; - + hooks = jQuery.attrHooks[ name ]; - + if ( value !== undefined ) { - + if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value )) !== undefined ) { return ret; - + } else if ( value === null ) { - elem.removeAttribute( name ); + jQuery.removeAttr( elem, name ); return undefined; - + } else { - // convert the value to a string (all browsers do this but IE) see #1070 - value = "" + value; elem.setAttribute( name, value ); return value; } - + } else { - + if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem )) !== undefined ) { return ret; - + } else { - - if ( !jQuery.hasAttr( elem, name ) ) { - return undefined; - } - var attr = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - return attr === null || attr === "undefined" ? undefined : attr; + return attr === null || attr === "undefined" || attr === "null" ? undefined : attr; } } }, - hasAttr: function( elem, name ) { - - return elem.hasAttribute ? - elem.hasAttribute( name ) : - (function() { - // Some browsers do not understand the associative indexes - // Look for the name in elem.attributes.name - var attrs = elem.attributes, i = 0, len = attrs.length; - for ( ; i < len; i++ ) { - if ( attrs[i].name === name ) { - return true; - } - } - return false; - })(); + // removeAttribute returns boolean in IE6/7 + // set property to null in that case + removeAttr: function( elem, name ) { + if ( typeof elem.removeAttribute( name ) === "boolean" ) { + elem.setAttribute( name, null ); + } }, - + attrHooks: { type: { set: function( elem, value ) { @@ -357,20 +341,6 @@ jQuery.extend({ jQuery.error( "type property can't be changed" ); } } - }, - - // 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/ - tabindex: { - get: function( elem ) { - var attributeNode = elem.getAttributeNode( "tabIndex" ); - - return attributeNode && attributeNode.specified ? - attributeNode.value : - rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? - 0 : - undefined; - } } }, @@ -414,20 +384,64 @@ jQuery.extend({ propHooks: {} }); +// IE6/7 do not support getting/setting some attributes with get/setAttribute +if ( !jQuery.support.getSetAttribute ) { + jQuery.attrFix = jQuery.extend( jQuery.attrFix, { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" + }); + + // Action attribute in ie6/7 returns form object + jQuery.attrHooks.action = jQuery.extend( jQuery.attrHooks.action, { + get: function( elem ) { + return elem.nodeName === "FORM" ? elem.getAttributeNode("action").nodeValue : elem.getAttribute("action"); + }, + set: function( elem, value ) { + elem.nodeName === "FORM" ? elem.getAttributeNode("action").nodeValue = value : elem.setAttribute("action", value); + return value; + } + }); +} + // Remove certain attrs if set to false jQuery.each([ "selected", "checked", "readonly", "disabled" ], function( i, name ) { + name = jQuery.attrFix[ name ] || name; + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { set: function( elem, value ) { if ( !value ) { // '', undefined, false, null will remove attr - elem.removeAttribute( name ); + jQuery.removeAttr( elem, name ); return false; } + elem.setAttribute( name, value ); return value; } }); }); +// 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/ +jQuery.attrHooks[ jQuery.attrFix.tabindex || "tabindex" ] = { + get: function( elem ) { + 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; + } +}; + // Some attributes require a special call on IE if ( !jQuery.support.hrefNormalized ) { jQuery.each([ "href", "src", "style" ], function( i, name ) { @@ -474,20 +488,4 @@ if ( !jQuery.support.optSelected ) { }; } -// IE6/7 do not support getting/setting some attributes with get/setAttribute -if ( jQuery.support.attrFix ) { - jQuery.extend( jQuery.attrFix, { - "for": "htmlFor", - "class": "className", - readonly: "readOnly", - maxlength: "maxLength", - cellspacing: "cellSpacing", - rowspan: "rowSpan", - colspan: "colSpan", - tabindex: "tabIndex", - usemap: "useMap", - frameborder: "frameBorder" - }); -} - })( jQuery ); \ No newline at end of file diff --git a/src/core.js b/src/core.js index 9312ee28..6b00a015 100644 --- a/src/core.js +++ b/src/core.js @@ -894,4 +894,4 @@ function doScrollCheck() { // Expose jQuery to the global object return jQuery; -})(); +})(); \ No newline at end of file diff --git a/src/support.js b/src/support.js index ebda569f..8e86c46c 100644 --- a/src/support.js +++ b/src/support.js @@ -59,7 +59,7 @@ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, - attrFix: div.className === "t", + getSetAttribute: div.className !== "t", // Will be defined later deleteExpando: true, diff --git a/test/unit/attributes.js b/test/unit/attributes.js index af423e34..d3293545 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -824,4 +824,4 @@ test("addClass, removeClass, hasClass", function() { ok( jq.hasClass("cla.ss3")==false, "Check the dotted class has been removed" ); jq.removeClass("class4"); ok( jq.hasClass("class4")==false, "Check the class has been properly removed" ); -}); +}); \ No newline at end of file From 9f88fa9165e73b879d0c955fdf81fdd681d2d192 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 13 Mar 2011 15:44:51 -0400 Subject: [PATCH 056/372] Full test suite now passes in all browsers! There are probably some tweaks we can make to shorten and simplify. - removeAttr now only uses setAttribute if camelCase setAttribute is not supported + Might want to rename jQuery.support.getSetAttribute - tabIndex is a special case now for hooks where undefined should be returned. + Should we be checking if hooks returns undefined? undefined might be the desired return value in future hooks. As of now, tabIndex is the only one that needs it, but the test suite will still pass if we don't check if hooks are undefined. --- src/attributes.js | 16 +++++++++------- src/support.js | 3 ++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index ad75a001..64b61261 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -313,7 +313,7 @@ jQuery.extend({ } else { - if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem )) !== undefined ) { + if ( hooks && "get" in hooks && notxml && ((ret = hooks.get( elem )) !== undefined || name === "tabIndex") ) { return ret; } else { @@ -325,11 +325,13 @@ jQuery.extend({ } }, - // removeAttribute returns boolean in IE6/7 - // set property to null in that case + // removeAttribute returns boolean in IE + // set property to null if getSetAttribute not supported (IE6-7) removeAttr: function( elem, name ) { - if ( typeof elem.removeAttribute( name ) === "boolean" ) { - elem.setAttribute( name, null ); + name = jQuery.attrFix[ name ] || name; + if ( typeof elem.removeAttribute( name ) === "boolean" && !jQuery.support.getSetAttribute ) { + // Setting className to null sets a class of "null" + name === "className" ? elem.className = "" : elem.setAttribute( name, null ); } }, @@ -399,7 +401,7 @@ if ( !jQuery.support.getSetAttribute ) { frameborder: "frameBorder" }); - // Action attribute in ie6/7 returns form object + // Action attribute in ie6/7 returns form objects jQuery.attrHooks.action = jQuery.extend( jQuery.attrHooks.action, { get: function( elem ) { return elem.nodeName === "FORM" ? elem.getAttributeNode("action").nodeValue : elem.getAttribute("action"); @@ -414,7 +416,7 @@ if ( !jQuery.support.getSetAttribute ) { // Remove certain attrs if set to false jQuery.each([ "selected", "checked", "readonly", "disabled" ], function( i, name ) { name = jQuery.attrFix[ name ] || name; - + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { set: function( elem, value ) { if ( !value ) { // '', undefined, false, null will remove attr diff --git a/src/support.js b/src/support.js index 8e86c46c..b227293d 100644 --- a/src/support.js +++ b/src/support.js @@ -58,7 +58,8 @@ // 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, - + + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) getSetAttribute: div.className !== "t", // Will be defined later From b85d2cd8a5c49487dc3ea7f6fad963efd9fd0f55 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 13 Mar 2011 16:17:13 -0400 Subject: [PATCH 057/372] Simplify jQuery.removeAttr and return this --- src/attributes.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 64b61261..c19b8292 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -325,14 +325,15 @@ jQuery.extend({ } }, - // removeAttribute returns boolean in IE - // set property to null if getSetAttribute not supported (IE6-7) removeAttr: function( elem, name ) { name = jQuery.attrFix[ name ] || name; - if ( typeof elem.removeAttribute( name ) === "boolean" && !jQuery.support.getSetAttribute ) { - // Setting className to null sets a class of "null" + + jQuery.support.getSetAttribute ? elem.removeAttribute( name ) : + // set property to null if getSetAttribute not supported (IE6-7) + // setting className to null makes the class "null" name === "className" ? elem.className = "" : elem.setAttribute( name, null ); - } + + return this; }, attrHooks: { From 77c559c3cbe361a87de735a67812695685b613e6 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 13 Mar 2011 16:23:21 -0400 Subject: [PATCH 058/372] No, don't return this. --- src/attributes.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index c19b8292..0a39cba8 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -332,8 +332,6 @@ jQuery.extend({ // set property to null if getSetAttribute not supported (IE6-7) // setting className to null makes the class "null" name === "className" ? elem.className = "" : elem.setAttribute( name, null ); - - return this; }, attrHooks: { From f578e0f99748ec5ae84d750f0922957e5fea25cb Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 13 Mar 2011 16:29:33 -0400 Subject: [PATCH 059/372] Don't use extend when setting the action attrHook for IE6/7 --- src/attributes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 0a39cba8..37a6c1e5 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -401,7 +401,7 @@ if ( !jQuery.support.getSetAttribute ) { }); // Action attribute in ie6/7 returns form objects - jQuery.attrHooks.action = jQuery.extend( jQuery.attrHooks.action, { + jQuery.attrHooks.action = { get: function( elem ) { return elem.nodeName === "FORM" ? elem.getAttributeNode("action").nodeValue : elem.getAttribute("action"); }, @@ -409,7 +409,7 @@ if ( !jQuery.support.getSetAttribute ) { elem.nodeName === "FORM" ? elem.getAttributeNode("action").nodeValue = value : elem.setAttribute("action", value); return value; } - }); + }; } // Remove certain attrs if set to false From dbe3b7a9d052b7bf0c73ead1ecd43a40152416a0 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 13 Mar 2011 21:27:45 -0400 Subject: [PATCH 060/372] Style edits according to comments from John and rwaldron. --- src/attributes.js | 28 +++++++++++++++++++--------- test/unit/attributes.js | 25 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 37a6c1e5..d045ca67 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -320,7 +320,9 @@ jQuery.extend({ var attr = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - return attr === null || attr === "undefined" || attr === "null" ? undefined : attr; + return attr === null || attr === "undefined" || attr === "null" ? + undefined : + attr; } } }, @@ -328,10 +330,17 @@ jQuery.extend({ removeAttr: function( elem, name ) { name = jQuery.attrFix[ name ] || name; - jQuery.support.getSetAttribute ? elem.removeAttribute( name ) : + if ( jQuery.support.getSetAttribute ) { + elem.removeAttribute( name ) + } else { // set property to null if getSetAttribute not supported (IE6-7) // setting className to null makes the class "null" - name === "className" ? elem.className = "" : elem.setAttribute( name, null ); + if ( name === "className" ) { + elem.className = "" + } else { + elem.setAttribute( name, null ); + } + } }, attrHooks: { @@ -345,10 +354,7 @@ jQuery.extend({ } }, - // TODO: Check to see if we really need any here. - propFix: { - - }, + propFix: {}, prop: function( elem, name, value ) { @@ -403,10 +409,14 @@ if ( !jQuery.support.getSetAttribute ) { // Action attribute in ie6/7 returns form objects jQuery.attrHooks.action = { get: function( elem ) { - return elem.nodeName === "FORM" ? elem.getAttributeNode("action").nodeValue : elem.getAttribute("action"); + return elem.nodeName === "FORM" ? + elem.getAttributeNode("action").nodeValue : + elem.getAttribute("action"); }, set: function( elem, value ) { - elem.nodeName === "FORM" ? elem.getAttributeNode("action").nodeValue = value : elem.setAttribute("action", value); + elem.nodeName === "FORM" ? + elem.getAttributeNode("action").nodeValue = value : + elem.setAttribute("action", value); return value; } }; diff --git a/test/unit/attributes.js b/test/unit/attributes.js index d3293545..8b483dcc 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -3,6 +3,31 @@ module("attributes", { teardown: moduleTeardown }); var bareObj = function(value) { return value; }; var functionReturningObj = function(value) { return (function() { return value; }); }; +if ( !jQuery.support.getSetAttribute ) { + test("jQuery.attrFix integrity test", function() { + expect(1); + + // This must be maintained and equal jQuery.attrFix when appropriate + // Ensure that accidental or erroneous property + // overwrites don't occur + // This is simply for better code coverage and future proofing. + var propsShouldBe = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" + }; + + same(propsShouldBe, jQuery.attrFix, "jQuery.attrFix passes integrity check"); + }); +} + test("prop", function() { equals( jQuery('#text1').prop('value'), "Test", 'Check for value attribute' ); equals( jQuery('#text1').prop('value', "Test2").prop('defaultValue'), "Test", 'Check for defaultValue attribute' ); From 5ac6ca3fa52a4a27d6952c71a77420e3e4a5d88a Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 13 Mar 2011 22:24:45 -0400 Subject: [PATCH 061/372] Restored 6 tests that I had commented to come back to later to split up between prop and attr. All tests still pass in all browsers. - I should make it clear that I have not removed any tests, but only moved some attr tests to prop where I thought it was appropriate. --- test/unit/attributes.js | 45 ++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 8b483dcc..89762e76 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -28,7 +28,8 @@ if ( !jQuery.support.getSetAttribute ) { }); } -test("prop", function() { +test("prop(String)", function() { + expect(19); equals( jQuery('#text1').prop('value'), "Test", 'Check for value attribute' ); equals( jQuery('#text1').prop('value', "Test2").prop('defaultValue'), "Test", 'Check for defaultValue attribute' ); equals( jQuery('#select2').prop('selectedIndex'), 3, 'Check for selectedIndex attribute' ); @@ -57,6 +58,14 @@ test("prop", function() { jQuery.each( [document, attributeNode, commentNode, textNode, obj, "#firstp"], function( i, ele ) { strictEqual( jQuery(ele).prop("nonexisting"), undefined, "prop works correctly for non existing attributes (bug #7500)." ); }); + + var obj = {}; + jQuery.each( [document, obj], function( i, ele ) { + var $ele = jQuery( ele ); + $ele.prop( "nonexisting", "foo" ); + equal( $ele.prop("nonexisting"), "foo", "prop(name, value) works correctly for non existing attributes (bug #7500)." ); + }); + jQuery( document ).removeProp("nonexisting"); }); test("attr(String)", function() { @@ -136,7 +145,7 @@ test("attr(Hash)", function() { }); test("attr(String, Object)", function() { - expect(24); + expect(28); var div = jQuery("div").attr("foo", "bar"), fail = false; @@ -169,25 +178,19 @@ test("attr(String, Object)", function() { equals( document.getElementById('name').maxLength, 5, 'Set maxlength attribute' ); jQuery("#name").attr('maxLength', '10'); equals( document.getElementById('name').maxLength, 10, 'Set maxlength attribute' ); - - // var attributeNode = document.createAttribute("irrelevant"), - // commentNode = document.createComment("some comment"), - // textNode = document.createTextNode("some text"), - // obj = {}; - // jQuery.each( [document, obj, "#firstp"], function( i, ele ) { - // var $ele = jQuery( ele ); - // $ele.attr( "nonexisting", "foo" ); - // equal( $ele.attr("nonexisting"), "foo", "attr(name, value) works correctly for non existing attributes (bug #7500)." ); - // }); - // jQuery.each( [commentNode, textNode, attributeNode], function( i, ele ) { - // var $ele = jQuery( ele ); - // $ele.attr( "nonexisting", "foo" ); - // strictEqual( $ele.attr("nonexisting"), undefined, "attr(name, value) works correctly on comment and text nodes (bug #7500)." ); - // }); - // //cleanup - // jQuery.each( [document, "#firstp"], function( i, ele ) { - // jQuery( ele ).removeAttr("nonexisting"); - // }); + var $p = jQuery('#firstp').attr('nonexisting', 'foo'); + equals( $p.attr('nonexisting'), 'foo', "attr(name, value) works correctly for non existing attributes (bug #7500)."); + $p.removeAttr('nonexisting'); + + var attributeNode = document.createAttribute("irrelevant"), + commentNode = document.createComment("some comment"), + textNode = document.createTextNode("some text"); + + jQuery.each( [commentNode, textNode, attributeNode], function( i, ele ) { + var $ele = jQuery( ele ); + $ele.attr( "nonexisting", "foo" ); + strictEqual( $ele.attr("nonexisting"), undefined, "attr(name, value) works correctly on comment and text nodes (bug #7500)." ); + }); var table = jQuery('#table').append("cellcellcellcellcell"), td = table.find('td:first'); From 2580420b7e1137acff7ec9fb38c1698e231e1d68 Mon Sep 17 00:00:00 2001 From: timmywil Date: Tue, 15 Mar 2011 22:47:20 -0400 Subject: [PATCH 062/372] Test description --- test/unit/attributes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 89762e76..b9605d15 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -28,7 +28,7 @@ if ( !jQuery.support.getSetAttribute ) { }); } -test("prop(String)", function() { +test("prop(String, Object)", function() { expect(19); equals( jQuery('#text1').prop('value'), "Test", 'Check for value attribute' ); equals( jQuery('#text1').prop('value', "Test2").prop('defaultValue'), "Test", 'Check for defaultValue attribute' ); From d28922bc03ea03dd7f02bbc4abc8061ea4c7305b Mon Sep 17 00:00:00 2001 From: timmywil Date: Wed, 16 Mar 2011 19:00:20 -0400 Subject: [PATCH 063/372] Pass jslint, 2 missing semicolons --- src/attributes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index d045ca67..972a02f7 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -331,12 +331,12 @@ jQuery.extend({ name = jQuery.attrFix[ name ] || name; if ( jQuery.support.getSetAttribute ) { - elem.removeAttribute( name ) + elem.removeAttribute( name ); } else { // set property to null if getSetAttribute not supported (IE6-7) // setting className to null makes the class "null" if ( name === "className" ) { - elem.className = "" + elem.className = ""; } else { elem.setAttribute( name, null ); } From dfeeb872d611c7ff7270fceb7234dd0e04671eb8 Mon Sep 17 00:00:00 2001 From: timmywil Date: Thu, 17 Mar 2011 22:59:05 -0400 Subject: [PATCH 064/372] Performance enhancement switching nodeType to a var --- src/attributes.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 972a02f7..55d22eb9 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -278,20 +278,20 @@ jQuery.extend({ attrFix: {}, attr: function( elem, name, value, pass ) { + var nType = elem.nodeType; // don't get/set attributes on text, comment and attribute nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return undefined; } if ( pass && name in jQuery.attrFn ) { return jQuery(elem)[name](value); } - - var ret, - notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), - hooks; - + + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + // Normalize the name if needed name = notxml && jQuery.attrFix[ name ] || name; @@ -357,13 +357,15 @@ jQuery.extend({ propFix: {}, prop: function( elem, name, value ) { + var nType = elem.nodeType; // don't get/set properties on text, comment and attribute nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) { + if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return undefined; } - var ret, hooks, notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ); + var ret, hooks, + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); // Try to normalize/fix the name name = notxml && jQuery.propFix[ name ] || name; From 11cfdb23940b2c76e1104c82afc9552ac6f3dc19 Mon Sep 17 00:00:00 2001 From: timmywil Date: Thu, 24 Mar 2011 00:42:00 -0400 Subject: [PATCH 065/372] Non-existent attribute for jQuery.attr no longer needs to check for "undefined" - Remove an unnecessary var - Use variable in removeAttr for better minification --- src/attributes.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 55d22eb9..dc9a333b 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -317,12 +317,12 @@ jQuery.extend({ return ret; } else { - var attr = elem.getAttribute( name ); + ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - return attr === null || attr === "undefined" || attr === "null" ? + return ret === null || ret === "null" ? undefined : - attr; + ret; } } }, @@ -336,7 +336,7 @@ jQuery.extend({ // set property to null if getSetAttribute not supported (IE6-7) // setting className to null makes the class "null" if ( name === "className" ) { - elem.className = ""; + elem[ name ] = ""; } else { elem.setAttribute( name, null ); } From 102053abd84124b1a69606565bd8da82bc5d30e9 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 00:35:50 -0400 Subject: [PATCH 066/372] Fix #7472 and added test for #3113 - Forms with an input that has either name="action" or name="some-other-attr-on-the-form" caused problems in IE6/7. This is fixed. - Changed check in $.attr for ret === null to typeof ret === "object" to catch any inputs that are accidentally retrieved in IE6/7, since attributes cannot be set to objects and typeof null === "object" --- src/attributes.js | 3 ++- test/index.html | 1 + test/unit/attributes.js | 8 +++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index dc9a333b..564eaeeb 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -320,7 +320,8 @@ jQuery.extend({ ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - return ret === null || ret === "null" ? + // Instead of checking for null, we check for typeof object to catch inputs in IE6/7. Bug #7472 + return typeof ret === "object" || ret === "null" ? undefined : ret; } diff --git a/test/index.html b/test/index.html index c7c2ae55..4a8aef52 100644 --- a/test/index.html +++ b/test/index.html @@ -203,6 +203,7 @@ Z +
diff --git a/test/unit/attributes.js b/test/unit/attributes.js index b9605d15..5b614446 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -69,7 +69,7 @@ test("prop(String, Object)", function() { }); test("attr(String)", function() { - expect(20); + expect(22); equals( jQuery('#text1').attr('type'), "text", 'Check for type attribute' ); equals( jQuery('#radio1').attr('type'), "radio", 'Check for type attribute' ); @@ -82,8 +82,10 @@ test("attr(String)", function() { equals( jQuery('#name').attr('name'), "name", 'Check for name attribute' ); equals( jQuery('#text1').attr('name'), "action", 'Check for name attribute' ); ok( jQuery('#form').attr('action').indexOf("formaction") >= 0, 'Check for action attribute' ); - // Temporarily disabled. See: #4299 - // ok( jQuery('#form').attr('action','newformaction').attr('action').indexOf("newformaction") >= 0, 'Check that action attribute was changed' ); + // [7472] & [3113] (form contains an input with name="action" or name="id") + equals( jQuery('#form').attr('action','newformaction').attr('action'), 'newformaction', 'Check that action attribute was changed' ); + equals( jQuery('#testForm').removeAttr('id').attr('id'), undefined, 'Test that id does not equal the input with name=id after id is removed [#7472]' ); + equals( jQuery('#text1').attr('maxlength'), '30', 'Check for maxlength attribute' ); equals( jQuery('#text1').attr('maxLength'), '30', 'Check for maxLength attribute' ); equals( jQuery('#area1').attr('maxLength'), '30', 'Check for maxLength attribute' ); From 9e05a0a37fcc6fc4985a95370f91e1f792e2273b Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 01:46:29 -0400 Subject: [PATCH 067/372] Fix #6562, tighten up the special code for form objects, add name attrHook for IE6/7, and don't check for undefined with getting hook'd attr --- src/attributes.js | 86 +++++++++++++++++++++-------------------- test/index.html | 3 +- test/unit/attributes.js | 36 ++++++++++------- 3 files changed, 69 insertions(+), 56 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 564eaeeb..3c6dee8b 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -275,7 +275,10 @@ jQuery.extend({ offset: true }, - attrFix: {}, + attrFix: { + // Always normalize to ensure hook usage + tabindex: "tabIndex" + }, attr: function( elem, name, value, pass ) { var nType = elem.nodeType; @@ -290,7 +293,8 @@ jQuery.extend({ } var ret, hooks, - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ), + isFormObjects = !jQuery.support.getSetAttribute && elem.nodeName === "FORM"; // Normalize the name if needed name = notxml && jQuery.attrFix[ name ] || name; @@ -307,17 +311,30 @@ jQuery.extend({ return undefined; } else { - elem.setAttribute( name, value ); + + // Check form objects in IE (multiple bugs related) + if ( isFormObjects ) { + elem.getAttributeNode( name ).nodeValue = value; + } else { + elem.setAttribute( name, value ); + } return value; } } else { - if ( hooks && "get" in hooks && notxml && ((ret = hooks.get( elem )) !== undefined || name === "tabIndex") ) { - return ret; + if ( hooks && "get" in hooks && notxml ) { + return hooks.get( elem ); } else { - ret = elem.getAttribute( name ); + + // Check form objects in IE (multiple bugs related) + if ( isFormObjects ) { + // Returns undefined for empty string, which is the blank nodeValue in IE + ret = elem.getAttributeNode( name ).nodeValue || undefined; + } else { + ret = elem.getAttribute( name ); + } // Non-existent attributes return null, we normalize to undefined // Instead of checking for null, we check for typeof object to catch inputs in IE6/7. Bug #7472 @@ -334,13 +351,9 @@ jQuery.extend({ if ( jQuery.support.getSetAttribute ) { elem.removeAttribute( name ); } else { - // set property to null if getSetAttribute not supported (IE6-7) - // setting className to null makes the class "null" - if ( name === "className" ) { - elem[ name ] = ""; - } else { - elem.setAttribute( name, null ); - } + // use DOM level 1 if getSetAttribute not supported (IE6-7) + elem.setAttribute( name, "" ); // Set to default empty string + elem.removeAttributeNode( elem.getAttributeNode( name ) ); } }, @@ -352,6 +365,19 @@ jQuery.extend({ jQuery.error( "type property can't be changed" ); } } + }, + 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; + } } }, @@ -404,23 +430,15 @@ if ( !jQuery.support.getSetAttribute ) { cellspacing: "cellSpacing", rowspan: "rowSpan", colspan: "colSpan", - tabindex: "tabIndex", usemap: "useMap", frameborder: "frameBorder" }); - - // Action attribute in ie6/7 returns form objects - jQuery.attrHooks.action = { - get: function( elem ) { - return elem.nodeName === "FORM" ? - elem.getAttributeNode("action").nodeValue : - elem.getAttribute("action"); - }, - set: function( elem, value ) { - elem.nodeName === "FORM" ? - elem.getAttributeNode("action").nodeValue = value : - elem.setAttribute("action", value); - return value; + + // Name attribute will not get removed in browsers that do not support getSetAttribute + // Return undefined on empty string or null + jQuery.attrHooks.name = { + get: function( elem, value ) { + return elem.getAttributeNode("name").nodeValue || undefined; } }; } @@ -442,20 +460,6 @@ jQuery.each([ "selected", "checked", "readonly", "disabled" ], function( i, name }); }); -// 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/ -jQuery.attrHooks[ jQuery.attrFix.tabindex || "tabindex" ] = { - get: function( elem ) { - 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; - } -}; - // Some attributes require a special call on IE if ( !jQuery.support.hrefNormalized ) { jQuery.each([ "href", "src", "style" ], function( i, name ) { diff --git a/test/index.html b/test/index.html index 4a8aef52..584f1f86 100644 --- a/test/index.html +++ b/test/index.html @@ -203,7 +203,8 @@ Z - + +
diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 5b614446..adc1d591 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -3,15 +3,18 @@ module("attributes", { teardown: moduleTeardown }); var bareObj = function(value) { return value; }; var functionReturningObj = function(value) { return (function() { return value; }); }; -if ( !jQuery.support.getSetAttribute ) { - test("jQuery.attrFix integrity test", function() { - expect(1); - // This must be maintained and equal jQuery.attrFix when appropriate - // Ensure that accidental or erroneous property - // overwrites don't occur - // This is simply for better code coverage and future proofing. - var propsShouldBe = { +test("jQuery.attrFix integrity test", function() { + expect(1); + + // This must be maintained and equal jQuery.attrFix when appropriate + // Ensure that accidental or erroneous property + // overwrites don't occur + // This is simply for better code coverage and future proofing. + var propsShouldBe; + if ( !jQuery.support.getSetAttribute ) { + propsShouldBe = { + tabindex: "tabIndex", "for": "htmlFor", "class": "className", readonly: "readOnly", @@ -19,14 +22,17 @@ if ( !jQuery.support.getSetAttribute ) { cellspacing: "cellSpacing", rowspan: "rowSpan", colspan: "colSpan", - tabindex: "tabIndex", usemap: "useMap", frameborder: "frameBorder" }; + } else { + propsShouldBe = { + tabindex: "tabIndex" + }; + } - same(propsShouldBe, jQuery.attrFix, "jQuery.attrFix passes integrity check"); - }); -} + same(propsShouldBe, jQuery.attrFix, "jQuery.attrFix passes integrity check"); +}); test("prop(String, Object)", function() { expect(19); @@ -69,7 +75,7 @@ test("prop(String, Object)", function() { }); test("attr(String)", function() { - expect(22); + expect(24); equals( jQuery('#text1').attr('type'), "text", 'Check for type attribute' ); equals( jQuery('#radio1').attr('type'), "radio", 'Check for type attribute' ); @@ -84,7 +90,9 @@ test("attr(String)", function() { ok( jQuery('#form').attr('action').indexOf("formaction") >= 0, 'Check for action attribute' ); // [7472] & [3113] (form contains an input with name="action" or name="id") equals( jQuery('#form').attr('action','newformaction').attr('action'), 'newformaction', 'Check that action attribute was changed' ); - equals( jQuery('#testForm').removeAttr('id').attr('id'), undefined, 'Test that id does not equal the input with name=id after id is removed [#7472]' ); + equals( jQuery('#testForm').attr('target'), undefined, 'Retrieving target does not equal the input with name=target' ); + equals( jQuery('#testForm').attr('target', 'newTarget').attr('target'), 'newTarget', 'Set target successfully on a form' ); + equals( jQuery('#testForm').removeAttr('id').attr('id'), undefined, 'Retrieving id does not equal the input with name=id after id is removed [#7472]' ); equals( jQuery('#text1').attr('maxlength'), '30', 'Check for maxlength attribute' ); equals( jQuery('#text1').attr('maxLength'), '30', 'Check for maxLength attribute' ); From 47c80c2050fbc15b84cb69edce309777e71b6387 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 02:07:15 -0400 Subject: [PATCH 068/372] Add test for bug#3685, remove added html and add dynamicly to avoid global test suite errors --- test/index.html | 2 -- test/unit/attributes.js | 7 ++++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/index.html b/test/index.html index 584f1f86..c7c2ae55 100644 --- a/test/index.html +++ b/test/index.html @@ -203,8 +203,6 @@ Z - -
diff --git a/test/unit/attributes.js b/test/unit/attributes.js index adc1d591..96a836f3 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -75,7 +75,7 @@ test("prop(String, Object)", function() { }); test("attr(String)", function() { - expect(24); + expect(25); equals( jQuery('#text1').attr('type'), "text", 'Check for type attribute' ); equals( jQuery('#radio1').attr('type'), "radio", 'Check for type attribute' ); @@ -88,11 +88,16 @@ test("attr(String)", function() { equals( jQuery('#name').attr('name'), "name", 'Check for name attribute' ); equals( jQuery('#text1').attr('name'), "action", 'Check for name attribute' ); ok( jQuery('#form').attr('action').indexOf("formaction") >= 0, 'Check for action attribute' ); + // [7472] & [3113] (form contains an input with name="action" or name="id") + var extras = jQuery('').appendTo('#testForm'); equals( jQuery('#form').attr('action','newformaction').attr('action'), 'newformaction', 'Check that action attribute was changed' ); equals( jQuery('#testForm').attr('target'), undefined, 'Retrieving target does not equal the input with name=target' ); equals( jQuery('#testForm').attr('target', 'newTarget').attr('target'), 'newTarget', 'Set target successfully on a form' ); equals( 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") + equals( jQuery('#testForm').attr('name'), undefined, 'Retrieving name does not retrieve input with name=name' ); + extras.remove(); equals( jQuery('#text1').attr('maxlength'), '30', 'Check for maxlength attribute' ); equals( jQuery('#text1').attr('maxLength'), '30', 'Check for maxLength attribute' ); From 3892df207d7a4a3babf5017a309263cceff48b65 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 10:40:46 -0400 Subject: [PATCH 069/372] Add test for bug #3116 --- src/attributes.js | 2 +- test/unit/attributes.js | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 3c6dee8b..dd484402 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -330,7 +330,7 @@ jQuery.extend({ // Check form objects in IE (multiple bugs related) if ( isFormObjects ) { - // Returns undefined for empty string, which is the blank nodeValue in IE + // Return undefined for empty string, which is the blank nodeValue in IE ret = elem.getAttributeNode( name ).nodeValue || undefined; } else { ret = elem.getAttribute( name ); diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 96a836f3..16123771 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -160,7 +160,7 @@ test("attr(Hash)", function() { }); test("attr(String, Object)", function() { - expect(28); + expect(29); var div = jQuery("div").attr("foo", "bar"), fail = false; @@ -220,9 +220,9 @@ test("attr(String, Object)", function() { jQuery("#name").attr('someAttr', '0'); equals( jQuery("#name").attr('someAttr'), '0', 'Set attribute to a string of "0"' ); jQuery("#name").attr('someAttr', 0); - equals( jQuery("#name").attr('someAttr'), 0, 'Set attribute to the number 0' ); + equals( jQuery("#name").attr('someAttr'), '0', 'Set attribute to the number 0' ); jQuery("#name").attr('someAttr', 1); - equals( jQuery("#name").attr('someAttr'), 1, 'Set attribute to the number 1' ); + equals( jQuery("#name").attr('someAttr'), '1', 'Set attribute to the number 1' ); // using contents will get comments regular, text, and comment nodes var j = jQuery("#nonnodes").contents(); @@ -232,7 +232,8 @@ test("attr(String, Object)", function() { j.removeAttr("name"); QUnit.reset(); - + + // Type var type = jQuery("#check2").attr('type'); var thrown = false; try { @@ -272,6 +273,13 @@ test("attr(String, Object)", function() { } ok( thrown, "Exception thrown when trying to change type property" ); equals( "button", button.attr('type'), "Verify that you can't change the type of a button element" ); + + // Setting attributes on svg elements (bug #3116) + var $svg = jQuery('' + + '' + + '').appendTo('body'); + equals( $svg.attr('cx', 100).attr('cx'), "100", "Set attribute on svg element" ); + $svg.remove(); }); test("attr(jquery_method)", function(){ From e0900a686d3c80054afd0ebe4c8908a8b5568444 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 21:13:25 -0400 Subject: [PATCH 070/372] Fix issue where non-existant attributes on forms in IE6/7 were throwing errors --- src/attributes.js | 12 +++++++----- test/unit/attributes.js | 9 +++++---- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index dd484402..b68b3edf 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -311,10 +311,11 @@ jQuery.extend({ return undefined; } else { - + // Check form objects in IE (multiple bugs related) - if ( isFormObjects ) { - elem.getAttributeNode( name ).nodeValue = value; + // Only use nodeValue if the attribute node exists on the form + if ( isFormObjects && (ret = elem.getAttributeNode( name )) ) { + ret.nodeValue = value; } else { elem.setAttribute( name, value ); } @@ -330,8 +331,9 @@ jQuery.extend({ // Check form objects in IE (multiple bugs related) if ( isFormObjects ) { - // Return undefined for empty string, which is the blank nodeValue in IE - ret = elem.getAttributeNode( name ).nodeValue || undefined; + // Return undefined if not specified instead of empty string + ret = elem.getAttributeNode( name ); + return ret && ret.specified ? ret.nodeValue : undefined; } else { ret = elem.getAttribute( name ); } diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 16123771..0260a6c1 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -75,7 +75,7 @@ test("prop(String, Object)", function() { }); test("attr(String)", function() { - expect(25); + expect(26); equals( jQuery('#text1').attr('type'), "text", 'Check for type attribute' ); equals( jQuery('#radio1').attr('type'), "radio", 'Check for type attribute' ); @@ -88,6 +88,7 @@ test("attr(String)", function() { equals( jQuery('#name').attr('name'), "name", 'Check for name attribute' ); equals( jQuery('#text1').attr('name'), "action", 'Check for name attribute' ); ok( jQuery('#form').attr('action').indexOf("formaction") >= 0, 'Check for action attribute' ); + equals( jQuery('#form').attr('blah', 'blah').attr('blah'), 'blah', 'Set non-existant attribute on a form' ); // [7472] & [3113] (form contains an input with name="action" or name="id") var extras = jQuery('').appendTo('#testForm'); @@ -214,7 +215,7 @@ test("attr(String, Object)", function() { td.attr("colspan", "2"); equals( td[0].colSpan, 2, "Check colspan is correctly set" ); table.attr("cellspacing", "2"); - equals( table[0].cellSpacing, 2, "Check cellspacing is correctly set" ); + equals( table[0].cellSpacing, "2", "Check cellspacing is correctly set" ); // for #1070 jQuery("#name").attr('someAttr', '0'); @@ -385,9 +386,9 @@ test("attr('tabindex', value)", function() { }); test("removeAttr(String)", function() { - expect(1); + expect(2); equals( jQuery('#mark').removeAttr( "class" )[0].className, "", "remove class" ); - + equals( jQuery('#form').removeAttr('id').attr('id'), undefined, 'Remove id' ); }); test("removeProp(String)", function() { From 479b28fb6aa7ec5619e1d14c4b0578b9464d5f2b Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 22:55:11 -0400 Subject: [PATCH 071/372] Modularize special form code for IE6/7 and clean up attr again --- src/attributes.js | 68 +++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index b68b3edf..295a5682 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -6,7 +6,8 @@ var rclass = /[\n\t\r]/g, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, rclickable = /^a(?:rea)?$/i, - rradiocheck = /^(?:radio|checkbox)$/i; + rradiocheck = /^(?:radio|checkbox)$/i, + formHook; jQuery.fn.extend({ attr: function( name, value ) { @@ -294,31 +295,25 @@ jQuery.extend({ var ret, hooks, notxml = nType !== 1 || !jQuery.isXMLDoc( elem ), - isFormObjects = !jQuery.support.getSetAttribute && elem.nodeName === "FORM"; + isFormObjects = !jQuery.support.getSetAttribute && ( name === "name" || elem.nodeName === "FORM" ); // Normalize the name if needed name = notxml && jQuery.attrFix[ name ] || name; - hooks = jQuery.attrHooks[ name ]; + // Get the appropriate hook, or the formHook if getSetAttribute is not supported and we have form objects in IE6/7 + hooks = isFormObjects && formHook ? formHook( name ) : jQuery.attrHooks[ name ]; if ( value !== undefined ) { - if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value )) !== undefined ) { - return ret; - - } else if ( value === null ) { + if ( value === null ) { jQuery.removeAttr( elem, name ); return undefined; - } else { + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value )) !== undefined ) { + return ret; - // Check form objects in IE (multiple bugs related) - // Only use nodeValue if the attribute node exists on the form - if ( isFormObjects && (ret = elem.getAttributeNode( name )) ) { - ret.nodeValue = value; - } else { - elem.setAttribute( name, value ); - } + } else { + elem.setAttribute( name, value ); return value; } @@ -328,15 +323,8 @@ jQuery.extend({ return hooks.get( elem ); } else { - - // Check form objects in IE (multiple bugs related) - if ( isFormObjects ) { - // Return undefined if not specified instead of empty string - ret = elem.getAttributeNode( name ); - return ret && ret.specified ? ret.nodeValue : undefined; - } else { - ret = elem.getAttribute( name ); - } + + ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined // Instead of checking for null, we check for typeof object to catch inputs in IE6/7. Bug #7472 @@ -353,8 +341,9 @@ jQuery.extend({ if ( jQuery.support.getSetAttribute ) { elem.removeAttribute( name ); } else { - // use DOM level 1 if getSetAttribute not supported (IE6-7) - elem.setAttribute( name, "" ); // Set to default empty string + // Set to default empty string + elem.setAttribute( name, "" ); + // Attempt to remove completely with DOM level 1 elem.removeAttributeNode( elem.getAttributeNode( name ) ); } }, @@ -436,12 +425,27 @@ if ( !jQuery.support.getSetAttribute ) { frameborder: "frameBorder" }); - // Name attribute will not get removed in browsers that do not support getSetAttribute - // Return undefined on empty string or null - jQuery.attrHooks.name = { - get: function( elem, value ) { - return elem.getAttributeNode("name").nodeValue || undefined; - } + // Use this for any attribute on a form in IE6/7 + // And the name attribute + formHook = function( name ) { + return jQuery.attrHooks[ name ] || { + get: function( elem ) { + var ret = elem.getAttributeNode( name ); + // Return undefined if not specified instead of empty string + return ret && ret.specified ? ret.nodeValue : undefined; + }, + set: function( elem, value ) { + // Check form objects in IE (multiple bugs related) + // Only use nodeValue if the attribute node exists on the form + var ret = elem.getAttributeNode( name ); + if ( ret ) { + ret.nodeValue = value; + } else { + elem.setAttribute( name, value ); + } + return value; + } + }; }; } From 56014a1a0089be9d8d44c286ce66fc9d2066acd7 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 22:57:01 -0400 Subject: [PATCH 072/372] Shorten even further --- src/attributes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 295a5682..6011c450 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -295,13 +295,13 @@ jQuery.extend({ var ret, hooks, notxml = nType !== 1 || !jQuery.isXMLDoc( elem ), - isFormObjects = !jQuery.support.getSetAttribute && ( name === "name" || elem.nodeName === "FORM" ); + isFormObjects = formHook && ( name === "name" || elem.nodeName === "FORM" ); // Normalize the name if needed name = notxml && jQuery.attrFix[ name ] || name; // Get the appropriate hook, or the formHook if getSetAttribute is not supported and we have form objects in IE6/7 - hooks = isFormObjects && formHook ? formHook( name ) : jQuery.attrHooks[ name ]; + hooks = isFormObjects ? formHook( name ) : jQuery.attrHooks[ name ]; if ( value !== undefined ) { From 5caf7d837630df4ac8e8fb21c79582dc897903f5 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 23:03:02 -0400 Subject: [PATCH 073/372] Clean up --- src/attributes.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 6011c450..bfeb6c4e 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -294,14 +294,15 @@ jQuery.extend({ } var ret, hooks, - notxml = nType !== 1 || !jQuery.isXMLDoc( elem ), - isFormObjects = formHook && ( name === "name" || elem.nodeName === "FORM" ); + notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); // Normalize the name if needed name = notxml && jQuery.attrFix[ name ] || name; // Get the appropriate hook, or the formHook if getSetAttribute is not supported and we have form objects in IE6/7 - hooks = isFormObjects ? formHook( name ) : jQuery.attrHooks[ name ]; + hooks = formHook && ( name === "name" || elem.nodeName === "FORM" ) ? + formHook( name ) : + jQuery.attrHooks[ name ]; if ( value !== undefined ) { @@ -432,7 +433,9 @@ if ( !jQuery.support.getSetAttribute ) { get: function( elem ) { var ret = elem.getAttributeNode( name ); // Return undefined if not specified instead of empty string - return ret && ret.specified ? ret.nodeValue : undefined; + return ret && ret.specified ? + ret.nodeValue : + undefined; }, set: function( elem, value ) { // Check form objects in IE (multiple bugs related) @@ -482,7 +485,6 @@ if ( !jQuery.support.style ) { get: function( elem ) { return elem.style.cssText; }, - set: function( elem, value ) { return (elem.style.cssText = "" + value); } From 448111cbd432864d0ae03c70ae321e97de989e9b Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 23:10:59 -0400 Subject: [PATCH 074/372] No longer need to check for objects or string of null with the special form treatment and updates to removeAttr --- src/attributes.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index bfeb6c4e..44b16825 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -328,8 +328,7 @@ jQuery.extend({ ret = elem.getAttribute( name ); // Non-existent attributes return null, we normalize to undefined - // Instead of checking for null, we check for typeof object to catch inputs in IE6/7. Bug #7472 - return typeof ret === "object" || ret === "null" ? + return ret === null ? undefined : ret; } From 03da4c7ca719443d52104c7f47abffc2e312753d Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 25 Mar 2011 23:36:07 -0400 Subject: [PATCH 075/372] Style formatting --- src/attributes.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 44b16825..c5f9dfbb 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -290,7 +290,7 @@ jQuery.extend({ } if ( pass && name in jQuery.attrFn ) { - return jQuery(elem)[name](value); + return jQuery( elem )[ name ]( value ); } var ret, hooks, @@ -299,7 +299,8 @@ jQuery.extend({ // Normalize the name if needed name = notxml && jQuery.attrFix[ name ] || name; - // Get the appropriate hook, or the formHook if getSetAttribute is not supported and we have form objects in IE6/7 + // Get the appropriate hook, or the formHook + // if getSetAttribute is not supported and we have form objects in IE6/7 hooks = formHook && ( name === "name" || elem.nodeName === "FORM" ) ? formHook( name ) : jQuery.attrHooks[ name ]; From 11c97bb06672a1203f39eb39ab373dcc56bd9465 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sat, 26 Mar 2011 00:15:25 -0400 Subject: [PATCH 076/372] Add attribute name to paramaters for hooks --- src/attributes.js | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index c5f9dfbb..6f634574 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -302,7 +302,7 @@ jQuery.extend({ // Get the appropriate hook, or the formHook // if getSetAttribute is not supported and we have form objects in IE6/7 hooks = formHook && ( name === "name" || elem.nodeName === "FORM" ) ? - formHook( name ) : + jQuery.attrHooks[ name ] || formHook : jQuery.attrHooks[ name ]; if ( value !== undefined ) { @@ -311,7 +311,7 @@ jQuery.extend({ jQuery.removeAttr( elem, name ); return undefined; - } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value )) !== undefined ) { + } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { @@ -322,7 +322,7 @@ jQuery.extend({ } else { if ( hooks && "get" in hooks && notxml ) { - return hooks.get( elem ); + return hooks.get( elem, name ); } else { @@ -428,27 +428,25 @@ if ( !jQuery.support.getSetAttribute ) { // Use this for any attribute on a form in IE6/7 // And the name attribute - formHook = function( name ) { - return jQuery.attrHooks[ name ] || { - get: function( elem ) { - var ret = elem.getAttributeNode( name ); - // Return undefined if not specified instead of empty string - return ret && ret.specified ? - ret.nodeValue : - undefined; - }, - set: function( elem, value ) { - // Check form objects in IE (multiple bugs related) - // Only use nodeValue if the attribute node exists on the form - var ret = elem.getAttributeNode( name ); - if ( ret ) { - ret.nodeValue = value; - } else { - elem.setAttribute( name, value ); - } - return value; + formHook = { + get: function( elem, name ) { + var ret = elem.getAttributeNode( name ); + // Return undefined if not specified instead of empty string + return ret && ret.specified ? + ret.nodeValue : + undefined; + }, + set: function( elem, value, name ) { + // Check form objects in IE (multiple bugs related) + // Only use nodeValue if the attribute node exists on the form + var ret = elem.getAttributeNode( name ); + if ( ret ) { + ret.nodeValue = value; + } else { + elem.setAttribute( name, value ); } - }; + return value; + } }; } From 217a7abc43967cb860fc0dccee13b475de81b07d Mon Sep 17 00:00:00 2001 From: timmywil Date: Sat, 26 Mar 2011 00:18:02 -0400 Subject: [PATCH 077/372] Add name to prop hooks as well --- src/attributes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 6f634574..70eeecfd 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -392,7 +392,7 @@ jQuery.extend({ hooks = jQuery.propHooks[ name ]; if ( value !== undefined ) { - if ( hooks && "set" in hooks && (ret = hooks.set( elem, value )) !== undefined ) { + if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { @@ -400,7 +400,7 @@ jQuery.extend({ } } else { - if ( hooks && "get" in hooks && (ret = hooks.get( elem )) !== undefined ) { + if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== undefined ) { return ret; } else { From a4d44979c6ecb4be59f1fbb50a0e5eaae804a0d3 Mon Sep 17 00:00:00 2001 From: timmywil Date: Tue, 29 Mar 2011 00:23:39 -0400 Subject: [PATCH 078/372] Shorten the logic for hooks, ternary was unnecessary --- src/attributes.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 70eeecfd..e80fede9 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -301,9 +301,7 @@ jQuery.extend({ // Get the appropriate hook, or the formHook // if getSetAttribute is not supported and we have form objects in IE6/7 - hooks = formHook && ( name === "name" || elem.nodeName === "FORM" ) ? - jQuery.attrHooks[ name ] || formHook : - jQuery.attrHooks[ name ]; + hooks = jQuery.attrHooks[ name ] || ( ( name === "name" || elem.nodeName === "FORM" ) && formHook ); if ( value !== undefined ) { From fa4373c11ba10e040a982a641c74f8ff96f312f3 Mon Sep 17 00:00:00 2001 From: timmywil Date: Tue, 29 Mar 2011 21:49:37 -0400 Subject: [PATCH 079/372] Add style attribute support tests to $.attr --- test/unit/attributes.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 0260a6c1..262f3499 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -75,7 +75,7 @@ test("prop(String, Object)", function() { }); test("attr(String)", function() { - expect(26); + expect(28); equals( jQuery('#text1').attr('type'), "text", 'Check for type attribute' ); equals( jQuery('#radio1').attr('type'), "radio", 'Check for type attribute' ); @@ -127,7 +127,10 @@ test("attr(String)", function() { ok( jQuery("
").attr("doesntexist") === undefined, "Make sure undefined is returned when no attribute is found." ); ok( jQuery().attr("doesntexist") === undefined, "Make sure undefined is returned when no element is there." ); - + + // Check for style support + ok( !!~jQuery('#dl').attr('style').indexOf('absolute'), 'Check style attribute getter' ); + ok( !!~jQuery('#foo').attr('style', 'position:absolute;').attr('style').indexOf('absolute'), 'Check style setter' ); }); if ( !isLocal ) { From 1e9b3ef3d87a0934dec969ed469cd3cc9c910ae8 Mon Sep 17 00:00:00 2001 From: timmywil Date: Wed, 30 Mar 2011 17:13:15 -0400 Subject: [PATCH 080/372] Move the check for the name attribute out of attr and down to the formHook definition --- src/attributes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index e80fede9..f0398559 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -301,7 +301,7 @@ jQuery.extend({ // Get the appropriate hook, or the formHook // if getSetAttribute is not supported and we have form objects in IE6/7 - hooks = jQuery.attrHooks[ name ] || ( ( name === "name" || elem.nodeName === "FORM" ) && formHook ); + hooks = jQuery.attrHooks[ name ] || ( elem.nodeName === "FORM" && formHook ); if ( value !== undefined ) { @@ -426,7 +426,7 @@ if ( !jQuery.support.getSetAttribute ) { // Use this for any attribute on a form in IE6/7 // And the name attribute - formHook = { + formHook = jQuery.attrHooks.name = { get: function( elem, name ) { var ret = elem.getAttributeNode( name ); // Return undefined if not specified instead of empty string From 5fc2281fcc83783b86647a5a86380b9ac21e7f79 Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 1 Apr 2011 21:13:01 -0400 Subject: [PATCH 081/372] - Added a hook to swap display none for width and height in browsers that do not sufficiently support get/setAttribute --- src/attributes.js | 14 ++++++++++++++ src/manipulation.js | 3 ++- test/unit/attributes.js | 12 ++++++++---- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index f0398559..f29c340a 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -446,6 +446,20 @@ if ( !jQuery.support.getSetAttribute ) { return value; } }; + + // Retrieving the width/height attributes on an + // element with display: none returns 0 in ie6/7 (#5413) + jQuery.each([ "width", "height" ], function( i, name ) { + jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { + get: function( elem ) { + var ret; + jQuery.swap( elem, { visibility: "hidden", display: "block" }, function() { + ret = elem.getAttribute( name ); + }); + return ret; + } + }); + }); } // Remove certain attrs if set to false diff --git a/src/manipulation.js b/src/manipulation.js index 81a55cb8..758cdbae 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -549,7 +549,8 @@ jQuery.extend({ // Return the cloned set return clone; -}, + }, + clean: function( elems, context, fragment, scripts ) { context = context || document; diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 262f3499..a73b51fc 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -75,7 +75,7 @@ test("prop(String, Object)", function() { }); test("attr(String)", function() { - expect(28); + expect(30); equals( jQuery('#text1').attr('type'), "text", 'Check for type attribute' ); equals( jQuery('#radio1').attr('type'), "radio", 'Check for type attribute' ); @@ -125,12 +125,16 @@ test("attr(String)", function() { optgroup.appendChild( option ); select.appendChild( optgroup ); - ok( jQuery("
").attr("doesntexist") === undefined, "Make sure undefined is returned when no attribute is found." ); - ok( jQuery().attr("doesntexist") === undefined, "Make sure undefined is returned when no element is there." ); - + var $img = jQuery('').appendTo('body'); + equals( $img.attr('width'), "215", "Retrieve width attribute an an element with display:none." ); + equals( $img.attr('height'), "53", "Retrieve height attribute an an element with display:none." ); + // Check for style support ok( !!~jQuery('#dl').attr('style').indexOf('absolute'), 'Check style attribute getter' ); ok( !!~jQuery('#foo').attr('style', 'position:absolute;').attr('style').indexOf('absolute'), 'Check style setter' ); + + ok( jQuery("
").attr("doesntexist") === undefined, "Make sure undefined is returned when no attribute is found." ); + ok( jQuery().attr("doesntexist") === undefined, "Make sure undefined is returned when no element is there." ); }); if ( !isLocal ) { From 8cbf551a48cbc47eccba2050e95745f70166ae1d Mon Sep 17 00:00:00 2001 From: timmywil Date: Fri, 1 Apr 2011 21:38:54 -0400 Subject: [PATCH 082/372] #5413 - Much shorter solution for getting width/height in ie6 - #8255 Added support for the list attribute in browsers that support it (it is automatically readonly, but can be set if using getAttribute( name, 2) --- src/attributes.js | 16 +--------------- test/index.html | 4 ++++ test/unit/attributes.js | 6 +++++- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index f29c340a..5afcffce 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -446,20 +446,6 @@ if ( !jQuery.support.getSetAttribute ) { return value; } }; - - // Retrieving the width/height attributes on an - // element with display: none returns 0 in ie6/7 (#5413) - jQuery.each([ "width", "height" ], function( i, name ) { - jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { - get: function( elem ) { - var ret; - jQuery.swap( elem, { visibility: "hidden", display: "block" }, function() { - ret = elem.getAttribute( name ); - }); - return ret; - } - }); - }); } // Remove certain attrs if set to false @@ -481,7 +467,7 @@ jQuery.each([ "selected", "checked", "readonly", "disabled" ], function( i, name // Some attributes require a special call on IE if ( !jQuery.support.hrefNormalized ) { - jQuery.each([ "href", "src", "style" ], function( i, name ) { + jQuery.each([ "href", "src", "style", "width", "height", "list" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { get: function( elem ) { return elem.getAttribute( name, 2 ); diff --git a/test/index.html b/test/index.html index c7c2ae55..a1065508 100644 --- a/test/index.html +++ b/test/index.html @@ -203,6 +203,10 @@ Z + + + +
diff --git a/test/unit/attributes.js b/test/unit/attributes.js index a73b51fc..ad051649 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -75,7 +75,7 @@ test("prop(String, Object)", function() { }); test("attr(String)", function() { - expect(30); + expect(31); equals( jQuery('#text1').attr('type'), "text", 'Check for type attribute' ); equals( jQuery('#radio1').attr('type'), "radio", 'Check for type attribute' ); @@ -108,6 +108,10 @@ test("attr(String)", function() { jQuery('').attr({ 'id': 'tAnchor5', 'href': '#5' }).appendTo('#main'); equals( jQuery('#tAnchor5').attr('href'), "#5", 'Check for non-absolute href (an anchor)' ); + // list attribute is readonly by default in browsers that support it + jQuery("#list-test").attr("list", "datalist"); + equals( jQuery("#list-test").attr("list"), "datalist", "Check setting list attribute" ); + // Related to [5574] and [5683] var body = document.body, $body = jQuery(body); From ff7576755864193b4c1a00464bf0919bbbe96e8b Mon Sep 17 00:00:00 2001 From: timmywil Date: Sat, 2 Apr 2011 14:23:33 -0400 Subject: [PATCH 083/372] Minor adjustments and cleanup, including normalizing the value to a string when setting( list of changes below ) - Normalize set value to string to synchronize return type cross-browser - Add style attrHook to propHooks to support style getting in all browsers for both attr and prop - Extend the selected propHook instead of overriding a possible set function - Remove selected propHook TODO since there is no selected content attribute and it should return null --- src/attributes.js | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 5afcffce..7c03cddb 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -313,7 +313,7 @@ jQuery.extend({ return ret; } else { - elem.setAttribute( name, value ); + elem.setAttribute( name, "" + value ); return value; } @@ -440,10 +440,8 @@ if ( !jQuery.support.getSetAttribute ) { var ret = elem.getAttributeNode( name ); if ( ret ) { ret.nodeValue = value; - } else { - elem.setAttribute( name, value ); + return value; } - return value; } }; } @@ -458,9 +456,6 @@ jQuery.each([ "selected", "checked", "readonly", "disabled" ], function( i, name jQuery.removeAttr( elem, name ); return false; } - - elem.setAttribute( name, value ); - return value; } }); }); @@ -477,7 +472,7 @@ if ( !jQuery.support.hrefNormalized ) { } if ( !jQuery.support.style ) { - jQuery.attrHooks.style = { + jQuery.propHooks.style = jQuery.attrHooks.style = { get: function( elem ) { return elem.style.cssText; }, @@ -490,24 +485,20 @@ if ( !jQuery.support.style ) { // 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.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { get: function( elem ) { var parent = elem.parentNode; - + if ( parent ) { parent.selectedIndex; - - // TODO: We may need an attrHook for selected that simply defers to prop? - // The attr is undefined if the option is created with createElement and not on the DOM - + // Make sure that it also works with optgroups, see #5701 if ( parent.parentNode ) { parent.parentNode.selectedIndex; } } } - }; + }); } })( jQuery ); \ No newline at end of file From 2a8a2b61488e7857b116bedc9eb75bd971772c2f Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 3 Apr 2011 16:49:48 -0400 Subject: [PATCH 084/372] Move the if statement in jQuery.fn.removeAttr to jQuery.removeAttr - Extra testing on removeAttr and IE form weirdness( all good ) --- src/attributes.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 7c03cddb..b472e617 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -16,9 +16,7 @@ jQuery.fn.extend({ removeAttr: function( name ) { return this.each(function() { - if ( this.nodeType === 1 ) { - jQuery.removeAttr( this, name ); - } + jQuery.removeAttr( this, name ); }); }, @@ -335,15 +333,17 @@ jQuery.extend({ }, removeAttr: function( elem, name ) { - name = jQuery.attrFix[ name ] || name; + if ( elem.nodeType === 1 ) { + name = jQuery.attrFix[ name ] || name; - if ( jQuery.support.getSetAttribute ) { - elem.removeAttribute( name ); - } else { - // Set to default empty string - elem.setAttribute( name, "" ); - // Attempt to remove completely with DOM level 1 - elem.removeAttributeNode( elem.getAttributeNode( name ) ); + if ( jQuery.support.getSetAttribute ) { + elem.removeAttribute( name ); + } else { + // Set to default empty string (No longer need to use attr for this) + elem.setAttribute( name, "" ); + // Attempt to remove completely with DOM level 1 + elem.removeAttributeNode( elem.getAttributeNode( name ) ); + } } }, From ad2b3bc9f908a8e529c4479c8c9baead23c2d827 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 3 Apr 2011 18:18:32 -0400 Subject: [PATCH 085/372] Found a problem removing the style attribute in IE - Style is now a special case in IE6/7 to set cssText. My goal is to avoid calling attr again for the performance benefit, and at this point it would also cause an infinite loop for the boolean attributes hooks such as selected & checked. Nevertheless, style seems to be the only one requiring a special call. --- src/attributes.js | 27 +++++++++++++++------------ test/unit/attributes.js | 13 +++++++++---- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index b472e617..ced9977e 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -276,7 +276,8 @@ jQuery.extend({ attrFix: { // Always normalize to ensure hook usage - tabindex: "tabIndex" + tabindex: "tabIndex", + readonly: "readOnly" }, attr: function( elem, name, value, pass ) { @@ -339,10 +340,14 @@ jQuery.extend({ if ( jQuery.support.getSetAttribute ) { elem.removeAttribute( name ); } else { - // Set to default empty string (No longer need to use attr for this) - elem.setAttribute( name, "" ); - // Attempt to remove completely with DOM level 1 - elem.removeAttributeNode( elem.getAttributeNode( name ) ); + // Only style is a special case. + if ( name === "style" ) { + elem.style.cssText = ""; + } else { + elem.setAttribute( name, "" ); + // Attempt to remove completely with DOM level 1 + elem.removeAttributeNode( elem.getAttributeNode( name ) ); + } } } }, @@ -415,7 +420,6 @@ if ( !jQuery.support.getSetAttribute ) { jQuery.attrFix = jQuery.extend( jQuery.attrFix, { "for": "htmlFor", "class": "className", - readonly: "readOnly", maxlength: "maxLength", cellspacing: "cellSpacing", rowspan: "rowSpan", @@ -447,12 +451,10 @@ if ( !jQuery.support.getSetAttribute ) { } // Remove certain attrs if set to false -jQuery.each([ "selected", "checked", "readonly", "disabled" ], function( i, name ) { - name = jQuery.attrFix[ name ] || name; - +jQuery.each([ "selected", "checked", "readOnly", "disabled" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { set: function( elem, value ) { - if ( !value ) { // '', undefined, false, null will remove attr + if ( !value ) { jQuery.removeAttr( elem, name ); return false; } @@ -472,9 +474,10 @@ if ( !jQuery.support.hrefNormalized ) { } if ( !jQuery.support.style ) { - jQuery.propHooks.style = jQuery.attrHooks.style = { + jQuery.attrHooks.style = { get: function( elem ) { - return elem.style.cssText; + // Return undefined in the case of empty string + return elem.style.cssText || undefined; }, set: function( elem, value ) { return (elem.style.cssText = "" + value); diff --git a/test/unit/attributes.js b/test/unit/attributes.js index ad051649..0e86a8bf 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -15,9 +15,9 @@ test("jQuery.attrFix integrity test", function() { if ( !jQuery.support.getSetAttribute ) { propsShouldBe = { tabindex: "tabIndex", + readonly: "readOnly", "for": "htmlFor", "class": "className", - readonly: "readOnly", maxlength: "maxLength", cellspacing: "cellSpacing", rowspan: "rowSpan", @@ -27,7 +27,8 @@ test("jQuery.attrFix integrity test", function() { }; } else { propsShouldBe = { - tabindex: "tabIndex" + tabindex: "tabIndex", + readonly: "readOnly" }; } @@ -172,7 +173,7 @@ test("attr(Hash)", function() { }); test("attr(String, Object)", function() { - expect(29); + expect(30); var div = jQuery("div").attr("foo", "bar"), fail = false; @@ -195,6 +196,8 @@ test("attr(String, Object)", function() { equals( jQuery("#name").attr('name'), undefined, 'Remove name attribute' ); jQuery("#check2").attr('checked', true); equals( document.getElementById('check2').checked, true, 'Set checked attribute' ); + jQuery("#check2").attr('checked', ''); + equals( document.getElementById('check2').checked, false, 'Setting checked to empty string removes it' ); jQuery("#check2").attr('checked', false); equals( document.getElementById('check2').checked, false, 'Set checked attribute' ); jQuery("#text1").attr('readonly', true); @@ -397,9 +400,11 @@ test("attr('tabindex', value)", function() { }); test("removeAttr(String)", function() { - expect(2); + expect(4); equals( jQuery('#mark').removeAttr( "class" )[0].className, "", "remove class" ); equals( jQuery('#form').removeAttr('id').attr('id'), undefined, 'Remove id' ); + equals( jQuery('#foo').attr('style', 'position:absolute;').removeAttr('style').attr('style'), undefined, 'Check removing style attribute' ); + equals( jQuery('#form').attr('style', 'position:absolute;').removeAttr('style').attr('style'), undefined, 'Check removing style attribute on a form' ); }); test("removeProp(String)", function() { From 6f79bee3e3ea874f27389a7e691c1bd7541f2ef6 Mon Sep 17 00:00:00 2001 From: timmywil Date: Sun, 3 Apr 2011 18:47:44 -0400 Subject: [PATCH 086/372] Normalize css property names to lowercase for comparisons on a .attr('style') call since IE uppercases everything --- src/attributes.js | 3 ++- test/unit/attributes.js | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index ced9977e..15d4d50e 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -477,7 +477,8 @@ if ( !jQuery.support.style ) { jQuery.attrHooks.style = { get: function( elem ) { // Return undefined in the case of empty string - return elem.style.cssText || undefined; + // Normalize to lowercase since IE uppercases css property names + return elem.style.cssText.toLowerCase() || undefined; }, set: function( elem, value ) { return (elem.style.cssText = "" + value); diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 0e86a8bf..4289bc3b 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -135,8 +135,8 @@ test("attr(String)", function() { equals( $img.attr('height'), "53", "Retrieve height attribute an an element with display:none." ); // Check for style support - ok( !!~jQuery('#dl').attr('style').indexOf('absolute'), 'Check style attribute getter' ); - ok( !!~jQuery('#foo').attr('style', 'position:absolute;').attr('style').indexOf('absolute'), 'Check style setter' ); + ok( !!~jQuery('#dl').attr('style').indexOf('position'), 'Check style attribute getter, also normalize css props to lowercase' ); + ok( !!~jQuery('#foo').attr('style', 'position:absolute;').attr('style').indexOf('position'), 'Check style setter' ); ok( jQuery("
").attr("doesntexist") === undefined, "Make sure undefined is returned when no attribute is found." ); ok( jQuery().attr("doesntexist") === undefined, "Make sure undefined is returned when no element is there." ); From 2ed81b44be958b5f2b5569ab15f22bde262b4eb6 Mon Sep 17 00:00:00 2001 From: jaubourg Date: Mon, 4 Apr 2011 17:41:30 +0200 Subject: [PATCH 087/372] Fixes #8744. Makes sure script transport abort method actually removes the script tag even if readyState exists. --- src/ajax/script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ajax/script.js b/src/ajax/script.js index 34ddd046..d3364ee6 100644 --- a/src/ajax/script.js +++ b/src/ajax/script.js @@ -53,7 +53,7 @@ jQuery.ajaxTransport( "script", function(s) { // Attach handlers for all browsers script.onload = script.onreadystatechange = function( _, isAbort ) { - if ( !script.readyState || /loaded|complete/.test( script.readyState ) ) { + if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { // Handle memory leak in IE script.onload = script.onreadystatechange = null; From 123dd72e808800d670769f9bca75c6f2c866326b Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Mon, 4 Apr 2011 11:21:15 -0700 Subject: [PATCH 088/372] Bug 7345; Add support for explicit/relative string values in .css - modified from original pull req by brandonaron #78 --- src/css.js | 10 +++++++++- test/unit/css.js | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/css.js b/src/css.js index 17ac136b..d23549fa 100644 --- a/src/css.js +++ b/src/css.js @@ -7,6 +7,8 @@ var ralpha = /alpha\([^)]*\)/i, rupper = /([A-Z]|^ms)/g, rnumpx = /^-?\d+(?:px)?$/i, rnum = /^-?\d/, + rrelNum = /=/, + rrelString = /[^+\-\de]+/g, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssWidth = [ "Left", "Right" ], @@ -75,7 +77,7 @@ jQuery.extend({ } // Make sure that we're working with the right name - var ret, origName = jQuery.camelCase( name ), + var ret, parsed, type, origName = jQuery.camelCase( name ), style = elem.style, hooks = jQuery.cssHooks[ origName ]; name = jQuery.cssProps[ origName ] || origName; @@ -87,6 +89,12 @@ jQuery.extend({ return; } + // convert string to number or relative number + if ( type === "string" ) { + parsed = +value.replace( rrelString, '' ); + value = rrelNum.test( value ) ? parsed + jQuery.css( elem, name ) : parsed; + } + // If a number was passed in, add 'px' to the (except for certain CSS properties) if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) { value += "px"; diff --git a/test/unit/css.js b/test/unit/css.js index 8ae8fcb3..c4724fcd 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -105,6 +105,27 @@ test("css(String|Hash)", function() { equals( child[0].style.fontSize, old, "Make sure font-size isn't changed on null." ); }); +test("css() explicit and relative values", function() { + var $elem = jQuery('#nothiddendiv'); + + $elem.css({ width: 1, height: 1 }); + ok( [$elem.width(), $elem.height()], [1,1] ); + $elem.css({ width: "+=9", height: "+=9" }); + ok( [$elem.width(), $elem.height()], [10,10] ); + $elem.css({ width: "-=9", height: "-=9" }); + ok( [$elem.width(), $elem.height()], [1,1] ); + $elem.css({ width: "+=9px", height: "+=9px" }); + ok( [$elem.width(), $elem.height()], [10,10] ); + $elem.css({ width: "-=9px", height: "-=9px" }); + ok( [$elem.width(), $elem.height()], [1,1] ); + $elem.css("width", "+=9").css("height", "+=9"); + ok( [$elem.width(), $elem.height()], [10,10] ); + $elem.css("width", "+9").css("height", "+9"); + ok( [$elem.width(), $elem.height()], [9,9] ); + $elem.css("width", "-9").css("height", "-9"); + ok( [$elem.width(), $elem.height()], [0,0] ); +}); + test("css(String, Object)", function() { expect(22); From 94fff6ff625be9fbbb54db53d9acec63f0919370 Mon Sep 17 00:00:00 2001 From: timmywil Date: Mon, 4 Apr 2011 14:22:58 -0400 Subject: [PATCH 089/372] Remove the unused radiocheck regex --- src/attributes.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 4c59a675..c8106e98 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -6,8 +6,7 @@ var rclass = /[\n\t\r]/g, rspecialurl = /^(?:href|src|style)$/, rtype = /^(?:button|input)$/i, rfocusable = /^(?:button|input|object|select|textarea)$/i, - rclickable = /^a(?:rea)?$/i, - rradiocheck = /^(?:radio|checkbox)$/i; + rclickable = /^a(?:rea)?$/i; jQuery.props = { "for": "htmlFor", From f7ccec1b70a42de21b55dbb7b3d65da5628ade9e Mon Sep 17 00:00:00 2001 From: louisremi Date: Mon, 31 Jan 2011 18:57:23 +0100 Subject: [PATCH 090/372] use requestAnimationFrame instead of setInterval for animations, when available. --- src/effects.js | 6 +++++- src/support.js | 8 ++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/effects.js b/src/effects.js index d9e9a8b3..a41efc28 100644 --- a/src/effects.js +++ b/src/effects.js @@ -363,7 +363,9 @@ jQuery.fx.prototype = { t.elem = this.elem; if ( t() && jQuery.timers.push(t) && !timerId ) { - timerId = setInterval(fx.tick, fx.interval); + jQuery.support.requestAnimationFrame ? + window[jQuery.support.requestAnimationFrame](fx.tick): + timerId = setInterval(fx.tick, fx.interval); } }, @@ -468,6 +470,8 @@ jQuery.extend( jQuery.fx, { if ( !timers.length ) { jQuery.fx.stop(); + } else if ( jQuery.support.requestAnimationFrame ) { + window[jQuery.support.requestAnimationFrame](this); } }, diff --git a/src/support.js b/src/support.js index 4c309562..6d331868 100644 --- a/src/support.js +++ b/src/support.js @@ -58,6 +58,14 @@ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, + // Verify requestAnimationFrame mechanism existence + // use the prefixed name as the value + requestAnimationFrame: mozRequestAnimationFrame ? + 'mozRequestAnimationFrame' : + webkitRequestAnimationFrame ? + 'webkitRequestAnimationFrame' : + false, + // Will be defined later deleteExpando: true, optDisabled: false, From 9dc63971877d583dac5bb5c8b0c3d73d1127f144 Mon Sep 17 00:00:00 2001 From: louisremi Date: Tue, 1 Feb 2011 12:02:02 +0100 Subject: [PATCH 091/372] omitting 'window.' was causing undefined errors --- src/support.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/support.js b/src/support.js index 6d331868..725575b3 100644 --- a/src/support.js +++ b/src/support.js @@ -60,9 +60,9 @@ // Verify requestAnimationFrame mechanism existence // use the prefixed name as the value - requestAnimationFrame: mozRequestAnimationFrame ? + requestAnimationFrame: window.mozRequestAnimationFrame ? 'mozRequestAnimationFrame' : - webkitRequestAnimationFrame ? + window.webkitRequestAnimationFrame ? 'webkitRequestAnimationFrame' : false, From 933ea8c5fa44f93085a7b720ac50c473a394251e Mon Sep 17 00:00:00 2001 From: louisremi Date: Tue, 1 Feb 2011 16:00:19 +0100 Subject: [PATCH 092/372] 'this' is the window --- src/effects.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/effects.js b/src/effects.js index a41efc28..196807ec 100644 --- a/src/effects.js +++ b/src/effects.js @@ -471,7 +471,7 @@ jQuery.extend( jQuery.fx, { if ( !timers.length ) { jQuery.fx.stop(); } else if ( jQuery.support.requestAnimationFrame ) { - window[jQuery.support.requestAnimationFrame](this); + window[jQuery.support.requestAnimationFrame](jQuery.fx.tick); } }, From 6de29b24b197f4fbbf3e48369343d457e7a80523 Mon Sep 17 00:00:00 2001 From: louisremi Date: Tue, 1 Feb 2011 18:26:41 +0100 Subject: [PATCH 093/372] timerId has to be set to true, to avoid starting multiple animation queues --- src/effects.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/effects.js b/src/effects.js index 196807ec..82548611 100644 --- a/src/effects.js +++ b/src/effects.js @@ -363,9 +363,9 @@ jQuery.fx.prototype = { t.elem = this.elem; if ( t() && jQuery.timers.push(t) && !timerId ) { - jQuery.support.requestAnimationFrame ? - window[jQuery.support.requestAnimationFrame](fx.tick): - timerId = setInterval(fx.tick, fx.interval); + timerId = jQuery.support.requestAnimationFrame ? + !window[jQuery.support.requestAnimationFrame](fx.tick): + setInterval(fx.tick, fx.interval); } }, From 03e6f7235bd671330f807642fefd297c42413c45 Mon Sep 17 00:00:00 2001 From: louisremi Date: Tue, 1 Feb 2011 19:57:14 +0100 Subject: [PATCH 094/372] there was no way to 'manually' stop an animation --- src/effects.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/effects.js b/src/effects.js index 82548611..6a72a88f 100644 --- a/src/effects.js +++ b/src/effects.js @@ -470,7 +470,7 @@ jQuery.extend( jQuery.fx, { if ( !timers.length ) { jQuery.fx.stop(); - } else if ( jQuery.support.requestAnimationFrame ) { + } else if ( jQuery.support.requestAnimationFrame && timerId) { window[jQuery.support.requestAnimationFrame](jQuery.fx.tick); } }, From 15e34d1f07d0c687d040af22dbc66f3978715217 Mon Sep 17 00:00:00 2001 From: louisremi Date: Wed, 2 Feb 2011 10:26:04 +0100 Subject: [PATCH 095/372] reduce impact of requestAnimationFrame on incompatible browsers by minimizing number of lookups --- src/effects.js | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/effects.js b/src/effects.js index 6a72a88f..12b87bd4 100644 --- a/src/effects.js +++ b/src/effects.js @@ -363,9 +363,17 @@ jQuery.fx.prototype = { t.elem = this.elem; if ( t() && jQuery.timers.push(t) && !timerId ) { - timerId = jQuery.support.requestAnimationFrame ? - !window[jQuery.support.requestAnimationFrame](fx.tick): - setInterval(fx.tick, fx.interval); + if ( jQuery.support.requestAnimationFrame ) { + timerId = true; + (function raf() { + if (timerId) { + window[jQuery.support.requestAnimationFrame](raf); + } + fx.tick(); + })(); + } else { + timerId = setInterval(fx.tick, fx.interval); + } } }, @@ -470,8 +478,6 @@ jQuery.extend( jQuery.fx, { if ( !timers.length ) { jQuery.fx.stop(); - } else if ( jQuery.support.requestAnimationFrame && timerId) { - window[jQuery.support.requestAnimationFrame](jQuery.fx.tick); } }, From c95ab2a39c178eee47ce7b1cbdffa812d7914bb6 Mon Sep 17 00:00:00 2001 From: louisremi Date: Wed, 2 Feb 2011 11:25:09 +0100 Subject: [PATCH 096/372] first tick should not occur immediatly; no tick should happen after a stop() + comments --- src/effects.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/effects.js b/src/effects.js index 12b87bd4..e5a10295 100644 --- a/src/effects.js +++ b/src/effects.js @@ -363,17 +363,16 @@ jQuery.fx.prototype = { t.elem = this.elem; if ( t() && jQuery.timers.push(t) && !timerId ) { - if ( jQuery.support.requestAnimationFrame ) { - timerId = true; - (function raf() { + // Use requestAnimationFrame instead of setInterval if available + ( timerId = jQuery.support.requestAnimationFrame ) ? + window[timerId](function raf() { + // timerId will be true as long as the animation hasn't been stopped if (timerId) { - window[jQuery.support.requestAnimationFrame](raf); + window[timerId](raf); + fx.tick(); } - fx.tick(); - })(); - } else { + }): timerId = setInterval(fx.tick, fx.interval); - } } }, From 5b0369366a83d7339f925bfef3a277d7287c9bd2 Mon Sep 17 00:00:00 2001 From: louisremi Date: Fri, 11 Mar 2011 11:33:15 +0100 Subject: [PATCH 097/372] shorten requestAnimationFrame test --- src/support.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/support.js b/src/support.js index 725575b3..64a54b83 100644 --- a/src/support.js +++ b/src/support.js @@ -13,7 +13,8 @@ a = div.getElementsByTagName("a")[0], select = document.createElement("select"), opt = select.appendChild( document.createElement("option") ), - input = div.getElementsByTagName("input")[0]; + input = div.getElementsByTagName("input")[0], + raf = "RequestAnimationFrame"; // Can't get basic test support if ( !all || !all.length || !a ) { @@ -60,11 +61,10 @@ // Verify requestAnimationFrame mechanism existence // use the prefixed name as the value - requestAnimationFrame: window.mozRequestAnimationFrame ? - 'mozRequestAnimationFrame' : - window.webkitRequestAnimationFrame ? - 'webkitRequestAnimationFrame' : - false, + requestAnimationFrame: + window['moz' + raf] ? 'moz' + raf : + window['webkit' + raf] ? 'webkit' + raf : + false, // Will be defined later deleteExpando: true, From fe3203bb5bdc0049467214e7f0979a3487d5681b Mon Sep 17 00:00:00 2001 From: timmywil Date: Mon, 4 Apr 2011 19:25:12 -0400 Subject: [PATCH 098/372] Some adjustments and style edits on lrbabe's pull for requestAnimationFrame - Moved support.js check to effects.js. This is just an assignment to the function if it exists. Removed string concatenations. + Still need to do the checks on window, but after that, window is no longer needed. - Switched ternary to an if statmenet - assigned timerId to a number rather than the function. I did perf tests to check which is faster. --- src/effects.js | 20 ++++++++++++-------- src/support.js | 10 +--------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/effects.js b/src/effects.js index e5a10295..9835e959 100644 --- a/src/effects.js +++ b/src/effects.js @@ -11,7 +11,8 @@ var elemdisplay = {}, [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ], // opacity animations [ "opacity" ] - ]; + ], + requestAnimationFrame = window.webkitRequestAnimationFrame || window.mozRequestionAnimationFrame; jQuery.fn.extend({ show: function( speed, easing, callback ) { @@ -364,15 +365,18 @@ jQuery.fx.prototype = { if ( t() && jQuery.timers.push(t) && !timerId ) { // Use requestAnimationFrame instead of setInterval if available - ( timerId = jQuery.support.requestAnimationFrame ) ? - window[timerId](function raf() { - // timerId will be true as long as the animation hasn't been stopped - if (timerId) { - window[timerId](raf); + if ( requestAnimationFrame ) { + timerId = 1; + requestAnimationFrame(function raf() { + // When timerId gets set to null at any point, this stops + if ( timerId ) { + requestAnimationFrame( raf ); fx.tick(); } - }): - timerId = setInterval(fx.tick, fx.interval); + }); + } else { + timerId = setInterval( fx.tick, fx.interval ); + } } }, diff --git a/src/support.js b/src/support.js index 64a54b83..4c309562 100644 --- a/src/support.js +++ b/src/support.js @@ -13,8 +13,7 @@ a = div.getElementsByTagName("a")[0], select = document.createElement("select"), opt = select.appendChild( document.createElement("option") ), - input = div.getElementsByTagName("input")[0], - raf = "RequestAnimationFrame"; + input = div.getElementsByTagName("input")[0]; // Can't get basic test support if ( !all || !all.length || !a ) { @@ -59,13 +58,6 @@ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, - // Verify requestAnimationFrame mechanism existence - // use the prefixed name as the value - requestAnimationFrame: - window['moz' + raf] ? 'moz' + raf : - window['webkit' + raf] ? 'webkit' + raf : - false, - // Will be defined later deleteExpando: true, optDisabled: false, From 44a3b5839e6db9e3735b3d2d3035c6f79b3bcbe8 Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Mon, 4 Apr 2011 16:48:24 -0700 Subject: [PATCH 099/372] Improve relative string performance in .css and some code cleanup --- src/css.js | 19 ++++++++++--------- test/unit/css.js | 43 +++++++++++++++++++++++++++---------------- 2 files changed, 37 insertions(+), 25 deletions(-) diff --git a/src/css.js b/src/css.js index d23549fa..65ec20f5 100644 --- a/src/css.js +++ b/src/css.js @@ -7,8 +7,8 @@ var ralpha = /alpha\([^)]*\)/i, rupper = /([A-Z]|^ms)/g, rnumpx = /^-?\d+(?:px)?$/i, rnum = /^-?\d/, - rrelNum = /=/, - rrelString = /[^+\-\de]+/g, + rrelNum = /^[+\-]=/, + rrelNumFilter = /[^+\-\.\de]+/g, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssWidth = [ "Left", "Right" ], @@ -77,26 +77,27 @@ jQuery.extend({ } // Make sure that we're working with the right name - var ret, parsed, type, origName = jQuery.camelCase( name ), + var ret, type, origName = jQuery.camelCase( name ), style = elem.style, hooks = jQuery.cssHooks[ origName ]; name = jQuery.cssProps[ origName ] || origName; // Check if we're setting a value if ( value !== undefined ) { + type = typeof value; + // Make sure that NaN and null values aren't set. See: #7116 - if ( typeof value === "number" && isNaN( value ) || value == null ) { + if ( type === "number" && isNaN( value ) || value == null ) { return; } - // convert string to number or relative number - if ( type === "string" ) { - parsed = +value.replace( rrelString, '' ); - value = rrelNum.test( value ) ? parsed + jQuery.css( elem, name ) : parsed; + // convert relative number strings (+= or -=) to relative numbers. #7345 + if ( type === "string" && rrelNum.test( value ) ) { + value = +value.replace( rrelNumFilter, '' ) + parseFloat( jQuery.css( elem, name ) ); } // If a number was passed in, add 'px' to the (except for certain CSS properties) - if ( typeof value === "number" && !jQuery.cssNumber[ origName ] ) { + if ( type === "number" && !jQuery.cssNumber[ origName ] ) { value += "px"; } diff --git a/test/unit/css.js b/test/unit/css.js index c4724fcd..08f50ef2 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -106,24 +106,35 @@ test("css(String|Hash)", function() { }); test("css() explicit and relative values", function() { + expect(9); var $elem = jQuery('#nothiddendiv'); - + $elem.css({ width: 1, height: 1 }); - ok( [$elem.width(), $elem.height()], [1,1] ); - $elem.css({ width: "+=9", height: "+=9" }); - ok( [$elem.width(), $elem.height()], [10,10] ); - $elem.css({ width: "-=9", height: "-=9" }); - ok( [$elem.width(), $elem.height()], [1,1] ); - $elem.css({ width: "+=9px", height: "+=9px" }); - ok( [$elem.width(), $elem.height()], [10,10] ); - $elem.css({ width: "-=9px", height: "-=9px" }); - ok( [$elem.width(), $elem.height()], [1,1] ); - $elem.css("width", "+=9").css("height", "+=9"); - ok( [$elem.width(), $elem.height()], [10,10] ); - $elem.css("width", "+9").css("height", "+9"); - ok( [$elem.width(), $elem.height()], [9,9] ); - $elem.css("width", "-9").css("height", "-9"); - ok( [$elem.width(), $elem.height()], [0,0] ); + equals( $elem.width(), 1, "Initial css set or width/height works (hash)" ); + + $elem.css({ width: "+=9" }); + equals( $elem.width(), 10, "'+=9' on width (hash)" ); + + $elem.css({ width: "-=9" }); + equals( $elem.width(), 1, "'-=9' on width (hash)" ); + + $elem.css({ width: "+=9px" }); + equals( $elem.width(), 10, "'+=9px' on width (hash)" ); + + $elem.css({ width: "-=9px" }); + equals( $elem.width(), 1, "'-=9px' on width (hash)" ); + + $elem.css( "width", "+=9" ); + equals( $elem.width(), 10, "'+=9' on width (params)" ); + + $elem.css( "width", "-=9" ) ; + equals( $elem.width(), 1, "'-=9' on width (params)" ); + + $elem.css( "width", "+=9px" ); + equals( $elem.width(), 10, "'+=9px' on width (params)" ); + + $elem.css( "width", "-=9px" ); + equals( $elem.width(), 1, "'-=9px' on width (params)" ); }); test("css(String, Object)", function() { From c72371f71474cbd6e2318c8ad909a2f92dcb915c Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Mon, 4 Apr 2011 23:59:54 -0700 Subject: [PATCH 100/372] Improve speed of $.map with object support (-5% previous speed) and improve .length detection --- src/core.js | 15 +++++++-------- src/sizzle | 2 +- test/qunit | 2 +- test/unit/core.js | 4 ++-- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/core.js b/src/core.js index 49c191b9..c9b560ae 100644 --- a/src/core.js +++ b/src/core.js @@ -704,16 +704,15 @@ jQuery.extend({ return ret; }, - // arg is for internal usage only + // arg is for internal usage only map: function( elems, callback, arg ) { var value, ret = [], - i = 0, + i = 0, length = elems.length, - // process .length if it's just an object member - isArray = length !== undefined && ( elems[ length - 1 ] || jQuery.isArray( elems ) ); - + // jquery objects are treated as arrays + isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || jQuery.isArray( elems ) ) ; + // Go through the array, translating each of the items to their - // new value (or values). if ( isArray ) { for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); @@ -723,8 +722,8 @@ jQuery.extend({ } } - // Go thorugh every key on the object, - } else { + // Go thorugh every key on the object, + } else { for ( key in elems ) { value = callback( elems[ key ], key, arg ); diff --git a/src/sizzle b/src/sizzle index ef19279f..f12b9309 160000 --- a/src/sizzle +++ b/src/sizzle @@ -1 +1 @@ -Subproject commit ef19279f54ba49242c6461d47577c703f4f4e80e +Subproject commit f12b9309269ba7e705a99efe099f86ed1fe98d58 diff --git a/test/qunit b/test/qunit index cc8460c7..d404faf8 160000 --- a/test/qunit +++ b/test/qunit @@ -1 +1 @@ -Subproject commit cc8460c7b44f023c4f84ab1810b72bf6c6ee4542 +Subproject commit d404faf8f587fcbe6b8907943022e6318dd51e0c diff --git a/test/unit/core.js b/test/unit/core.js index 08d80400..c15884fc 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -625,7 +625,7 @@ test("map()", function() { q("ap","ap","ap"), "Single Map" ); - + //for #2616 var keys = jQuery.map( {a:1,b:2}, function( v, k ){ return k; @@ -636,7 +636,7 @@ test("map()", function() { return v; }); equals( values.join(""), "12", "Map the values from a hash to an array" ); - + // object with length prop var values = jQuery.map( {a:1,b:2, length:3}, function( v, k ){ return v; From a7e7dbd978b97c55a29b364fd277c4ade1ec22b6 Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Tue, 5 Apr 2011 01:43:14 -0700 Subject: [PATCH 101/372] Bug 7587; Enhancement/1.6 Feature: Bypass regexp filter on $.parseJSON and use native thrown exceptions if window.JSON.parse is available --- src/core.js | 16 +++++++++------- test/unit/ajax.js | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/core.js b/src/core.js index 9312ee28..205a6e30 100644 --- a/src/core.js +++ b/src/core.js @@ -515,16 +515,18 @@ jQuery.extend({ // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); + // Attempt to parse using the native JSON parser first + if ( window.JSON && window.JSON.parse ) { + return window.JSON.parse( 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, "")) ) { + if ( rvalidchars.test( data.replace( rvalidescape, "@" ) + .replace( rvalidtokens, "]" ) + .replace( rvalidbraces, "")) ) { - // Try to use the native JSON parser first - return window.JSON && window.JSON.parse ? - window.JSON.parse( data ) : - (new Function("return " + data))(); + return (new Function( "return " + data ))(); } else { jQuery.error( "Invalid JSON: " + data ); diff --git a/test/unit/ajax.js b/test/unit/ajax.js index 7c572a32..e9c7a00c 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1600,7 +1600,7 @@ test("jQuery.ajax() - malformed JSON", function() { }, error: function(xhr, msg, detailedMsg) { equals( "parsererror", msg, "A parse error occurred." ); - ok( /^Invalid JSON/.test(detailedMsg), "Detailed parsererror message provided" ); + ok( /^(Invalid|SyntaxError|exception)/i.test(detailedMsg), "Detailed parsererror message provided" ); start(); } }); From 3609bed9e7aa4c0aea4ebfc446ad15bc216aed0f Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Tue, 5 Apr 2011 07:20:58 -0700 Subject: [PATCH 102/372] Remove extra else in parseJSON --- src/core.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core.js b/src/core.js index 205a6e30..d8ed38c5 100644 --- a/src/core.js +++ b/src/core.js @@ -528,9 +528,8 @@ jQuery.extend({ return (new Function( "return " + data ))(); - } else { - jQuery.error( "Invalid JSON: " + data ); } + jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing From c0389e3e37447aa7eb70cfb4837f4df6cdec5bba Mon Sep 17 00:00:00 2001 From: Dan Heberden Date: Tue, 5 Apr 2011 08:33:14 -0700 Subject: [PATCH 103/372] Add missing var declaration for --- src/core.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core.js b/src/core.js index c9b560ae..f2101099 100644 --- a/src/core.js +++ b/src/core.js @@ -706,7 +706,7 @@ jQuery.extend({ // arg is for internal usage only map: function( elems, callback, arg ) { - var value, ret = [], + var value, key, ret = [], i = 0, length = elems.length, // jquery objects are treated as arrays From 23a411b6bcbb96edbbfe53e11ec1671dccaa92b6 Mon Sep 17 00:00:00 2001 From: rwldrn Date: Tue, 5 Apr 2011 15:55:40 -0400 Subject: [PATCH 104/372] Ticket #8753 Allow special properties to explicitly defined on jQuery.Event objects --- src/event.js | 17 ++++++++++++++--- test/unit/event.js | 29 +++++++++++++++++++++++------ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/event.js b/src/event.js index bc2cf76e..eadfa05c 100644 --- a/src/event.js +++ b/src/event.js @@ -1,6 +1,7 @@ (function( jQuery ) { -var rnamespaces = /\.(.*)$/, +var hasOwn = Object.prototype.hasOwnProperty, + rnamespaces = /\.(.*)$/, rformElems = /^(?:textarea|input|select)$/i, rperiod = /\./g, rspace = / /g, @@ -581,6 +582,15 @@ jQuery.Event = function( src ) { this.originalEvent = src; this.type = src.type; + // Push explicitly provided properties onto the event object + for ( var prop in src ) { + // Ensure we don't clobber jQuery.Event prototype + // with own properties. + if ( hasOwn.call( src, prop ) ) { + this[ prop ] = src[ prop ]; + } + } + // 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 || @@ -868,10 +878,10 @@ function trigger( type, elem, args ) { // Create "bubbling" focus and blur events if ( document.addEventListener ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - + // Attach a single capturing handler while someone wants focusin/focusout var attaches = 0; - + jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { @@ -1184,3 +1194,4 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl }); })( jQuery ); + diff --git a/test/unit/event.js b/test/unit/event.js index 2a6d8a66..d19c7ec4 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -685,7 +685,6 @@ test("hover()", function() { test("mouseover triggers mouseenter", function() { expect(1); - var count = 0, elem = jQuery(""); elem.mouseenter(function () { @@ -693,7 +692,6 @@ test("mouseover triggers mouseenter", function() { }); elem.trigger('mouseover'); equals(count, 1, "make sure mouseover triggers a mouseenter" ); - elem.remove(); }); @@ -930,6 +928,27 @@ test("trigger(eventObject, [data], [fn])", function() { $parent.unbind().remove(); }); +test("jQuery.Event({ /* props */ })", function() { + + expect(4); + + var event = jQuery.Event({ type: "keydown", keyCode: 64 }), + handler = function( event ) { + ok( "keyCode" in event, "Special property 'keyCode' exists" ); + equal( event.keyCode, 64, "event.keyCode has explicit value '64'" ); + }; + + // Supports jQuery.Event implementation + equal( event.type, "keydown", "Verify type" ); + + ok( "keyCode" in event, "Special 'keyCode' property exists" ); + + jQuery("body").bind( "keydown", handler ).trigger( event ); + + jQuery("body").unbind( "keydown" ); + +}); + test("jQuery.Event.currentTarget", function(){ expect(1); @@ -1982,8 +2001,7 @@ test("window resize", function() { test("focusin bubbles", function() { expect(5); - - var input = jQuery( '' ).prependTo( "body" ), + var input = jQuery( '' ).prependTo( "body" ), order = 0; jQuery( "body" ).bind( "focusin.focusinBubblesTest", function(){ @@ -1996,12 +2014,10 @@ test("focusin bubbles", function() { // DOM focus method input[0].focus(); - // To make the next focus test work, we need to take focus off the input. // This will fire another focusin event, so set order to reflect that. order = 1; jQuery("#text1")[0].focus(); - // jQuery trigger, which calls DOM focus order = 0; input.trigger( "focus" ); @@ -2027,3 +2043,4 @@ test("event properties", function() { }).click(); }); */ + From b1b2e83394ef6ebcbaa5167d95e827f86655b74c Mon Sep 17 00:00:00 2001 From: rwldrn Date: Tue, 5 Apr 2011 16:20:55 -0400 Subject: [PATCH 105/372] Move this.type setting to after prop set; avoid setting twice --- src/event.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/event.js b/src/event.js index eadfa05c..7f2e1d8b 100644 --- a/src/event.js +++ b/src/event.js @@ -580,7 +580,6 @@ jQuery.Event = function( src ) { // Event object if ( src && src.type ) { this.originalEvent = src; - this.type = src.type; // Push explicitly provided properties onto the event object for ( var prop in src ) { @@ -591,6 +590,10 @@ jQuery.Event = function( src ) { } } + if ( !this.type ) { + 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 || From 9db18ddd84adf63166f411a4f2c776b51d1840e0 Mon Sep 17 00:00:00 2001 From: timmywil Date: Tue, 5 Apr 2011 16:28:25 -0400 Subject: [PATCH 106/372] Per rwaldron's request, added oRequestAnimationFrame as a possibility --- src/effects.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/effects.js b/src/effects.js index 9835e959..727c1a7a 100644 --- a/src/effects.js +++ b/src/effects.js @@ -12,7 +12,9 @@ var elemdisplay = {}, // opacity animations [ "opacity" ] ], - requestAnimationFrame = window.webkitRequestAnimationFrame || window.mozRequestionAnimationFrame; + requestAnimationFrame = window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame; jQuery.fn.extend({ show: function( speed, easing, callback ) { From 92a4d59c3221ada339177ca860570893766a6429 Mon Sep 17 00:00:00 2001 From: rwldrn Date: Tue, 5 Apr 2011 16:32:42 -0400 Subject: [PATCH 107/372] Remove this.type assignment --- src/event.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/event.js b/src/event.js index 7f2e1d8b..fe197189 100644 --- a/src/event.js +++ b/src/event.js @@ -590,10 +590,6 @@ jQuery.Event = function( src ) { } } - if ( !this.type ) { - 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 || From 4b0c26f0af96da05ab1a0166268c2925a6e6e6ac Mon Sep 17 00:00:00 2001 From: rwldrn Date: Tue, 5 Apr 2011 18:12:50 -0400 Subject: [PATCH 108/372] Ticket #8777 undelegate by namespace --- src/event.js | 13 +++++++++++-- test/unit/event.js | 34 ++++++++++++++++++++++++++++------ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/event.js b/src/event.js index bc2cf76e..6fac59c7 100644 --- a/src/event.js +++ b/src/event.js @@ -868,10 +868,10 @@ function trigger( type, elem, args ) { // Create "bubbling" focus and blur events if ( document.addEventListener ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { - + // Attach a single capturing handler while someone wants focusin/focusout var attaches = 0; - + jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { @@ -1027,6 +1027,14 @@ jQuery.each(["live", "die"], function( i, name ) { return this; } + if ( name === "die" && !types && + origSelector && origSelector[0] === "." ) { + + context.unbind( origSelector ); + + return this; + } + if ( jQuery.isFunction( data ) ) { fn = data; data = undefined; @@ -1184,3 +1192,4 @@ jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblcl }); })( jQuery ); + diff --git a/test/unit/event.js b/test/unit/event.js index 2a6d8a66..cc6901ff 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -685,7 +685,7 @@ test("hover()", function() { test("mouseover triggers mouseenter", function() { expect(1); - + var count = 0, elem = jQuery(""); elem.mouseenter(function () { @@ -693,7 +693,7 @@ test("mouseover triggers mouseenter", function() { }); elem.trigger('mouseover'); equals(count, 1, "make sure mouseover triggers a mouseenter" ); - + elem.remove(); }); @@ -1956,6 +1956,27 @@ test("delegate with submit", function() { jQuery(document).undelegate(); }); +test("undelegate() with only namespaces", function(){ + expect(2); + + var $delegate = jQuery("#liveHandlerOrder"), + count = 0; + + $delegate.delegate("a", "click.ns", function(e) { + count++; + }); + + jQuery("a", $delegate).eq(0).trigger("click.ns"); + + equals( count, 1, "delegated click.ns"); + + $delegate.undelegate(".ns"); + + jQuery("a", $delegate).eq(1).trigger("click.ns"); + + equals( count, 1, "no more .ns after undelegate"); +}); + test("Non DOM element events", function() { expect(1); @@ -1982,8 +2003,8 @@ test("window resize", function() { test("focusin bubbles", function() { expect(5); - - var input = jQuery( '' ).prependTo( "body" ), + + var input = jQuery( '' ).prependTo( "body" ), order = 0; jQuery( "body" ).bind( "focusin.focusinBubblesTest", function(){ @@ -1996,12 +2017,12 @@ test("focusin bubbles", function() { // DOM focus method input[0].focus(); - + // To make the next focus test work, we need to take focus off the input. // This will fire another focusin event, so set order to reflect that. order = 1; jQuery("#text1")[0].focus(); - + // jQuery trigger, which calls DOM focus order = 0; input.trigger( "focus" ); @@ -2027,3 +2048,4 @@ test("event properties", function() { }).click(); }); */ + From c1316a4cb1fa9b9f85ef96f0e2ce45768ccd59cd Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Tue, 5 Apr 2011 21:59:09 -0400 Subject: [PATCH 109/372] Shorten up the code and do event cleanup on test cases. --- src/event.js | 11 +++-------- test/unit/event.js | 2 ++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/event.js b/src/event.js index 9164bd67..b8de9386 100644 --- a/src/event.js +++ b/src/event.js @@ -1027,15 +1027,10 @@ jQuery.each(["live", "die"], function( i, name ) { return this; } - if ( jQuery.isFunction( data ) || data === false ) { - fn = data; + if ( data === false || jQuery.isFunction( data ) ) { + fn = data || returnFalse; data = undefined; - } - - if ( fn === false ) { - fn = returnFalse; - } - + } types = (types || "").split(" "); diff --git a/test/unit/event.js b/test/unit/event.js index 48a97a1d..0b4b364b 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -567,6 +567,7 @@ test("live(name, false), die(name, false)", function() { jQuery("#ap").die("click", false); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); + jQuery("#main").die("click"); }); test("delegate(selector, name, false), undelegate(selector, name, false)", function() { @@ -587,6 +588,7 @@ test("delegate(selector, name, false), undelegate(selector, name, false)", funct jQuery("#ap").undelegate("#groups", "click", false); jQuery("#groups").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); + jQuery("#main").undelegate("#ap", "click"); }); test("bind()/trigger()/unbind() on plain object", function() { From d47c0ae4228a59fcf731f626d650bb55c4e34609 Mon Sep 17 00:00:00 2001 From: timmywil Date: Tue, 5 Apr 2011 22:40:12 -0400 Subject: [PATCH 110/372] Performance testing: localize val to each block and only set val to value when not a function --- src/attributes.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index c8106e98..9fdb1492 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -153,15 +153,15 @@ jQuery.fn.extend({ }, val: function( value ) { - var hooks, val, + var hooks, ret, elem = this[0]; if ( !arguments.length ) { if ( elem ) { hooks = jQuery.valHooks[ elem.nodeName.toLowerCase() ] || jQuery.valHooks[ elem.type ]; - if ( hooks && "get" in hooks && (val = hooks.get( elem )) !== undefined ) { - return val; + if ( hooks && "get" in hooks && (ret = hooks.get( elem )) !== undefined ) { + return ret; } return (elem.value || "").replace(rreturn, ""); @@ -173,15 +173,16 @@ jQuery.fn.extend({ var isFunction = jQuery.isFunction( value ); return this.each(function( i ) { - var self = jQuery(this); + var self = jQuery(this), val; if ( this.nodeType !== 1 ) { return; } - val = value; if ( isFunction ) { val = value.call( this, i, self.val() ); + } else { + val = value; } // Treat null/undefined as ""; convert numbers to string From e0856738e6151368cffc963800e06ebcc0bbc314 Mon Sep 17 00:00:00 2001 From: carpie Date: Wed, 19 Jan 2011 17:37:31 -0600 Subject: [PATCH 111/372] Skip id regex check when large html strings are passed to the jQuery constructor (#7990). --- src/core.js | 7 ++++++- test/unit/core.js | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/core.js b/src/core.js index f19de96d..a893fc9b 100644 --- a/src/core.js +++ b/src/core.js @@ -96,7 +96,12 @@ jQuery.fn = jQuery.prototype = { // Handle HTML strings if ( typeof selector === "string" ) { // Are we dealing with HTML string or an ID? - match = quickExpr.exec( selector ); + if ( selector.length > 1024 ) { + // Assume very large strings are HTML and skip the regex check + match = [ null, selector, null ]; + } else { + match = quickExpr.exec( selector ); + } // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { diff --git a/test/unit/core.js b/test/unit/core.js index a8da85fc..03325ab7 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -469,7 +469,7 @@ test("isWindow", function() { }); test("jQuery('html')", function() { - expect(15); + expect(18); QUnit.reset(); jQuery.foo = false; @@ -501,6 +501,19 @@ test("jQuery('html')", function() { ok( jQuery("
")[0], "Create a div with closing tag." ); ok( jQuery("
")[0], "Create a table with closing tag." ); + + // Test very large html string #7990 + var i; + var li = '
  • very large html string
  • '; + var html = ['
      ']; + for ( i = 0; i < 50000; i += 1 ) { + html.push(li); + } + html.push('
    '); + html = jQuery(html.join(''))[0]; + equals( html.nodeName.toUpperCase(), 'UL'); + equals( html.firstChild.nodeName.toUpperCase(), 'LI'); + equals( html.childNodes.length, 50000 ); }); test("jQuery('html', context)", function() { From bfa32317d2a56145a2d1151c60ce2d71d1328dd9 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Thu, 10 Feb 2011 23:43:45 -0500 Subject: [PATCH 112/372] Switch from recursion to iteration for event triggering. Move event-name namespace processing out of event handler, since it has to always go through trigger. --- src/event.js | 122 ++++++++++++++++++++++----------------------------- 1 file changed, 52 insertions(+), 70 deletions(-) diff --git a/src/event.js b/src/event.js index b8de9386..2837c1e0 100644 --- a/src/event.js +++ b/src/event.js @@ -277,13 +277,12 @@ jQuery.event = { } }, - // bubbling is internal - trigger: function( event, data, elem /*, bubbling */ ) { + trigger: function( event, data, elem ) { // Event object or event type var type = event.type || event, - bubbling = arguments[3]; + bubbling = arguments[3], + namespaces = []; - if ( !bubbling ) { event = typeof event === "object" ? // jQuery.Event object event[ jQuery.expando ] ? event : @@ -293,10 +292,19 @@ jQuery.event = { jQuery.Event(type); if ( type.indexOf("!") >= 0 ) { + // Exclusive events trigger only for the bare event type (no namespaces) event.type = type = type.slice(0, -1); event.exclusive = true; } - + if ( type.indexOf(".") >= 0 ) { + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split("."); + event.type = type = namespaces.shift(); + namespaces.sort(); + } + event.namespace = namespaces.join("."); + event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); + // Handle a global trigger if ( !elem ) { // Don't bubble custom events when global (to avoid too much overhead) @@ -317,13 +325,12 @@ jQuery.event = { } }); } + return; } - // Handle triggering a single element - // don't do events on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { - return undefined; + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; } // Clean up in case it is reused @@ -333,62 +340,53 @@ jQuery.event = { // 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" ); + // Always fire on the current element, e.g. triggerHandler or global trigger + var cur = elem; + do { + var handle = jQuery._data( cur, "handle" ); + event.currentTarget = cur; if ( handle ) { - handle.apply( elem, data ); + handle.apply( cur, 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 ) { + // Trigger an inline bound script; IE dies on special-char event names + try { + if ( jQuery.acceptData( cur ) && cur[ "on" + type ] && cur[ "on" + type ].apply( cur, data ) === false ) { event.result = false; event.preventDefault(); } - } + } catch ( ieError ) {} - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (inlineError) {} + cur = cur.parentNode || cur.ownerDocument; + } while ( cur && !event.isPropagationStopped() ); - if ( !event.isPropagationStopped() && parent ) { - jQuery.event.trigger( event, data, parent, true ); - - } else if ( !event.isDefaultPrevented() ) { + // If nobody prevented the default action, do it now + if ( !event.isDefaultPrevented() ) { var old, - target = event.target, - targetType = type.replace( rnamespaces, "" ), - isClick = jQuery.nodeName( target, "a" ) && targetType === "click", - special = jQuery.event.special[ targetType ] || {}; + special = jQuery.event.special[ type ] || {}; - if ( (!special._default || special._default.call( elem, event ) === false) && - !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && + !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { + // IE may die here on non-alpha event names or hidden elements (#3533) try { - if ( target[ targetType ] ) { - // Make sure that we don't accidentally re-trigger the onFOO events - old = target[ "on" + targetType ]; + if ( elem[ type ] ) { + // Don't accidentally re-trigger the onFOO events + old = elem[ "on" + type ]; if ( old ) { - target[ "on" + targetType ] = null; + elem[ "on" + type ] = null; } jQuery.event.triggered = event.type; - target[ targetType ](); + elem[ type ](); } - - // prevent IE from throwing an error for some elements with some event types, see #3533 - } catch (triggerError) {} + } catch ( ieError ) {} if ( old ) { - target[ "on" + targetType ] = old; + elem[ "on" + type ] = old; } jQuery.event.triggered = undefined; @@ -397,38 +395,24 @@ jQuery.event = { }, handle: function( event ) { - var all, handlers, namespaces, namespace_re, events, - namespace_sort = [], + // It's rare to arrive without handlers to call, so do all setup here. + // Copy the handler list since a called handler may add/remove events. + event = jQuery.event.fix( event || window.event ); + var events = jQuery._data( this, "events" ), + handlers = ((events || {})[ event.type ] || []).slice(0), + all_handlers = !event.exclusive && !event.namespace, args = jQuery.makeArray( arguments ); - event = args[0] = jQuery.event.fix( event || window.event ); + // Use the fix-ed Event rather than the (read-only) native event + args[0] = 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_sort = namespaces.slice(0).sort(); - namespace_re = new RegExp("(^|\\.)" + namespace_sort.join("\\.(?:.*\\.)?") + "(\\.|$)"); - } - - event.namespace = event.namespace || namespace_sort.join("."); - - 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_re.test( handleObj.namespace ) ) { + // Triggered event must 1) be non-exclusive and have no namespace, or + // 2) have namespace(s) a subset or equal to those in the bound event. + if ( all_handlers || event.namespace_re.test( handleObj.namespace ) ) { // Pass in a reference to the handler function itself // So that we can later remove it event.handler = handleObj.handler; @@ -450,8 +434,6 @@ jQuery.event = { } } } - } - return event.result; }, From 246757bacdd6224724c667b7b9812d7d88bdd8e1 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Tue, 15 Mar 2011 23:40:25 -0400 Subject: [PATCH 113/372] Only bubble a triggered event if we have attached a jQuery handler, but check the current element for an inline handler regardless. Make some other size optimizations as well. --- src/event.js | 57 +++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/event.js b/src/event.js index 2837c1e0..25168ffb 100644 --- a/src/event.js +++ b/src/event.js @@ -143,7 +143,7 @@ jQuery.event = { // Add the function to the element's handler list handlers.push( handleObj ); - // Keep track of which events have been used, for global triggering + // Keep track of which events have been used, for event optimization jQuery.event.global[ type ] = true; } @@ -280,8 +280,10 @@ jQuery.event = { trigger: function( event, data, elem ) { // Event object or event type var type = event.type || event, - bubbling = arguments[3], - namespaces = []; + ontype = "on" + type, + handling = jQuery.event.global, + namespaces = [], + cur = elem; event = typeof event === "object" ? // jQuery.Event object @@ -310,8 +312,8 @@ jQuery.event = { // 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 ] ) { + // Save some time, only trigger if we've ever bound an event for this type + if ( handling[ type ] ) { // XXX This code smells terrible. event.js should not be directly // inspecting the data cache jQuery.each( jQuery.cache, function() { @@ -328,21 +330,20 @@ jQuery.event = { return; } - // don't do events on text and comment nodes + // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } - // Clean up in case it is reused + // Clean up the event in case it is being reused event.result = undefined; event.target = elem; - // Clone the incoming data, if any + // Clone any incoming data and prepend the event, creating the handler arg list data = jQuery.makeArray( data ); data.unshift( event ); - // Always fire on the current element, e.g. triggerHandler or global trigger - var cur = elem; + // Fire event on the current element, then bubble up the DOM tree do { var handle = jQuery._data( cur, "handle" ); @@ -351,16 +352,16 @@ jQuery.event = { handle.apply( cur, data ); } - // Trigger an inline bound script; IE dies on special-char event names + // Trigger an inline bound script; IE<9 dies on special-char event name try { - if ( jQuery.acceptData( cur ) && cur[ "on" + type ] && cur[ "on" + type ].apply( cur, data ) === false ) { + if ( jQuery.acceptData( cur ) && cur[ ontype ] && cur[ ontype ].apply( cur, data ) === false ) { event.result = false; event.preventDefault(); } - } catch ( ieError ) {} + } catch ( ieError1 ) {} cur = cur.parentNode || cur.ownerDocument; - } while ( cur && !event.isPropagationStopped() ); + } while ( cur && !event.isPropagationStopped() && handling[ type ] ); // If nobody prevented the default action, do it now if ( !event.isDefaultPrevented() ) { @@ -370,23 +371,25 @@ jQuery.event = { if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) && !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { - // IE may die here on non-alpha event names or hidden elements (#3533) + // 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. + // Use try/catch so IE<9 won't die on special-char event name or hidden element (#3533). try { if ( elem[ type ] ) { - // Don't accidentally re-trigger the onFOO events - old = elem[ "on" + type ]; + // Don't re-trigger an onFOO event when we call its FOO() method + old = elem[ ontype ]; if ( old ) { - elem[ "on" + type ] = null; + elem[ ontype ] = null; } - jQuery.event.triggered = event.type; + jQuery.event.triggered = type; elem[ type ](); } - } catch ( ieError ) {} + } catch ( ieError2 ) {} if ( old ) { - elem[ "on" + type ] = old; + elem[ ontype ] = old; } jQuery.event.triggered = undefined; @@ -395,11 +398,10 @@ jQuery.event = { }, handle: function( event ) { - // It's rare to arrive without handlers to call, so do all setup here. - // Copy the handler list since a called handler may add/remove events. + // It's rare to arrive without handlers to call, so do all setup now. + // Snapshot the handlers list since a called handler may add/remove events. event = jQuery.event.fix( event || window.event ); - var events = jQuery._data( this, "events" ), - handlers = ((events || {})[ event.type ] || []).slice(0), + var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), all_handlers = !event.exclusive && !event.namespace, args = jQuery.makeArray( arguments ); @@ -472,8 +474,9 @@ jQuery.event = { // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && event.clientX != null ) { - var doc = document.documentElement, - body = document.body; + var eventDocument = event.target.ownerDocument || document, + doc = eventDocument.documentElement, + body = eventDocument.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); From 29386db3196e883bffeda63f9e9db1f9ed336bba Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Wed, 6 Apr 2011 10:31:14 -0400 Subject: [PATCH 114/372] Sadly, we still have to bubble the event so inline handlers will work. --- src/event.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/event.js b/src/event.js index 25168ffb..acaaf281 100644 --- a/src/event.js +++ b/src/event.js @@ -71,8 +71,8 @@ jQuery.event = { if ( !eventHandle ) { elemData.handle = eventHandle = function( e ) { - // Handle the second event of a trigger and when - // an event is called after a page has unloaded + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? jQuery.event.handle.apply( eventHandle.elem, arguments ) : undefined; @@ -281,7 +281,6 @@ jQuery.event = { // Event object or event type var type = event.type || event, ontype = "on" + type, - handling = jQuery.event.global, namespaces = [], cur = elem; @@ -313,7 +312,7 @@ jQuery.event = { event.stopPropagation(); // Save some time, only trigger if we've ever bound an event for this type - if ( handling[ type ] ) { + if ( jQuery.event.global[ type ] ) { // XXX This code smells terrible. event.js should not be directly // inspecting the data cache jQuery.each( jQuery.cache, function() { @@ -361,7 +360,7 @@ jQuery.event = { } catch ( ieError1 ) {} cur = cur.parentNode || cur.ownerDocument; - } while ( cur && !event.isPropagationStopped() && handling[ type ] ); + } while ( cur && !event.isPropagationStopped() ); // If nobody prevented the default action, do it now if ( !event.isDefaultPrevented() ) { From 879be3d8121179da4e7cafe1d36f7f1b1a97263b Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Wed, 6 Apr 2011 11:34:41 -0400 Subject: [PATCH 115/372] Fix some spacing and comment issues that crept in with the rebase. --- src/event.js | 117 +++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 59 deletions(-) diff --git a/src/event.js b/src/event.js index acaaf281..424ad02f 100644 --- a/src/event.js +++ b/src/event.js @@ -284,19 +284,19 @@ jQuery.event = { namespaces = [], cur = elem; - event = typeof event === "object" ? - // jQuery.Event object - event[ jQuery.expando ] ? event : - // Object literal - jQuery.extend( jQuery.Event(type), event ) : - // Just the event type (string) - jQuery.Event(type); + event = typeof event === "object" ? + // jQuery.Event object + event[ jQuery.expando ] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); - if ( type.indexOf("!") >= 0 ) { - // Exclusive events trigger only for the bare event type (no namespaces) - event.type = type = type.slice(0, -1); - event.exclusive = true; - } + if ( type.indexOf("!") >= 0 ) { + // Exclusive events trigger only for the bare event type (no namespaces) + event.type = type = type.slice(0, -1); + event.exclusive = true; + } if ( type.indexOf(".") >= 0 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split("."); @@ -306,50 +306,50 @@ jQuery.event = { event.namespace = namespaces.join("."); event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); - // Handle a global trigger - if ( !elem ) { - // Don't bubble custom events when global (to avoid too much overhead) - event.stopPropagation(); + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); // Save some time, only trigger if we've ever bound an event for this type if ( jQuery.event.global[ type ] ) { - // XXX This code smells terrible. event.js should not be directly - // inspecting the data cache - jQuery.each( jQuery.cache, function() { - // internalKey variable is just used to make it easier to find - // and potentially change this stuff later; currently it just - // points to jQuery.expando - var internalKey = jQuery.expando, - internalCache = this[ internalKey ]; - if ( internalCache && internalCache.events && internalCache.events[ type ] ) { - jQuery.event.trigger( event, data, internalCache.handle.elem ); - } - }); - } - return; + // XXX This code smells terrible. event.js should not be directly + // inspecting the data cache + jQuery.each( jQuery.cache, function() { + // internalKey variable is just used to make it easier to find + // and potentially change this stuff later; currently it just + // points to jQuery.expando + var internalKey = jQuery.expando, + internalCache = this[ internalKey ]; + if ( internalCache && internalCache.events && internalCache.events[ type ] ) { + jQuery.event.trigger( event, data, internalCache.handle.elem ); + } + }); } + return; + } // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; - } + } // Clean up the event in case it is being reused - event.result = undefined; - event.target = elem; + event.result = undefined; + event.target = elem; // Clone any incoming data and prepend the event, creating the handler arg list - data = jQuery.makeArray( data ); - data.unshift( event ); + data = jQuery.makeArray( data ); + data.unshift( event ); // Fire event on the current element, then bubble up the DOM tree do { var handle = jQuery._data( cur, "handle" ); event.currentTarget = cur; - if ( handle ) { + if ( handle ) { handle.apply( cur, data ); - } + } // Trigger an inline bound script; IE<9 dies on special-char event name try { @@ -397,44 +397,43 @@ jQuery.event = { }, handle: function( event ) { - // It's rare to arrive without handlers to call, so do all setup now. - // Snapshot the handlers list since a called handler may add/remove events. event = jQuery.event.fix( event || window.event ); + // Snapshot the handlers list since a called handler may add/remove events. var handlers = ((jQuery._data( this, "events" ) || {})[ event.type ] || []).slice(0), - all_handlers = !event.exclusive && !event.namespace, + run_all = !event.exclusive && !event.namespace, args = jQuery.makeArray( arguments ); // Use the fix-ed Event rather than the (read-only) native event args[0] = event; event.currentTarget = this; - for ( var j = 0, l = handlers.length; j < l; j++ ) { - var handleObj = handlers[ j ]; + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; // Triggered event must 1) be non-exclusive and have no namespace, or // 2) have namespace(s) a subset or equal to those in the bound event. - if ( all_handlers || event.namespace_re.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; + if ( run_all || event.namespace_re.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, args ); + var ret = handleObj.handler.apply( this, args ); - if ( ret !== undefined ) { - event.result = ret; - if ( ret === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - - if ( event.isImmediatePropagationStopped() ) { - break; + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); } } + + if ( event.isImmediatePropagationStopped() ) { + break; + } } + } return event.result; }, From b7dd8404c52518bc4d71b0e715c506252d651a3f Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Wed, 6 Apr 2011 22:11:58 -0400 Subject: [PATCH 116/372] Fixes #8712. Bubble custom events to the window when they are triggered. Ride that, Cowboy! --- src/event.js | 3 ++- test/unit/event.js | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/event.js b/src/event.js index 424ad02f..0323ffb7 100644 --- a/src/event.js +++ b/src/event.js @@ -359,7 +359,8 @@ jQuery.event = { } } catch ( ieError1 ) {} - cur = cur.parentNode || cur.ownerDocument; + // Bubble up to document, then to window + cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument && window; } while ( cur && !event.isPropagationStopped() ); // If nobody prevented the default action, do it now diff --git a/test/unit/event.js b/test/unit/event.js index 6ad112c0..a26f54d2 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -779,10 +779,11 @@ test("trigger() shortcuts", function() { }); test("trigger() bubbling", function() { - expect(14); + expect(17); - var doc = 0, html = 0, body = 0, main = 0, ap = 0; + var win = 0, doc = 0, html = 0, body = 0, main = 0, ap = 0; + jQuery(window).bind("click", function(e){ win++; }); jQuery(document).bind("click", function(e){ if ( e.target !== document) { doc++; } }); jQuery("html").bind("click", function(e){ html++; }); jQuery("body").bind("click", function(e){ body++; }); @@ -790,15 +791,18 @@ test("trigger() bubbling", function() { jQuery("#ap").bind("click", function(){ ap++; return false; }); jQuery("html").trigger("click"); + equals( win, 1, "HTML bubble" ); equals( doc, 1, "HTML bubble" ); equals( html, 1, "HTML bubble" ); jQuery("body").trigger("click"); + equals( win, 2, "Body bubble" ); equals( doc, 2, "Body bubble" ); equals( html, 2, "Body bubble" ); equals( body, 1, "Body bubble" ); jQuery("#main").trigger("click"); + equals( win, 3, "Main bubble" ); equals( doc, 3, "Main bubble" ); equals( html, 3, "Main bubble" ); equals( body, 2, "Main bubble" ); From bbd9c776ea22296a6807d5b760bd4e82ee5f4414 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Mon, 4 Apr 2011 10:27:31 -0400 Subject: [PATCH 117/372] Fix #8732. Change feature detect for focusin event support, so IE9 won't have duplicate events. --- src/event.js | 2 +- src/support.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/event.js b/src/event.js index 0323ffb7..9a63b5f9 100644 --- a/src/event.js +++ b/src/event.js @@ -850,7 +850,7 @@ function trigger( type, elem, args ) { } // Create "bubbling" focus and blur events -if ( document.addEventListener ) { +if ( !jQuery.support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler while someone wants focusin/focusout diff --git a/src/support.js b/src/support.js index 4c309562..8b950e25 100644 --- a/src/support.js +++ b/src/support.js @@ -226,6 +226,7 @@ jQuery.support.submitBubbles = eventSupported("submit"); jQuery.support.changeBubbles = eventSupported("change"); + jQuery.support.focusinBubbles = document.attachEvent && eventSupported("focusin"); // release memory in IE div = all = a = null; From 75a4bc4a4e55360c7c3c734cbef2558050ed4456 Mon Sep 17 00:00:00 2001 From: jaubourg Date: Thu, 7 Apr 2011 05:07:20 +0200 Subject: [PATCH 118/372] Makes sure each animation tick has the same timestamp for all animations in the batch. --- src/effects.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/effects.js b/src/effects.js index d9e9a8b3..5ff85d13 100644 --- a/src/effects.js +++ b/src/effects.js @@ -11,7 +11,17 @@ var elemdisplay = {}, [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ], // opacity animations [ "opacity" ] - ]; + ], + fxNow; + +function clearFxNow() { + fxNow = undefined; +} + +function createFxNow() { + setTimeout( clearFxNow, 0 ); + return ( fxNow = jQuery.now() ); +} jQuery.fn.extend({ show: function( speed, easing, callback ) { @@ -349,7 +359,7 @@ jQuery.fx.prototype = { var self = this, fx = jQuery.fx; - this.startTime = jQuery.now(); + this.startTime = fxNow || createFxNow(); this.start = from; this.end = to; this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" ); @@ -394,7 +404,8 @@ jQuery.fx.prototype = { // Each step of an animation step: function( gotoEnd ) { - var t = jQuery.now(), done = true; + var t = fxNow || createFxNow(), + done = true; if ( gotoEnd || t >= this.options.duration + this.startTime ) { this.now = this.end; From 2f11ba7c98d4d2d2157b7ae554f57f1798b04306 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Wed, 6 Apr 2011 23:41:47 -0400 Subject: [PATCH 119/372] Allow specific custom events to exit trigger early if there are no handlers bound for that type. --- src/event.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/event.js b/src/event.js index 9a63b5f9..d39bf7ac 100644 --- a/src/event.js +++ b/src/event.js @@ -276,6 +276,14 @@ jQuery.event = { } } }, + + // Events that are safe to short-circuit if no handlers are attached. + // Native DOM events should not be added, they may have inline handlers. + customEvent: { + "getData": true, + "setData": true, + "changeData": true + }, trigger: function( event, data, elem ) { // Event object or event type @@ -293,7 +301,7 @@ jQuery.event = { jQuery.Event(type); if ( type.indexOf("!") >= 0 ) { - // Exclusive events trigger only for the bare event type (no namespaces) + // Exclusive events trigger only for the bare event type (no namespaces) event.type = type = type.slice(0, -1); event.exclusive = true; } @@ -305,7 +313,12 @@ jQuery.event = { } event.namespace = namespaces.join("."); event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); - + + if ( jQuery.event.customEvent[ type ] && !jQuery.event.global[ type ] ) { + // No jQuery handlers for this event type, and it can't have inline handlers + return; + } + // Handle a global trigger if ( !elem ) { // Don't bubble custom events when global (to avoid too much overhead) From bb99899ca0de93dd12f5a53f409ff6f72bfcf94c Mon Sep 17 00:00:00 2001 From: jaubourg Date: Thu, 7 Apr 2011 05:49:32 +0200 Subject: [PATCH 120/372] Adds always and chain methods to deferreds. --- src/deferred.js | 32 +++- test/unit/deferred.js | 428 +++++++++++++++++++++++++++--------------- 2 files changed, 307 insertions(+), 153 deletions(-) diff --git a/src/deferred.js b/src/deferred.js index 90f9c808..feaccaef 100644 --- a/src/deferred.js +++ b/src/deferred.js @@ -1,7 +1,7 @@ (function( jQuery ) { var // Promise methods - promiseMethods = "then done fail isResolved isRejected promise".split( " " ), + promiseMethods = "done fail isResolved isRejected promise then always chain".split( " " ), // Static reference to slice sliceDeferred = [].slice; @@ -100,10 +100,38 @@ jQuery.extend({ deferred.done( doneCallbacks ).fail( failCallbacks ); return this; }, + always: function() { + return deferred.done.apply( deferred, arguments ).fail.apply( this, arguments ); + }, fail: failDeferred.done, rejectWith: failDeferred.resolveWith, reject: failDeferred.resolve, isRejected: failDeferred.isResolved, + // Chain + chain: function( fnDone, fnFail ) { + return jQuery.Deferred(function( newDefer ) { + jQuery.each( { + done: [ fnDone, "resolve" ], + fail: [ fnFail, "reject" ] + }, function( handler, data ) { + var fn = data[ 0 ], + action = data[ 1 ], + returned; + if ( jQuery.isFunction( fn ) ) { + deferred[ handler ](function() { + returned = fn.apply( this, arguments ); + if ( jQuery.isFunction( returned.promise ) ) { + returned.promise().then( newDefer.resolve, newDefer.reject ); + } else { + newDefer[ action ]( returned ); + } + }); + } else { + deferred[ handler ]( newDefer[ action ] ); + } + } ); + }).promise(); + }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { @@ -169,4 +197,4 @@ jQuery.extend({ } }); -})( jQuery ); +})( jQuery ); \ No newline at end of file diff --git a/test/unit/deferred.js b/test/unit/deferred.js index 6ba4767a..c1ed7c57 100644 --- a/test/unit/deferred.js +++ b/test/unit/deferred.js @@ -1,153 +1,273 @@ module("deferred", { teardown: moduleTeardown }); -test("jQuery._Deferred()", function() { +jQuery.each( [ "", " - new operator" ], function( _, withNew ) { - expect( 11 ); - - var deferred, - object, - test; - - deferred = jQuery._Deferred(); - - test = false; - - deferred.done( function( value ) { - equals( value , "value" , "Test pre-resolve callback" ); - test = true; - } ); - - deferred.resolve( "value" ); - - ok( test , "Test pre-resolve callbacks called right away" ); - - test = false; - - deferred.done( function( value ) { - equals( value , "value" , "Test post-resolve callback" ); - test = true; - } ); - - ok( test , "Test post-resolve callbacks called right away" ); - - deferred.cancel(); - - test = true; - - deferred.done( function() { - ok( false , "Cancel was ignored" ); - test = false; - } ); - - ok( test , "Test cancel" ); - - deferred = jQuery._Deferred().resolve(); - - try { - deferred.done( function() { - throw "Error"; - } , function() { - ok( true , "Test deferred do not cancel on exception" ); - } ); - } catch( e ) { - strictEqual( e , "Error" , "Test deferred propagates exceptions"); - deferred.done(); + function createDeferred() { + return withNew ? new jQuery._Deferred() : jQuery._Deferred(); } - test = ""; - deferred = jQuery._Deferred().done( function() { + test("jQuery._Deferred" + withNew, function() { - test += "A"; + expect( 11 ); - }, function() { + var deferred, + object, + test; - test += "B"; + deferred = createDeferred(); - } ).resolve(); + test = false; - strictEqual( test , "AB" , "Test multiple done parameters" ); + deferred.done( function( value ) { + equals( value , "value" , "Test pre-resolve callback" ); + test = true; + } ); - test = ""; + deferred.resolve( "value" ); - deferred.done( function() { + ok( test , "Test pre-resolve callbacks called right away" ); + + test = false; + + deferred.done( function( value ) { + equals( value , "value" , "Test post-resolve callback" ); + test = true; + } ); + + ok( test , "Test post-resolve callbacks called right away" ); + + deferred.cancel(); + + test = true; + + deferred.done( function() { + ok( false , "Cancel was ignored" ); + test = false; + } ); + + ok( test , "Test cancel" ); + + deferred = createDeferred().resolve(); + + try { + deferred.done( function() { + throw "Error"; + } , function() { + ok( true , "Test deferred do not cancel on exception" ); + } ); + } catch( e ) { + strictEqual( e , "Error" , "Test deferred propagates exceptions"); + deferred.done(); + } + + test = ""; + deferred = createDeferred().done( function() { + + test += "A"; + + }, function() { + + test += "B"; + + } ).resolve(); + + strictEqual( test , "AB" , "Test multiple done parameters" ); + + test = ""; deferred.done( function() { - test += "C"; + deferred.done( function() { + test += "C"; + + } ); + + test += "A"; + + }, function() { + + test += "B"; } ); - test += "A"; + strictEqual( test , "ABC" , "Test done callbacks order" ); - }, function() { + deferred = createDeferred(); - test += "B"; + deferred.resolveWith( jQuery , [ document ] ).done( function( doc ) { + ok( this === jQuery && arguments.length === 1 && doc === document , "Test fire context & args" ); + }); + + // #8421 + deferred = createDeferred(); + deferred.resolveWith().done(function() { + ok( true, "Test resolveWith can be called with no argument" ); + }); + }); +} ); + +jQuery.each( [ "", " - new operator" ], function( _, withNew ) { + + function createDeferred( fn ) { + return withNew ? new jQuery.Deferred( fn ) : jQuery.Deferred( fn ); + } + + test("jQuery.Deferred" + withNew, function() { + + expect( 8 ); + + createDeferred().resolve().then( function() { + ok( true , "Success on resolve" ); + ok( this.isResolved(), "Deferred is resolved" ); + }, function() { + ok( false , "Error on resolve" ); + }).always( function() { + ok( true , "Always callback on resolve" ); + }); + + createDeferred().reject().then( function() { + ok( false , "Success on reject" ); + }, function() { + ok( true , "Error on reject" ); + ok( this.isRejected(), "Deferred is rejected" ); + }).always( function() { + ok( true , "Always callback on reject" ); + }); + + createDeferred( function( defer ) { + ok( this === defer , "Defer passed as this & first argument" ); + this.resolve( "done" ); + }).then( function( value ) { + strictEqual( value , "done" , "Passed function executed" ); + }); + }); +} ); + +test( "jQuery.Deferred.chain - filtering (done)", function() { + + expect(3); + + var defer = jQuery.Deferred(), + chained = defer.chain(function( a, b ) { + return a * b; + }), + value1, + value2, + value3; + + chained.done(function( result ) { + value3 = result; + }); + + defer.done(function( a, b ) { + value1 = a; + value2 = b; + }); + + defer.resolve( 2, 3 ); + + strictEqual( value1, 2, "first resolve value ok" ); + strictEqual( value2, 3, "second resolve value ok" ); + strictEqual( value3, 6, "result of filter ok" ); + + jQuery.Deferred().reject().chain(function() { + ok( false, "chain should not be called on reject" ); + }); +}); + +test( "jQuery.Deferred.chain - filtering (fail)", function() { + + expect(3); + + var defer = jQuery.Deferred(), + chained = defer.chain( null, function( a, b ) { + return a * b; + } ), + value1, + value2, + value3; + + chained.fail(function( result ) { + value3 = result; + }); + + defer.fail(function( a, b ) { + value1 = a; + value2 = b; + }); + + defer.reject( 2, 3 ); + + strictEqual( value1, 2, "first reject value ok" ); + strictEqual( value2, 3, "second reject value ok" ); + strictEqual( value3, 6, "result of filter ok" ); + + jQuery.Deferred().resolve().chain( null, function() { + ok( false, "chain should not be called on resolve" ); } ); - - strictEqual( test , "ABC" , "Test done callbacks order" ); - - deferred = jQuery._Deferred(); - - deferred.resolveWith( jQuery , [ document ] ).done( function( doc ) { - ok( this === jQuery && arguments.length === 1 && doc === document , "Test fire context & args" ); - }); - - // #8421 - deferred = jQuery._Deferred(); - deferred.resolveWith().done(function() { - ok( true, "Test resolveWith can be called with no argument" ); - }); }); -test("jQuery.Deferred()", function() { +test( "jQuery.Deferred.chain - deferred (done)", function() { - expect( 10 ); + expect(3); - jQuery.Deferred( function( defer ) { - strictEqual( this , defer , "Defer passed as this & first argument" ); - this.resolve( "done" ); - }).then( function( value ) { - strictEqual( value , "done" , "Passed function executed" ); + var defer = jQuery.Deferred(), + chained = defer.chain(function( a, b ) { + return jQuery.Deferred(function( defer ) { + defer.reject( a * b ); + }); + }), + value1, + value2, + value3; + + chained.fail(function( result ) { + value3 = result; }); - jQuery.Deferred().resolve().then( function() { - ok( true , "Success on resolve" ); - }, function() { - ok( false , "Error on resolve" ); + defer.done(function( a, b ) { + value1 = a; + value2 = b; }); - jQuery.Deferred().reject().then( function() { - ok( false , "Success on reject" ); - }, function() { - ok( true , "Error on reject" ); - }); + defer.resolve( 2, 3 ); - ( new jQuery.Deferred( function( defer ) { - strictEqual( this , defer , "Defer passed as this & first argument (new)" ); - this.resolve( "done" ); - }) ).then( function( value ) { - strictEqual( value , "done" , "Passed function executed (new)" ); - }); - - ( new jQuery.Deferred() ).resolve().then( function() { - ok( true , "Success on resolve (new)" ); - }, function() { - ok( false , "Error on resolve (new)" ); - }); - - ( new jQuery.Deferred() ).reject().then( function() { - ok( false , "Success on reject (new)" ); - }, function() { - ok( true , "Error on reject (new)" ); - }); - - var tmp = jQuery.Deferred(); - - strictEqual( tmp.promise() , tmp.promise() , "Test deferred always return same promise" ); - strictEqual( tmp.promise() , tmp.promise().promise() , "Test deferred's promise always return same promise as deferred" ); + strictEqual( value1, 2, "first resolve value ok" ); + strictEqual( value2, 3, "second resolve value ok" ); + strictEqual( value3, 6, "result of filter ok" ); }); -test("jQuery.when()", function() { +test( "jQuery.Deferred.chain - deferred (fail)", function() { + + expect(3); + + var defer = jQuery.Deferred(), + chained = defer.chain( null, function( a, b ) { + return jQuery.Deferred(function( defer ) { + defer.resolve( a * b ); + }); + } ), + value1, + value2, + value3; + + chained.done(function( result ) { + value3 = result; + }); + + defer.fail(function( a, b ) { + value1 = a; + value2 = b; + }); + + defer.reject( 2, 3 ); + + strictEqual( value1, 2, "first reject value ok" ); + strictEqual( value2, 3, "second reject value ok" ); + strictEqual( value3, 6, "result of filter ok" ); +}); + +test( "jQuery.when" , function() { expect( 23 ); @@ -166,57 +286,63 @@ test("jQuery.when()", function() { } , function( message , value ) { - ok( jQuery.isFunction( jQuery.when( value ).then( function( resolveValue ) { + ok( jQuery.isFunction( jQuery.when( value ).done(function( resolveValue ) { strictEqual( resolveValue , value , "Test the promise was resolved with " + message ); - } ).promise ) , "Test " + message + " triggers the creation of a new Promise" ); + }).promise ) , "Test " + message + " triggers the creation of a new Promise" ); } ); - ok( jQuery.isFunction( jQuery.when().then( function( resolveValue ) { + ok( jQuery.isFunction( jQuery.when().done(function( resolveValue ) { strictEqual( resolveValue , undefined , "Test the promise was resolved with no parameter" ); - } ).promise ) , "Test calling when with no parameter triggers the creation of a new Promise" ); + }).promise ) , "Test calling when with no parameter triggers the creation of a new Promise" ); var cache, i; for( i = 1 ; i < 4 ; i++ ) { jQuery.when( cache || jQuery.Deferred( function() { this.resolve( i ); - }) ).then( function( value ) { + }) ).done(function( value ) { strictEqual( value , 1 , "Function executed" + ( i > 1 ? " only once" : "" ) ); cache = value; - }, function() { - ok( false , "Fail called" ); }); } }); -test("jQuery.when() - joined", function() { +test("jQuery.when - joined", function() { - expect(8); + expect(25); - jQuery.when( 1, 2, 3 ).done( function( a, b, c ) { - strictEqual( a , 1 , "Test first param is first resolved value - non-observables" ); - strictEqual( b , 2 , "Test second param is second resolved value - non-observables" ); - strictEqual( c , 3 , "Test third param is third resolved value - non-observables" ); - }).fail( function() { - ok( false , "Test the created deferred was resolved - non-observables"); - }); + var deferreds = { + value: 1, + success: jQuery.Deferred().resolve( 1 ), + error: jQuery.Deferred().reject( 0 ), + futureSuccess: jQuery.Deferred(), + futureError: jQuery.Deferred() + }, + willSucceed = { + value: true, + success: true, + error: false, + futureSuccess: true, + futureError: false + }; - var successDeferred = jQuery.Deferred().resolve( 1 , 2 , 3 ), - errorDeferred = jQuery.Deferred().reject( "error" , "errorParam" ); - - jQuery.when( 1 , successDeferred , 3 ).done( function( a, b, c ) { - strictEqual( a , 1 , "Test first param is first resolved value - resolved observable" ); - same( b , [ 1 , 2 , 3 ] , "Test second param is second resolved value - resolved observable" ); - strictEqual( c , 3 , "Test third param is third resolved value - resolved observable" ); - }).fail( function() { - ok( false , "Test the created deferred was resolved - resolved observable"); - }); - - jQuery.when( 1 , errorDeferred , 3 ).done( function() { - ok( false , "Test the created deferred was rejected - rejected observable"); - }).fail( function( error , errorParam ) { - strictEqual( error , "error" , "Test first param is first rejected value - rejected observable" ); - strictEqual( errorParam , "errorParam" , "Test second param is second rejected value - rejected observable" ); - }); + jQuery.each( deferreds, function( id1, defer1 ) { + jQuery.each( deferreds, function( id2, defer2 ) { + var shouldResolve = willSucceed[ id1 ] && willSucceed[ id2 ], + expected = shouldResolve ? [ 1, 1 ] : [ 0, undefined ], + code = id1 + "/" + id2; + jQuery.when( defer1, defer2 ).done(function( a, b ) { + if ( shouldResolve ) { + same( [ a, b ], expected, code + " => resolve" ); + } + }).fail(function( a, b ) { + if ( !shouldResolve ) { + same( [ a, b ], expected, code + " => resolve" ); + } + }); + } ); + } ); + deferreds.futureSuccess.resolve( 1 ); + deferreds.futureError.reject( 0 ); }); From 4552d135f404b78f4fa1494a3de2911b2e2e4773 Mon Sep 17 00:00:00 2001 From: jaubourg Date: Thu, 7 Apr 2011 06:00:52 +0200 Subject: [PATCH 121/372] Adds fn.promise as a mean to observe the completion of animations on a set of elements. Only queued animations are handled for now, non-queued animations support coming soon. Effects unit tests updated to test the feature (needs more testing though). --- src/queue.js | 45 +++++++++++++++++++++++++++++++++++++++++++- test/unit/effects.js | 41 ++++++++++++++++++++++------------------ 2 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/queue.js b/src/queue.js index 9e3e2fb5..701d06ad 100644 --- a/src/queue.js +++ b/src/queue.js @@ -28,7 +28,8 @@ jQuery.extend({ type = type || "fx"; var queue = jQuery.queue( elem, type ), - fn = queue.shift(); + fn = queue.shift(), + defer; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { @@ -49,6 +50,17 @@ jQuery.extend({ if ( !queue.length ) { jQuery.removeData( elem, type + "queue", true ); + // Look if we have observers and resolve if needed + if (( defer = jQuery.data( elem, type + "defer", undefined, true ) )) { + // Give room for hard-coded callbacks to fire first + // and eventually add another animation on the element + setTimeout( function() { + if ( !jQuery.data( elem, type + "queue", undefined, true ) ) { + jQuery.removeData( elem, type + "defer", true ); + defer.resolve(); + } + }, 0 ); + } } } }); @@ -93,6 +105,37 @@ jQuery.fn.extend({ 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, object ) { + if ( typeof type !== "string" ) { + object = type; + type = undefined; + } + type = type || "fx"; + var defer = jQuery.Deferred(), + elements = this, + i = elements.length, + count = 1, + deferDataKey = type + "defer", + queueDataKey = type + "queue"; + function resolve() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + } + while( i-- ) { + if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) || + jQuery.data( elements[ i ], queueDataKey, undefined, true ) && + jQuery.data( elements[ i ], deferDataKey, jQuery._Deferred(), true ) )) { + count++; + tmp.done( resolve ); + } + } + resolve(); + return defer.promise(); } }); diff --git a/test/unit/effects.js b/test/unit/effects.js index c0a812f4..4f678511 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -717,59 +717,64 @@ jQuery.each( { var anim = { width: t_w, height: t_h, opacity: t_o }; - elem.animate(anim, 50, function(){ + elem.animate(anim, 50); + + jQuery.when( elem ).done(function( elem ){ + + elem = elem[ 0 ]; + if ( t_w == "show" ) - equals( this.style.display, "block", "Showing, display should block: " + this.style.display); + equals( elem.style.display, "block", "Showing, display should block: " + elem.style.display); if ( t_w == "hide"||t_w == "show" ) - ok(f_w === "" ? this.style.width === f_w : this.style.width.indexOf(f_w) === 0, "Width must be reset to " + f_w + ": " + this.style.width); + ok(f_w === "" ? elem.style.width === f_w : elem.style.width.indexOf(f_w) === 0, "Width must be reset to " + f_w + ": " + elem.style.width); if ( t_h == "hide"||t_h == "show" ) - ok(f_h === "" ? this.style.height === f_h : this.style.height.indexOf(f_h) === 0, "Height must be reset to " + f_h + ": " + this.style.height); + ok(f_h === "" ? elem.style.height === f_h : elem.style.height.indexOf(f_h) === 0, "Height must be reset to " + f_h + ": " + elem.style.height); - var cur_o = jQuery.style(this, "opacity"); + var cur_o = jQuery.style(elem, "opacity"); if ( t_o == "hide" || t_o == "show" ) equals(cur_o, f_o, "Opacity must be reset to " + f_o + ": " + cur_o); if ( t_w == "hide" ) - equals(this.style.display, "none", "Hiding, display should be none: " + this.style.display); + equals(elem.style.display, "none", "Hiding, display should be none: " + elem.style.display); if ( t_o.constructor == Number ) { equals(cur_o, t_o, "Final opacity should be " + t_o + ": " + cur_o); - ok(jQuery.css(this, "opacity") != "" || cur_o == t_o, "Opacity should be explicitly set to " + t_o + ", is instead: " + cur_o); + ok(jQuery.css(elem, "opacity") != "" || cur_o == t_o, "Opacity should be explicitly set to " + t_o + ", is instead: " + cur_o); } if ( t_w.constructor == Number ) { - equals(this.style.width, t_w + "px", "Final width should be " + t_w + ": " + this.style.width); + equals(elem.style.width, t_w + "px", "Final width should be " + t_w + ": " + elem.style.width); - var cur_w = jQuery.css(this,"width"); + var cur_w = jQuery.css(elem,"width"); - ok(this.style.width != "" || cur_w == t_w, "Width should be explicitly set to " + t_w + ", is instead: " + cur_w); + ok(elem.style.width != "" || cur_w == t_w, "Width should be explicitly set to " + t_w + ", is instead: " + cur_w); } if ( t_h.constructor == Number ) { - equals(this.style.height, t_h + "px", "Final height should be " + t_h + ": " + this.style.height); + equals(elem.style.height, t_h + "px", "Final height should be " + t_h + ": " + elem.style.height); - var cur_h = jQuery.css(this,"height"); + var cur_h = jQuery.css(elem,"height"); - ok(this.style.height != "" || cur_h == t_h, "Height should be explicitly set to " + t_h + ", is instead: " + cur_w); + ok(elem.style.height != "" || cur_h == t_h, "Height should be explicitly set to " + t_h + ", is instead: " + cur_w); } if ( t_h == "show" ) { - var old_h = jQuery.css(this, "height"); - jQuery(this).append("
    Some more text
    and some more..."); + var old_h = jQuery.css(elem, "height"); + jQuery(elem).append("
    Some more text
    and some more..."); if ( /Auto/.test( fn ) ) { - notEqual(jQuery.css(this, "height"), old_h, "Make sure height is auto."); + notEqual(jQuery.css(elem, "height"), old_h, "Make sure height is auto."); } else { - equals(jQuery.css(this, "height"), old_h, "Make sure height is not auto."); + equals(jQuery.css(elem, "height"), old_h, "Make sure height is not auto."); } } // manually remove generated element - jQuery(this).remove(); + jQuery(elem).remove(); start(); }); From f3c6077da02f080f09d73ec4d8a8029f76654c2b Mon Sep 17 00:00:00 2001 From: jaubourg Date: Thu, 7 Apr 2011 06:47:15 +0200 Subject: [PATCH 122/372] Rewrite of globalEval. Uses window.execScript or window.eval with a trick to ensure proper context. Unit tests added. --- src/core.js | 27 ++++++++++----------------- test/unit/core.js | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/core.js b/src/core.js index a893fc9b..7f63012a 100644 --- a/src/core.js +++ b/src/core.js @@ -561,24 +561,17 @@ jQuery.extend({ noop: function() {}, - // Evalulates a script in a global context + // 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 && 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 ); + if ( data && rnotwhite.test( 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 ); } }, diff --git a/test/unit/core.js b/test/unit/core.js index 03325ab7..79710025 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -172,6 +172,26 @@ test("selector state", function() { ); }); +test( "globalEval", function() { + + expect( 3 ); + + jQuery.globalEval( "var globalEvalTest = true;" ); + ok( window.globalEvalTest, "Test variable declarations are global" ); + + window.globalEvalTest = false; + + jQuery.globalEval( "globalEvalTest = true;" ); + ok( window.globalEvalTest, "Test variable assignments are global" ); + + window.globalEvalTest = false; + + jQuery.globalEval( "this.globalEvalTest = true;" ); + ok( window.globalEvalTest, "Test context (this) is the window object" ); + + window.globalEvalTest = undefined; +}); + if ( !isLocal ) { test("browser", function() { stop(); From c1dcad69427b78f3e70628ab1444f42033ee593a Mon Sep 17 00:00:00 2001 From: jaubourg Date: Thu, 7 Apr 2011 06:51:37 +0200 Subject: [PATCH 123/372] Rewrite of the support module. We use a temporary body element in order not to have to wait for the document to be ready for boxModel-related support tests. --- src/support.js | 273 ++++++++++++++++++++++++------------------------- 1 file changed, 132 insertions(+), 141 deletions(-) diff --git a/src/support.js b/src/support.js index 4c309562..d5625bed 100644 --- a/src/support.js +++ b/src/support.js @@ -1,44 +1,58 @@ (function( jQuery ) { -(function() { +jQuery.support = (function() { - jQuery.support = {}; + var div = document.createElement( "div" ), + all, + a, + select, + opt, + input, + support, + fragment, + body, + bodyStyle, + tds, + events, + eventName, + i, + isSupported; - var div = document.createElement("div"); - - div.style.display = "none"; + // Preliminary tests div.innerHTML = "
    a"; - var all = div.getElementsByTagName("*"), - a = div.getElementsByTagName("a")[0], - select = document.createElement("select"), - opt = select.appendChild( document.createElement("option") ), - input = div.getElementsByTagName("input")[0]; + all = div.getElementsByTagName( "*" ); + a = div.getElementsByTagName( "a" )[ 0 ]; // Can't get basic test support if ( !all || !all.length || !a ) { - return; + return {}; } - jQuery.support = { + // First batch of supports tests + select = document.createElement( "select" ); + opt = select.appendChild( document.createElement("option") ); + input = div.getElementsByTagName( "input" )[ 0 ]; + + support = { // IE strips leading whitespace when .innerHTML is used - leadingWhitespace: div.firstChild.nodeType === 3, + 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, + 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, + htmlSerialize: !!div.getElementsByTagName( "link" ).length, // Get the style information from getAttribute - // (IE uses .cssText insted) + // (IE uses .cssText instead) style: /red/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) - hrefNormalized: a.getAttribute("href") === "/a", + hrefNormalized: ( a.getAttribute( "href" ) === "/a" ), // Make sure that element opacity exists // (IE uses filter instead) @@ -59,175 +73,152 @@ optSelected: opt.selected, // Will be defined later + submitBubbles: true, + changeBubbles: true, deleteExpando: true, - optDisabled: false, - checkClone: false, noCloneEvent: true, - noCloneChecked: true, - boxModel: null, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, - reliableHiddenOffsets: true, reliableMarginRight: true }; + // Make sure checked status is properly cloned input.checked = true; - jQuery.support.noCloneChecked = input.cloneNode( true ).checked; + support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled - // (WebKit marks them as diabled) + // (WebKit marks them as disabled) select.disabled = true; - jQuery.support.optDisabled = !opt.disabled; - - var _scriptEval = null; - jQuery.support.scriptEval = function() { - if ( _scriptEval === null ) { - var root = document.documentElement, - script = document.createElement("script"), - id = "script" + jQuery.now(); - - // 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) - try { - script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); - } catch(e) {} - - root.insertBefore( script, root.firstChild ); - - if ( window[ id ] ) { - _scriptEval = true; - delete window[ id ]; - } else { - _scriptEval = false; - } - - root.removeChild( script ); - } - - return _scriptEval; - }; + support.optDisabled = !opt.disabled; // Test to see if it's possible to delete an expando from an element // Fails in Internet Explorer try { delete div.test; - - } catch(e) { - jQuery.support.deleteExpando = false; + } catch( e ) { + support.deleteExpando = false; } if ( !div.addEventListener && div.attachEvent && div.fireEvent ) { - div.attachEvent("onclick", function click() { + 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"); + support.noCloneEvent = false; + div.detachEvent( "onclick", click ); + } ); + div.cloneNode( true ).fireEvent( "onclick" ); } - div = document.createElement("div"); div.innerHTML = ""; - var fragment = document.createDocumentFragment(); + 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; + support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; + + div.innerHTML = ""; // 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"), - body = document.getElementsByTagName("body")[0]; + div.style.width = div.style.paddingLeft = "1px"; - // Frameset documents with no body should not run this code - if ( !body ) { - return; - } + // We use our own, invisible, body + body = document.createElement( "body" ); + bodyStyle = { + visibility: "hidden", + width: 0, + height: 0, + border: 0, + margin: 0 + }; + for ( i in bodyStyle ) { + body.style[ i ] = bodyStyle[ i ]; + } + body.appendChild( div ); + document.documentElement.appendChild( body ); - div.style.width = div.style.paddingLeft = "1px"; - body.appendChild( div ); - jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + support.boxModel = div.offsetWidth === 2; - if ( "zoom" in div.style ) { - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - // (IE < 8 does this) - div.style.display = "inline"; - div.style.zoom = 1; - jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2; + if ( "zoom" in div.style ) { + // Check if natively block-level elements act like inline-block + // elements when setting their display to 'inline' and giving + // them layout + // (IE < 8 does this) + div.style.display = "inline"; + div.style.zoom = 1; + support.inlineBlockNeedsLayout = ( div.offsetWidth === 2 ); - // Check if elements with layout shrink-wrap their children - // (IE 6 does this) - div.style.display = ""; - div.innerHTML = "
    "; - jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2; - } + // Check if elements with layout shrink-wrap their children + // (IE 6 does this) + div.style.display = ""; + div.innerHTML = "
    "; + support.shrinkWrapBlocks = ( div.offsetWidth !== 2 ); + } - div.innerHTML = "
    t
    "; - var tds = div.getElementsByTagName("td"); + div.innerHTML = "
    t
    "; + tds = div.getElementsByTagName( "td" ); - // Check if table cells still have offsetWidth/Height when they are set - // to display:none and there are still other visible table cells in a - // table row; if so, offsetWidth/Height are not reliable for use when - // determining if an element has been hidden directly using - // display:none (it is still safe to use offsets if a parent element is - // hidden; don safety goggles and see bug #4512 for more information). - // (only IE 8 fails this test) - jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0; + // Check if table cells still have offsetWidth/Height when they are set + // to display:none and there are still other visible table cells in a + // table row; if so, offsetWidth/Height are not reliable for use when + // determining if an element has been hidden directly using + // display:none (it is still safe to use offsets if a parent element is + // hidden; don safety goggles and see bug #4512 for more information). + // (only IE 8 fails this test) + isSupported = ( tds[ 0 ].offsetHeight === 0 ); - tds[0].style.display = ""; - tds[1].style.display = "none"; + tds[ 0 ].style.display = ""; + tds[ 1 ].style.display = "none"; - // Check if empty table cells still have offsetWidth/Height - // (IE < 8 fail this test) - jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0; - div.innerHTML = ""; + // Check if empty table cells still have offsetWidth/Height + // (IE < 8 fail this test) + support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); + div.innerHTML = ""; - // Check if div with explicit width and no margin-right incorrectly - // gets computed margin-right based on width of container. For more - // info see bug #3333 - // Fails in WebKit before Feb 2011 nightlies - // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right - if ( document.defaultView && document.defaultView.getComputedStyle ) { - div.style.width = "1px"; - div.style.marginRight = "0"; - jQuery.support.reliableMarginRight = ( parseInt(document.defaultView.getComputedStyle(div, null).marginRight, 10) || 0 ) === 0; - } + // Check if div with explicit width and no margin-right incorrectly + // gets computed margin-right based on width of container. For more + // info see bug #3333 + // Fails in WebKit before Feb 2011 nightlies + // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right + if ( document.defaultView && document.defaultView.getComputedStyle ) { + div.style.width = "1px"; + div.style.marginRight = "0"; + support.reliableMarginRight = + ( parseInt( document.defaultView.getComputedStyle(div).marginRight, 10 ) || 0 ) === 0; + } - body.removeChild( div ).style.display = "none"; - div = tds = null; - }); + // Remove the body element we added + document.documentElement.removeChild( body ); // 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; - - // We only care about the case where non-standard event systems - // are used, namely in IE. Short-circuiting here helps us to - // avoid an eval call (in setAttribute) which can cause CSP - // to go haywire. See: https://developer.mozilla.org/en/Security/CSP - if ( !el.attachEvent ) { - return true; + // We only care about the case where non-standard event systems + // are used, namely in IE. Short-circuiting here helps us to + // avoid an eval call (in setAttribute) which can cause CSP + // to go haywire. See: https://developer.mozilla.org/en/Security/CSP + if ( div.attachEvent ) { + for( i in { + submit: 1, + change: 1, + focusin: 1 + } ) { + eventName = "on" + i; + isSupported = ( eventName in div ); + if ( !isSupported ) { + div.setAttribute( eventName, "return;" ); + isSupported = ( typeof div[ eventName ] === "function" ); + } + support[ i + "Bubbles" ] = isSupported; } - - var isSupported = (eventName in el); - if ( !isSupported ) { - el.setAttribute(eventName, "return;"); - isSupported = typeof el[eventName] === "function"; - } - return isSupported; - }; - - jQuery.support.submitBubbles = eventSupported("submit"); - jQuery.support.changeBubbles = eventSupported("change"); + } // release memory in IE - div = all = a = null; + body = div = all = a = tds = undefined; + + return support; })(); + +// Keep track of boxModel +jQuery.boxModel = jQuery.support.boxModel; + })( jQuery ); From 14193e449efe76105df61d745ebd7031dd7fe783 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Wed, 2 Feb 2011 21:57:44 -0500 Subject: [PATCH 124/372] Create jQuery.holdReady(true/false) method to encapsulate jQuery.readyWait++ / jQuery.ready(true) logic. Fix problem where jQuery.ready may trigger twice, causing the (unsupported) document.onready to run twice. Fixes #8803 . --- src/core.js | 18 +++++++++++------- test/data/readywaitloader.js | 6 +++--- test/readywait.html | 18 ++++++++++-------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/core.js b/src/core.js index a893fc9b..b81fa764 100644 --- a/src/core.js +++ b/src/core.js @@ -374,15 +374,19 @@ jQuery.extend({ // 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 ) { - // A third-party is pushing the ready event forwards - if ( wait === true ) { - jQuery.readyWait--; - } - - // Make sure that the DOM is not already loaded - if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) { + // Either a released hold or an DOMready/load event and not yet ready + if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) { // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready, 1 ); diff --git a/test/data/readywaitloader.js b/test/data/readywaitloader.js index 483e07c4..e07dac7a 100644 --- a/test/data/readywaitloader.js +++ b/test/data/readywaitloader.js @@ -1,14 +1,14 @@ -// Simple script loader that uses jQuery.readyWait +// Simple script loader that uses jQuery.readyWait via jQuery.holdReady() //Hold on jQuery! -jQuery.readyWait++; +jQuery.holdReady(true); var readyRegExp = /^(complete|loaded)$/; function assetLoaded( evt ){ var node = evt.currentTarget || evt.srcElement; if ( evt.type === "load" || readyRegExp.test(node.readyState) ) { - jQuery.ready(true); + jQuery.holdReady(false); } } diff --git a/test/readywait.html b/test/readywait.html index 4f124767..b4d8111e 100644 --- a/test/readywait.html +++ b/test/readywait.html @@ -1,13 +1,13 @@ - jQuery.readyWait Test + jQuery.holdReady Test @@ -147,6 +151,7 @@ test element + Float test. diff --git a/test/unit/event.js b/test/unit/event.js index b46ef9eb..491396f9 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -776,6 +776,9 @@ test("trigger() shortcuts", function() { // manually clean up detached elements elem.remove(); + + // test that special handlers do not blow up with VML elements (#7071) + jQuery("#oval").click().keydown(); }); test("trigger() bubbling", function() { From 352715bd0802e2df041f86e1a82669574183ec04 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Tue, 12 Apr 2011 17:46:15 -0400 Subject: [PATCH 174/372] Use explicit "new jQuery.Event" to avoid double-function-call overhead. --- src/event.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/event.js b/src/event.js index b8a2e37e..5e2baf0d 100644 --- a/src/event.js +++ b/src/event.js @@ -314,9 +314,9 @@ jQuery.event = { // jQuery.Event object event[ jQuery.expando ] ? event : // Object literal - jQuery.extend( jQuery.Event(type), event ) : + jQuery.extend( new jQuery.Event(type), event ) : // Just the event type (string) - jQuery.Event(type); + new jQuery.Event(type); event.namespace = namespaces.join("."); event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); event.exclusive = exclusive; @@ -989,7 +989,7 @@ jQuery.fn.extend({ triggerHandler: function( type, data ) { if ( this[0] ) { - var event = jQuery.Event( type ); + var event = new jQuery.Event( type ); event.preventDefault(); event.stopPropagation(); jQuery.event.trigger( event, data, this[0] ); From 73f9ab67058d2dc14ab81c62bd9b228b0e1cad93 Mon Sep 17 00:00:00 2001 From: timmywil Date: Tue, 12 Apr 2011 18:30:21 -0400 Subject: [PATCH 175/372] JSLint failed due to function created within for loop --- src/manipulation.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/manipulation.js b/src/manipulation.js index 52d59d83..711cb5e8 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -553,6 +553,8 @@ jQuery.extend({ }, clean: function( elems, context, fragment, scripts ) { + var checkScriptType; + context = context || document; // !context.createElement fails in IE with an error but returns typeof 'object' @@ -630,15 +632,16 @@ jQuery.extend({ } if ( fragment ) { + checkScriptType = function( elem ) { + return !elem.type || rscriptType.test( elem.type ); + }; for ( i = 0; ret[i]; i++ ) { if ( scripts && jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) { scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] ); } else { if ( ret[i].nodeType === 1 ) { - var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), function( elem ) { - return !elem.type || rscriptType.test( elem.type ); - }); + var jsTags = jQuery.grep( ret[i].getElementsByTagName( "script" ), checkScriptType ); ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); } From 9e71ad1b120e2b20c7430c017629877ba277f667 Mon Sep 17 00:00:00 2001 From: Dave Methvin Date: Tue, 12 Apr 2011 18:32:23 -0400 Subject: [PATCH 176/372] Explicitly set event.type in case we chopped out a namespace or exclusive flag. --- src/event.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/event.js b/src/event.js index 5e2baf0d..f6cd97cc 100644 --- a/src/event.js +++ b/src/event.js @@ -317,6 +317,7 @@ jQuery.event = { jQuery.extend( new jQuery.Event(type), event ) : // Just the event type (string) new jQuery.Event(type); + event.type = type; event.namespace = namespaces.join("."); event.namespace_re = new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)"); event.exclusive = exclusive; From 81de96af740f8d397585d8a6fc2a3765dfd16d49 Mon Sep 17 00:00:00 2001 From: rwldrn Date: Tue, 12 Apr 2011 17:27:45 -0400 Subject: [PATCH 177/372] Fixes #8099 using iframe to capture an element's real default display; suggested by lrbabe/louisremi --- src/effects.js | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/effects.js b/src/effects.js index e7987d21..bdd0715e 100644 --- a/src/effects.js +++ b/src/effects.js @@ -548,35 +548,24 @@ if ( jQuery.expr && jQuery.expr.filters ) { } function defaultDisplay( nodeName ) { - var iframe, iframeDoc, iframeNode, display; if ( !elemdisplay[ nodeName ] ) { - iframe = defaultDisplay.iframe.clone()[ 0 ]; + var iframe, iframeDoc, iframeNode, display, elem; - iframe.style.display = "none"; + iframe = defaultDisplay.iframe.clone()[ 0 ]; document.body.appendChild( iframe ); - iframeDoc = iframe.contentWindow && iframe.contentWindow || - iframe.contentDocument.document && iframe.contentDocument.document || - iframe.contentDocument; + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - iframeNode = jQuery( "<" + nodeName + ">" ).appendTo( jQuery( "body", iframeDoc.document ) ); + iframeDoc.open(); + iframeDoc.write(""); + elem = iframeDoc.createElement( nodeName ); + iframeDoc.body.appendChild( elem ); + iframeDoc.close(); - if ( !iframeNode.length ) { - // this will only occur in IE - iframeDoc.document.open(); - iframeDoc.document.write(""); - elem = iframeDoc.document.createElement( nodeName ); - iframeDoc.document.body.appendChild( elem ); - iframeDoc.document.close(); - - iframeNode = jQuery( elem ); - } - - // firefox returns undefined from css("display") - display = iframeNode.css("display") || iframeNode[ 0 ].style.display; + display = jQuery( elem ).css( "display" ); if ( display === "none" || display === "" ) { display = "block"; @@ -591,6 +580,12 @@ function defaultDisplay( nodeName ) { return elemdisplay[ nodeName ]; } -defaultDisplay.iframe = jQuery(" diff --git a/test/unit/attributes.js b/test/unit/attributes.js index c78a2961..2bcc5046 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -492,6 +492,7 @@ test("val()", function() { var testVal = function(valueObj) { expect(8); + QUnit.reset(); jQuery("#text1").val(valueObj( "test" )); equals( document.getElementById("text1").value, "test", "Check for modified (via val(String)) value of input element" ); @@ -504,15 +505,16 @@ var testVal = function(valueObj) { jQuery("#text1").val(valueObj( null )); equals( document.getElementById("text1").value, "", "Check for modified (via val(null)) value of input element" ); - jQuery("#select1").val(valueObj( "3" )); - equals( jQuery("#select1").val(), "3", "Check for modified (via val(String)) value of select element" ); + var $select1 = jQuery("#select1"); + $select1.val(valueObj( "3" )); + equals( $select1.val(), "3", "Check for modified (via val(String)) value of select element" ); - jQuery("#select1").val(valueObj( 2 )); - equals( jQuery("#select1").val(), "2", "Check for modified (via val(Number)) value of select element" ); + $select1.val(valueObj( 2 )); + equals( $select1.val(), "2", "Check for modified (via val(Number)) value of select element" ); - jQuery("#select1").append(""); - jQuery("#select1").val(valueObj( 4 )); - equals( jQuery("#select1").val(), "4", "Should be possible to set the val() to a newly created option" ); + $select1.append(""); + $select1.val(valueObj( 4 )); + equals( $select1.val(), "4", "Should be possible to set the val() to a newly created option" ); // using contents will get comments regular, text, and comment nodes var j = jQuery("#nonnodes").contents(); diff --git a/test/unit/event.js b/test/unit/event.js index 491396f9..8ffbcd5b 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -778,6 +778,8 @@ test("trigger() shortcuts", function() { elem.remove(); // test that special handlers do not blow up with VML elements (#7071) + jQuery('').appendTo('head'); + jQuery(' ').appendTo('#form'); jQuery("#oval").click().keydown(); }); From 4344d0841756f8572c56490f12739ac204f40966 Mon Sep 17 00:00:00 2001 From: jaubourg Date: Wed, 13 Apr 2011 18:35:38 +0200 Subject: [PATCH 180/372] Fixes #8635 again (fix was lost in rewrite). Also removes unnecessary "manual" garbage collection. --- src/support.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/support.js b/src/support.js index 6b19c083..1bd35cab 100644 --- a/src/support.js +++ b/src/support.js @@ -73,7 +73,7 @@ jQuery.support = (function() { // 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, - + // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) getSetAttribute: div.className !== "t", @@ -196,7 +196,7 @@ jQuery.support = (function() { marginDiv.style.marginRight = "0"; div.appendChild( marginDiv ); support.reliableMarginRight = - ( parseInt( document.defaultView.getComputedStyle( marginDiv ).marginRight, 10 ) || 0 ) === 0; + ( parseInt( document.defaultView.getComputedStyle( marginDiv, null ).marginRight, 10 ) || 0 ) === 0; } // Remove the body element we added @@ -224,9 +224,6 @@ jQuery.support = (function() { } } - // release memory in IE - body = div = all = a = tds = undefined; - return support; })(); From 4ad9b44deada9da9639f53b1ca3cc4cf2ebf2df2 Mon Sep 17 00:00:00 2001 From: jaubourg Date: Wed, 13 Apr 2011 19:27:19 +0200 Subject: [PATCH 181/372] Ensures callback placeholders are tested for and eventually replaced in data only when contentType is application/x-www-form-urlencoded and data is a string. Removes json to jsonp promotion when jsonp or jsonpCallback options are present. Uses new Deferred.always method to bind cleanUp function. --- src/ajax/jsonp.js | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/ajax/jsonp.js b/src/ajax/jsonp.js index 4fb09401..6b0f95d5 100644 --- a/src/ajax/jsonp.js +++ b/src/ajax/jsonp.js @@ -14,13 +14,12 @@ jQuery.ajaxSetup({ // Detect, normalize options and install callbacks for jsonp requests jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { - var dataIsString = ( typeof s.data === "string" ); + var inspectData = s.contentType === "application/x-www-form-urlencoded" && + ( typeof s.data === "string" ); if ( s.dataTypes[ 0 ] === "jsonp" || - originalSettings.jsonpCallback || - originalSettings.jsonp != null || s.jsonp !== false && ( jsre.test( s.url ) || - dataIsString && jsre.test( s.data ) ) ) { + inspectData && jsre.test( s.data ) ) ) { var responseContainer, jsonpCallback = s.jsonpCallback = @@ -28,20 +27,12 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { previous = window[ jsonpCallback ], url = s.url, data = s.data, - replace = "$1" + jsonpCallback + "$2", - cleanUp = function() { - // Set callback back to previous value - window[ jsonpCallback ] = previous; - // Call if it was a function and we have a response - if ( responseContainer && jQuery.isFunction( previous ) ) { - window[ jsonpCallback ]( responseContainer[ 0 ] ); - } - }; + replace = "$1" + jsonpCallback + "$2"; if ( s.jsonp !== false ) { url = url.replace( jsre, replace ); if ( s.url === url ) { - if ( dataIsString ) { + if ( inspectData ) { data = data.replace( jsre, replace ); } if ( s.data === data ) { @@ -59,8 +50,15 @@ jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { responseContainer = [ response ]; }; - // Install cleanUp function - jqXHR.then( cleanUp, cleanUp ); + // Clean-up function + jqXHR.always(function() { + // Set callback back to previous value + window[ jsonpCallback ] = previous; + // Call if it was a function and we have a response + if ( responseContainer && jQuery.isFunction( previous ) ) { + window[ jsonpCallback ]( responseContainer[ 0 ] ); + } + }); // Use data converter to retrieve json after script execution s.converters["script json"] = function() { From 4fde550cb62219d7edd14653888608fbbf39c22a Mon Sep 17 00:00:00 2001 From: rwldrn Date: Wed, 13 Apr 2011 13:43:52 -0400 Subject: [PATCH 182/372] Ticket #8099 Conditional iframe approache, caches both iframe and iframedoc for reuse --- src/effects.js | 63 +++++++++++++++++++++++++++----------------- test/unit/effects.js | 8 ++++-- 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/src/effects.js b/src/effects.js index bdd0715e..828798cb 100644 --- a/src/effects.js +++ b/src/effects.js @@ -551,41 +551,56 @@ function defaultDisplay( nodeName ) { if ( !elemdisplay[ nodeName ] ) { - var iframe, iframeDoc, iframeNode, display, elem; + var elem = jQuery( "<" + nodeName + ">" ).appendTo( "body" ), + display = elem.css( "display" ); - iframe = defaultDisplay.iframe.clone()[ 0 ]; - - document.body.appendChild( iframe ); - - iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; - - iframeDoc.open(); - iframeDoc.write(""); - elem = iframeDoc.createElement( nodeName ); - iframeDoc.body.appendChild( elem ); - iframeDoc.close(); - - display = jQuery( elem ).css( "display" ); + elem.remove(); if ( display === "none" || display === "" ) { - display = "block"; + + var iframe = defaultDisplay.iframe, + iframeDoc = defaultDisplay.iframeDoc; + + // No iframe to use yet, so create it + if ( !defaultDisplay.iframe ) { + + iframe = document.createElement( "iframe" ); + iframe.width = iframe.height = 0; + + document.body.appendChild( iframe ); + + iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document; + iframeDoc.write(""); + + // Cache iframe element + defaultDisplay.iframe = iframe; + defaultDisplay.iframeDoc = iframeDoc; + } else { + + // Reuse previous iframe + document.body.appendChild( iframe ); + + } + + elem = iframeDoc.createElement( nodeName ); + + iframeDoc.body.appendChild( elem ); + + display = jQuery( elem ).css( "display" ); + + iframe.parentNode.removeChild( iframe ); } // Store the correct default display elemdisplay[ nodeName ] = display; - - iframe.parentNode.removeChild( iframe ); } return elemdisplay[ nodeName ]; } -defaultDisplay.iframe = jQuery("
    -
    +

    See this blog entry for more information.

    Here are some links in a normal paragraph: Google, diff --git a/test/unit/ajax.js b/test/unit/ajax.js index a8a5fa0d..9f084136 100644 --- a/test/unit/ajax.js +++ b/test/unit/ajax.js @@ -1782,7 +1782,7 @@ test("jQuery.ajaxSetup({timeout: Number}) - with global timeout", function() { passed++; if ( passed == 2 ) { ok( true, "Check local and global callbacks after timeout" ); - jQuery("#main").unbind("ajaxError"); + jQuery("#qunit-fixture").unbind("ajaxError"); start(); } }; @@ -1792,7 +1792,7 @@ test("jQuery.ajaxSetup({timeout: Number}) - with global timeout", function() { start(); }; - jQuery("#main").ajaxError(pass); + jQuery("#qunit-fixture").ajaxError(pass); jQuery.ajax({ type: "GET", diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 8ea27aa3..a497effa 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -108,7 +108,7 @@ test("attr(String)", function() { equals( 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("#main"); + jQuery("").attr({ "id": "tAnchor5", "href": "#5" }).appendTo("#qunit-fixture"); equals( jQuery("#tAnchor5").attr("href"), "#5", "Check for non-absolute href (an anchor)" ); // list attribute is readonly by default in browsers that support it @@ -599,7 +599,7 @@ test("val(Function) with incoming value", function() { test("val(select) after form.reset() (Bug #2551)", function() { expect(3); - jQuery("

    ").appendTo("#main"); + jQuery("
    ").appendTo("#qunit-fixture"); jQuery("#kkk").val( "gf" ); diff --git a/test/unit/core.js b/test/unit/core.js index 8d29575a..cc744e7b 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -29,7 +29,7 @@ test("jQuery()", function() { equals( jQuery(window).length, 1, "Correct number of elements generated for jQuery(window)" ); - var main = jQuery("#main"); + var main = jQuery("#qunit-fixture"); same( jQuery("div p", main).get(), q("sndp", "en", "sap"), "Basic selector with jQuery object as context" ); /* @@ -115,54 +115,54 @@ test("selector state", function() { equals( test.selector, "", "Body Selector" ); equals( test.context, document.body, "Body Context" ); - test = jQuery("#main"); - equals( test.selector, "#main", "#main Selector" ); - equals( test.context, document, "#main Context" ); + test = jQuery("#qunit-fixture"); + equals( test.selector, "#qunit-fixture", "#qunit-fixture Selector" ); + equals( test.context, document, "#qunit-fixture Context" ); test = jQuery("#notfoundnono"); equals( test.selector, "#notfoundnono", "#notfoundnono Selector" ); equals( test.context, document, "#notfoundnono Context" ); - test = jQuery("#main", document); - equals( test.selector, "#main", "#main Selector" ); - equals( test.context, document, "#main Context" ); + test = jQuery("#qunit-fixture", document); + equals( test.selector, "#qunit-fixture", "#qunit-fixture Selector" ); + equals( test.context, document, "#qunit-fixture Context" ); - test = jQuery("#main", document.body); - equals( test.selector, "#main", "#main Selector" ); - equals( test.context, document.body, "#main Context" ); + test = jQuery("#qunit-fixture", document.body); + equals( test.selector, "#qunit-fixture", "#qunit-fixture Selector" ); + equals( test.context, document.body, "#qunit-fixture Context" ); // Test cloning test = jQuery(test); - equals( test.selector, "#main", "#main Selector" ); - equals( test.context, document.body, "#main Context" ); + equals( test.selector, "#qunit-fixture", "#qunit-fixture Selector" ); + equals( test.context, document.body, "#qunit-fixture Context" ); - test = jQuery(document.body).find("#main"); - equals( test.selector, "#main", "#main find Selector" ); - equals( test.context, document.body, "#main find Context" ); + test = jQuery(document.body).find("#qunit-fixture"); + equals( test.selector, "#qunit-fixture", "#qunit-fixture find Selector" ); + equals( test.context, document.body, "#qunit-fixture find Context" ); - test = jQuery("#main").filter("div"); - equals( test.selector, "#main.filter(div)", "#main filter Selector" ); - equals( test.context, document, "#main filter Context" ); + test = jQuery("#qunit-fixture").filter("div"); + equals( test.selector, "#qunit-fixture.filter(div)", "#qunit-fixture filter Selector" ); + equals( test.context, document, "#qunit-fixture filter Context" ); - test = jQuery("#main").not("div"); - equals( test.selector, "#main.not(div)", "#main not Selector" ); - equals( test.context, document, "#main not Context" ); + test = jQuery("#qunit-fixture").not("div"); + equals( test.selector, "#qunit-fixture.not(div)", "#qunit-fixture not Selector" ); + equals( test.context, document, "#qunit-fixture not Context" ); - test = jQuery("#main").filter("div").not("div"); - equals( test.selector, "#main.filter(div).not(div)", "#main filter, not Selector" ); - equals( test.context, document, "#main filter, not Context" ); + test = jQuery("#qunit-fixture").filter("div").not("div"); + equals( test.selector, "#qunit-fixture.filter(div).not(div)", "#qunit-fixture filter, not Selector" ); + equals( test.context, document, "#qunit-fixture filter, not Context" ); - test = jQuery("#main").filter("div").not("div").end(); - equals( test.selector, "#main.filter(div)", "#main filter, not, end Selector" ); - equals( test.context, document, "#main filter, not, end Context" ); + test = jQuery("#qunit-fixture").filter("div").not("div").end(); + equals( test.selector, "#qunit-fixture.filter(div)", "#qunit-fixture filter, not, end Selector" ); + equals( test.context, document, "#qunit-fixture filter, not, end Context" ); - test = jQuery("#main").parent("body"); - equals( test.selector, "#main.parent(body)", "#main parent Selector" ); - equals( test.context, document, "#main parent Context" ); + test = jQuery("#qunit-fixture").parent("body"); + equals( test.selector, "#qunit-fixture.parent(body)", "#qunit-fixture parent Selector" ); + equals( test.context, document, "#qunit-fixture parent Context" ); - test = jQuery("#main").eq(0); - equals( test.selector, "#main.slice(0,1)", "#main eq Selector" ); - equals( test.context, document, "#main eq Context" ); + test = jQuery("#qunit-fixture").eq(0); + equals( test.selector, "#qunit-fixture.slice(0,1)", "#qunit-fixture eq Selector" ); + equals( test.context, document, "#qunit-fixture eq Context" ); var d = "
    "; equals( @@ -228,7 +228,7 @@ test("noConflict", function() { equals( jQuery.noConflict(true), $$, "noConflict returned the jQuery object" ); equals( jQuery, originaljQuery, "Make sure jQuery was reverted." ); equals( $, original$, "Make sure $ was reverted." ); - ok( $$("#main").html("test"), "Make sure that jQuery still works." ); + ok( $$("#qunit-fixture").html("test"), "Make sure that jQuery still works." ); jQuery = $$; }); @@ -571,29 +571,29 @@ test("end()", function() { test("length", function() { expect(1); - equals( jQuery("#main p").length, 6, "Get Number of Elements Found" ); + equals( jQuery("#qunit-fixture p").length, 6, "Get Number of Elements Found" ); }); test("size()", function() { expect(1); - equals( jQuery("#main p").size(), 6, "Get Number of Elements Found" ); + equals( jQuery("#qunit-fixture p").size(), 6, "Get Number of Elements Found" ); }); test("get()", function() { expect(1); - same( jQuery("#main p").get(), q("firstp","ap","sndp","en","sap","first"), "Get All Elements" ); + same( jQuery("#qunit-fixture p").get(), q("firstp","ap","sndp","en","sap","first"), "Get All Elements" ); }); test("toArray()", function() { expect(1); - same( jQuery("#main p").toArray(), + same( jQuery("#qunit-fixture p").toArray(), q("firstp","ap","sndp","en","sap","first"), "Convert jQuery object to an Array" ) }) test("get(Number)", function() { expect(2); - equals( jQuery("#main p").get(0), document.getElementById("firstp"), "Get A Single Element" ); + equals( jQuery("#qunit-fixture p").get(0), document.getElementById("firstp"), "Get A Single Element" ); strictEqual( jQuery("#firstp").get(1), undefined, "Try get with index larger elements count" ); }); diff --git a/test/unit/css.js b/test/unit/css.js index 33bc1548..60e8744c 100644 --- a/test/unit/css.js +++ b/test/unit/css.js @@ -3,7 +3,7 @@ module("css", { teardown: moduleTeardown }); test("css(String|Hash)", function() { expect( 42 ); - equals( jQuery("#main").css("display"), "block", "Check for css property \"display\""); + equals( jQuery("#qunit-fixture").css("display"), "block", "Check for css property \"display\""); ok( jQuery("#nothiddendiv").is(":visible"), "Modifying CSS display: Assert element is visible"); jQuery("#nothiddendiv").css({display: "none"}); diff --git a/test/unit/data.js b/test/unit/data.js index 888f71cb..8b5ce961 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -316,7 +316,7 @@ test("data-* attributes", function() { div.remove(); - child.appendTo("#main"); + child.appendTo("#qunit-fixture"); equals( child.data("myobj"), "old data", "Value accessed from data-* attribute"); child.data("myobj", "replaced"); @@ -406,7 +406,7 @@ test("data-* attributes", function() { } var metadata = "
    1. Some stuff
    2. Some stuff
    3. Some stuff
    4. Some stuff
    ", - elem = jQuery(metadata).appendTo("#main"); + elem = jQuery(metadata).appendTo("#qunit-fixture"); elem.find("li").each(testData); elem.remove(); diff --git a/test/unit/effects.js b/test/unit/effects.js index 8b7cf467..5b93b83b 100644 --- a/test/unit/effects.js +++ b/test/unit/effects.js @@ -2,7 +2,7 @@ module("effects", { teardown: moduleTeardown }); test("sanity check", function() { expect(1); - ok( jQuery("#dl:visible, #main:visible, #foo:visible").length === 3, "QUnit state is correct for testing effects" ); + ok( jQuery("#dl:visible, #qunit-fixture:visible, #foo:visible").length === 3, "QUnit state is correct for testing effects" ); }); test("show()", function() { @@ -14,7 +14,7 @@ test("show()", function() { equals( hiddendiv.css("display"), "block", "Make sure a pre-hidden div is visible." ); - var div = jQuery("
    ").hide().appendTo("#main").show(); + var div = jQuery("
    ").hide().appendTo("#qunit-fixture").show(); equal( div.css("display"), "block", "Make sure pre-hidden divs show" ); @@ -32,7 +32,7 @@ test("show()", function() { hiddendiv.css("display",""); - var pass = true, div = jQuery("#main div"); + var pass = true, div = jQuery("#qunit-fixture div"); div.show().each(function(){ if ( this.style.display == "none" ) pass = false; }); @@ -62,7 +62,7 @@ test("show()", function() { }); // #show-tests * is set display: none in CSS - jQuery("#main").append("

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

    "); var old = jQuery("#test-table").show().css("display") !== "table"; jQuery("#test-table").remove(); @@ -96,7 +96,7 @@ test("show(Number) - other displays", function() { stop(); // #show-tests * is set display: none in CSS - jQuery("#main").append("

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

    "); var old = jQuery("#test-table").show().css("display") !== "table", num = 0; @@ -138,7 +138,7 @@ test("Persist correct display value", function() { stop(); // #show-tests * is set display: none in CSS - jQuery("#main").append("
    foo
    "); + jQuery("#qunit-fixture").append("
    foo
    "); var $span = jQuery("#show-tests span"), displayNone = $span.css("display"), @@ -581,7 +581,7 @@ jQuery.checkOverflowDisplay = function(){ } test( "jQuery.fx.prototype.cur()", 6, function() { - var div = jQuery( "
    " ).appendTo( "#main" ).css({ + var div = jQuery( "
    " ).appendTo( "#qunit-fixture" ).css({ color: "#ABC", border: "5px solid black", left: "auto", @@ -954,7 +954,7 @@ test("hide hidden elements (bug #7141)", function() { expect(3); QUnit.reset(); - var div = jQuery("
    ").appendTo("#main"); + var div = jQuery("
    ").appendTo("#qunit-fixture"); equals( div.css("display"), "none", "Element is hidden by default" ); div.hide(); ok( !jQuery._data(div, "olddisplay"), "olddisplay is undefined after hiding an already-hidden element" ); @@ -969,7 +969,7 @@ test("hide hidden elements, with animation (bug #7141)", function() { QUnit.reset(); stop(); - var div = jQuery("
    ").appendTo("#main"); + var div = jQuery("
    ").appendTo("#qunit-fixture"); equals( div.css("display"), "none", "Element is hidden by default" ); div.hide(1, function () { ok( !jQuery._data(div, "olddisplay"), "olddisplay is undefined after hiding an already-hidden element" ); @@ -982,7 +982,7 @@ test("hide hidden elements, with animation (bug #7141)", function() { test("animate unit-less properties (#4966)", 2, function() { stop(); - var div = jQuery( "
    " ).appendTo( "#main" ); + var div = jQuery( "
    " ).appendTo( "#qunit-fixture" ); equal( div.css( "z-index" ), "0", "z-index is 0" ); div.animate({ zIndex: 2 }, function() { equal( div.css( "z-index" ), "2", "z-index is 2" ); diff --git a/test/unit/event.js b/test/unit/event.js index a1aee191..454ada3b 100644 --- a/test/unit/event.js +++ b/test/unit/event.js @@ -169,7 +169,7 @@ test("bind(), namespace with special add", function() { }); // Should trigger 2 - div.appendTo("#main").remove(); + div.appendTo("#qunit-fixture").remove(); delete jQuery.event.special.test; }); @@ -307,7 +307,7 @@ test("live/delegate immediate propagation", function() { test("bind/delegate bubbling, isDefaultPrevented", function() { expect(2); var $anchor2 = jQuery( "#anchor2" ), - $main = jQuery( "#main" ), + $main = jQuery( "#qunit-fixture" ), fakeClick = function($jq) { // Use a native click so we don't get jQuery simulated bubbling if ( document.createEvent ) { @@ -415,7 +415,7 @@ test("bind(), namespaced events, cloned events", 18, function() { }).trigger("tester"); // Make sure events stick with appendTo'd elements (which are cloned) #2027 - jQuery("test").click(function(){ return false; }).appendTo("#main"); + jQuery("test").click(function(){ return false; }).appendTo("#qunit-fixture"); ok( jQuery("a.test:first").triggerHandler("click") === false, "Handler is bound to appendTo'd elements" ); }); @@ -538,7 +538,7 @@ test("bind(name, false), unbind(name, false)", function() { expect(3); var main = 0; - jQuery("#main").bind("click", function(e){ main++; }); + jQuery("#qunit-fixture").bind("click", function(e){ main++; }); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); @@ -553,14 +553,14 @@ test("bind(name, false), unbind(name, false)", function() { equals( main, 1, "Verify that the trigger happened correctly." ); // manually clean up events from elements outside the fixture - jQuery("#main").unbind("click"); + jQuery("#qunit-fixture").unbind("click"); }); test("live(name, false), die(name, false)", function() { expect(3); var main = 0; - jQuery("#main").live("click", function(e){ main++; }); + jQuery("#qunit-fixture").live("click", function(e){ main++; }); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); @@ -573,7 +573,7 @@ test("live(name, false), die(name, false)", function() { jQuery("#ap").die("click", false); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); - jQuery("#main").die("click"); + jQuery("#qunit-fixture").die("click"); }); test("delegate(selector, name, false), undelegate(selector, name, false)", function() { @@ -581,7 +581,7 @@ test("delegate(selector, name, false), undelegate(selector, name, false)", funct var main = 0; - jQuery("#main").delegate("#ap", "click", function(e){ main++; }); + jQuery("#qunit-fixture").delegate("#ap", "click", function(e){ main++; }); jQuery("#ap").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); @@ -594,7 +594,7 @@ test("delegate(selector, name, false), undelegate(selector, name, false)", funct jQuery("#ap").undelegate("#groups", "click", false); jQuery("#groups").trigger("click"); equals( main, 1, "Verify that the trigger happened correctly." ); - jQuery("#main").undelegate("#ap", "click"); + jQuery("#qunit-fixture").undelegate("#ap", "click"); }); test("bind()/trigger()/unbind() on plain object", function() { @@ -798,7 +798,7 @@ test("trigger() bubbling", function() { jQuery(document).bind("click", function(e){ if ( e.target !== document) { doc++; } }); jQuery("html").bind("click", function(e){ html++; }); jQuery("body").bind("click", function(e){ body++; }); - jQuery("#main").bind("click", function(e){ main++; }); + jQuery("#qunit-fixture").bind("click", function(e){ main++; }); jQuery("#ap").bind("click", function(){ ap++; return false; }); jQuery("html").trigger("click"); @@ -812,7 +812,7 @@ test("trigger() bubbling", function() { equals( html, 2, "Body bubble" ); equals( body, 1, "Body bubble" ); - jQuery("#main").trigger("click"); + jQuery("#qunit-fixture").trigger("click"); equals( win, 3, "Main bubble" ); equals( doc, 3, "Main bubble" ); equals( html, 3, "Main bubble" ); @@ -828,7 +828,7 @@ test("trigger() bubbling", function() { // manually clean up events from elements outside the fixture jQuery(document).unbind("click"); - jQuery("html, body, #main").unbind("click"); + jQuery("html, body, #qunit-fixture").unbind("click"); }); test("trigger(type, [data], [fn])", function() { @@ -872,7 +872,7 @@ test("trigger(type, [data], [fn])", function() { pass = true; try { - jQuery("#main table:first").bind("test:test", function(){}).trigger("test:test"); + jQuery("#qunit-fixture table:first").bind("test:test", function(){}).trigger("test:test"); } catch (e) { pass = false; } @@ -1189,11 +1189,11 @@ test(".live()/.die()", function() { jQuery("div").die("submit"); // Test binding with a different context - var clicked = 0, container = jQuery("#main")[0]; + var clicked = 0, container = jQuery("#qunit-fixture")[0]; jQuery("#foo", container).live("click", function(e){ clicked++; }); jQuery("div").trigger("click"); jQuery("#foo").trigger("click"); - jQuery("#main").trigger("click"); + jQuery("#qunit-fixture").trigger("click"); jQuery("body").trigger("click"); equals( clicked, 2, "live with a context" ); @@ -1716,11 +1716,11 @@ test(".delegate()/.undelegate()", function() { jQuery("#body").undelegate("div", "submit"); // Test binding with a different context - var clicked = 0, container = jQuery("#main")[0]; - jQuery("#main").delegate("#foo", "click", function(e){ clicked++; }); + var clicked = 0, container = jQuery("#qunit-fixture")[0]; + jQuery("#qunit-fixture").delegate("#foo", "click", function(e){ clicked++; }); jQuery("div").trigger("click"); jQuery("#foo").trigger("click"); - jQuery("#main").trigger("click"); + jQuery("#qunit-fixture").trigger("click"); jQuery("body").trigger("click"); equals( clicked, 2, "delegate with a context" ); @@ -1728,7 +1728,7 @@ test(".delegate()/.undelegate()", function() { ok( jQuery._data(container, "events").live, "delegate with a context" ); // Test unbinding with a different context - jQuery("#main").undelegate("#foo", "click"); + jQuery("#qunit-fixture").undelegate("#foo", "click"); jQuery("#foo").trigger("click"); equals( clicked, 2, "undelegate with a context"); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index de65daa1..e0fb369a 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -483,19 +483,19 @@ test("appendTo(String|Element|Array<Element>|jQuery)", function() { var div = jQuery("
    ").click(function(){ ok(true, "Running a cloned click."); }); - div.appendTo("#main, #moretests"); + div.appendTo("#qunit-fixture, #moretests"); - jQuery("#main div:last").click(); + jQuery("#qunit-fixture div:last").click(); jQuery("#moretests div:last").click(); QUnit.reset(); - var div = jQuery("
    ").appendTo("#main, #moretests"); + var div = jQuery("
    ").appendTo("#qunit-fixture, #moretests"); equals( div.length, 2, "appendTo returns the inserted elements" ); div.addClass("test"); - ok( jQuery("#main div:last").hasClass("test"), "appendTo element was modified after the insertion" ); + ok( jQuery("#qunit-fixture div:last").hasClass("test"), "appendTo element was modified after the insertion" ); ok( jQuery("#moretests div:last").hasClass("test"), "appendTo element was modified after the insertion" ); QUnit.reset(); @@ -507,10 +507,10 @@ test("appendTo(String|Element|Array<Element>|jQuery)", function() { div = jQuery("#moretests div"); - var num = jQuery("#main div").length; - div.remove().appendTo("#main"); + var num = jQuery("#qunit-fixture div").length; + div.remove().appendTo("#qunit-fixture"); - equals( jQuery("#main div").length, num, "Make sure all the removed divs were inserted." ); + equals( jQuery("#qunit-fixture div").length, num, "Make sure all the removed divs were inserted." ); QUnit.reset(); }); @@ -750,7 +750,7 @@ var testReplaceWith = function(val) { ok( !jQuery("#yahoo")[0], "Verify that original element is gone, after element" ); QUnit.reset(); - jQuery("#main").append("
    "); + jQuery("#qunit-fixture").append("
    "); jQuery("#baz").replaceWith("Baz"); equals( jQuery("#bar").text(),"Baz", "Replace element with text" ); ok( !jQuery("#baz")[0], "Verify that original element is gone, after element" ); @@ -813,14 +813,14 @@ var testReplaceWith = function(val) { QUnit.reset(); - jQuery("#main").append("
    "); - equals( jQuery("#main").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); + jQuery("#qunit-fixture").append("
    "); + equals( jQuery("#qunit-fixture").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); jQuery("#replaceWith").replaceWith( val("
    ") ); - equals( jQuery("#main").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); + equals( jQuery("#qunit-fixture").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); jQuery("#replaceWith").replaceWith( val("
    ") ); - equals( jQuery("#main").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); + equals( jQuery("#qunit-fixture").find("div[id=replaceWith]").length, 1, "Make sure only one div exists." ); } test("replaceWith(String|Element|Array<Element>|jQuery)", function() { @@ -881,7 +881,7 @@ test("jQuery.clone() (#8017)", function() { ok( jQuery.clone && jQuery.isFunction( jQuery.clone ) , "jQuery.clone() utility exists and is a function."); - var main = jQuery("#main")[0], + var main = jQuery("#qunit-fixture")[0], clone = jQuery.clone( main ); equals( main.childNodes.length, clone.childNodes.length, "Simple child length to ensure a large dom tree copies correctly" ); @@ -890,7 +890,7 @@ test("jQuery.clone() (#8017)", function() { test("clone() (#8070)", function () { expect(2); - jQuery("").appendTo("#main"); + jQuery("").appendTo("#qunit-fixture"); var selects = jQuery(".test8070"); selects.append(""); @@ -1062,7 +1062,7 @@ var testHtml = function(valueObj) { jQuery.scriptorder = 0; - var div = jQuery("#main > div"); + var div = jQuery("#qunit-fixture > div"); div.html(valueObj("test")); var pass = true; for ( var i = 0; i < div.size(); i++ ) { @@ -1079,10 +1079,10 @@ var testHtml = function(valueObj) { ok( /^\xA0$|^ $/.test( space ), "Make sure entities are passed through correctly." ); equals( jQuery("
    ").html(valueObj("&"))[0].innerHTML, "&", "Make sure entities are passed through correctly." ); - jQuery("#main").html(valueObj("")); + jQuery("#qunit-fixture").html(valueObj("")); - equals( jQuery("#main").children().length, 1, "Make sure there is a child element." ); - equals( jQuery("#main").children()[0].nodeName.toUpperCase(), "STYLE", "And that a style element was inserted." ); + equals( jQuery("#qunit-fixture").children().length, 1, "Make sure there is a child element." ); + equals( jQuery("#qunit-fixture").children()[0].nodeName.toUpperCase(), "STYLE", "And that a style element was inserted." ); QUnit.reset(); // using contents will get comments regular, text, and comment nodes @@ -1093,9 +1093,9 @@ var testHtml = function(valueObj) { j.find("b").removeData(); equals( j.html().replace(/ xmlns="[^"]+"/g, "").toLowerCase(), "bold", "Check node,textnode,comment with html()" ); - jQuery("#main").html(valueObj("")); + jQuery("#qunit-fixture select").html(valueObj("")); + equals( jQuery("#qunit-fixture select").val(), "O2", "Selected option correct" ); var $div = jQuery("
    "); equals( $div.html(valueObj( 5 )).html(), "5", "Setting a number as html" ); @@ -1113,23 +1113,23 @@ var testHtml = function(valueObj) { QUnit.reset(); - jQuery("#main").html(valueObj("
    ")); + jQuery("#qunit-fixture").html(valueObj("
    ")); - var child = jQuery("#main").find("script"); + var child = jQuery("#qunit-fixture").find("script"); equals( child.length, 2, "Make sure that two non-JavaScript script tags are left." ); equals( child[0].type, "something/else", "Verify type of script tag." ); equals( child[1].type, "something/else", "Verify type of script tag." ); - jQuery("#main").html(valueObj("")); - jQuery("#main").html(valueObj("")); - jQuery("#main").html(valueObj("")); + jQuery("#qunit-fixture").html(valueObj("")); + jQuery("#qunit-fixture").html(valueObj("")); + jQuery("#qunit-fixture").html(valueObj("")); - jQuery("#main").html(valueObj("")); + jQuery("#qunit-fixture").html(valueObj("")); - jQuery("#main").html(valueObj("foo
    ")); + jQuery("#qunit-fixture").html(valueObj("foo
    ")); - jQuery("#main").html(valueObj(" + + + + + + + + + + + + + + + + + + + + + + + + +

    jQuery Test Suite

    +

    +
    +

    +
      + + +
      +
      +
      + + +
      +
      +

      See this blog entry for more information.

      +

      + Here are some links in a normal paragraph: Google, + Google Groups (Link). + This link has class="blog": + diveintomark + +

      +
      +

      Everything inside the red border is inside a div with id="foo".

      +

      This is a normal link: Yahoo

      +

      This link has class="blog": Simon Willison's Weblog

      + +
      + +

      Try them out:

      +
        +
          +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + test element +
          + Float test. + +
          + + +
          +
          + +
          + + + + +
          + +
          + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
          +
          +
          + +
          +
          hi there
          +
          +
          +
          +
          + +
          +
            +
          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 +
          +
          +
          +
          +
          +
          fadeIn
          fadeIn
          +
          fadeOut
          fadeOut
          + +
          show
          show
          +
          hide
          hide
          + +
          togglein
          togglein
          +
          toggleout
          toggleout
          + + +
          slideUp
          slideUp
          +
          slideDown
          slideDown
          + +
          slideToggleIn
          slideToggleIn
          +
          slideToggleOut
          slideToggleOut
          + +
          fadeToggleIn
          fadeToggleIn
          +
          fadeToggleOut
          fadeToggleOut
          + +
          fadeTo
          fadeTo
          +
          + +
          +
          + + From ea24cd106b86dae2411e5b87c367f6ff5163aee8 Mon Sep 17 00:00:00 2001 From: timmywil Date: Mon, 2 May 2011 17:53:55 -0400 Subject: [PATCH 268/372] Avoid changing html in two places; add minified jQuery as an option to the main test page --- test/data/testrunner.js | 3 - test/data/versioncheck.js | 8 ++ test/index.built.html | 264 -------------------------------------- test/index.html | 6 +- 4 files changed, 13 insertions(+), 268 deletions(-) create mode 100644 test/data/versioncheck.js delete mode 100644 test/index.built.html diff --git a/test/data/testrunner.js b/test/data/testrunner.js index 1da67651..6d44b460 100644 --- a/test/data/testrunner.js +++ b/test/data/testrunner.js @@ -28,9 +28,6 @@ jQuery.noConflict(); // Allow the test to run with other libs or jQuery's. // QUnit Aliases (function() { - window.equals = window.equal; window.same = window.deepEqual; - })(); - diff --git a/test/data/versioncheck.js b/test/data/versioncheck.js new file mode 100644 index 00000000..f4b7790d --- /dev/null +++ b/test/data/versioncheck.js @@ -0,0 +1,8 @@ +// Run minified source from dist (do make first) +// Should be loaded before QUnit but after src +(function() { + if ( /jquery\=min/.test( window.location.search ) ) { + jQuery.noConflict( true ); + document.write(unescape("%3Cscript%20src%3D%27../dist/jquery.min.js%27%3E%3C/script%3E")); + } +})(); \ No newline at end of file diff --git a/test/index.built.html b/test/index.built.html deleted file mode 100644 index aad27a1f..00000000 --- a/test/index.built.html +++ /dev/null @@ -1,264 +0,0 @@ - - - - - jQuery Test Suite - Fully Built and Compressed - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

          jQuery Test Suite

          -

          -
          -

          -
            - - -
            -
            -
            - - -
            -
            -

            See this blog entry for more information.

            -

            - Here are some links in a normal paragraph: Google, - Google Groups (Link). - This link has class="blog": - diveintomark - -

            -
            -

            Everything inside the red border is inside a div with id="foo".

            -

            This is a normal link: Yahoo

            -

            This link has class="blog": Simon Willison's Weblog

            - -
            - -

            Try them out:

            -
              -
                -
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - test element -
                - Float test. - -
                - - -
                -
                - -
                - - - - -
                - -
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                -
                -
                - -
                -
                hi there
                -
                -
                -
                -
                - -
                -
                  -
                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 -
                -
                -
                -
                -
                -
                fadeIn
                fadeIn
                -
                fadeOut
                fadeOut
                - -
                show
                show
                -
                hide
                hide
                - -
                togglein
                togglein
                -
                toggleout
                toggleout
                - - -
                slideUp
                slideUp
                -
                slideDown
                slideDown
                - -
                slideToggleIn
                slideToggleIn
                -
                slideToggleOut
                slideToggleOut
                - -
                fadeToggleIn
                fadeToggleIn
                -
                fadeToggleOut
                fadeToggleOut
                - -
                fadeTo
                fadeTo
                -
                - -
                -
                - - diff --git a/test/index.html b/test/index.html index b19673d9..1a4d0582 100644 --- a/test/index.html +++ b/test/index.html @@ -28,6 +28,8 @@ + + @@ -48,7 +50,9 @@ -

                jQuery Test Suite

                +

                jQuery Test Suite + (minified) +

                From 6d2fd57f452398123f8edefa25eef8045d1b586e Mon Sep 17 00:00:00 2001 From: timmywil Date: Mon, 2 May 2011 18:14:12 -0400 Subject: [PATCH 269/372] Fix QUnit Header links --- test/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/index.html b/test/index.html index 1a4d0582..3d421a56 100644 --- a/test/index.html +++ b/test/index.html @@ -50,7 +50,7 @@ -

                jQuery Test Suite +

                jQuery Test Suite (minified)

                From 4ac2fdda2c26e9b64502b9ef50748427bed2f3c6 Mon Sep 17 00:00:00 2001 From: timmywil Date: Tue, 3 May 2011 14:48:36 -0400 Subject: [PATCH 270/372] Fix setting value attributes on option elements. Fixes #9071. --- src/attributes.js | 2 +- test/unit/attributes.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/attributes.js b/src/attributes.js index 017a32da..2da2e163 100644 --- a/src/attributes.js +++ b/src/attributes.js @@ -199,7 +199,7 @@ jQuery.fn.extend({ hooks = jQuery.valHooks[ this.nodeName.toLowerCase() ] || jQuery.valHooks[ this.type ]; // If set returns undefined, fall back to normal setting - if ( !hooks || ("set" in hooks && hooks.set( this, val, "value" ) === undefined) ) { + if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); diff --git a/test/unit/attributes.js b/test/unit/attributes.js index 37e854d0..b1cfe3db 100644 --- a/test/unit/attributes.js +++ b/test/unit/attributes.js @@ -447,7 +447,7 @@ test("removeProp(String)", function() { }); test("val()", function() { - expect(25); + expect(26); document.getElementById("text1").value = "bla"; equals( jQuery("#text1").val(), "bla", "Check for modified value of input element" ); @@ -513,6 +513,8 @@ test("val()", function() { var $button = jQuery("").insertAfter("#button"); equals( $button.val(), "foobar", "Value retrieval on a button does not return innerHTML" ); equals( $button.val("baz").html(), "text", "Setting the value does not change innerHTML" ); + + equals( jQuery("