jQuery.support.parentNode disappeared between 1.4.2 and 1.5.1. It is used in domManip to check (in a very suspicious way) if a fragment can be reused.
Since jQuery.support.parentNode is not defined any more, that "optimization" is never applied.
Instead of removing the jQuery.support.parentNode part to re-enabling the optimization, I suggest to remove it entirely because it would unlikely happen anyway, and could wrongly reuse an existent fragment that contains not only the interested elements.
The other thing that I spotted is about code introduced by this commit. Removing that code, I was unabled to reproduce the bug because I have not an sufficiently old WebKit browser. However, even without reproducing it, it is obvious that the check (and respective unit tests) considers only the first argument, and only if it is a string, ignoring the fact that a fragment could also be generated (and than cloned) by rest of arguments, and that those arguments can also be existent nodes. Also, the fix ignores the fact that jQuery.clone already handles similar problems, so to resolve this I suggest to remove any usage of support.checkClone and to combine it with support.noCloneChecked. In this way jQuery.clone would be able to automatically handle the problem via cloneFixAttributes.
For both problems I am willing to open tickets with respective patches.
First off all I would precise that I am a huge fan of .on/off() as much better names then .bind/unbind() (shorter and less confusion with func.bind()).
Also I applause the decision to deprecate .live/die() for too many reasons...
However, I am not that excited for also making .on/off() the substitution for .delegate/undelegate(). I think it could raise too many readability issues, and I would like to expose some of those.
Using .delegate() it is immediately clear that we are doing some event delegation, while using .on(), the reader have to spot, not the first, but the second argument to conclude the same thing.
Also, in my opinion, .delegate() has much better arguments order. Having the selector as first argument is not only more logical reading the entire line from left to right, but also provides much clear/structured delegation using map of events:
$("#foo").delegate(".boo", {
"click": function( event ) {
blablabla( filililula, hahaha );
},
"hover": function( event ) {
blablabla( filililula, hahaha );
}
);
$("#foo").on({
"click": function( event ) {
blablabla( filililula, hahaha );
},
"hover": function( event ) {
blablabla( filililula, hahaha );
}},
".boo"
);
Using .delegate() it is clear form the first line on which elements two handlers will be applied, while using .on(), the reader have to scroll at the very end to only realize that it is delegation and not simple binding.
At the end, .on() is shorter then .delegate(), but it makes code less readable when used for event delegation, making our code harder to maintain.
Maybe it is too late, but I would still ask you to consider to un-deprecate .delegate/undelegate() and to deprecate .on/off() for event delegation instead.
Sorry guys, but there are problems how errors are handled while resolving an deferred. So I will try to explain those, and to propose some possible solutions.
My English is not specially good, so I will try to be as concise as possible.
Running this test, you will get "A ! B D" as result. The last line is not evaluated because resolve() throws an error (do not catch the thrown one). For that reason, "C" is never displayed in the result. Maybe this is expected, so I will not necessarily consider this as a problem.
"D" is the one called asynchronously. Removing it, you will get "A !". See the test. So the "B" is missing!
I you look at the resolveWith() code, you will see that the thrown "!" is not caught, so the "B" callback is not called at all. The reason why it appears in the first test, is because the async "D" call (10ms after) forced the rest of callbacks (B and D) to be called.
In this way, the result of the second test would be "A ! B".
Solution B
It could be important to make resolving an safe operation. In that way you could safely chain the resolve() and resolveWith(), but also safely resolve more deferreds:
dfd0.resolve();
dfd1.resolve();
In that case the result of the second test would be "A ! B C" and "A ! B C D" in the first one.
So to accomplish that we could simply replace the jQuery.error(e) of the solution A with a jQuery.reportError(e) that would simply output the error to console (if exists).
For quite some time now I had intention to open this discussion because of increasing tendency of using data/event API on native objects.
Why this is a problem? Well, the current $.data implementation is optimized for host objects only, and not for native objects too. In fact, it uses a cache object to store all related data and an expando with numerical values to keep references. The need of such solution is unquestionable and it fits well because elements are normally "eliminated" by using .remove() that also cleans respective data. Native objects, in other hand, are not "eliminated" with such call, and related data exists until the window is closed.
Of course, this problem also exists with the event API, that uses data API to store handlers...
Solution A Probably the easiest fix would consist on storing data as expando property of native objects.
// ...
if ( elem.nodeType ) {
cache[ id ] = dataObject;
elem[ expando ] = id;
} else {
elem[ expando ] = dataObject;
}
// ...
Inheritance problem Unfortunately that fix would not be sufficient once the object inheritance will become mainstream.
$.data( objA ) === $.data( objB ) // => true - ...objA and objB have the same data object!
If you think that the returned value at line 5 would be 'undefined', then using hasOwnProperty on reading objectData of native objects will resolve the problem at lines 7-9. Otherwise, keep reading.
Solution B To inherit values of parent objects, we have to store values in native objects itself!
// ...
if ( elem.nodeType ) {
dataObject[ name ] = value;
} else {
elem[ expando +"_" + name ] = value;
}
// ...
The only lack of this solution is that we can not return the data object of the native object, because it doesn't exists!
$.data( objA ); // => null? there is no data objects for native objects!
jQuery.fn.filter also works with callbacks (apart selectors, and elements). jQuery.filter doesn't.
I would propose to integrate jQuery.grep inside jQuery.filter and to make those aliases.
Also consider that there is intention to add a jQuery.forEach that would be inline to the ES5 spec, and making jQuery.filter inline with that spec too would be a logical move anyway.
Now that jQuery.makeArray(nodeList) is supported correctly, maybe it is wanted to make that also for jQuery.each, jQuery.map and jQuery.grep. There are mainly two reasons why I think it is worth of consideration: 1. $.each(nodeList) is already possible and I suppose that there are individuals that are considering that action legal because NodeLists are array like things too. Unfortunately it is not always true in IE and Opera where length expando can be overwrited. 2. Using $.each, $.map and $.grep directly with NodeLists can be still useful, not only for optimizing jQuery itself. I made a patch that would fix this http://github.com/rkatic/jquery/commit/7203092c23d5ddb623495f9145d2dab3edf1c529 If this change is welcome, than I will open a ticket... --
Wat a hell is going here? // Recurse if we're merging object values if ( deep && copy && typeof copy === "object" && !copy.nodeType ) { var clone; if ( src ) { clone = src; } else if ( jQuery.isArray(copy) ) { clone = []; } else if ( jQuery.isObject(copy) ) { clone = {}; } else { clone = copy; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); You are going to extend with any object including a Date, a String, a Number... (ah yes, excluding nodes). You are going to extend (with) arrays? [1,2] and [4] to obtain [4,2]. Really? If an object is not an array nor an object literal then extend object with itself??? The only things to extend recursively are objects literals to me: if ( deep && copy && jQuery.isObject(copy) && (!src || jQuery.isObject (src)) ) { target[ name ] = jQuery.extend( deep, src || {}, copy ); } Am I loosing my mind? :) --
Using $.fn.add(selector) the context property remains the same. It's ok, but the given selector will be applied always with the default context (document). This is not correct for me if we are using jQuery with xml documents for example. $("user", xmlDoc).add("lusers"); There is no way to add lusers of the xmlDoc document! Here an optional context argument would be useful: $("user", xmlDoc).add("lusers", xmlDoc); But even this is not ideal for me. If the context argument is not given (first example), which document would be used? I suppose the obvious answer is xmlDoc. An corrected implementation of add() would be something like this: jQuery.fn.add = function( selector ) { return this.pushStack( jQuery.unique( jQuery.merge( this.get(), typeof selector === "string" ? jQuery( selector, (this.context || this[0] || 0).ownerDocument ) : jQuery.makeArray( selector ) ))); }; --
jQuery.merge() is the only function that discards comment nodes (?). This means that $( nodeList ) can contains comment nodes, but $([]).add( nodeList ) can not. Why such different behaviors? Is the jQuery.makeArray() more appropriate to filter comment nodes? Am I missing something here? --
I suppose it is rear to use multiple namespaces to unbind an event and that it is the reason why no one spotted this bug (I spotted it by examining code, not by using the feature). This is the problem: $("div").bind("click.aaa.bbb", function(){...}); $("div").unbind("click.a.bbb"); //this is unbinding the previous bind!!! Now someone would suppose: "Well it seams fine, there is .bbb so it will unbind click.aaa.bbb too", but it is not true: $("div").unbind("click.bbb.other") // will not unbind click.aaa.bbb The problem seams to be the generated regexp into event.remove() and event.handle(): var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\ \.") + "(\\.|$)"); that for me would be: var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join("\\. (?:.*\\.)?") + "(\\.|$)"); Am I missing something here? Here is a test-case http://jsbin.com/aledo And here is the same case with the corrected event.remove() function: http://jsbin.com/eqofo (I hope jsbin.com has no problems any more) Will I open a ticket?
I suppose it is rear to use multiple namespaces to unbind an event and that it is the reason why no one spotted this bug (I spotted it by examining code, not by using the feature). This is the problem: $("div").bind("click.aaa.bbb", function(){...}); $("div").unbind("click.a.bbb"); //this is unbinding the previous bind!!! Here is a test-case http://jsbin.com/aledo And here is the same case with the corrected even.remove() function: http://jsbin.com/eqofo (I hope jsbin.com has no more problems) Will I open a ticket?
The querySelectorAll returns elements in documents order, but Sizzle (for now?) treat each selector separately. Maybe this can be easily resolved joining each result array in one with nodes in documents order? If so, maybe something like this would help (not tested). Or you are thinking to sort results all together? var precedes = ( document.documentElement.sourceIndex == 0 ) && function( a, b ) { return a.sourceIndex < b.sourceIndex; } || ( document.documentElement.compareDocumentPosition ) && function( a, b ) { return !!( a.compareDocumentPosition(b) & 4 ); } || function( a, b ) { if ( a === b || b.contains(a) ) return false if ( a.contains(b) ) return true; var c = a.parentNode; while ( !c.contains(b) ) { a = c; c = c.parentNode; } var p = b.parentNode; while ( p !== c ) { b = p; p = p.parentNode; } var nodes = c.childNodes; for ( var i = 0, node = nodes[0]; node; node = nodes[+ +i] ) { if ( node === a ) return true; if ( node === b ) return false; } return false; }; function joinResultsHelper( res, a, i, b, j ) { if ( b[j] ) { for ( var l = a.length; i < l; ++i ) { if ( a[i] === b[j] ) ++j; else if ( precedes(a[i], b[j]) ) res.push( a[i] ); else { res.push( b[j++] ); joinResultsHelper( res, b, j, a, i ); break; } } } else { for ( var l = a.length; i < l; ++i ) res.push( a[i] ); } return res; } function joinResults( a, b ) { if ( a.length === 0 ) return b; if ( b.length === 0 ) return a; return joinResultsHelper( [], a, 0, b, 0 ); }
My English is not so good so will be short. I am not sure why the get() function exists. Because it is shorter then toArray()? But my code would by more clear with an toArray instead, An foo.get(index) is not clearer nor shorter then foo[index] for me. In my opinion the "get" function is not really necessary and would by deprecated if an more explicit toArray would exists. The implementation of toArray() would be banal: jQuery.fn.toArray = function() { return Array.prototype.slice.apply (this, arguments) }; or even: jQuery.fn.toArray = Array.prototype.slice; Thoughts? Am I disregarding something here?