22 febrero 2012

Resueltos los problemas en los comentarios anidados con la actualización de Blogger


Hubo una actualización de Blogger en el script de los comentarios anidados, que resuelve los siguientes problemas, según compruebo, y que a muchos nos causó dolores de cabeza:
  • El problema de incompatibilidad con el widget de perfil de Twitter.
  • El problema de que al entrar a un post, la página daba un salto hasta el fondo, específicamente al formulario de comentarios, en navegadores como Firefox, Internet Explorer y Opera.
  • Se ponía la página en Blanco en Internet explorer, al ingresar a un post.
  • El problema de compatibilidad con scriptaculous.
Si usas plantillas personalizadas, muy probablemente tendrás que hacer la actualización del script manualmente, antes de hacerlo te recomiendo guardar una copia de seguridad de tu plantilla por si pegas algo mal, y verificar en vista previa que todo luzca bien, antes de guardar el cambio.  

Si no lo haces, seguramente tendrás problemas, y el enlace de "Responder" no funcionará. Al parecer también hubo cambios en el HTML de los comentarios, y si tenias cambios en esa parte, como personalizar el mensaje que aparece arriba de el formulario, probablemente habrá que modificarlo un poco para que se vea como quieres, aunque esto no afecta el funcionamiento de los comentarios.

Cuéntanos tu experiencia :)

21 febrero 2012

Miles de ideas de decoración para inspirarte

houzz
Houzz es un sitio increíble, perfecto para los amantes de la decoración de interiores y exteriores. Actualmente cuenta con un repertorio enorme de fotografías que los mismos usuarios suben, entre ellas, fotografías de los portafolios de diseñadores profesionales en interiorismo, arquitectos, aficionados o entusiastas de la decoración, etc.

Puedes buscar fácilmente fotografías basándote en el estilo que quieras ver, por ejemplo, asiático, tradicional, contemporáneo, etc, y a su vez, filtar los resultados según el espacio que te interesa, como cocina, habitación para el bebé, terraza, porche, jardín, etc.

Al abrir una cuenta, que por supuesto es gratuita, puedes guardar tu colección de fotografías favoritas o "Idealbooks", para tenerlas siempre disponibles, o compartirlas en tu sitio web o blog, u otros medios,  y a su vez, puedes subir fotografías de tus propios proyectos de decoración en tu casa u oficina, etc, y añadir la dirección web de tu página o blog, siendo esto último ideal para profesionales en el ramo que busquen promover sus servicios, sobre todo para quienes residen en Estados Unidos.

Hace tiempo visito este sitio, y más de una vez me a servido de inspiración en el desarrollo de un proyecto de decoración en mi casa. Así que si que si andas en busca de ideas para algún proyecto en tu hogar u oficina, echa un vistazo, seguramente encontrarás inspiración...

¿No funciona el enlace de "Responder" de los comentarios anidados?, prueba esta solución...


Desde ayer por la tarde, empecé a tener problemas con los comentarios, no funcionaba el enlace de "Responder",  me extrañó, y empece a preguntar si a otros les pasaba en G+ y Twitter,  y desde G+ el Potro de Ciudad Blogger me comentaba que desde hace aproximadamente dos semanas, empezó a tener algunos problemas de forma esporádica.

Decidí averiguar un poco, y empecé por el script de los comentarios (me alegra haberlo hecho) sustituyéndolo en mi plantilla por el script de una plantilla sin modificaciones de Blogger, y santo remedio, empezó a funcionar el enlace.

Actualización explicándolo paso a paso:


Si tienes el mismo problema muy probablemente se deba a que no tienes en tu plantilla una actualización que hizo Blogger al sistema de comentarios anidados, y tendrás que hacerlo manualmente:

Cómo hacerlo paso a paso

