Micaela 2 de Noviembre de 2009 a las 09.02
   Imprimir artículo
elWebmaster.com

Crea un sistema de comentarios estilo Google Wave

googlewaveTodos hemos visto los videos (y algunos incluso han tenido acceso a la previsualización de desarrolladores) del nuevo producto de Google: Google Wave.

Esta herramienta que posee una gran IU es realmente inspiradora. Es por eso que en esta nota te enseñaremos cómo crear un sistema de comentarios estilo Google Wave.

Paso 1 - XHTML

Las tecnologías que estamos utilizando incluyen PHP como un back-end, MySQL como un almacenador de datos, jQuery, CSS y  XHTML para el front-end con AJAX en el medio. El deslizador es un componente creado con jQuery UI.

Primero echémosle un vistazo a la sección del cuerpo de demo.php

demo.php

  1. <div id="main">
  2.  
  3. <p id="orig">View the <a href="http://tutorialzine.com/2009/10/google-wave-history-slider-jquery/" target="_blank">original tutorial &raquo;</a></p>
  4. <h1>Google Wave-like</h1>
  5. <h2>History Slider</h2>
  6.  
  7. <div id="wave">
  8. <div id="topBar">Your Demo Wave</div>
  9. <div id="subBar">
  10. <img src="img/tutorialzine.png" alt="Tutorialzine" /><img src="img/demo.png" alt="Demo" /><img src="img/curious.png" alt="Curious" />
  11. </div>
  12.  
  13. <div id="sliderContainer">
  14. <div id="slider"></div>
  15. <div class="clear"></div>
  16. </div>
  17.  
  18. <div id="commentArea">
  19.  
  20. <?php
  21. foreach($comments as $c)
  22. {
  23.     showComment($c);
  24.     // Showing each comment
  25. }
  26. ?>
  27.  
  28. </div>
  29. <input type="button" class="waveButtonMain" value="Add a comment" onclick="addComment()" />
  30.  
  31. <div id="bottomBar">
  32. </div>
  33.  
  34. </div>
  35. </div>

Esto es básicamente todo el diseño que usaremos. La razón principal por la cual el código es tan corto es que estamos usando CSS para darle estilo, y la salida de comentarios está manejada por una función PHP especial, que explicaremos pronto.

google

Paso 2 - CSS

Lo genial de jQuery es que, gracias a CDN de Google, se puede añadir directamente en tu sitio, sin tener que descargarlo y almacenarlo en tu servidor. Esto también ayuda al tiempo de carga de tu página.

Lo miso sucede con la UI de jQuery, que contiene nuestro deslizador. No sólo eso, sino que el CDN también contiene el estilo y las imágenes necesarias para mostrarlo de forma apropiada.

Sin embargo, todavía tenemos que incluir nuestros propios estilos personales. Los archivos de ejemplo se pueden encontrar en demo.css. Aquí sólo se muestran las partes más interesantes:

