En un proyecto personal utilizo la archiconocida librería javascript jQuery y varios iframes en los que necesito utilizar la mencionada librería.
Concretamente, la página contiene varios iframes, es decir, tenemos una ventana padre principal (top o parent window) y varias ventanas hijas (iframes o child windows).
Como ya sabreis el lenguaje Javascript permite la comunicación entre scripts situados en diferentes ventanas anidadas (frames e iframes) mediante varias propiedades del objeto window (frames, parent, top y self).
De modo que incluí jQuery exclusivamente en la ventana padre (etiqueta script) y en cada iframe haría una referencia al objeto $ o jQuery de la ventana padre como se suele hacer en javascript para no tener que incluir la librería jQuery en cada iframe:
// Codigo en iframe, referencia al objeto jQuery de la ventana padre
$ = window.top.$;
// Utilizamos jQuery
$(...);
Bien, probamos y tachan…no funciona el código javascript (jQuery) del iframe.
¿Por qué no funciona?
Bien, el problema surge porque jQuery a partir de la versión 1.4 se autoinicializa “sandboxed” y establece por defecto la ventana (objeto window) en la que se incluye la librería (etiqueta script) como contexto padre para todos los selectores que pasemos a jQuery.
Es decir, el contexto de nuestros selectores será la ventana padre, no la ventana del iframe (ventana hija) en la que se ejecuta nuestro código y, por tanto, la selección de nodos no funciona.
Soluciones:
- Establecer el contexto correcto en cada selección:
En mi opinión, esta solución es poco idónea ya que por cada selector tendremos que especificar el contexto de ventana o documento correcto y en los casos de selectores más complejos en los que es recomendable especificar un contexto a partir del cual realizar la selección el tema se complica más hasta hacerse incomodísimo, de modo que ideé a la siguiente solución.// Codigo en iframe, referencia al objeto jQuery de la ventana padre $ = window.top.$; // Utilizamos jQuery fijando el contexto de ventana correcto (ventana del iframe) $("a", window.document); // Funciona!! - La función jQueryContext:
Dado que jQuery se inicializa sandboxed (dentro de una función anónima) y no nos provee de un método para cambiar el contexto de la ventana o documento sólo me quedaba la opción de modificar la inicialización de la librería. La modificación es muy sencilla, basta con modificar la primera y última línea de la librería y solucionado:
De este modo, en cada ventana hija (iframe o frame) podremos modificar el contexto del documento en una sola sentencia y utilizar jQuery normalmente:// Modificar primera y última línea de jQuery 1.4.x: (function( window, undefined ) { // ........ // ........ })(window); // por: window.jQueryContext = function(window, undefined){ // ...... // ...... }; window.jQueryContext(window);
Y eso es todo!!// Código en iframe. jQuery no incluido en iframe, unicamente en la ventana padre // Inicializamos jQuery y fijamos el contexto de los selectores a la ventana o documento del iframe window.top.jQueryContext(window); // Utilizamos jQuery en el iframe como si no hubiera pasado nada $("a", $("#links")); // Funciona!!
Envié un ticket al equipo de jQuery, lo consideraron pero decidieron no dar soporte para este caso por ahora. De todos modos se tomaron la molestia de crear un archivo make para el compilador de Google para que pudiese compilar jQuery con mi modificación.
Notas finales:
- Si incluís jQuery en cada iframe (que lo considero una chapuza y es lo que quería evitar) no tendris ningún problema con los contextos ya que cada instancia de jQuery tendrá como contexto la ventana o documento que lo ha incluido.
- No es posible modificar el contexto del documento o ventana mediante un plugin debido al modo de autoinicialización de jQuery.
Espero que a alguno de vosotros le sirva si se encuentra con el problema y si necesita el script modificado, que lo pida y lo colgaré en nuestro servidor.