Paso 1. Ve a la Edición de HTML de la plantilla, marca la casilla de expandir plantillas de artilugios, y busca la parte del código que marque de rojo, con la ayuda de ctrl F, en algunas ocaciones, según me han comentado, esa parte si se actualiza, y ya aparece como async='async', el problema entonces es el script que está debajo y que puse de color morado:
<script defer='defer' expr:src='data:post.commentSrc' type='text/javascript'/>
  <script type='text/javascript'>
    (function() {
      var items = <data:post.commentJso/>;
      var msgs = <data:post.commentMsgs/>;
      var postId = &#39;<data:post.id/>&#39;;
      var feed = &#39;<data:post.commentFeed/>&#39;;
      var authorName = &#39;<data:post.author/>&#39;;
      var authorUrl = &#39;<data:post.authorUrl/>&#39;;
      var blogId = &#39;<data:top.id/>&#39;;
      var baseUri = &#39;<data:post.commentBase/>&#39;;
      var maxThreadDepth = &#39;<data:post.commentMaxThreadDepth/>&#39;;
// <![CDATA[
      feed += '?alt=json&v=2&orderby=published&reverse=false&max-results=50';
      var cursor = null;
      if (items && items.length > 0) {
        cursor = parseInt(items[items.length - 1].timestamp) + 1;
      }
      var bodyFromEntry = function(entry) {
        if (entry.gd$extendedProperty) {
          for (var k in entry.gd$extendedProperty) {
            if (entry.gd$extendedProperty[k].name == 'blogger.contentRemoved') {
              return '<span class="deleted-comment">' + entry.content.$t + '</span>';
            }
          }
        }
        return entry.content.$t;
      }
      var parse = function(data) {
        cursor = null;
        var comments = [];
        if (data && data.feed && data.feed.entry) {
          for (var i = 0, entry; entry = data.feed.entry[i]; i++) {
            var comment = {};
            // comment ID, parsed out of the original id format
            var id = /blog-(\d+).post-(\d+)/.exec(entry.id.$t);
            comment.id = id ? id[2] : null;
            comment.body = bodyFromEntry(entry);
            comment.timestamp = Date.parse(entry.published.$t) + '';
            if (entry.author && entry.author.constructor === Array) {
              var auth = entry.author[0];
              if (auth) {
                comment.author = {
                  name: (auth.name ? auth.name.$t : undefined),
                  profileUrl: (auth.uri ? auth.uri.$t : undefined),
                  avatarUrl: (auth.gd$image ? auth.gd$image.src : undefined)
                };
              }
            }
            if (entry.link) {
              if (entry.link[2]) {
                comment.link = comment.permalink = entry.link[2].href;
              }
              if (entry.link[3]) {
                var pid = /.*comments\/default\/(\d+)\?.*/.exec(entry.link[3].href);
                if (pid && pid[1]) {
                  comment.parentId = pid[1];
                }
              }
            }
            comment.deleteclass = 'item-control blog-admin';
            if (entry.gd$extendedProperty) {
              for (var k in entry.gd$extendedProperty) {
                console.log(entry.gd$extendedProperty[k].name + ' - ' + entry.gd$extendedProperty[k].value);
                if (entry.gd$extendedProperty[k].name == 'blogger.itemClass') {
                  comment.deleteclass += ' ' + entry.gd$extendedProperty[k].value;
                }
              }
            }
            comments.push(comment);
          }
        }
        return comments;
      };
      var paginator = function(callback) {
        if (hasMore()) {
          var url = feed;
          if (cursor) {
            url += '&published-min=' + new Date(cursor).toISOString();
          }
          window.bloggercomments = function(data) {
            var parsed = parse(data);
            cursor = parsed.length < 50 ? null
                : parseInt(parsed[parsed.length - 1].timestamp) + 1
            callback(parsed);
            window.bloggercomments = null;
          }
          url += '&callback=bloggercomments';
          var script = document.createElement('script');
          script.type = 'text/javascript';
          script.src = url;
          document.getElementsByTagName('head')[0].appendChild(script);
        }
      };
      var hasMore = function() {
        return !!cursor;
      };
      var getMeta = function(key, comment) {
        if ('iswriter' == key) {
          var matches = !!comment.author
              && comment.author.name == authorName
              && comment.author.profileUrl == authorUrl;
          return matches ? 'true' : '';
        } else if ('deletelink' == key) {
          return baseUri + '/delete-comment.g?blogID=' + blogId + '&postID=' + comment.id;
        } else if ('deleteclass' == key) {
          return comment.deleteclass;
        }
        return '';
      };
      var replybox = null;
      var replyUrlParts = null;
      var replyParent = undefined;
      var onReply = function(commentId, domId) {
        if (replybox == null) {
          // lazily cache replybox, and adjust to suit this style:
          replybox = document.getElementById('comment-editor');
          if (replybox != null) {
            replybox.height = '250px';
            replybox.style.display = 'block';
            replyUrlParts = replybox.src.split('#');
          }
        }
        if (replybox && (commentId !== replyParent)) {
          document.getElementById(domId).insertBefore(replybox, null);
          replybox.src = replyUrlParts[0]
              + (commentId ? '&parentID=' + commentId : '')
              + '#' + replyUrlParts[1];
          replyParent = commentId;
        }
      };
      var tok = 'comment-form_';
      var hash = window.location.hash || '';
      var startThread = hash.indexOf(tok) == 1 ? hash.substring(tok.length + 1) : undefined;
      // Configure commenting API:
      var configJso = {
        'maxDepth': maxThreadDepth
      };
      var provider = {
        'id': postId,
        'data': items,
        'loadNext': paginator,
        'hasMore': hasMore,
        'getMeta': getMeta,
        'onReply': onReply,
        'rendered': true,
        'initReplyThread': startThread,
        'config': configJso,
        'messages': msgs
      };
      var render = function() {
        if (window.goog && window.goog.comments) {
          var holder = document.getElementById('comment-holder');
          window.goog.comments.render(holder, provider);
        }
      };
      // render now, or queue to render when library loads:
      if (window.goog && window.goog.comments) {
        render();
      } else {
        window.goog = window.goog || {};
        window.goog.comments = window.goog.comments || {};
        window.goog.comments.loadQueue = window.goog.comments.loadQueue || [];
        window.goog.comments.loadQueue.push(render);
      }
    })();