demo.css

  1. #orig{
  2.     /* The link that float to the right of the title */
  3.     float:right;
  4.     font-family:"MyRiad Pro",Arial;
  5.     font-size:10px;
  6.     letter-spacing:1px;
  7.     text-transform:uppercase;
  8.     padding-top:10px;
  9. }
  10.  
  11. .clear{
  12.     /* Clearfix, needed by IE6 */
  13.     clear:both;
  14. }
  15.  
  16. #main{
  17.     /* The main container */
  18.     width:600px;
  19.     margin:30px auto;
  20. }
  21.  
  22. #wave{
  23.     /* CSS rounded corners */
  24.     -moz-border-radius:6px;
  25.     -khtml-border-radius: 6px;
  26.     -webkit-border-radius: 6px;
  27.     border-radius:6px;
  28.  
  29.     background:white;
  30.     width:100%;
  31.     overflow:hidden;
  32. }
  33.  
  34. #topBar{
  35.     background:url(img/bg.jpg) repeat-x;
  36.     font-size:12px;
  37.     color:white;
  38.  
  39.     height:20px;
  40.     overflow:hidden;
  41.     padding:5px 0 0 10px;
  42.  
  43.     border-bottom:1px solid #e4f1ff;
  44.     -moz-border-radius:6px 6px 0 0;
  45.     /* A Firefox fix, for once */
  46. }
  47.  
  48. #bottomBar{
  49.     height:40px;
  50.     background-color:#c9e2fc;
  51.     -moz-border-radius:0 0 6px 6px;
  52.     border-top:1px solid #CCCCCC;
  53. }
  54.  
  55. #subBar{
  56.     background-color:#c9e2fc;
  57.     padding-left:10px;
  58. }
  59.  
  60. #subBar img{
  61.     /* The avatars at the top of the page */
  62.     margin:8px 8px 8px 0;
  63.     border:1px solid #cccccc;
  64. }
  65.  
  66. .waveButton,.waveButtonMain{
  67.     /* The submit buttons */
  68.     background:url(img/button_bg.jpg) repeat-x 50% 50%;
  69.     border:1px solid #DDDDDD;
  70.     padding:4px;
  71.  
  72.     cursor:pointer;
  73. }
  74.  
  75. .waveButtonMain{
  76.     display:block;
  77.     margin:10px 20px;
  78. }
  79.  
  80. .textArea{
  81.     padding:4px;
  82.     font-family:Arial,Helvetica,Sans-serif;
  83.     font-size:12px;
  84.     color:#666666;
  85.     border:1px solid #66aff9;
  86.     margin-bottom:10px;
  87. }
  88.  
  89. .replyLink{
  90.     float:right;
  91. }
  92.  
  93. #commentArea{
  94.     padding:10px;
  95.     color:#444444;
  96. }
  97.  
  98. .commentText{
  99.     margin-left:40px;
  100. }
  101.  
  102. .waveComment .waveComment{
  103.     padding-left:30px;
  104. }
  105.  
  106. .waveComment .waveComment .replyLink{
  107.     /* Hiding the reply link on the comment replies -
  108.     only 2 levels of ancestry are allowed */
  109.  
  110.     display:none;
  111. }
  112.  
  113. .waveTime{
  114.     color:#999999;
  115.     float:right;
  116.     font-size:10px;
  117. }
  118.  
  119. #slider{
  120.     width:400px;
  121.     font-size:10px;
  122.     float:right;
  123.     margin-right:10px;
  124. }
  125.  
  126. #sliderContainer{
  127.     background:url(img/dark_bg.jpg) repeat-x #f5f5f5 50% 50%;
  128.     padding:9px 10px;
  129.     border:1px solid #bbbbbb;
  130.     border-left:0;
  131.     border-right:0;
  132.  
  133.     height:10px;
  134.     padding:9px 10px;
  135. }
  136.  
  137. div.ui-widget-content{
  138.     /* Styling the slider */
  139.     background:#FFFFFF;
  140.     border:1px solid #CCCCCC;
  141. }
  142.  
  143. .comment{
  144.     margin:5px 10px;
  145.     padding:8px 10px;
  146.     border:2px solid #cccccc;
  147.  
  148.     /* Rounding the comment */
  149.     -moz-border-radius:6px;
  150.     -khtml-border-radius: 6px;
  151.     -webkit-border-radius: 6px;
  152.     border-radius:6px;
  153.  
  154.     overflow:hidden;
  155. }
  156.  
  157. span.name{
  158.     font-weight:bold;
  159.     color:#999999;
  160. }
  161.  
  162. .commentAvatar{
  163.     width:30px;
  164.     height:30px;
  165.     float:left;
  166.     margin-right:10px;
  167. }

google2

Paso 3 - PHP

Hay 4 archivos PHP principales que manejan el back-end:

1. demo.php - da salida a los comentarios;

2. ajax/saveComment.php - añade nuevos comentarios, se llega a él por medio de peticiones AJAX;

3. functions.php - retiene algunas funciones utilizadas por demo.php;

4. connect.php - maneja la conexión de base de datos.

Aquí sólo miraremos los tres primeros archivos:

demo.php

  1. define("INCLUDE_CHECK",1);
  2. require 'connect.php';
  3. require 'functions.php';
  4. // Including the files for the DB connection and our custom functions
  5. // Removing comments that are older than an hour.
  6.  
  7. mysql_query("DELETE FROM wave_comments WHERE id>5 AND dt<SUBTIME(NOW(),'0 1:0:0')");
  8.  
  9. $comments_result = mysql_query("SELECT * FROM wave_comments ORDER BY id ASC");
  10. // Selecting all the comments ordered by id in ascending order
  11.  
  12. $comments=array();
  13. $js_history='';
  14.  
  15. while($row=mysql_fetch_assoc($comments_result))
  16. {
  17.     if($row['parent']==0)
  18.     // If the comment is not a reply to a previous comment, put it into $comments directly
  19.     $comments[$row['id']] = $row;
  20.     else
  21.     {
  22.         if(!$comments[$row['parent']]) continue;
  23.  
  24.         $comments[$row['parent']]['replies'][] = $row;
  25.         // If it is a reply, put it in the 'replies' property of its parent
  26.     }
  27.  
  28.     $js_history.='addHistory({id:"'.$row['id'].'"});'.PHP_EOL;
  29.     // Adds JS history for each comment
  30. }
  31.  
  32. $js_history='<script type="text/javascript">
  33. '.$js_history.'
  34. </script>';
  35.  
  36. // This is later put into the head and executed on page load

