Páginas

29 febrero 2012

Modificaciones en los anidados de Blogger .. again

Como uno trata de estar lo más lejos posible de los caprichos de Blogger, no me había dado cuenta de los cambios que ha hecho en los comentarios anidados y los problemas que estaba causando en varios sitios hasta que empezaron a llegar comentarios al respecto.

El problema con estas cosas es que podemos arreglarlas pero seguimos a merced de futuros cambios ya que todo ese código se genera de modo automático.

El primer punto que vi al tratar de responder a esas preguntas es que hay un cambio en el script de Blogger que es el que se encuentra en este includable:
<b:includable id='threaded_comment_js' var='post'>
  .......
</b:includable>
Y ese includable, al parecer, debe ser actualizado manualmente así que lo mejor es que lo eliminemos, guardemos la plantilla y volverá a agregarse solito pero con el nuevo contenido.

El segundo problema surge con los emoticones si es que han seguido la idea descripta en esta entrada; como ahora, los textos de los comentarios no se encuentran en una etiqueta BLOCKQUOTE sino en una etique P, deberíamos cambiar esa línea del script:
function NEWemoticonComentario() {
  var  c = document.getElementById("comment-holder");
  if(c!=null) {
    var listacoms = c.getElementsByTagName("p");
    if(listacoms.length>0){
      for(var i=0; i<listacoms.length; ++i) {
        comlTexto = listacoms[i].innerHTML;
        listacoms[i].innerHTML = DRAWemo(comlTexto);
      }
    }
  }
}
Con eso, todo quedaría funcionando nuevamente ... hasta nuevo aviso.

27 febrero 2012

Comentarios anidados sin el nuevo código

Somos muchos los que no usamos los nuevos comentarios anidados de Blogger por diferentes razones.

Porque lo intentamos cuando apenas salieron y había tantos problemas que les tomamos antipatía; porque si bien muchos de esos errores se corrigieron hay otro errores que persisten; porque no nos da ganas volver a escribir el CSS y dejar las cosas a nuestro gusto, etc etc. Tantas razones como usuarios existen. Yo soy uno de ellos y la verdad es que tantas ideas y vueltas me quitaron las ganas de usarlos. Además el que se lean desde los feeds en lugar de ser parte del servidor mismo me pareció siempre una tontera ... lenta. Demasiadas vueltas y demasiada falta de control de los resultados para mi gusto.

Sin embargo ...

Un día apareció Felipe con una idea que publicó en NicoNico donde arma los comentarios anidados con las opciones de reply incluidas pero sin el sistema de Blogger, simplemente (no tan simplemente) agregando una serie de códigos a los comentarios normales lo que nos permite, tener tanto control sobre su forma de verse como teníamos antes; es más, colocando esos códigos tal y como los muestra en su entrada, los comentarios se verán igual y sólo habrá que agregarle CSS a los agregados.

La explicación detallada la pueden ver en su página y acá la repetiré acá con las variantes que usé en mi plantilla.

Tal como dice, lo primero es expandir la plantilla y buscar esto que es el formulario de comentarios; allí cambiaremos ese DIV:
<b:includable id='comment-form' var='post'>
<div id='comment-form'>
    .......
</div>
</b:if>
por esto:
<div class='comment-form' id='comment-form-thread'>
Ahora, vamos a tener que modificar el loop donde se muestran los comentarios así que buscamos esto:
<b:loop values='data:post.comments' var='comment'>
  .......
</b:loop>
Básicamente, deberíamos cambiar el contenido y eso debe hacer con cuidado así que sugiero hacer una copia previa:
<b:loop values='data:post.comments' var='comment'>
  <b:if cond='data:comment.inReplyTo'>
    <!--FIX-->
  <b:else/>
    ....... dejamos el código tal como está .......
    ....... y debajo, agregaremos el código extra .......
  </b:if>
</b:loop>
Ese código extra es el que NicoNico muestra en su página en color azul. Acá, dejo el código completo del loop tal como lo uso en este blog, con los agregados que requiere en caso de usar scripts o las personalizaciones propias de esta plantilla.

<b:loop values='data:post.comments' var='comment'>

<b:if cond='data:comment.inReplyTo'>
  <!-- FIX -->
