javascript - iframewin - postmessage receivemessage
Javascript de ventana cruzada: ¿hay una manera correcta? (4)
Problema
Estoy intentando hacer un método que transfiera objetos a un método similar en una ventana emergente. No tengo control sobre el código en el método de destino o el objeto pasado. El método de destino actualmente serializa el objeto, usando JSON.stringify
siempre que sea posible, o instanceof Array
.
El primer problema con esto es un error en IE8 (ver a continuación). El segundo, y más fundamental, es que las primitivas no son las mismas en las ventanas:
w = open("http://google.com")
w.Array == Array // returns false
Anulando en la ventana emergente cualquier clase que pueda pasarse, y luego restaurándolas después de que la llamada funciona, pero es realmente frágil y un dolor de cabeza de mantenimiento.
Serializando el objeto en JSON y luego analizándolo en el contexto de la ventana, aparece el siguiente error de Firefox.
También soy un poco reacio a hacer una copia profunda del objeto o analizar el JSON utilizando new w.Object
, etc. porque no parece que deba ser tan complicado.
¿Alguien puede sugerir una manera sensata de tratar con esto, o debería simplemente aceptar que los objetos no se pueden pasar textualmente entre ventanas?
IE bug
JSON.stringify
no funciona en todas las ventanas de IE8. Si paso un objeto al menú emergente, que intenta serializarlo, stringify devuelve undefined
. Para ver este problema, abra la consola de script en IE8 e intente:
w = open("http://google.com")
JSON.stringify(Object()) // returns "{}"
w.JSON.stringify(w.Object()) // returns "{}"
w.JSON.stringify(Object()) // returns "undefined" on IE8
JSON.stringify(w.Object()) // returns "undefined" on IE8
JSON.stringify([1, w.Object()]) // returns "[1,null]" on IE8
Intenté w.JSON = JSON
esto configurando w.JSON = JSON
, pero como muestra la última prueba, se rompe cuando tienes objetos de ambas ventanas.
Error de Firefox
Parece que llamar a w.Object()
para crear un objeto en Firefox llama a window.Object()
. El mismo error se produce al llamar a w.JSON.parse
o w.eval
. Para ver esto, abre la consola de Firebug y prueba:
w = open("http://google.com")
new w.Object instanceof w.Object // returns true
w.Object() instanceof w.Object // returns false on Firefox 3.5
w.Object() instanceof Object // returns true on Firefox 3.5
w.Object.call(w) instanceof Object // returns true on Firefox 3.5
w.JSON.parse("{}") instanceof w.Object // returns false on Firefox 3.5
w.JSON.parse("{}") instanceof Object // returns true on Firefox 3.5
w.eval("[]") instanceof w.Array // returns false on Firefox 3.5
w.eval("[]") instanceof Array // returns true on Firefox 3.5
w.eval.call(w, "[]") instanceof Array // returns true on Firefox 3.5
La única solución que puedo ver es analizar la cadena JSON yo mismo.
Para ver esto, abre la consola de Firebug y prueba:
Error: Permiso denegado para <> para obtener la propiedad Window.Object de <google>. En cualquier línea, excepto la primera: w = abrir (" http://google.com ") Firefox 3.5.7
Piense por un momento: está tratando de abrir una nueva ventana con un sitio arbitrario y le envía los datos disponibles a js. Parece demasiado inseguro para permitir esto.
No puedo decir que entienda su problema por completo, pero hay un interesante truco de window.name
que merece la pena visitar: http://www.sitepen.com/blog/2008/07/22/windowname-transport/ (la publicación del blog usa dojo pero, por supuesto, también se puede hacer con JS puro). Es más seguro que JSONP, fácil de implementar y parece funcionar en todos los navegadores.
Básicamente, le permite almacenar cualquier dato, de cualquier longitud en la variable window.name
. Lo increíble es que esta variable no se borra / borra al cambiar / actualizar la página, por lo que con un uso inteligente de iframes obtienes un transporte entre dominios simple y seguro :)
Por lo que vale, esto es lo que estoy haciendo por ahora:
- Asegúrese de que jquery-json esté cargado en la ventana emergente
- Stringify el objeto
- Llame a
w.$.evalJSON(str)
, que une las primitivas correctamente - Pase ese resultado al método en la ventana emergente
Alternativamente (si jquery-json no está disponible), puede inyectar la siguiente secuencia de comandos en el destino:
<script type="text/javascript">
function parseJSON(j) {
return JSON.parse(j)
}
</script>
ya que capturará el JSON de la ventana emergente, y no el de la persona que llama.
Cualquier mejor solución agradecida.
Si está intentando hacer scripts de dominios cruzados, parece que vale la pena investigar JSONP .