Los comentarios son o parents (se anadem directamente al thread) o children (añadidos como una rélica a un parent). Sólo se permiten dos niveles de ancestría (lo que quiere decir que las réplicas para los children están deshabilitadas).

Los comentarios son mostrados por la función showComment (se puede ver en el paso XHTML de arriba).

ajax / saveComment.php

  1. define("INCLUDE_CHECK",1);
  2. require'../connect.php';
  3.  
  4. if(empty($_POST['comment'])) die("0");
  5. // If there isn't a comment text, exit
  6.  
  7. $comment = mysql_real_escape_string(nl2br(strip_tags($_POST['comment'])));
  8. $user='Demo';
  9. // This would be a nice place to start customizing - the default user
  10. // You can integrate it to any site and show a different username.
  11.  
  12. $addon='';
  13. if($_POST['parent']) $addon=',parent='.(int)$_POST['parent'];
  14.  
  15. mysql_query("INSERT INTO wave_comments SET usr='".$user."', comment='".$comment."', dt=NOW()".$addon);
  16.  
  17. if(mysql_affected_rows($link)==1)
  18.     echo mysql_insert_id($link);
  19.     // If the insert was successful, echo the newly assigned ID
  20. else
  21.     echo '0';

Y por ultimo, está functions.php

functions.php

  1. if(!defined('INCLUDE_CHECK')) die('You are not allowed to execute this file directly');
  2.  
  3. function showComment($arr)
  4. {
  5.     echo '
  6.     <div class="waveComment com-'.$arr['id'].'">
  7.         <div class="comment">
  8.         <div class="waveTime">'.waveTime($arr['dt']).'</div>
  9.         <div class="commentAvatar">
  10.         <img src="img/'.strtolower($arr['usr']).'.png" width="30" height="30" alt="'.$arr['usr'].'" />
  11.         </div>
  12.         <div class="commentText">
  13.         <span class="name">'.$arr['usr'].':</span> '.$arr['comment'].'
  14.         </div>
  15.         <div class="replyLink">
  16.         <a href="" onclick="addComment(this,'.$arr['id'].');return false;">add a reply &raquo;</a>
  17.         </div>
  18.         <div class="clear"></div>
  19.     </div>';
  20.  
  21.     // Output the comment, and its replies, if any
  22.     if($arr['replies'])
  23.     {
  24.         foreach($arr['replies'] as $r)
  25.         showComment($r);
  26.     }
  27.     echo '</div>';
  28. }
  29.  
  30. function waveTime($t)
  31. {
  32.     $t = strtotime($t);
  33.  
  34.     if(date('d')==date('d',$t)) return date('h:i A',$t);
  35.     return date('F jS Y h:i A',$t);
  36.     // If the comment was written today, output only the hour and minute
  37.     // if it was not, output a full date/time
  38. }

El último paso es el más complicado, en este caso es el código jQuery.

Paso 4 - jQuery

Todo el código JS está localizado en script.js. Lo dividiremos en dos partes:

script.js - parte 1

  1. $(document).ready(function(){
  2.     // Executed once all the page elements are loaded
  3.  
  4.     lastVal = totHistory;
  5.  
  6.     // Create the slider:
  7.     $("#slider").slider({
  8.         value:totHistory,
  9.         min: 1,
  10.         max: totHistory,
  11.         animate: true,
  12.         slide: function(event, ui) {
  13.  
  14.             if(lastVal>ui.value)
  15.             $(buildQ(lastVal,ui.value)).hide('fast').find('.addComment').remove();
  16.             // Using buildQ to build the jQuery selector
  17.             // If we are moving the slider backward, hide the previous comment
  18.  
  19.             else if(lastVal<ui.value)
  20.             $(buildQ(lastVal,ui.value)).show('fast');
  21.             // Otherwise show it
  22.  
  23.             lastVal = ui.value;
  24.         }
  25.     });
  26. });
  27.  
  28. var totHistory=0;
  29. // Holds the number of comments
  30.  
  31. var positions = new Array();
  32. var lastVal;
  33.  
  34. function addHistory(obj)
  35. {
  36.     /* Gets called on page load for each comment, and on comment submit */
  37.     totHistory++;
  38.     positions.push(obj.id);
  39. }
  40.  
  41. function buildQ(from,to)
  42. {
  43.     /* Building a jQuery selector from the begin
  44.     and end point of the slide */
  45.  
  46.     if(from>to)
  47.     {
  48.         var tmp=to;
  49.         to=from;
  50.         from=tmp;
  51.     }
  52.  
  53.     from++;
  54.     to++;
  55.  
  56.     var query='';
  57.     for(var i=from;i<to;i++)
  58.     {
  59.         if(i!=from) query+=',';
  60.         query+='.com-'+positions[i-1];
  61.     }
  62.  
  63.     /* Each comment has an unique com-(Comment ID) class
  64.     that we are using to address it */
  65.  
  66.     return query;
  67. }