<b:else/>
  <div class='comentariobloque' expr:id='data:comment.id'>
    <div class='comentario-base'>
      <a expr:name='&quot;comment-&quot; + data:comment.id'/>
      <dt expr:class='&quot;comment-author &quot; + data:comment.authorClass' expr:id='data:comment.anchorName'>
        <b:if cond='data:comment.favicon'>
          <img expr:src='data:comment.favicon' height='16' style='margin-bottom:-2px;' width='16'/>
        </b:if>
        <a expr:name='data:comment.anchorName'/>
        <b:if cond='data:blog.enabledCommentProfileImages'>
          <data:comment.authorAvatarImage/>
        </b:if>
        <span class='autorcomentario'>
          <b:if cond='data:comment.authorUrl'>
            <a expr:href='data:comment.authorUrl' rel='nofollow'><data:comment.author/></a>
          <b:else/>
            <data:comment.author/>
          </b:if>
        </span>
        <span class='comment-footer'>
          <span class='comment-timestamp'>
            <a expr:href='&quot;#comment-&quot; + data:comment.id' title='comment permalink'>
              <!-- uso un script para mostrar la fecha relativa -->
              <script type='text/javascript'>fecharelativa(&#39;<data:comment.timestamp/>&#39;);</script>
            </a>
            <b:include data='comment' name='commentDeleteIcon'/>
          </span>
        </span>
      </dt>
      <dd class='comment-body'>
        <b:if cond='data:comment.isDeleted'>
          <span class='deleted-comment'><data:comment.body/></span>
        <b:else/>
          <p expr:id='&quot;combody-&quot; + data:comment.anchorName'><data:comment.body/></p>
          <!-- uso un script para mostrar los emoticones -->
          <script type='text/javascript'>
            cual = &quot;combody-&quot; + &quot;<data:comment.anchorName/>&quot;;
            emoticonComentario(cual);
          </script>
        </b:if>
      </dd>
    </div>
    <div class='contenedor-respuestas'>
      <b:loop values='data:post.comments' var='comentariohijo'>
        <b:if cond='data:comentariohijo.inReplyTo == data:comment.id'>
          <div class='respuestas-comentarios'>
            <div expr:class='&quot;comment-author-thread &quot; + data:comentariohijo.authorClass' expr:id='data:comentariohijo.anchorName'>
              <b:if cond='data:comentariohijo.favicon'>
                <img expr:src='data:comentariohijo.favicon' height='16px' style='margin-bottom:-2px;' width='16px'/>
              </b:if>
              <a expr:name='data:comentariohijo.anchorName'/>
              <b:if cond='data:blog.enabledCommentProfileImages'>
                <data:comentariohijo.authorAvatarImage/>
              </b:if>
            </div>
            <div class='respuesta'>
              <span class='autorcomentario'>
                <b:if cond='data:comentariohijo.authorUrl'>
                  <a expr:href='data:comentariohijo.authorUrl' rel='nofollow'><data:comentariohijo.author/></a>
                 <b:else/>
                   <data:comentariohijo.author/>
                 </b:if>
              </span>
              <span class='comment-footer'>
                <span class='comment-timestamp'>
                  <!-- uso un script para mostrar la fecha relativa -->
                  <a expr:href='&quot;#comment-&quot; + data:comment.id' title='comment permalink'>
                     <script type='text/javascript'>fecharelativa(&#39;<data:comentariohijo.timestamp/>&#39;);</script>
                  </a>
                  <b:include data='comentariohijo' name='commentDeleteIcon'/>
                </span>
              </span>
              <div class='comment-body'>
                <b:if cond='data:comentariohijo.isDeleted'>
                  <span class='deleted-comment'><data:comentariohijo.body/></span>
                <b:else/>
                  <p expr:id='&quot;combody-&quot; + data:comentariohijo.anchorName'><data:comentariohijo.body/></p>
                  <!-- uso un script apra mostrar los emoticones -->
                  <script type='text/javascript'>
                    cual = &quot;combody-&quot; + &quot;<data:comentariohijo.anchorName/>&quot;;
                    emoticonComentario(cual);
                  </script>
                </b:if>
              </div>
            </div>
          </div>
        </b:if>
      </b:loop>
    </div>
    <b:if cond='data:post.numComments &lt; 200'>
      <a class='reply-action' expr:id='&quot;replyboton-&quot; + data:comment.id' expr:onclick='&quot;reply(&apos;&quot; + data:comment.id + &quot;&apos;);return false;&quot;' href='#'>Responder</a>
    <b:else/>
      <script type='text/javascript'>
        var indexc = &#39;<data:post.numComments/>&#39;
        var indexcomment = &#39;<data:comment.id/>&#39;
        //<![CDATA[
        var indexpage = indexc/200;
        indexpage = Math.ceil(indexpage);
        var indexl = window.location.href;
        indexl = indexl.indexOf("commentPage=" + indexpage + "");
        var replyAction = "<a id='replyboton-" + indexcomment +"' class='reply-action' onclick='reply(&quot;" + indexcomment + "&quot;);return false;' href='#'>Responder</a>";
        if(indexl!=-1) {
          if(indexc < (indexpage*200)) { document.write(replyAction) }
        }
        //]]>
      </script>
    </b:if>
    <div class='contenedorreply' expr:id='&quot;contenedorreply-&quot; + data:comment.id'/>
  </div>
</b:if>

</b:loop>

Último paso; buscamos:
<b:includable id='comments' var='post'>
y justo debajo, agregamos lo siguiente:
<b:if cond='data:blog.pageType == &quot;item&quot;'>
  <script type='text/javascript'>var flagItem = 0;</script>
</b:if>
<b:if cond='data:blog.pageType == &quot;static_page&quot;'>
  <script type='text/javascript'>var flagItem = 1;</script>
</b:if>
<script type='text/javascript'>
  /* Código bajo Licencia Creative Commons 3.0 (Atribución-No Comercial)
     Felipe @ http://gplus.to/iFelipeCalvo */
  var indexa = &#39;<data:top.id/>&#39;;
  var indexb = &#39;<data:post.id/>&#39;;
  //<![CDATA[
    // Distingue entre post y página estática
    flagItem="0"==flagItem?"&postID=":"&pageID=";
    // ACA VAN LAS DOS FUNCIONES
  //]]>
</script>
Acá hay una variante respecto del código original. Simplemente coloqué las dos funciones del script junto con el resto por razones de comodidad pero es indistinto agregarlas allí o en el head; las dos funciones tsl como las uso, dicen lo siguiente:

<script type='text/javascript'>
//<![CDATA[
function replyOriginal() {
  var b = document.getElementById("comment-editor").getAttribute("src"), a = b.indexOf("#"), b = b.substring(a), a = document.getElementById("comment-editor");
  a.parentNode.removeChild(a);
  a = document.getElementById("replypost");
  a.parentNode.removeChild(a);
  b = "http://www.blogger.com/comment-iframe.g?blogID=" + (indexa + flagItem + indexb + b) + "";
  a = document.createElement("iframe");
  a.setAttribute("id", "comment-editor");
  a.setAttribute("name", "comment-editor");
  a.setAttribute("src", b);
  a.setAttribute("height", "250px");
  a.setAttribute("width", "100%");
  a.setAttribute("frameborder", "0");
  a.setAttribute("allowtransparency", "true");
  document.getElementById("comment-form-thread").appendChild(a)
}

function reply(b) {
  var a = document.getElementById("comment-editor").getAttribute("src"), c = a.indexOf("#"), a = a.substring(c), c = document.getElementById("comment-editor");
  var boton = c.parentElement.getAttribute("id").replace("contenedorreply-", "replyboton-");
  if(document.getElementById(boton).innerHTML=="Cancelar") {
    document.getElementById(boton).innerHTML="Responder";
  }
  if(c.parentElement.getAttribute("id").indexOf(b)>=0) { replyOriginal();
    return;
  }
  c.parentNode.removeChild(c);
  a = "http://www.blogger.com/comment-iframe.g?blogID=" + (indexa + flagItem + indexb) + "&parentID=" + (b + a) + "";
  c = document.createElement("iframe");
  c.setAttribute("id", "comment-editor");
  c.setAttribute("name", "comment-editor");
  c.setAttribute("src", a);
  c.setAttribute("height", "250px");
  c.setAttribute("width", "100%");
  c.setAttribute("frameborder", "0");
  c.setAttribute("allowtransparency", "true");
  document.getElementById("contenedorreply-" + b + "").appendChild(c);
  document.getElementById("replyboton-"+b).innerHTML = "Cancelar";
  document.getElementById("replypost") || (b = document.createElement("a"), b.innerHTML = "Agregar un comentario", b.setAttribute("id", "replypost"), b.setAttribute("class", "LoadMore"), b.setAttribute("href", "#"), b.setAttribute("onclick", "replyOriginal();return false;"), document.getElementById("comment-form-thread").appendChild(b))
}
//]]>
</script>

Y por último, como siempre, el CSS antes de </head> que,como dije, sólo requiere que se agreguen las nuevas reglas y que dependerán totlamente del blog donde se agregaue esto asi que me limito a enumerarlas:
<:style>
  .respuestas-comentarios {}
  .comment-author-thread {}
  #comments .contenedor-respuestas .avatar-image-container {}
  .contenedor-respuestas {}
  .comment-body-thread {}
  .comment-body-thread p {}
  .reply-action {}
  #replypost {}
<:/style>

¿Problemas? Pocos por no decir ninguno. Un detalle menor impide que cuando hay más de 200 comentarios, las funciones de "Responder" sólo se muestren en la ultima página, es decir, en esa donde se encuentran los comentarios más recientes pero, salvo condiciones muy particulares, es un detale que no me parce que tenga relevancia alguna.

24 febrero 2012

Textualizer: Efectos en textos con jQuery

Textualizer es un plugin para jQuery con el que se pueden generar transiciones entre distintos textos de manera bastante extraña, cambiando las letras de lugar con efectos diversos.

Su uso es muy sencillo, basta agregar el script que puede descargarse desde la página del autor ya sea en su versión minimizada como completa y agregarlo antes de </head>

Luego, para usarlo debemos agregar un contenedor al que identificamos mediante su ID, allí donde quisiéramos que se mostrara; por ejemplo:
<div id="demo"></div>
y llamamos a la función con las opciones que se nos ocurran:
<script>
  var list = [un txto', 'otro texto, 'último texto'];  // la lista de textos a mostrar
  var txt = $('#demo');  // el ID del contenedor
  var options = {
    duration: 1000, // el tiempo que el texto permanecerá visible
    rearrangeDuration: 1000, // ella duración del efecto
    effect: 'random', // el efecto que puede ser fadeIn, slideLeft, slideTop o random
    centered: true // si queremos que se centre
  }
  txt.textualizer(list, options); // enviamos los datos
  txt.textualizer('start'); // y lo ejecutamos
</script>
Como cualquier otra etiqueta, podemos definir su estilo; por ejemplo:
<style>
  #demo {
    color: #FFF;
    font-family: Georgia;
    font-size: 20px;
    height:140px;
    width: 500px;
  }
</style>

Eventualmente, tres funciones más nos permitirían controlarlo:
.textualizer('pause') pausaria la animación
.textualizer('stop') la detendría por completo
.textualizer('destroy') la elimininaría

22 febrero 2012

Algunas de las nuevas opciones de text-align

Que algo esté alineado (text-align) o que flote (propiedad float) no es lo mismo. Puede parecerlo pero es completamente diferente, de allí que muchas veces, nos encontramos con problemas cuando tratamos de ubicar algo en una determinada posición.

20 febrero 2012

CSS Shapes


#circle { 
  background: red; 
  border-radius: 70px;
  height: 100px;
  width: 100px;
}
#oval1 {
  background: yellow; 
  border-radius: 100px / 50px;
  height: 100px; 
  width: 200px; 
}
#oval2 {
  background: SandyBrown; 
  border-radius: 50px / 100px;
  height: 160px; 
  width: 80px; 
}




