Respuesta elaborada y bonita al final de la pregunta. Como en la vida real XD

On 2/24/06, Arnau Siches <[EMAIL PROTECTED]> wrote:
> ---- Planteo ----
>
> Estoy modificando un XHTML 1.0 Strict tipo:
>
> [...]
>     <table>
>
>         <thead id="demo">
>             <tr>
>                 <th rowspan="2"></th>
>                 <th colspan="6">CSS 2</th>
>                 <th colspan="4">CSS 3</th>
>             </tr>
>        </thead>
>       <tbody> [...] </tbody>
>    </table>
> [...]
>
> Añadiendole un elemento <col>:
>
>     <table summary="Suport d'alguns selectors CSS 2 i CSS 3 pels navegadors
> més comuns">
>         <caption>Suport d'alguns selectors CSS 2 i CSS 3 pels navegadors més
> comuns</caption>
>         <col span="8">
>         <thead id="demo">
>             <tr>
>                 <th rowspan="2"></th>
>                 <th colspan="6">CSS 2</th>
>                 <th colspan="4">CSS 3</th>
>             </tr>
>
> Con la función:
>
> function agregarCol() {
>     var elementThead = document.getElementById("demo");
>     var elementCol = document.createElement("col");
>
>     elementCol.setAttribute("span","8");
>     elementThead.parentNode.insertBefore(elementCol,elementThead);
> }
>
> Via CSS estoy aplicando un estilo al elemento <col> del tipo:
>
> col {
>     background: #ff6;
>     font-weight: bold;
>     }
>
> ---- El Problema ----
>
> Cuando visualizo el HTML con Internet Explorer 6 no se aplica el estilo  de
> <col>
> En Firefox 1.5.0.1 (win) y Opera 9b2 (win) sí. (no dispongo de más
> navegadores a mano ahora)
>
> ¿Alguien se ha encontrado con casos parecidos? ¿Alguna solución?

Pues sí, pero no con el elemento `col` sino con el select multiple que
se comentó en la lista hace un par de días (bueno, y el problema
tampoco lo encontré yo).

Así que lo primero que he probado ha sido a aplicar la técnica del relojito:

    setTimeout(
        function() {
            // ver nota #1 al final del mensaje
            elementCol.span = elementCol.span - 1;
            elementCol.span = elementCol.span + 1;
        }, 10
    );

Que hace que el elemento se tenga que redibujar. Lamentablemente, no
soluciona ná de ná.

Se me ocurre entonces utilizar la _devToolBar_ de IE y comparar el
árbol de un documento que incluye el elemento `col` en el marcado con
el de un documento que añade el elemento `col` mediante scripting.

Surprise!

Con el `col` en el marcado (la tabla con la que he hecho las
_primeras_ pruebas no incluía los elementos `caption` y `thead`):

    * table
      * caption
      * colgroup
        * col
      * thead
        * tr
        * th, etc.
      * tbody
        * tr
          * td, etc.

Con el `col` generado mediante scripting:
    * table
      * caption
      * col  <-- nótese que aquí no hay colgroup pariente.
      * thead
        * tr
        * th, etc.
      * tbody
        * tr
          * td, etc.

Parece que aquí está la clave, el árbol no es el mismo.

Pues por mis cojones, con perdón, que va a ser el mismo XD.

Voy a trabajar sobre esta tabla:

        <table id="test">
        <caption>Bla bla</caption>
        <thead>
                <tr>
                        <th colspan="2">Uno y dos</th>
                        <td>Tres</td>
                </tr>
        </thead>
        <tbody>
                <tr>
                        <td>Uno</td>
                        <td>Dos</td>
                        <td>Tres</td>
                </tr>
        </tbody>
        </table>

Con esta hoja de estilos:

        col {
                background: red;
                font-weight: bold;
        }


Y este script:

        window.onload = addCol;
        function addCol() {
                var t = document.getElementById('test');
                var cg = document.createElement('colgroup');
                var col = document.createElement('col');
                col.span = '2';
                cg.appendChild(col);
                t.insertBefore( // ver nota #2
                        cg,
                        t.getElementsByTagName('thead')[0]
                        ||
                        t.getElementsByTagName('tbody')[0]
                );
        }

Caca de la vaca, el árbol es correcto pero IE sigue sin aplicar los estilos.

Así que vuelvo a la carga con el relojito. Después del
`t.insertBefore...` y antes de la llave que cierra la función, añado:

        setTimeout(
                function() {
                        col.span = col.span - 1;
                        col.span = col.span + 1;
                }, 0
        );

Y el mundo es un poco menos imperfecto :)

Aquí queda solucionado, pues, el problemilla de Arnau.

Conclusión: otro bug de IE

Solución: al añadir un `col` mediante scripting hay que hacerlo como
hijo de un `colGroup`. No solo eso, también hay que darle un
empujoncito reasignando el atributo `span`.

Os dejo con un par notas acerca del código que habéis leído. Considero
que merece la pena su lectura.

## Notas ##

### Nota 1

Este pedacito de código va dentro de la función `agregarCol()`, así
que la variable `elementCol` que referencia al elemento `col`
insertado está dentro del _scope_ (ámbito). Por tanto, la podemos
utilizar dentro de una función anónima en lo que se llama una
_closure_ (no sé si existe traducción para este término).


### Nota 2

Otro truquito: quiero insertar el `colgroup` después del `caption`.
Pero no todas las tablas llevan `caption`, así que será mejor que lo
inserte **antes** del primer `thead`.

Pero... y si la tabla no incluye `thead`?

Entonces antes del `tbody`. Para _encontrar_ el elemento que busco
--puesto que utilizo `element.insertBefore(newElement,
elementDescendant)`-- podría utilizar una serie de `if` anidados o
aprovechar uno de los maravillosos atajos de los que el señor nos
provee (el señor ECMAScript, entiéndase).

Como en otros lenguajes, en una expresión compuesta como esta

    1 + 1 || 2 + 2;

en la que el primer componente evaluado como booleano es distinto de
false, no se procesa la segunda expresión (y el valor devuelto es
`2`).

En cambio, en

    1 - 1 || 2 + 2;

La primera expresión resulta en cero, que, convertido en booleano, es
más falso que los duros de chocolate. Se evalúa el segundo componente
y el valor devuelto es 4.

Así pues, en

    t.getElementsByTagName('thead')[0] || t.getElementsByTagName('tbody')[0]

el resultado es el `thead` de la tabla `t` _si existe_; en caso
contrario, el resultado es el primer `tbody` de la tabla `t`.

Salud, compañeros.

--
Choan C. Gálvez

* Desarrollo web
  <http://choangalvez.nom.es/>

* Mundo Du. Cuentos breves, relatos sorprendentes
  <http://du.lacalabaza.net/>
_______________________________________________
javaEScript mailing list
javaEScript@scriptia.net
http://lists.scriptia.net/listinfo.cgi/javaescript-scriptia.net

Responder a