// ]]>
  </script>

Paso 2. Ya que encontarste todo ese código, lo sustituyes por el siguiente, si el primer script (y que puse de azul) ya aparecía actualizado, es decir ya aparece como async='async',  entonces, sólo sustituyes el que está debajo:
<script async='async' expr:src='data:post.commentSrc' type='text/javascript'/>
  <script type='text/javascript'>
    (function() {
      var items = <data:post.commentJso/>;
      var msgs = <data:post.commentMsgs/>;
      var config = <data:post.commentConfig/>;
// <![CDATA[
      var cursor = null;
      if (items && items.length > 0) {
        cursor = parseInt(items[items.length - 1].timestamp) + 1;
      }
      var bodyFromEntry = function(entry) {
        if (entry.gd$extendedProperty) {
          for (var k in entry.gd$extendedProperty) {
            if (entry.gd$extendedProperty[k].name == 'blogger.contentRemoved') {
              return '<span class="deleted-comment">' + entry.content.$t + '</span>';
            }
          }
        }
        return entry.content.$t;
      }
      var parse = function(data) {
        cursor = null;
        var comments = [];
        if (data && data.feed && data.feed.entry) {
          for (var i = 0, entry; entry = data.feed.entry[i]; i++) {
            var comment = {};
            // comment ID, parsed out of the original id format
            var id = /blog-(\d+).post-(\d+)/.exec(entry.id.$t);
            comment.id = id ? id[2] : null;
            comment.body = bodyFromEntry(entry);
            comment.timestamp = Date.parse(entry.published.$t) + '';
            if (entry.author && entry.author.constructor === Array) {
              var auth = entry.author[0];
              if (auth) {
                comment.author = {
                  name: (auth.name ? auth.name.$t : undefined),
                  profileUrl: (auth.uri ? auth.uri.$t : undefined),
                  avatarUrl: (auth.gd$image ? auth.gd$image.src : undefined)
                };
              }
            }
            if (entry.link) {
              if (entry.link[2]) {
                comment.link = comment.permalink = entry.link[2].href;
              }
              if (entry.link[3]) {
                var pid = /.*comments\/default\/(\d+)\?.*/.exec(entry.link[3].href);
                if (pid && pid[1]) {
                  comment.parentId = pid[1];
                }
              }
            }
            comment.deleteclass = 'item-control blog-admin';
            if (entry.gd$extendedProperty) {
              for (var k in entry.gd$extendedProperty) {
                if (entry.gd$extendedProperty[k].name == 'blogger.itemClass') {
                  comment.deleteclass += ' ' + entry.gd$extendedProperty[k].value;
                }
              }
            }
            comments.push(comment);
          }
        }
        return comments;
      };
      var paginator = function(callback) {
        if (hasMore()) {
          var url = config.feed + '?alt=json&v=2&orderby=published&reverse=false&max-results=50';
          if (cursor) {
            url += '&published-min=' + new Date(cursor).toISOString();
          }
          window.bloggercomments = function(data) {
            var parsed = parse(data);
            cursor = parsed.length < 50 ? null
                : parseInt(parsed[parsed.length - 1].timestamp) + 1
            callback(parsed);
            window.bloggercomments = null;
          }
          url += '&callback=bloggercomments';
          var script = document.createElement('script');
          script.type = 'text/javascript';
          script.src = url;
          document.getElementsByTagName('head')[0].appendChild(script);
        }
      };
      var hasMore = function() {
        return !!cursor;
      };
      var getMeta = function(key, comment) {
        if ('iswriter' == key) {
          var matches = !!comment.author
              && comment.author.name == config.authorName
              && comment.author.profileUrl == config.authorUrl;
          return matches ? 'true' : '';
        } else if ('deletelink' == key) {
          return config.baseUri + '/delete-comment.g?blogID='
               + config.blogId + '&postID=' + comment.id;
        } else if ('deleteclass' == key) {
          return comment.deleteclass;
        }
        return '';
      };
      var replybox = null;
      var replyUrlParts = null;
      var replyParent = undefined;
      var onReply = function(commentId, domId) {
        if (replybox == null) {
          // lazily cache replybox, and adjust to suit this style:
          replybox = document.getElementById('comment-editor');
          if (replybox != null) {
            replybox.height = '250px';
            replybox.style.display = 'block';
            replyUrlParts = replybox.src.split('#');
          }
        }
        if (replybox && (commentId !== replyParent)) {
          document.getElementById(domId).insertBefore(replybox, null);
          replybox.src = replyUrlParts[0]
              + (commentId ? '&parentID=' + commentId : '')
              + '#' + replyUrlParts[1];
          replyParent = commentId;
        }
      };
      var hash = (window.location.hash || '#').substring(1);
      var startThread, targetComment;
      if (/^comment-form_/.test(hash)) {
        startThread = hash.substring('comment-form_'.length);
      } else if (/^c[0-9]+$/.test(hash)) {
        targetComment = hash.substring(1);
      }
      // Configure commenting API:
      var configJso = {
        'maxDepth': config.maxThreadDepth
      };
      var provider = {
        'id': config.postId,
        'data': items,
        'loadNext': paginator,
        'hasMore': hasMore,
        'getMeta': getMeta,
        'onReply': onReply,
        'rendered': true,
        'initComment': targetComment,
        'initReplyThread': startThread,
        'config': configJso,
        'messages': msgs
      };
      var render = function() {
        if (window.goog && window.goog.comments) {
          var holder = document.getElementById('comment-holder');
          window.goog.comments.render(holder, provider);
        }
      };
      // render now, or queue to render when library loads:
      if (window.goog && window.goog.comments) {
        render();
      } else {
        window.goog = window.goog || {};
        window.goog.comments = window.goog.comments || {};
        window.goog.comments.loadQueue = window.goog.comments.loadQueue || [];
        window.goog.comments.loadQueue.push(render);
      }
    })();