#trapezium1 {
  border-right: 40px solid transparent;
  border-bottom: 80px solid Aquamarine;
  border-left: 40px solid transparent;
  height: 0; 
  width: 80px;
}
#trapezium2 {
   border-top: 80px solid Coral;
   border-right: 40px solid transparent;
   border-left: 40px solid transparent;
   height: 0; 
   width: 80px;
}
#parallelogram {
  background: pink;
  height: 75px;
  width: 130px; 
  -moz-transform: skew(20deg); 
  -webkit-transform: skew(20deg); 
  -o-transform: skew(20deg);
  transform: skew(20deg);
}



#up-triangle {
   border-right: 60px solid transparent; 
   border-bottom: 80px solid green; 
   border-left: 60px solid transparent; 
   height: 0; 
   width: 0; 
}
#down-triangle { 
   border-top: 80px solid pink;
   border-right: 60px solid transparent; 
   border-left: 60px solid transparent; 
   height: 0;
   width: 0; 
}
#left-triangle {
   border-top: 50px solid transparent;
   border-right: 100px solid orange;
   border-bottom: 50px solid transparent;
   height: 0;
   width: 0;
}
#right-triangle {
   border-top: 50px solid transparent;
   border-bottom: 50px solid transparent;
   border-left: 100px solid red;
   height: 0;
   width: 0;
}




