La explicación más corta es "jQuery 1.8.0 tiene un error en ella, actualice a 1.8.1 para el arreglo", pero que no acaba de responder a todo.
jQuery 1.8.x tiene un motor "Sizzle" significativamente mejorado, que es lo que usa para los selectores. La forma en que se llaman los selectores personalizados se ha alterado como parte de este cambio, pero además se ha alterado la forma en que se procesan muchos selectores. Varias suposiciones sobre el orden en que se procesan las reglas ya no son ciertas, etc. También es significativamente más rápido en varios casos de uso.
Incluso al actualizar a la versión 1.8.1, aún verá que las cosas se ven bastante diferentes de como lo hicieron en 1.7.2 (la última versión de la serie anterior a la 1.8.x) al procesar el ejemplo que proporcionó . Esto explica lo que está viendo en la selección de "el primer elemento <a> en la página". Es decir: su expectativa de cómo funcionan los selectores personalizados no es cómo realmente funcionan, y si permitió que el ciclo continuara (en lugar de llamar a "depurador" en la primera iteración), vería que en realidad está pasando por todos <a> elementos). En resumen: Sizzle no garantiza en qué orden se llamarán las distintas reglas, solo que el resultado las igualará a todas.
Si está seguro de que su regla personalizada será menos eficiente que otras reglas (quizás porque está seguro de que otras reglas pueden reducir drásticamente la cantidad de elementos coincidentes), puede forzarlas a ejecutar primero seleccionándolas, a continuación, llamar .find() en sólo que subconjunto de elementos, por ejemplo:
$(".ui-datepicker-calendar").find("td a:test(3)");
cuanto a la "pila" está sin definir, como Kevin B señala, aunque la actualización 1.8.1 restaura compatibilidad hacia atrás, el API ha cambiado, y parece que "stack" simplemente ya no pasa al pseudo. Esto tiene sentido, en realidad, debido al orden alterado en que se pueden llamar las pruebas. Es decir: la pila está vacía en el momento en que la alcanzas, porque "ver si alguno de los elementos <a> coincide con este pseudo-selector" es la primera regla que se procesa. Las pruebas siempre deben ser autocontenidas, por lo que la pila no sería realmente útil de todos modos (solo puede generar confusión).
Entonces, si 1.8.1 restaura la compatibilidad con versiones anteriores, ¿cuál es el método compatible con versiones anteriores para crear pseudo-selectores? Como puede ver en the documentation for Sizzle's pseudo-selectors, el método preferido para crear pseudo-selectores a partir de jQuery 1.8 es el método "createPseudo" ($ .expr.createPseudo), que prefiere usar un cierre en lugar del argumento "meta". Así que para sus ejemplos particulares, las "nuevas" formas de hacer ellos serían:
$.expr[":"].test = $.expr.createPseudo(function(tomatch)
{
return function(el2)
{
debugger;
console.log(el2); // not much else to see here
};
})
donde "tomatch" es el argumento al: prueba (...) Selector. Como puede ver, los argumentos adicionales que estaba buscando ya no son necesarios en esta nueva sintaxis. En cuanto a algo un poco más útil:
$.expr[":"].exactly = $.expr.createPseudo(function(s)
{
return function(el)
{
if(!s) return false;
return eval("/^" + s + "$/i").test($(el).text());
};
});
Esta versión de "exactamente" debe ser compatible con 1.8+, y es el método preferido * de hacer las cosas.
Creo que incluso con el bache en la versión jQuery/api, el código que proporcionó todavía no hará exactamente lo que quiere, ya que es probable que el datepicker se reconstruya por el capricho del complemento. Todavía hay un breve momento en el que puede ver que los elementos deseados se resaltan de la manera prevista, por lo que el selector en sí parece estar funcionando.
A continuación encontrará un ejemplo completo, basado en las muestras que proporcionó. Puede ver las diferencias en el comportamiento cambiando la versión de jQuery utilizada entre 1.7.2, 1.8.0 y 1.8.1. Para la compatibilidad entre versiones, se ha agregado una prueba para $ .expr.createPseudo a las asignaciones de función de pseudo-selector. Tenga en cuenta que todo "depurador"; las declaraciones han sido comentadas, ya que tener un punto de corte en cada iteración en todos los enlaces de fecha en datepicker es bastante tedioso, y la llamada a getJSON ha sido burlada para permitir que la prueba sea independiente.
<html>
<head>
<title>jQuery custom selector, "undefined"</title>
<!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.js"></script> -->
<!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.js"></script> -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.js"></script>
<link rel="stylesheet"
href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/themes/base/jquery-ui.css" />
<script>
$(function()
{
$.expr[":"].test = $.expr.createPseudo ?
$.expr.createPseudo(function(tomatch)
{
return function(el2)
{
// debugger;
console.log(el2);
};
}) :
function(el2,index2,meta2,stack2)
{
// debugger;
console.log(el2);
console.log(index2);
console.log(meta2);
console.log(stack2);
};
})
$(function()
{
function getJsonDate(year, month)
{
//$.getJSON('dates.php?year='+year+'&month='+month, function(data)
//{
var data = {data:[
{d:1,link:"a"},
{d:15,link:"b"},
{d:25,link:"c"}
]};
var i = 0;
for (i = 0; i < data.data.length; i++)
{
// debugger;
var myDay = data.data[i]['d'];
$('.ui-datepicker-calendar td a:exactly('+data.data[i]['d']+')').
css({color: '#f00'}).
attr('href',data.data[i]['link']).
parent().attr('onclick','');
}
//});
}
$.expr[":"].exactly = $.expr.createPseudo ?
$.expr.createPseudo(function(s)
{
return function(el)
{
if(!s) return false;
return eval("/^" + s + "$/i").test($(el).text());
};
}) :
function(el, index, meta, stack)
{
// debugger;
console.log(el);
console.log(index);
console.log(meta);
console.log(stack);
var s = meta[3];
if (!s) return false;
return eval("/^" + s + "$/i").test($(el).text());
};
$('#datepicker').datepicker(
{
inline: true,
onSelect: function(dateText, inst)
{
Date.prototype.toString = function() {
return isNaN (this) ?
'NaN' :
[this.getDate(), this.getMonth(), this.getFullYear()].join('/')
}
d = new Date(dateText);
getJsonDate(d.getFullYear(), d.getMonth()+1);
},
onChangeMonthYear: function(year, month, inst)
{
//alert(year);
//alert(month);
getJsonDate(year, month);
return false;
}
});
});
</script>
<script>
(function($){$(function(){
$("<input />").
attr({type:"button", value: "run test selector"}).
click(function(){
$(".ui-datepicker-calendar td:test(3) a");
// Or, if you are certain that your test will be less-efficient than an exclusion based
// on parents, you could do:
// $(".ui-datepicker-calendar").find("td a:test(3)");
}).
appendTo("body");
})}(window.jQuery));
</script>
</head>
<body>
<a href="#ignoreThisLink">.</a>
<a href="#ignoreThisToo">.</a>
<p>
(first, click the input box to cause the datepicker to initialise)
</p>
<input type="text" id="datepicker" />
</body>
</html>
Espero que eso ayude a arrojar algo de luz sobre las cosas.
* Digo que este es el método "preferido", pero todavía está utilizando "eval". Esto es altamente desaconsejado, ya que es lento y puede conducir a resultados inesperados/sorprendentes/peligrosos. Una mejor manera de construir expresiones regulares en base a una cadena sería
return (new RegExp("^" + s + "$", "i")).test($(el).text());
aunque incluso esto no tiene problemas, como "s" puede contener RegExp especiales caracteres. En este caso particular, sin embargo, una expresión regular no es ni siquiera necesario, y las cosas se puede probar mucho más eficiente a través de:
return String(s).toUpperCase() === $(el).text().toUpperCase();
Incluso puede guardar un poco más rodando la conversión en el cierre, que le da la función completa de:
$.expr[":"].exactly = $.expr.createPseudo(function(s)
{
if(!s) return function(){ return false; };
s = String(s).toUpperCase();
return function(el)
{
return (s === $(el).text().toUpperCase());
};
});
corrí al mismo problema esta mañana pasó 2h, para mí meta aún no está definido. Estaba funcionando perfectamente antes, por favor mantenme actualizado si encuentras algo. Gracias. –
Hola @JakubKuchar, no logré que funcione, así que hice una solución y seleccioné el elemento que necesitaba de otra manera. Pero aun así estoy realmente interesado en saber la respuesta. – Jordashiro
Sizzle se actualizó en jQuery 1.8, lo que generó importantes cambios de sintaxis en la creación del selector personalizado. Mire la documentación de chisporroteo para más información. https://github.com/jquery/sizzle/wiki/Sizzle-Documentation Parece que si actualiza a jQuery 1.8.1, los selectores antiguos volverán a funcionar. –