Como recordarán, hemos generado una string PHP especial, que contiene las llamadas a la función addHistory. Cada vez que se ejecuta, incrementa el contador totHistory. Luego de que todos los comentarios se cargan el $(document).ready se ejecuta y el slider se inicia con totHistory como el máximo valor del deslizador. El valor mínimo es 1, porque deseamos tener por lo menos un comentario visible.

Ahora, miremos la segunda parte del archivo:

script.js - parte 2

  1. function addComment(where,parent)
  2. {
  3.     /*  This functions gets called from both the "Add a comment" button
  4.     on the bottom of the page, and the add a reply link.
  5.     It shows the comment submition form */
  6.  
  7.     var $el;
  8.     if($('.waveButton').length) return false;
  9.     // If there already is a comment submition form
  10.     // shown on the page, return and exit
  11.  
  12.     if(!where)
  13.         $el = $('#commentArea');
  14.     else
  15.         $el = $(where).closest('.waveComment');
  16.  
  17.     if(!parent) parent=0;
  18.  
  19.     // If we are adding a comment, but there are hidden comments by the slider:
  20.     $('.waveComment').show('slow');
  21.     lastVal = totHistory;
  22.  
  23.     $('#slider').slider('option','value',totHistory);
  24.     // Move the slider to the end point and show all comments
  25.     var comment = '<div class="waveComment addComment">\
  26.     \
  27.     <div class="comment">\
  28.     <div class="commentAvatar">\
  29.     <img src="img/demo.png" width="30" height="30" />\
  30.     </div>\
  31.     \
  32.     <div class="commentText">\
  33.     \
  34.     <textarea class="textArea" rows="2" cols="70" name="" />\
  35.     <div><input type="button" class="waveButton" value="Add comment" onclick="addSubmit(this,'+parent+')" /> or <a href="" onclick="cancelAdd(this);return false">cancel</a></div>\
  36.     \
  37.     </div>\
  38.     </div>\
  39.     \
  40.     </div>';
  41.  
  42.     $el.append(comment);
  43.     // Append the form
  44. }
  45.  
  46. function cancelAdd(el)
  47. {
  48.     $(el).closest('.waveComment').remove();
  49. }
  50.  
  51. function addSubmit(el,parent)
  52. {
  53.     /* Executed when clicking the submit button */
  54.     var cText = $(el).closest('.commentText');
  55.     var text = cText.find('textarea').val();
  56.     var wC = $(el).closest('.waveComment');
  57.     if(text.length<4)
  58.     {
  59.         alert("Your comment is too short!");
  60.         return false;
  61.     }
  62.  
  63.     $(el).parent().html('<img src="img/ajax_load.gif" width="16" height="16" />');
  64.     // Showing the loading gif animation
  65.     // Send an AJAX request:
  66.  
  67.     $.ajax({
  68.         type: "POST",
  69.         url: "ajax/saveComment.php",
  70.         data: "comment="+encodeURIComponent(text)+"&parent="+parent,
  71.         /* Sending both the text and the parent of the comment */
  72.         success: function(msg){
  73.  
  74.             /* PHP returns the automatically assigned ID of the new comment */
  75.             var ins_id = parseInt(msg);
  76.             if(ins_id)
  77.             {
  78.                 wC.addClass('com-'+ins_id);
  79.                 addHistory({id:ins_id});
  80.                 $('#slider').slider('option', 'max', totHistory).slider('option','value',totHistory);
  81.                 lastVal=totHistory;
  82.             }
  83.  
  84.             transForm(text,cText);
  85.             // Hiding the form and showing the newly-added comment in its place
  86.         }
  87.     });
  88. }
  89.  
  90. function transForm(text,cText)
  91. {
  92.     var tmpStr ='<span class="name">Demo:</span> '+text;
  93.     cText.html(tmpStr);
  94. }