// ]]>
  </script>
Nota: El código anterior, lo estoy tomando de una plantilla de Blogger sin editar, que ha sido actualizada.

Paso 3. Verifica en vista previa que todo luce bien, y si es así guarda los cambios.

Espero sea útil, ya me contarás...

Ultima actualización:  febreo 25, 2012.


19 febrero 2012

Deshabilitar el botón derecho del mouse: ¿una acción innecesaria o un mal necesario?

Deshabilitar el boton derecho del mouse
Te decides a compartir tus conocimientos y experiencias en un blog o sitio web, y te invade la duda de si deberías o no proteger el contenido contra el plagio, cosa bastante común en la red.

Luego, investigando, te das cuenta de que puedes deshabilitar el botón derecho del mouse, para frustar los intentos de aquellos que no vacilan en copiar lo que tanto te costó redactar, o bien esas imágenes a las que dedicaste tanto trabajo y esfuerzo.

Pero, ¿será la mejor opción deshabilitar el botón derecho del mouse, para evitar que te copien tu contenido?. Reflexionemos un poco sobre esto.

¿Por qué no hacerlo?

Es limitante, y  puede resultar molesto, desconcertante, incluso insultante
No todos los usuarios de tu blog, estarán pensando en copiar tu contenido, y entre ellos seguramente habrá usuarios que utilicen constantemente todas aquellas opciones que trae consigo el navegador a través del botón derecho del mouse.

