I have noticed that the problem comes from the functions dirCheck and
dirNodeCheck.
I am trying to explain the problem that leads me to this solution :
if you type this selector for exemple :
"div .foobar"
this will search elements with the class "foobar", then the first
parent Node that is a div. For example :
<div><div><p class="foobar"></p></div></div>
This will stop the search at the second div.
In that case, that works, because we are asking for nodes whose class
is "foobar" and who has a div parent node.
Now, we type this selector :
".bar ~ div .foobar"
this will do the same search, but this will check for each first div
ancestor Node, if there is a "previous sibling" node whose class is
"bar".
Now, consider two examples :
- this one works :
<div><span class="bar">foo</span><div><p class="foobar">hi</p></div></
div>
because the second div is after a node whose class is "bar"
- this one does not work with Sizzle, but works with CSS
<span class="bar">foo</span><div><div><p class="foobar">hi</p></div></
div>
because the second div node (who is the first ancestor of ".foobar")
is not after a node whose class is "bar".
However, the grand-parent node (the first div node) is really after a
node whose class is "bar".
Thus, in the piece of code I wrote, I add all ancestors nodes (even
grand-parent nodes ...) in an array (others) and if there is no match,
the next "other" node is shifted.
But, this must not be optimized enough. Moreover, I had to disable the
cache functionality .
I hope this will help, and that my explanation is clear enough. Sorry
for the possible mistakes or non-sens I did.
function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck,
isXML ) {
var sibDir = dir == "previousSibling" && !isXML;
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
if ( sibDir && elem.nodeType === 1 ){
elem.sizcache = doneName;
elem.sizset = i;
}
elem = elem[dir];
var match = false;
while ( elem ) {
if ( elem.sizcache === doneName ) {
if(!match) // modifs
match = checkSet[elem.sizset];
else if(elem.nodeName != "BODY" ){
match.others = match.others || new Array();
match.others.push(checkSet[elem.sizset]);
}
else
break;
elem = elem[dir];
continue;
}
if ( elem.nodeType === 1 && !isXML ){
elem.sizcache = doneName;
elem.sizset = i;
}
if ( elem.nodeName === cur ) {
if(!match) // modifs
match = elem;
else if(elem.nodeName != "BODY"){
match.others = match.others || new Array();
match.others.push(elem);
}
else
break;
elem = elem[dir];
continue;
}
elem = elem[dir];
}
if(!match && checkSet[i].others && checkSet[i].others.length > 0){
var tmp = checkSet[i].others;
checkSet[i] = tmp.shift();
checkSet[i].others = tmp;
tmp = null;
i--;
}
else
checkSet[i] = match;
}
}
}
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
var sibDir = dir == "previousSibling" && !isXML;
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
if ( sibDir && elem.nodeType === 1 ) {
elem.sizcache = doneName;
elem.sizset = i;
}
elem = elem[dir];
var match = false;
while ( elem ) {
if (false && elem.sizcache === doneName ) { // disabled ! (causes
problems with the modifications)
match = checkSet[elem.sizset];
if(match != false)
break;
}
if ( elem.nodeType === 1 ) {
if ( !isXML ) {
elem.sizcache = doneName;
elem.sizset = i;
}
if ( typeof cur !== "string" ) {
if ( elem === cur ) {
match = true;
break;
}
} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
match = elem;
break;
}
}
elem = elem[dir];
}
if(!match && checkSet[i].others && checkSet[i].others.length > 0){
var tmp = checkSet[i].others;
checkSet[i] = tmp.shift();
checkSet[i].others = tmp;
tmp = null;
i--;
}
else
checkSet[i] = match;
}
}
}