#octagon {
  background: DarkTurquoise;
  height: 100px; 
  width: 100px; 
}
#octagon:before {
  border-bottom: 30px solid DarkTurquoise;
  border-right: 30px solid #101921; /* el color del fondo */
  border-left: 30px solid #101921; /* el color del fondo */
  content:"";
  height: 0;
  position: absolute; 
  width: 40px;
}
#octagon:after {
   border-top: 30px solid DarkTurquoise; 
   border-right: 30px solid #101921; /* el color del fondo */
   border-left: 30px solid #101921; /* el color del fondo */
   content:"";
   height: 0;
   margin: 70px 0 0 0;
   position: absolute; 
   width: 40px;
}

#diamond {
   background: SkyBlue;
   height: 80px; 
   width: 80px; 
   -moz-transform: rotate(-45deg);
   -webkit-transform: rotate(-45deg);
   -ms-transform: rotate(-45deg);
   -o-transform: rotate(-45deg);
   transform: rotate(-45deg);
   -moz-transform-origin: 0 100%;
   -webkit-transform-origin: 0 100%;
   -ms-transform-origin: 0 100%;
   -o-transform-origin: 0 100%;
   transform-origin: 0 100%;
}




#twelve-point-star {
  background: orange;
  height: 100px;
  position: absolute;
  width: 100px;
}
#twelve-point-star:before {
  background: orange;
  content:"";
  height: 100px;
  position: absolute;
  width: 100px;
  -moz-transform: rotate(30deg);
  -webkit-transform: rotate(30deg);
  -ms-transform: rotate(30deg);
  -o-transform: rotate(30deg);
  transform: rotate(30deg);
}
#twelve-point-star:after {
  background: orange;
  content:"";
  height: 100px;
  position: absolute;
  width: 100px;
  -moz-transform: rotate(-30deg);
  -webkit-transform: rotate(-30deg);
  -ms-transform: rotate(-30deg);
  -o-transform: rotate(-30deg);
  transform: rotate(-30deg);
}


#six-point-star {
  border-bottom: 80px solid red;
  border-right: 50px solid transparent; 
  border-left: 50px solid transparent; 
  position: absolute;
  height: 0; 
  width: 0; 
}
#six-point-star:after {
  border-top: 80px solid red;
  border-right: 50px solid transparent; 
  border-left: 50px solid transparent; 
  content:"";
  height: 0; 
  margin: 30px 0 0 -50px;
  position: absolute;
  width: 0; 
}



#speech-bubble {
  background: Thistle;
  border-radius: 10px;
  height: 80px;
  position: absolute;
  width: 120px;
}
#speech-bubble:before {
  border-top: 13px solid transparent;
  border-right: 26px solid Thistle;
  border-bottom: 13px solid transparent;
  content:"";
  height: 0;
  margin: 13px 0 0 -25px;
  position: absolute;
  width: 0;
}



#pacman {
  border-top: 60px solid yellow;
  border-right: 60px solid transparent;
  border-bottom: 60px solid yellow;
  border-left: 60px solid yellow;
  border-radius: 60px;
  height: 0px;
  width: 0px;
}