Al inhabilitar esta función, los usuarios se verán imposibilitados a usar dichas opciones y peor aún, podrían molestarse por tan drástica decisión que tomaste, incluso, podrían dejar de visitar tu blog.

Es inútil
Puede copiar el contenido no sólo desde tu blog, sino a través del feed, si por ejemplo facilitas a tus usuarios la suscripción a tu sitio por medio del correo electrónico. Desde sus bandejas de correo lo pueden copiar sin problemas, a menos que hayas cambiado la opción, y no reciban el post completo.

No es un remedio infalible
Además el método comúnmente usado no es infalible, ya que investigando un poco, sabrán que es posible habilitar el botón derecho del mouse de nuevo, con seguir unos simples pasos.

Piensa esto: al final de cuentas, cualquier usuario que esté decidido a copiar tu contenido lo hará, aún pongas miles de trampas.

Y ¿qué si sólo deshabilito el botón derecho del mouse para que no copien las imágenes?

Para el caso de las imágenes, el usuario puede hacer una captura de pantalla y santo remedio, de todos modos se llevarán la imagen.

Pienso que si se quiere proteger imágenes, ya sea por que éstas se venden, etc, deberían publicarse en un tamaño más pequeño que el original,  y ponerse marca de agua, cosa que hacen aquellas páginas que se dedican a vender gráficos online.

Sin duda podemos usar alternativas más amigables, cuando se intenta proteger las imágenes, sin afectar tanto a los usuarios de nuestro sitio, siendo claros con los términos de uso que le pueden dar a éstas y en general a todo tu contenido.

Y ¿qué si alguien copia mi contenido?

Como usuario de Blogger, puedes reportar cualquier infracción de derechos de autor, completando este formulario, te puedo asegurar que si tomarán cartas en el asunto, aunque antes, no descartes la posibilidad de ponerte en contacto con el administrador del sitio que está usando tu contenido sin previa autorización, de ese modo, quizás no sea necesario tomar medidas más drásticas.

+ información y otros puntos de vista:
Don't disable right click
Deshabilitar el botón derecho del mouse en una página...
Si nos copian...

Imagen obtenida de:
tips4pc.com