Imprimir capas
Agradecería muchísimo si me contaras por favor (es que llevo bastante tiempo rompiéndome la cabeza) como podría imprimir el contenido de una capa tanto en netscape como en iexplore.
Muchas gracias.
Muchas gracias.
1 Respuesta
Respuesta de bruckner
1
1
El problema de imprimir tan sólo una parte del contenido de una página determinada es *extremadamente* complejo de resolver, en particular cuando se tienen en cuenta todos los navegadores.
El problema fundamental es que print() es un método del objeto window, con lo que sólo puede invocarse sobre ventanas o marcos (frames). No así sobre una capa. Dicho esto, hay varios enfoques posibles para atacar el asunto:
a) Una solución que funcionara en todos los navegadores pasaría necesariamente por la duplicación del contenido de la capa en una página HTML aparte, que podría cargarse en una ventana (o mejor aún, en un frame oculto), sobre el que sí puede usarse el método print().
b) Si nos olvidamos de las versiones antiguas (Netscape 4.x y Explorer 4) es posible trazar una solución (más o menos) compleja para imprimir el contenido de cualquier cosa, no sólo una capa, con tal de que el código HTML esté bien formado (que todos los tags se abran y cierren, y que si A se abre antes que B, B se cierre antes que A).
Para implementar la solución de b), es necesario contener la página de la que queremos imprimir capas en un FRAMESET como este:
<frameset rows="100%,*" border="0">
<frame name="main" src="test1.html" noresize>
<frame name="printBuffer" src="">
</frameset>
La página de la que vamos a sacar contenido para imprimir se llama test1.html. Observa que el frameset define dos frames, pero que uno de ellos no es visible (printBuffer), y que esta situación no puede alterarse debido al "noresize" del otro frame.
En test1.html...
<html>
<head>
<script language="Javascript"><!--
function printContents(idRef) {
var elem=document.getElementById(idRef);
if (!elem) {
alert('El elemento indicado no existe.');
return false;
}
var html='<html><head><\/head><body onload="focus();print()">';
html+=elem.innerHTML;
html+='<\/body><\/html>';
parent.printBuffer.document.write(html);
parent.printBuffer.document.close();
}
// --></script>
</head>
<body>
<div id="capa0" style="position:absolute;top:200;left:200;height:200;width:200">
<h1>Texto de prueba 1</h1>
<hr>
Aquí insertamos texto de prueba.
</div>
<div id="capa1" style="position:absolute;top:250;left:250;height:200;width:200;z-index:2">
<h1>Texto de prueba 2</h1>
<hr>
Aquí insertamos texto de prueba.
</div>
<form>
<input name="contents" type="text"><input type="button" value="Imprimir" onclick="printContents(this.form.contents.value)">
</form>
</body>
</html>
Observa que es una página que tiene dos capas llamadas "capa0" y "capa1". Si tecleas "capa0" o "capa1" en la caja de texto, y pulsas Imprimir, se llama a la función printContents(), definida en el SCRIPT de cabecera.
Esta función utiliza la cadena de texto que se le pasa para buscar en la página un elemento que tenga ese nombre (atributo ID), y escribir dinámicamente su código interno (lo que contenga ese elemento) en el frame printBuffer, rodeado de algo de HTML que hace que se imprima en cuanto termine de escribirse.
He probado esta solución con un Explorer 5.5 y con Mozilla 0.9, que es el programa en el que se basa Netscape 6 (de hecho, Netscape 6 se basa en una versión anterior de Mozilla, pero eso no debería ser indicativo de problemas). Explorer tiene el curioso requerimiento de que el marco a imprimir debe tener el foco, así que por eso, en el código generado sobre la marcha para escribir en printBuffer, hay un focus() en el onLoad de BODY.
Como ves, no es sencillo, pero si te limitas a soportar los navegadores más modernos, es factible implementar esto sin recurrir a duplicar el contenido de las capas en ficheros HTML aparte, e imprimirlos mediante un frameset parecido al que te he descrito, o mediante ventanas independientes (solución todavía menos elegante...)
Pregúntame de nuevo si te surge cualquier duda sobre este u otros temas.
El problema fundamental es que print() es un método del objeto window, con lo que sólo puede invocarse sobre ventanas o marcos (frames). No así sobre una capa. Dicho esto, hay varios enfoques posibles para atacar el asunto:
a) Una solución que funcionara en todos los navegadores pasaría necesariamente por la duplicación del contenido de la capa en una página HTML aparte, que podría cargarse en una ventana (o mejor aún, en un frame oculto), sobre el que sí puede usarse el método print().
b) Si nos olvidamos de las versiones antiguas (Netscape 4.x y Explorer 4) es posible trazar una solución (más o menos) compleja para imprimir el contenido de cualquier cosa, no sólo una capa, con tal de que el código HTML esté bien formado (que todos los tags se abran y cierren, y que si A se abre antes que B, B se cierre antes que A).
Para implementar la solución de b), es necesario contener la página de la que queremos imprimir capas en un FRAMESET como este:
<frameset rows="100%,*" border="0">
<frame name="main" src="test1.html" noresize>
<frame name="printBuffer" src="">
</frameset>
La página de la que vamos a sacar contenido para imprimir se llama test1.html. Observa que el frameset define dos frames, pero que uno de ellos no es visible (printBuffer), y que esta situación no puede alterarse debido al "noresize" del otro frame.
En test1.html...
<html>
<head>
<script language="Javascript"><!--
function printContents(idRef) {
var elem=document.getElementById(idRef);
if (!elem) {
alert('El elemento indicado no existe.');
return false;
}
var html='<html><head><\/head><body onload="focus();print()">';
html+=elem.innerHTML;
html+='<\/body><\/html>';
parent.printBuffer.document.write(html);
parent.printBuffer.document.close();
}
// --></script>
</head>
<body>
<div id="capa0" style="position:absolute;top:200;left:200;height:200;width:200">
<h1>Texto de prueba 1</h1>
<hr>
Aquí insertamos texto de prueba.
</div>
<div id="capa1" style="position:absolute;top:250;left:250;height:200;width:200;z-index:2">
<h1>Texto de prueba 2</h1>
<hr>
Aquí insertamos texto de prueba.
</div>
<form>
<input name="contents" type="text"><input type="button" value="Imprimir" onclick="printContents(this.form.contents.value)">
</form>
</body>
</html>
Observa que es una página que tiene dos capas llamadas "capa0" y "capa1". Si tecleas "capa0" o "capa1" en la caja de texto, y pulsas Imprimir, se llama a la función printContents(), definida en el SCRIPT de cabecera.
Esta función utiliza la cadena de texto que se le pasa para buscar en la página un elemento que tenga ese nombre (atributo ID), y escribir dinámicamente su código interno (lo que contenga ese elemento) en el frame printBuffer, rodeado de algo de HTML que hace que se imprima en cuanto termine de escribirse.
He probado esta solución con un Explorer 5.5 y con Mozilla 0.9, que es el programa en el que se basa Netscape 6 (de hecho, Netscape 6 se basa en una versión anterior de Mozilla, pero eso no debería ser indicativo de problemas). Explorer tiene el curioso requerimiento de que el marco a imprimir debe tener el foco, así que por eso, en el código generado sobre la marcha para escribir en printBuffer, hay un focus() en el onLoad de BODY.
Como ves, no es sencillo, pero si te limitas a soportar los navegadores más modernos, es factible implementar esto sin recurrir a duplicar el contenido de las capas en ficheros HTML aparte, e imprimirlos mediante un frameset parecido al que te he descrito, o mediante ventanas independientes (solución todavía menos elegante...)
Pregúntame de nuevo si te surge cualquier duda sobre este u otros temas.
De antemano te agradezco el interés que has puesto para darme la solución. Muy poca gente se prestaría como tú para ayudar de una manera tan dedicada.
Muchísimas gracias.
No obstate me ha surgido un problemilla. Bueno es más bien una curiosidad.
Bueno, ya he aplicado tu solución, pero cuando he terminado de aplicarlo, me he dado cuenta de que innerHTML, no lo acepta netscape. Yo había llegado a probar lo siguiente con esta propiedad característica de explorer:
Había probado asignar a una variable, el contenido de la capa que yo quería imprimir con la propiedad innerHTML. Acto seguido, cuando pulsaba un botón de imprimir, abría una pag html:
<script language="JavaScript" >
// Capturamos el contenido de la capa mediante su identificador id y lo pasamos a una variable.
var n = (document.layers)? true:false;
var ie = (document.all)? true:false;
if (ie){
hello=eval("window.opener.document.all.id_de_la_capa.innerHTML");
document.write(hello);
// window.print();
}
if (n){
hello=eval("window.opener.document.id_de_la_capa.innerHTML");// aquí no funciona, y el valor de hello es undefined.
document.write(hello);
// window.print();
}
</script>
¿Habrá algo parecido a innerHTML en netscape? Yo lo he intentado buscar pero no lo encuentro.
Si se te ocurre alguna idea...
Muchas gracias de nuevo.
Muchísimas gracias.
No obstate me ha surgido un problemilla. Bueno es más bien una curiosidad.
Bueno, ya he aplicado tu solución, pero cuando he terminado de aplicarlo, me he dado cuenta de que innerHTML, no lo acepta netscape. Yo había llegado a probar lo siguiente con esta propiedad característica de explorer:
Había probado asignar a una variable, el contenido de la capa que yo quería imprimir con la propiedad innerHTML. Acto seguido, cuando pulsaba un botón de imprimir, abría una pag html:
<script language="JavaScript" >
// Capturamos el contenido de la capa mediante su identificador id y lo pasamos a una variable.
var n = (document.layers)? true:false;
var ie = (document.all)? true:false;
if (ie){
hello=eval("window.opener.document.all.id_de_la_capa.innerHTML");
document.write(hello);
// window.print();
}
if (n){
hello=eval("window.opener.document.id_de_la_capa.innerHTML");// aquí no funciona, y el valor de hello es undefined.
document.write(hello);
// window.print();
}
</script>
¿Habrá algo parecido a innerHTML en netscape? Yo lo he intentado buscar pero no lo encuentro.
Si se te ocurre alguna idea...
Muchas gracias de nuevo.
Como te comentaba en mi primera respuesta, la solución que usa innerHTML no sirve para Netscape 4 (sí para Netscape 6). Netscape 4 es un navegador obsoleto, y no deja de dar problemas a los desarrolladores...
El problema fundamental no es ya de por sí la inexistencia de innerHTML en Netscape 4, sino la imposibilidad de acceder a la mayor parte de los contenidos y propiedades de la página debido al limitadísimo interfaz DOM que proporciona. Lo único similar que se podría llegar a hacer iría por estas líneas:
El tag LAYER (la versión propietaria de capas que sólo funciona en Netscape 4 --no en Netscape 6, que usa DIV, igual que Explorer) admite un atributo SRC. Como habrás adivinado, puedes asignarle una URL a una capa, lo cual parece un avance impresionante. Eso es algo que Explorer sólo puede hacer mediante IFRAME, pero Netscape 4 tiene la ventaja de poder manejar LAYERs como capas transparentes, asignarles alturas (z-index)... mientras que Explorer (hasta la versión 5.5) no puede hacer IFRAMEs transparentes, por ejemplo.
Como verás, esto no nos acerca mucho a una solución, y tampoco es una gran ventaja para NS4. Empecemos por la "supuesta ventaja"...
Nada impide, en Explorer, cargar contenidos en un IFRAME oculto (con STYLE="display:none") y después acceder a ellos a través de la jerarquía document.all. A partir de Explorer 5 pueden usarse métodos del DOM para esto mismo; estos métodos también están disponibles en Netscape 6, con lo que la incorporación en una página de elementos cargados "a posteriori" se hace mucho más sencilla, e interoperativa.
La solución del SRC en el LAYER de NS4 puede ser más cómoda, pero no está bien implementada; hasta el punto de que es posible colgar el navegador en determinadas circunstancias si se usa.
Ahora veremos por qué no constituye una solución válida para el problema que nos ocupa: aunque podemos cargar contenido en un LAYER... NO SE PUEDE RECUPERAR. Es, a todos los efectos, invisible para nuestro código Javascript. No es posible (igual que no es posible acceder al texto de un <p></p>). Por tanto, no se puede "tomar", y "colocar" en un frame o una ventana, y mandarlo imprimir. Por añadidura, el método print() no puede aplicarse a LAYERs. Y en el caso de poderse aplicar, el resultado tampoco sería muy interesante, porque para empezar tendrías que disponer del contenido del LAYER en un fichero. ¿Por qué no cargarlo en un frame oculto e imprimirlo?
La ausencia de innerHTML en NS4 es uno de los principales motivos por los que este navegador debería desaparecer de la faz de la Tierra: hay una inmensa cantidad de aplicaciones que son totalmente imposibles de implementar en NS4 sólo por este detalle.
Si, a pesar de todo, quieres dar soporte a NS4, la única solución es que dispongas separadamente de todos los trozos de contenido imprimibles (en páginas separadas), con un onload="focus();print()" en el body. Soy consciente de que esto es muy difícil de mantener, porque tienes que disponer de copias separadas y sincronizadas de un mismo contenido: por un lado las capas incluidas en la páginas, y por otro los fragmentos destinados a la impresión. No importará que cargues estos fragmentos en una ventana aparte o en un frame oculto (y esto último es más elegante), pero no te librarás de hacer tu trabajo dos veces...
Una vez leí que "la Web es una de esas plataformas en las que hay cosas que, simplemente, no se pueden hacer". Algunas no se pueden hacer por diseño (por restricciones de seguridad), pero otras son imposibles por la incompetencia de los programadores de los navegadores. Y te aseguro que el peor de todos es Netscape 4.
Lamento la perorata... Y lamento no poder darte una solución aceptable para NS4: personalmente, te aseguro que no existe. Si quieres comentar cualquier otra cosa, no dudes en volverme a escribir.
El problema fundamental no es ya de por sí la inexistencia de innerHTML en Netscape 4, sino la imposibilidad de acceder a la mayor parte de los contenidos y propiedades de la página debido al limitadísimo interfaz DOM que proporciona. Lo único similar que se podría llegar a hacer iría por estas líneas:
El tag LAYER (la versión propietaria de capas que sólo funciona en Netscape 4 --no en Netscape 6, que usa DIV, igual que Explorer) admite un atributo SRC. Como habrás adivinado, puedes asignarle una URL a una capa, lo cual parece un avance impresionante. Eso es algo que Explorer sólo puede hacer mediante IFRAME, pero Netscape 4 tiene la ventaja de poder manejar LAYERs como capas transparentes, asignarles alturas (z-index)... mientras que Explorer (hasta la versión 5.5) no puede hacer IFRAMEs transparentes, por ejemplo.
Como verás, esto no nos acerca mucho a una solución, y tampoco es una gran ventaja para NS4. Empecemos por la "supuesta ventaja"...
Nada impide, en Explorer, cargar contenidos en un IFRAME oculto (con STYLE="display:none") y después acceder a ellos a través de la jerarquía document.all. A partir de Explorer 5 pueden usarse métodos del DOM para esto mismo; estos métodos también están disponibles en Netscape 6, con lo que la incorporación en una página de elementos cargados "a posteriori" se hace mucho más sencilla, e interoperativa.
La solución del SRC en el LAYER de NS4 puede ser más cómoda, pero no está bien implementada; hasta el punto de que es posible colgar el navegador en determinadas circunstancias si se usa.
Ahora veremos por qué no constituye una solución válida para el problema que nos ocupa: aunque podemos cargar contenido en un LAYER... NO SE PUEDE RECUPERAR. Es, a todos los efectos, invisible para nuestro código Javascript. No es posible (igual que no es posible acceder al texto de un <p></p>). Por tanto, no se puede "tomar", y "colocar" en un frame o una ventana, y mandarlo imprimir. Por añadidura, el método print() no puede aplicarse a LAYERs. Y en el caso de poderse aplicar, el resultado tampoco sería muy interesante, porque para empezar tendrías que disponer del contenido del LAYER en un fichero. ¿Por qué no cargarlo en un frame oculto e imprimirlo?
La ausencia de innerHTML en NS4 es uno de los principales motivos por los que este navegador debería desaparecer de la faz de la Tierra: hay una inmensa cantidad de aplicaciones que son totalmente imposibles de implementar en NS4 sólo por este detalle.
Si, a pesar de todo, quieres dar soporte a NS4, la única solución es que dispongas separadamente de todos los trozos de contenido imprimibles (en páginas separadas), con un onload="focus();print()" en el body. Soy consciente de que esto es muy difícil de mantener, porque tienes que disponer de copias separadas y sincronizadas de un mismo contenido: por un lado las capas incluidas en la páginas, y por otro los fragmentos destinados a la impresión. No importará que cargues estos fragmentos en una ventana aparte o en un frame oculto (y esto último es más elegante), pero no te librarás de hacer tu trabajo dos veces...
Una vez leí que "la Web es una de esas plataformas en las que hay cosas que, simplemente, no se pueden hacer". Algunas no se pueden hacer por diseño (por restricciones de seguridad), pero otras son imposibles por la incompetencia de los programadores de los navegadores. Y te aseguro que el peor de todos es Netscape 4.
Lamento la perorata... Y lamento no poder darte una solución aceptable para NS4: personalmente, te aseguro que no existe. Si quieres comentar cualquier otra cosa, no dudes en volverme a escribir.
- Compartir respuesta
- Anónimo
ahora mismo