From 67d445a703491c90a7d3c46be34bcdceb4d1c896 Mon Sep 17 00:00:00 2001 From: John Resig Date: Fri, 25 Sep 2009 17:55:20 +0000 Subject: [PATCH] A follow-up to [6578] (which stopped adding expandos to elements that didn't have data). That broke jQuery.unique() (so we're now using the unique from Sizzle). Using Sizzle's unique (which also sorts in document order) changed how add, andSelf, parents, nextAll, prevAll, and siblings work. after and before were changed to not use .add() (in order to guarantee their position in the jQuery set). Also, jQuery.data(elem) was updated to return that element's data object (instead of its ID). $("
").after("") => [ div, span ] (calling after on a disconnected DOM node adds the nodes to the end of the jQuery set) $("
").before("") => [ span, div ] (calling before on a disconnected DOM node adds the nodes to the beginning of the jQuery set) $("div").add("span") => [ div, span, span, div, span ] (results now come out in document order) $("div").find("code").andSelf(); => [ div, code, code ] (results now come out in document order) Same goes for .parents(), .nextAll(), .prevAll(), and .siblings(). Exception: .parents() will still return the results in reverse document order. jQuery.data(elem) => { object of data } (no longer returns the unique ID assigned to the node) --- src/core.js | 19 ------------------- src/data.js | 12 +++++++----- src/manipulation.js | 18 ++++++++---------- src/selector.js | 25 +++++++++++++++++++++++++ src/traversing.js | 23 ++++++++++++++++------- test/unit/core.js | 12 +++++++++++- test/unit/data.js | 2 +- test/unit/manipulation.js | 4 ++-- test/unit/traversing.js | 6 +++--- 9 files changed, 73 insertions(+), 48 deletions(-) diff --git a/src/core.js b/src/core.js index 3b11ed8f0b..ed1f7d5b18 100644 --- a/src/core.js +++ b/src/core.js @@ -462,25 +462,6 @@ jQuery.extend({ return first; }, - unique: function( array ) { - var ret = [], done = {}, id; - - try { - for ( var i = 0, length = array.length; i < length; i++ ) { - id = jQuery.data( array[ i ] ); - - if ( !done[ id ] ) { - done[ id ] = true; - ret.push( array[ i ] ); - } - } - } catch( e ) { - ret = array; - } - - return ret; - }, - grep: function( elems, callback, inv ) { var ret = []; diff --git a/src/data.js b/src/data.js index 085db0bb32..500f7ea43f 100644 --- a/src/data.js +++ b/src/data.js @@ -14,8 +14,8 @@ jQuery.extend({ var id = elem[ expando ], cache = jQuery.cache, thisCache; // Handle the case where there's no name immediately - if ( !name ) { - return id; + if ( !name && !id ) { + return null; } // Compute a unique ID for the element @@ -39,7 +39,7 @@ jQuery.extend({ thisCache[ name ] = data; } - return name === true ? thisCache : thisCache[ name ]; + return name ? thisCache[ name ] : thisCache; }, removeData: function( elem, name ) { @@ -116,7 +116,9 @@ jQuery.extend({ jQuery.fn.extend({ data: function( key, value ){ - if(typeof key === "undefined" && this.length) return jQuery.data(this[0], true); + if ( typeof key === "undefined" && this.length ) { + return jQuery.data( this[0] ); + } var parts = key.split("."); parts[1] = parts[1] ? "." + parts[1] : ""; @@ -165,4 +167,4 @@ jQuery.fn.extend({ clearQueue: function(type){ return this.queue( type || "fx", [] ); } -}); \ No newline at end of file +}); diff --git a/src/manipulation.js b/src/manipulation.js index 2a1e9237f4..547acc184f 100644 --- a/src/manipulation.js +++ b/src/manipulation.js @@ -111,12 +111,10 @@ jQuery.fn.extend({ return this.domManip(arguments, false, function(elem){ this.parentNode.insertBefore( elem, this ); }); - } else { - var set = jQuery.isFunction(arguments[0]) ? - jQuery( arguments[0]() ) : - jQuery.apply(jQuery, arguments); - - return this.pushStack( set.add( this ), "before", arguments ); + } else if ( arguments.length ) { + var set = jQuery(arguments[0]); + set.push.apply( set, this.toArray() ); + return this.pushStack( set, "before", arguments ); } }, @@ -125,10 +123,10 @@ jQuery.fn.extend({ return this.domManip(arguments, false, function(elem){ this.parentNode.insertBefore( elem, this.nextSibling ); }); - } else { - return jQuery.isFunction(arguments[0]) ? - this.add( arguments[0]() ) : - this.add.apply( this, arguments ); + } else if ( arguments.length ) { + var set = this.pushStack( this, "after", arguments ); + set.push.apply( set, jQuery(arguments[0]).toArray() ); + return set; } }, diff --git a/src/selector.js b/src/selector.js index 64222c3f66..de8830aa1d 100644 --- a/src/selector.js +++ b/src/selector.js @@ -144,6 +144,8 @@ Sizzle.uniqueSort = function(results){ } } } + + return results; }; Sizzle.matches = function(expr, set){ @@ -703,6 +705,13 @@ var sortOrder; if ( document.documentElement.compareDocumentPosition ) { sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; if ( ret === 0 ) { hasDuplicate = true; @@ -711,6 +720,13 @@ if ( document.documentElement.compareDocumentPosition ) { }; } else if ( "sourceIndex" in document.documentElement ) { sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + var ret = a.sourceIndex - b.sourceIndex; if ( ret === 0 ) { hasDuplicate = true; @@ -719,6 +735,13 @@ if ( document.documentElement.compareDocumentPosition ) { }; } else if ( document.createRange ) { sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); aRange.selectNode(a); aRange.collapse(true); @@ -1036,6 +1059,8 @@ jQuery.sibling = function(n, elem){ return r; }; +jQuery.unique = Sizzle.uniqueSort; + return; window.Sizzle = Sizzle; diff --git a/src/traversing.js b/src/traversing.js index 0e379c72b0..8f1e5eb501 100644 --- a/src/traversing.js +++ b/src/traversing.js @@ -69,12 +69,14 @@ jQuery.fn.extend({ }, add: function( selector ) { - return this.pushStack( jQuery.unique( jQuery.merge( - this.get(), - typeof selector === "string" ? + var set = typeof selector === "string" ? jQuery( selector ) : - jQuery.makeArray( selector ) - ))); + jQuery.makeArray( selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( set[0] && (set[0].setInterval || set[0].nodeType === 9 || (set[0].parentNode && set[0].parentNode.nodeType !== 11)) ? + jQuery.unique( all ) : + all ); }, eq: function( i ) { @@ -125,9 +127,16 @@ jQuery.each({ jQuery.fn[ name ] = function( selector ) { var ret = jQuery.map( this, fn ); - if ( selector && typeof selector == "string" ) + if ( selector && typeof selector === "string" ) { ret = jQuery.multiFilter( selector, ret ); + } + + ret = this.length > 1 ? jQuery.unique( ret ) : ret; + + if ( name === "parents" && this.length > 1 ) { + ret = ret.reverse(); + } - return this.pushStack( jQuery.unique( ret ), name, selector ); + return this.pushStack( ret, name, selector ); }; }); diff --git a/test/unit/core.js b/test/unit/core.js index d3e0a44713..3a3b42f840 100644 --- a/test/unit/core.js +++ b/test/unit/core.js @@ -399,7 +399,7 @@ test("get(-Number)",function() { }) test("add(String|Element|Array|undefined)", function() { - expect(12); + expect(16); isSet( jQuery("#sndp").add("#en").add("#sap").get(), q("sndp", "en", "sap"), "Check elements from document" ); isSet( jQuery("#sndp").add( jQuery("#en")[0] ).add( jQuery("#sap") ).get(), q("sndp", "en", "sap"), "Check elements from document" ); ok( jQuery([]).add(jQuery("#form")[0].elements).length >= 13, "Check elements from array" ); @@ -408,6 +408,16 @@ test("add(String|Element|Array|undefined)", function() { // use jQuery([]).add(form.elements) instead. //equals( jQuery([]).add(jQuery("#form")[0].elements).length, jQuery(jQuery("#form")[0].elements).length, "Array in constructor must equals array in add()" ); + var tmp = jQuery("
"); + + var x = jQuery([]).add(jQuery("

xxx

").appendTo(tmp)).add(jQuery("

xxx

").appendTo(tmp)); + equals( x[0].id, "x1", "Check on-the-fly element1" ); + equals( x[1].id, "x2", "Check on-the-fly element2" ); + + var x = jQuery([]).add(jQuery("

xxx

").appendTo(tmp)[0]).add(jQuery("

xxx

").appendTo(tmp)[0]); + equals( x[0].id, "x1", "Check on-the-fly element1" ); + equals( x[1].id, "x2", "Check on-the-fly element2" ); + var x = jQuery([]).add(jQuery("

xxx

")).add(jQuery("

xxx

")); equals( x[0].id, "x1", "Check on-the-fly element1" ); equals( x[1].id, "x2", "Check on-the-fly element2" ); diff --git a/test/unit/data.js b/test/unit/data.js index 6a367f78cc..8401fce87e 100644 --- a/test/unit/data.js +++ b/test/unit/data.js @@ -32,7 +32,7 @@ test("jQuery.data", function() { jQuery.data(div, "test", "success"); equals( jQuery.data(div, "test"), "success", "Check for added data" ); - var data = jQuery.data(div, true); + var data = jQuery.data(div); same( data, { "test": "success" }, "Return complete data set" ); jQuery.data(div, "test", "overwritten"); diff --git a/test/unit/manipulation.js b/test/unit/manipulation.js index 541776ceb5..1b99b66701 100644 --- a/test/unit/manipulation.js +++ b/test/unit/manipulation.js @@ -340,7 +340,7 @@ var testBefore = function(val) { jQuery('#yahoo').before(val( jQuery("#first, #mark") )); equals( expected, jQuery('#en').text(), "Insert jQuery before" ); - var set = jQuery("
").before(val("test")); + var set = jQuery("
").before("test"); equals( set[0].nodeName.toLowerCase(), "span", "Insert the element before the disconnected node." ); equals( set.length, 2, "Insert the element before the disconnected node." ); } @@ -396,7 +396,7 @@ var testAfter = function(val) { jQuery('#yahoo').after(val( jQuery("#first, #mark") )); equals( expected, jQuery('#en').text(), "Insert jQuery after" ); - var set = jQuery("
").after(val("test")); + var set = jQuery("
").after("test"); equals( set[1].nodeName.toLowerCase(), "span", "Insert the element after the disconnected node." ); equals( set.length, 2, "Insert the element after the disconnected node." ); }; diff --git a/test/unit/traversing.js b/test/unit/traversing.js index 46a49bb978..2793f2f374 100644 --- a/test/unit/traversing.js +++ b/test/unit/traversing.js @@ -145,8 +145,8 @@ test("not(jQuery)", function() { test("andSelf()", function() { expect(4); - isSet( jQuery("#en").siblings().andSelf().get(), q("sndp", "sap","en"), "Check for siblings and self" ); - isSet( jQuery("#foo").children().andSelf().get(), q("sndp", "en", "sap", "foo"), "Check for children and self" ); + isSet( jQuery("#en").siblings().andSelf().get(), q("sndp", "en", "sap"), "Check for siblings and self" ); + isSet( jQuery("#foo").children().andSelf().get(), q("foo", "sndp", "en", "sap"), "Check for children and self" ); isSet( jQuery("#sndp, #en").parent().andSelf().get(), q("foo","sndp","en"), "Check for parent and self" ); isSet( jQuery("#groups").parents("p, div").andSelf().get(), q("main", "ap", "groups"), "Check for parents and self" ); }); @@ -157,7 +157,7 @@ test("siblings([String])", function() { isSet( jQuery("#sndp").siblings(":has(code)").get(), q("sap"), "Check for filtered siblings (has code child element)" ); isSet( jQuery("#sndp").siblings(":has(a)").get(), q("en", "sap"), "Check for filtered siblings (has anchor child element)" ); isSet( jQuery("#foo").siblings("form, b").get(), q("form", "floatTest", "lengthtest", "name-tests", "testForm"), "Check for multiple filters" ); - var set = q("en", "sap", "sndp"); + var set = q("sndp", "en", "sap"); isSet( jQuery("#en, #sndp").siblings().get(), set, "Check for unique results from siblings" ); });