#heart { 
  position: relative;
}
#heart:before, #heart:after {
  background: red;
  border-radius: 50px 50px 0 0;
  content: "";
  height: 115px;
  left: 70px;
  position: absolute;
  top: 0;
  width: 70px;
  -moz-transform: rotate(-45deg);
  -webkit-transform: rotate(-45deg);
  -ms-transform: rotate(-45deg);
  -o-transform: rotate(-45deg);
  transform: rotate(-45deg);
  -moz-transform-origin: 0 100%;
  -webkit-transform-origin: 0 100%;
  -ms-transform-origin: 0 100%;
  -o-transform-origin: 0 100%;
  transform-origin: 0 100%;
}
#heart:after { 
 left: 0; 
  -moz-transform: rotate(45deg); 
  -webkit-transform: rotate(45deg); 
  -ms-transform: rotate(45deg); 
  -o-transform: rotate(45deg);
  transform: rotate(45deg);
  -moz-transform-origin: 100% 100%;
  -webkit-transform-origin: 100% 100%;
  -ms-transform-origin: 100% 100%;
  -o-transform-origin: 100% 100%;
  transform-origin :100% 100%;
}


REFERENCIAS:CSS3 Shapes

19 febrero 2012

Iconos Grunge y Pink

Extreme grunge
Contiene 12 íconos de 256x256, en formato PNG.
descargar

Pink ribbon
Contiene 24 128x128, 256x256 y 512x51, en formato PNG.
descargar

17 febrero 2012

El atributo placeholder

Es común utilizar etiquetas INPUT para que los usuarios ingresen alguna clase de dato, por ejemplo, buscar algo. Suelen ser etiquetas a las que no prestamos atención ni personalizamos aunque, como cualquier otra, admiten el uso de CSS (más información: 1 | 2).

Básicamente dicen esto aunque podrían tener más atributos:
<input type="text" value="" />
Y en estos ejemplos, todas tienen una clase con esta regla de estilo:
input.demos[type=text] {
  background: #FFF;
  border: 2px solid Chocolate;
  border-radius: 4px;
  color: #888;
  font-size: 20px;
  height: 32px;
  margin: 10px 0;
  padding: 0 10px;
  text-align: center;
  width: 300px;
}
Se vería así:


Así, sin nada extra, suele ocurrir que el usuario no sepa qué tipo de dato poner o que formato debería tener por lo que es común que se le adose esa información; si esto lo hacemos en el atributo value será incómodo ya que quien lo use, deberá borrar ese texto y luego poner el dato:
<input type="text" value="el texto por defecto" />

Para evitar eso, muchas veces debemos haber visto que se usan dos eventos extras: onblur y onfocus a los que se les agrega un poco de JavaScript que lo que hace es permutar el valor del atributo value, si el control no está activo y no hay nada agregado, se ve el texto por defecto y ese texto desaparece cuando hacemos click dentro para escribir algo.
<input type="text" value="el texto por defecto" onfocus="if (this.value=='el texto por defecto') this.value='';" onblur="if (this.value=='') this.value='el texto por defecto';" />

Funciona perfectamente pero es un código largo y engorroso que las nuevas técnicas del HTML5 y el CSS3 hacen innecesario ya que para eso, ahora podemos usar un nuevo atributo llamado placeholder que hará todo eso de modo automático aunque, en versiones de Internet Explorer viejas no tendrá ningún efecto:
<input type="text" placeholder="el texto por defecto" value="" />


También es posible personalizar placeholder para que se vea "distinto" pero, eso requiere el uso de propiedades con prefijos que son tres:

:-moz-placeholder {} /* para Firefox */
::-webkit-input-placeholder {} /* para Chrome */
:-ms-input-placeholder {} /* para Internet Explorer */


Lamentablemente, por ahora, las diferencias entre los navegadores también son varias; por ejemplo, en Firefox se pueden usar propiedades como background-color, border y padding pero en Chrome no o bien son mostradas de modo extraño. Además, se debe tener en cuenta que estas reglas de estilo hay que aplicarlas de modo individual y no pueden ser agrupadas:
input.demos:-moz-placeholder {
  background: #DDD;
  color: Chocolate;
  font-size: 16px;
  font-style: italic;
  font-weight: bold;
  letter-spacing: 3px;
}
inputdemos::-webkit-input-placeholder {
  background: #DDD;
  color: Chocolate;
  font-size: 16px;
  font-style: italic;
  font-weight: bold;
  letter-spacing: 3px;
}
input.demos:-ms-input-placeholder {
  background: #DDD;
  color: Chocolate;
  font-size: 16px;
  font-style: italic;
  font-weight: bold;
  letter-spacing: 3px;
}

15 febrero 2012

Un script para manejar listas

Aunque este script tal vez no tenga demasiado uso en Blogger, no deja de ser una alternativa interesante, bastante fácil de usar y realmente potente dado su escaso tamaño. Se trata de List.js y no requiere librerías extras.

Una vez insertada en un sitio, nos permite transformar listas (UL LI) de tal modo que pueda buscarse en ellas de modo dinámico, filtrarlas, ordenarlas e incluso editarlas, agregando o borrando items. Obviamente, en Blogger, la parte de edición carece de sentido porque no podríamos guardar esos cambios pero, el resto de las opciones pueden ser aplicadas sin inconvenientes.