Las funciones de esta parte del código manejan la entrega de comentarios via AJAX al back-end PHP.

Como saben, se llama cuando hemos ejecutado de forma exitosa la petición AJAX (en este caso se llama si el comentario fue escrito a la base de datos MySQL).

Dentro de está función verificamos si se devuelve una ID apropiada, que corresponde a la id MySQL interna que se dió al campo auto-incrementado (miren abajo para la parte MySQL part o miren table.sql en los archivos de ejemplo).

Si todo está bien, llamamos la función addHistory con la nueva información y actualizamos el valor máximo del deslizador. Esto asegura que el nuevo comentario añadido sea históricamente scrollable con el resto de ellos.

Step 5 - MySQL

Este paso sólo se necesita si deseas hacer andar un demo en tu propio servidor.

Para poder hacer funcionar el demo, deberás crear la table MySQL wave_comments  con el siguiente código (también disponible en los archivos de ejemplo table.sql):

  1. CREATE TABLE `wave_comments` (
  2. `id` int(11) NOT NULL auto_increment,
  3. `parent` int(11) NOT NULL default '0',
  4. `usr` varchar(16) collate utf8_unicode_ci NOT NULL default '',
  5. `comment` text collate utf8_unicode_ci NOT NULL,
  6. `dt` datetime NOT NULL default '0000-00-00 00:00:00',
  7. PRIMARY KEY  (`id`),
  8. KEY `parent` (`parent`,`id`)
  9. ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Con esto, ¡Nuestro deslizador histórico tipo Google Wave está completo!

Conclusión

Siéntanse libres de modificar el código de este ejemplo y utilizarlo en sus propios sitios. También sería genial que compartan lo que realicen con la comunidad. ¡Esperamos ver sus logros!

Descarga los archivos aquí»

Fuente: Tutorialzine

Enviar a Del.icio.us Enviar a Meneame Enviar a Digg Enviar a Fresqui Enviar a Enchilame

Comentarios (11)

  1. Henry Cabrera dice:

    Es realmente interesante y muchas gracias por los archivos me ayudaron bastante sigan asi

  2. Pablo Sela dice:

    Quiero que me llegue la invitación!!! quiero probar google wave!!!

  3. jose andres dice:

    Muy interesenate , sigan asi por favor y no se detengan en inculcar mas acerca de los tips , para beneficio y prosperidad de las paginas web. Gracias

  4. ERIC IGNACIO SANTIAGO TOGA dice:

    Me parece estupendo la mejora de las paginas WEB ya que ayuda aprovechando al maximo la funcionalidad
    de las paginas WEB

  5. uSorac2009 dice:

    Muy buen ejemplo. Gracias

  6. william gonzalez dice:

    muy buen tutorial y muy interezante lastima que no cuento con las herramientas para ponerlo en practica pero gracias por ayudarnos.

  7. panikus dice:

    Estaria bueno un tuto para implementarlo a algun sistema de foros o sistema de blogging

  8. jhonattan dice:

    Hola, muy bueno el tutorial, soy muy novato en esto del php, así que quiero preguntar cómo serías posible incluir esto en cada articulo de una página web para que la gente comente, pero solo los que esten registrados. Gracias.

  9. Pedro dice:

    Hola, intente implementarlo en mi pagina, tal cual ya que soy nuevo y primero queria verlo en funcionamiento para despues hacerle algunas modificaciones (Si es que puedo) pero no he podido echarlo a andar, la direccion es esta, y marca el error, me podrían ayudar?

    http://www.harteforjada.com/06productos/demo/demo.php

  10. Vicnero dice:

    hola me permito felicitar este blog en general me ah ayudado bastante
    tengo una duda acerca de este tema
    como le podre hacer para agregar
    un nuevo campo de entrada por ejemplo
    agregar un campo para el nombre de quien comenta
    se podra hacer? bueno espero y respondan
    zaludos!

  11. Maxorchuck dice:

    Muy bueno pero lo malo que no se como ponerlo en wordpress

Deja tu opinión

© 2007 - 2008 elWebmaster.com | Powered by Wordpress | Diseño CSS y XHTML válido. | Algunos íconos basados en FamFamFam Mini
Iniciar sesión