Descargamos el archivo, lo alojamos en algún servidor como DropBox o Google Sites y luego, lo agregamos a la plantilla:
<script src='URL_list.min.js' type='text/javascript'></script>
Para usarlo, sólo necesitamos un DIV al que identificaremos con un ID y adentro, agregaremos una lista cuya clase será list y donde cada item puede contener cualquier tipo de etiqueta que también deberemos identificar con una clase que será la que nos sirva para, por ejemplo, ordenarlas.

Un ejemplo:
<div id="miprimerejemplo">
  <span class="sort" rel="nombre"> NOMBRE </span>
  <span class="sort" rel="apellido"> APELLIDO </span>
  <ul class="list">
    <li>
      <span class="nombre"> texto 1 </span>
      <span class="apellido"> texto 2 </span>
    </li>
    <li>
      <span class="nombre"> texto 3 </span>
      <span class="apellido"> texto 4 </span>
    </li>
    .......
  </ul>
</div>
Si debajo del HTML llamamos a la función:
<script>
  var opciones = {valueNames: [ "nombre","apellido" ]};
  var featureList = new List("miprimerejemplo", opciones);
</script>
tendremos una lista que podrá ser ordenada haciendo click en los textos NOMBRE o APELLIDO.

Las características gráficas son las que se nos ocurra, no hay limitaciones al respecto.

Un poco más espectacular es la forma de buscar en una lista ya que se hace de manera dinámica, a medida que vamos ingresando el texto, la lista se va filtrando.

Es similar al ejemplo anterior, acá, lo haremos sobre una lista que contiene algunas entradas del blog:
<div id="otralista">
  <span>buscar</span> <input class="search" />
  <ul class="list">
    <li><a class="orden" href="URL_1"> título 1</a></li>
    <li><a class="orden" href="URL_2"> título 2</a></li>
    <li><a class="orden" href="URL_3"> título 3</a></li>
    ......
  </ul>
</div>
<script>
  var opciones = {valueNames: [ "orden" ]};
  var featureList = new List("otralista", opciones);
</script>

13 febrero 2012

Jugando con :after y :before

before es lo que está antes , after es lo que está después ... los pseudo-elementos ::after y ::before resultan ser muy sencillos de manejar y tener infinitas posibilidades ya que nos permiten agregar contenido utilizando el CSS.

10 febrero 2012

jFlip: Una vuelta de hoja

jFlip es un plugin de jQuery que genera una galería de imágenes con un singular efecto donde los cambios se ven como si se diera vuelta una página de un libro.

De todos los que he visto similares, es uno de los más simples ya que sólo requiere agregar el script y ejecutar la función, aplicándola sobre listas simples, pudiéndose agregar varias en una misma página.

Lamentablemente, como este tipo de efecto se realiza con etiquetas canvas, en Ias versiones viejas de Internet Explorer hay problemas y proponen usar algún script adicional como ExplorerCanvas peo, no veo que funcione bien así que acá, lo pasaré por alto.

El plugin lo descargamos desde la página del autor, ya sea en su versión full como minimizada y lo agregamos comos siempre, antes de </head>

Luego, el HTML no tiene misterio alguno, colocamos una lista con un ID y las imágenes a mostrar:
<ul id="jflipDEMO">
  <li><img src="URL_IMAGEN_1" /></li>
  <li><img src="URL_IMAGEN_2" /></li>
  <li><img src="URL_IMAGEN_3" /></li>
  <!-- seguimos poniendo cuantas imágenes se nos ocurra -->
</ul>
Y lo ejecutamos de este modo:
<script>
  $("#jflipDEMO").jFlip(300,300,{background:"#903941",cornersTop:true,scale:"fit"});
</script>
Allí es donde podemos establecer algunas opciones; en este caso:

300,300 son el ancho y alto del contenedor (por defecto 300x300)
background es el color de fondo si la imagen es más chica (por defecto es verde)
cornersTop indica si los enlaces para "dar vuelta las hojas" se verán arriba (true) o abajo (false)
scale tiene tres valores posibles:
noresize no hará nada, las imágenes se mostrarán tal cual son
fit ajusta su tamaño para que "entren" en el contenedor
fill re-dimensiona las imágenes para mantener la proporción del aspecto del contenedor

Otro ejemplo:
$("#jflipDEMO").jFlip(350,350,{background:"#903941",cornersTop:false,scale:"fill"});

08 febrero 2012

La etiqueta CANVAS (funciones básicas)

La etiqueta canvas es muy simple de agregar, sólo tiene tres atributos posibles, el ID con que la identificaremos, el ancho y el alto. Incluso estos dos últimos son opcionales y si no los ponemos, tendrá un tamaño por defecto de 300x150:
<canvas id="nombre" width="valor" height="valor"></canvas>
Puesta así no veremos absolutamente nada ya que es transparente aunque con CSS es posible agregarle algunas propiedades como márgenes, bordes, fondos, etc. Es que, en realidad, lo que hace la etiqueta no es otra cosa que crear un "lienzo", un espacio particular en donde podremos dibujar pixel por pixel utilizando JavaScript.

Como aún no todos los navegadores la soportan, es aconsejable colocar algún tipo de contenido alternativo, un texto, una imagen, algo que advierta que allí habrá algo; por ejemplo:
<canvas id="nombre" width="valor" height="valor"> ... aquí hay algo ... </canvas>
Una alternativa para que internet Exporer soporte esta etiqueta es agregar el script ExplorerCanvas y es lo que está agregado en esta entrada así que el demo (en teoría) también debería verse en ese navegador.

El script lo descargamos y lo agregamos de manera condicional (más información):
<!--[if IE]><script src="URL_excanvas.js"></script><![endif]-->
Para empezar a manipular el contenido de nuestro canvas, debemos empezar a escribir scripts; lo elemental es poder identificarla y para eso está el ID:
var miCANVAS = document.getElementById("nombre");
if (miCANVAS.getContext) {
var canvas = miCANVAS.getContext("2d");
// aquí lo manipularemos
} else {
// advertencia : el navegador no soporta canvas
}
A partir de eso, usaremos la variable para darle órdenes y lo primero será colocarle un color de fondo.
var miCANVAS = document.getElementById("nombre");
if (miCANVAS.getContext) {
var canvas = miCANVAS.getContext("2d");
canvas.fillStyle = "#FFF";
canvas.fillRect (0,0,300,200);
} else {
// advertencia : el navegador no soporta canvas
}
Usamos dos funciones, fillStyle y fillRect() que son las elementales. Con la primera, definimos el color de lo que dibujaremos:

fillStyle = "color" donde el color puede escribirse en cualquier formato ( "white"; "#FFFFFF", "rgb(255,255,255)", "rgba(255,255,255,1)"

y con la segunda, dibujamos un rectángulo lleno:

fillRect(x,y,ancho,alto) donde x e y son las coordenadas de inicio

así que simplemente, hemos hecho que nuestro canvas sea de color blanco, dibujando un rectángulo lleno que es igual al tamaño total.

Los rectángulos son las formas más simples y tenemos dos opciones disponibles, rectángulos llenos como el anterior o rectángulos que sólo tengan un borde, para esto último usamos otra función:

strokeRect(x,y,ancho,alto)

Para estas cosas básicas, hay una función más que nos permite "borrar" (hacer que algo sea transparente):

clearRect(x,y,ancho,alto)

Todas esas funciones tienen los mismos parámetros, definimos dónde se dibujará (con x e y) y definimos su tamaño.


Algunos ejemplos para jugar.

Creo tres funciones; con una, inicializo el lienzo, con otra dibujo rectángulos llenos y con otra cuadrados sin fondo; nada espectacular pero, para quien nada sabe de esto (yo) es un paso comparable al primer viaje a la luna.


<script type="text/javascript">
function iniCANVAS(cual){
var miCANVAS = document.getElementById(cual);
if (miCANVAS.getContext) {
var canvas=miCANVAS.getContext("2d");
canvas.fillStyle="#FFF";
canvas.fillRect (0,0,300,200);
}
}
function drawSQUARES(cual,x1,y1,w,h,c) {
var miCANVAS = document.getElementById(cual);
if (miCANVAS.getContext) {
var canvas=miCANVAS.getContext("2d");
canvas.fillStyle=c;
canvas.fillRect(x1,y1,w,h);
}
}
function drawRECS(cual,x1,y1,w,h,c) {
var miCANVAS = document.getElementById(cual);
if (miCANVAS.getContext) {
var canvas=miCANVAS.getContext("2d");
canvas.fillStyle=c;
canvas.strokeRect(x1,y1,w,h);
}
}
</script>

<canvas id="demo" width="300" height="200"> <img src="URL_imagenAlterna" /> </canvas>

<script>iniCANVAS('demo')</script>

<button type="button" onclick="drawSQUARES('demo',10,20,50,50,'#F00');"> rectangulo 1 </button>
<button type="button" onclick="drawSQUARES('demo',30,100,70,50,'#00F');"> rectangulo 2 </button>
<button type="button" onclick="drawRECS('demo',50,10,50,50,'#000');"> rectangulo 3 </button>
<button type="button" onclick="drawRECS('demo',160,110,70,50,'#000');"> rectangulo 4 </button>

06 febrero 2012

Las tablas que no son tablas siguen siendo tablas

¿Qué diferencia hay entre una tabla y una tabla? Que una es una tabla y la otra no es una tabla pero ambas son tablas.

Parece un galimatias pero es lo que ofrecen algunas propiedades recientes del CSS que tienen algún uso práctico cuando se trata de alinear cosas verticalmente pero que no estoy muy seguro que aporten nada nuevo aunque ya se sabe que en estas cosas, a veces, lo sencillo se complica porque es más cool.

Acá hay dos modelos ¿hay alguna diferencia ente ellos?

esta es una tabla que es tabla
Columna 1 Columna 2 Columna 3
Fila 1 Celda 1 Fila 1 Celda 2 Fila 1 Celda 3
Fila 2 Celda 1 Fila 2 Celda 2 Fila 2 Celda 3
Fila 3 Celda 1 Fila 3 Celda 2 Fila 3 Celda 3

una tabla que no es tabla
Columna 1Columna 2Columna 3
Fila 1 Celda 1Fila 1 Celda 2Fila 1 Celda 3
Fila 2 Celda 1Fila 2 Celda 2Fila 2 Celda 3
Fila 3 Celda 1Fila 3 Celda 2Fila 3 Celda 3

Pocas. Así, sin propiedades extras, dependiendo del navegador, veremos alguna fila centrada en lugar de alineada a la izquierda o una diferencia en la fuente de los textos, tamaños levemente distintos. La primera, es una tabla tabla es decir, está armada con etiquetas HTML:
<table>
  <caption>esta es una tabla que es tabla</caption>
  <tr>
    <th>Columna 1</th>
    <th>Columna 2</th>
    <th>Columna 3</th>
  </tr>
  <tr>
    <td>Fila 1 Celda 1</td>
    <td>Fila 1 Celda 2</td>
    <td>Fila 1 Celda 3</td>
  </tr>
  .......
</table>
La segunda, es un conjunto de DIVs con ciertas propiedades CSS:
<style>
  #tabla {display: table;}
  #tabla .caption {display: table-caption}
  #tabla .fila {display: table-row;}
  #tabla .celda {display: table-cell;}
  #tabla .filatitulo {display: table-row;}
  #tabla .filatitulo .celda {display: table-cell;}
</style>

<div id="tabla">
  <div class="caption">una tabla que no es tabla</div>
  <div class="filatitulo">
    <span class="celda">Columna 1</span>
    <span class="celda">Columna 2</span>
    <span class="celda">Columna 3</span>
  </div>
  <div class="fila">
    <span class="celda">Fila 1 Celda 1</span>
    <span class="celda">Fila 1 Celda 2</span>
    <span class="celda">Fila 1 Celda 3</span>
  </div>
.......
</div>
La propiedad básica que permite "simular" una tabla es display y puede tener estos valores:

table es el equivalente a la etiqueta TABLE
table-row es el equivalente a la etiqueta TR
table-cell es el equivalente a las etiquetas TD y TH
table-caption es el equivalente a la etiqueta CAPTION
table-header-group es el equivalente a la etiqueta THEAD
table-row-group es el equivalente a la etiqueta TBODY
table-footer-group es el equivalente a la etiqueta TFOOT
table-column-group es el equivalente a la etiqueta COLGROUP
table-column es el equivalente a la etiqueta COL

Si bien pueden usarse en cualquier navegador, incluyendo IE8, al igual que su pariente HTML, las tablas con CSS pueden verse de modo diferente en cada uno de ellos.

Más allá de algún uso concreto, el resultado final será similar, unas y otras tienen ventajas y desventajas y las discusiones sobre cual es mejor o peor, hay que dejárselas a lo interesados en estas cuestiones que casi son religiosas; como usuarios, si algo se ve bien y funciona en al mayoría de los navegadores, es que está bien. Podrá mejorarse pero nada más. Mucho más interesante será cuando los navegadores comiencen a soportar el llamado Grid Layout, algo que por ahora, sólo es parte del futuro incierto.

REFERENCIAS:vanseodesign.com

03 febrero 2012

Float: Lo principal y lo secundario

Cuando a un elemento le agregamos la propiedad float, lo convertimos en un bloque pero con una característica especial: su ancho no ocupa el 100% del contenedor sino sólo el de su contenido pero, además, lo quitamos del orden natural de la página; de este modo, todo lo que lo rodea se moverá y se acomodará como pueda para hacerle lugar.

01 febrero 2012

Blogger comenzará a redirigir los dominios blogspot

Google ha anunciado que a partir de ahora, comenzará a redirigir los blogs alojados en Blogger a dominios específicos del país así que si un blog cuya URL era:
http://nombre_blog.blogspot.com
podrá verse como:
http://nombre_blog.blogspot.com.au
http://nombre_blog.blogspot.com.es
http://nombre_blog.blogspot.com.pk
dependiendo de si es que está en Australia, España o Pakistán.

Aunque en este momento, eso sólo parece afectar a los blogs de la India, la página de Google explica que dichos cambios son paulatinos e irán siendo aplicados a lo largo de los próximos meses aunque no especifica si eso será válido par todos o se limitará a ciertos países.

Según al empresa, este cambio se realiza para evitar los intentos de censura clara o más o menos velada que están imponiendo algunos gobiernos en las legislaciones respectivas. De este modo, ante cualquier reclamo que implique la obligación de eliminar un sitio, eso sólo afectaría a la "copia" local y el blog continuaría accesible bajo el dominio genérico de Blogger y por lo tanto, seguiría siendo accesible para el resto de los usuarios.

¿Esto a afectará a los buscadores, la indexación y los sitios podrían ser penalizados por contenido duplicado?

La pregunta se la hacen ellos pero a mi entender, no lo responden de modo satisfactorio, hablan de "esforzarse" en minimizar los efectos de ese cambio y que esto afecte el posicionamiento de los sitios. De hecho, sugieren que se establezca el dominio con la etiqueta META canonical, es decir, si el dominio pasa a ser local, esta, debería cambiarse para apuntar a ese dominio local.

¿Por qué? Porque todo blog tendrá dos direcciones URL en lugar de una. Esto, además, podría traer problemas si el sitio está asociado a redes sociales o servicios externos ¿Qué pasará con los feeds? No tengo idea; habrá que ver y estar atentos.

Como regla general, han decidido que el agregado de ncr al final de la URL redirija siempre a los servidores de USA
http://nombre_blog.blogspot.com/ncr