Notas adhesivas habilitadas para AJAX con PHP y jQuery

Hoy estamos creando un sistema de gestión de notas adhesivas compatible con AJAX. Brindará a los visitantes la capacidad de crear notas con una vista previa en vivo y moverlas en la pantalla. Cada movimiento se enviará al back-end a través de AJAX y se guardará en la base de datos.

Estamos usando la versión 1.4 de jQuery y el complemento fancybox (también puede consultar nuestro tutorial de la galería CSS3 Lightbox, donde también usamos fancybox).

Puede descargar los archivos de ejemplo y mantener el sitio de demostración abierto en una pestaña para que sea más fácil seguir los pasos del tutorial.

Paso 1 - XHTML

El primer paso es crear la estructura XHTML necesaria. El marcado en el archivo de demostración principal - demo.php es bastante sencillo, como puedes ver por ti mismo en el siguiente código.

demo.php

<div id="main">
<a id="addButton" class="green-button" href="add_note.html">Add a note</a>

<?php echo $notes?>

</div>

Contiene el principal div, que contiene todas las notas y limita su movimiento durante el proceso de arrastre. PHP genera dinámicamente el resto después de ejecutar una consulta SELECT en la base de datos y después de almacenar el resultado en las $notas. variable como verá en el siguiente paso.

Si hace clic en el botón "Agregar una nota" en el sitio de demostración, verá que aparece un formulario con una vista previa en vivo. Esta funcionalidad la proporciona fancybox, que obtiene add_note.html (que contiene el formulario) y lo muestra dentro de una ventana emergente.

añadir_nota.html

<h3 class="popupTitle">Add a new note</h3>

<!-- The preview: -->
<div id="previewNote" class="note yellow" style="left:0;top:65px;z-index:1">
<div class="body"></div>
<div class="author"></div>
<span class="data"></span>
</div>

<div id="noteData"> <!-- Holds the form -->
<form action="" method="post" class="note-form">

<label for="note-body">Text of the note</label>
<textarea name="note-body" id="note-body" class="pr-body" cols="30" rows="6"></textarea>

<label for="note-name">Your name</label>
<input type="text" name="note-name" id="note-name" class="pr-author" value="" />

<label>Color</label> <!-- Clicking one of the divs changes the color of the preview -->
<div class="color yellow"></div>
<div class="color blue"></div>
<div class="color green"></div>

<!-- The green submit button: -->
<a id="note-submit" href="" class="green-button">Submit</a>

</form>
</div>

En el formulario puedes rellenar el texto de la nota, tu nombre y elegir un color. Proporcionar una forma para que los usuarios vean cómo aparecerá su nota en la página en tiempo real es una adición útil que tiene otro propósito práctico:al hacer clic en el botón Enviar y se cierra la ventana de la caja de luz, la nota de vista previa se copia a la principal div, lo que nos evita escribir código adicional.

Paso 2 - PHP

Como se mencionó anteriormente, PHP llena las $notas variable ejecutando una consulta en la base de datos y la muestra en la página. Veamos cómo funciona esto.

demo.php

$query = mysql_query("SELECT * FROM notes ORDER BY id DESC");

$notes = '';
$left='';
$top='';
$zindex='';
while($row=mysql_fetch_assoc($query))
{
    // The xyz column holds the position and z-index in the form 200x100x10:
    list($left,$top,$zindex) = explode('x',$row['xyz']);
    $notes.= '
        <div class="note '.$row['color'].'" style="left:'.$left.'px;top:'.$top.'px;  z-index:'.$zindex.'">
        '.htmlspecialchars($row['text']).'
        <div class="author">'.htmlspecialchars($row['name']).'</div>
        <span class="data">'.$row['id'].'</span>
    </div>';
}

La tabla de notas no solo almacena el texto y el autor de la nota, sino que también tiene una columna dedicada para la x y y coordenadas, así como para el z-index (u orden de apilamiento). Esos se almacenan en el xyz campo de la tabla, que es actualizado por AJAX.

Después de que el visitante haga clic en "Agregar una nota botón ", caja elegante toma add_note.html (que se cubrió en el paso uno) y muestra el formulario de vista previa en vivo. Cuando se envía, los datos se envían a través de AJAX a post.php , dado a continuación.

publicación.php

// Escaping the input data:
$author = mysql_real_escape_string(strip_tags($_POST['author']));
$body = mysql_real_escape_string(strip_tags($_POST['body']));
$color = mysql_real_escape_string($_POST['color']);
$zindex = (int)$_POST['zindex'];

/* Inserting a new record in the notes DB: */
mysql_query('   INSERT INTO notes (text,name,color,xyz)
VALUES ("'.$body.'","'.$author.'","'.$color.'","0x0x'.$zindex.'")');

if(mysql_affected_rows($link)==1)
{
    // Return the id of the inserted row:
    echo mysql_insert_id($link);
}
else echo '0';

Después de escapar todos los datos de entrada e insertarlos en la tabla, el script verifica si hubo filas afectadas después de la consulta de inserción. Si mysql_affected_rows devuelve 1, esto significaría que la inserción fue exitosa y el auto_increment asignado automáticamente Se emite ID.

AJAX también se usa para guardar las posiciones de las notas individuales después del final de cada movimiento. El código JavaScript que realmente solicita estas llamadas AJAX se presenta en el paso 4 de este tutorial. El código PHP se incluye a continuación:

actualizar_posición.php

// Validating the input data:
if(!is_numeric($_GET['id']) || !is_numeric($_GET['x']) || !is_numeric($_GET['y']) || !is_numeric($_GET['z']))
die("0");

// Escaping:
$id = (int)$_GET['id'];
$x = (int)$_GET['x'];
$y = (int)$_GET['y'];
$z = (int)$_GET['z'];

// Saving the position and z-index of the note:
mysql_query("UPDATE notes SET xyz='".$x."x".$y."x".$z."' WHERE id=".$id);

echo "1";

Después de asegurarse de que los datos de entrada sean válidos, la secuencia de comandos actualiza el campo xyz de la fila de la nota en cuestión e imprime 1 en caso de éxito.

Continuemos con el paso tres.

Paso 3 - CSS

Todo el marcado está en su lugar, por lo que es hora de agregar un estilo elegante. Los estilos se definen en styles.css. Dividí el archivo en tres partes.

estilos.css - Parte 1

.note{
    height:150px;
    padding:10px;
    width:150px;
    position:absolute;
    overflow:hidden;
    cursor:move;

    font-family:Trebuchet MS,Tahoma,Myriad Pro,Arial,Verdana,sans-serif;
    font-size:22px;

    /* Adding a CSS3 shadow below the note, in the browsers which support it: */
    -moz-box-shadow:2px 2px 0 #DDDDDD;
    -webkit-box-shadow:2px 2px 0 #DDDDDD;
    box-shadow:2px 2px 0 #DDDDDD;
}

#fancy_ajax .note{ cursor:default; }

/* Three styles for the notes: */

.yellow{
    background-color:#FDFB8C;
    border:1px solid #DEDC65;
}

.blue{
    background-color:#A6E3FC;
    border:1px solid #75C5E7;
}

.green{
    background-color:#A5F88B;
    border:1px solid #98E775;
}

/* Each note has a data span, which holds its ID */
span.data{ display:none; }

/* The "Add a note" button: */
#addButton{
    position:absolute;
    top:-70px;
    left:0;
}

En la primera parte, definimos la apariencia de las notas y proporcionamos tres esquemas de color:amarillo, azul y verde. Esas clases de color también se utilizan en el formulario de vista previa en vivo al crear una nota.

Cada nota tiene un elemento de intervalo especial con un nombre de clase de datos , que contiene el ID interno que se le asigna en la base de datos. jQuery usa esta ID y la devuelve con las llamadas AJAX al servidor para actualizar la posición de la nota y el índice z. Estamos ocultando este tramo de la vista con display:none .

estilos.css - Parte 2

/* Green button class: */
a.green-button,a.green-button:visited{
    color:black;
    display:block;
    font-size:10px;
    font-weight:bold;
    height:15px;
    padding:6px 5px 4px;
    text-align:center;
    width:60px;

    text-shadow:1px 1px 1px #DDDDDD;
    background:url(img/button_green.png) no-repeat left top;
}

a.green-button:hover{
    text-decoration:none;
    background-position:left bottom;
}

.author{
    /* The author name on the note: */
    bottom:10px;
    color:#666666;
    font-family:Arial,Verdana,sans-serif;
    font-size:12px;
    position:absolute;
    right:10px;
}

#main{
    /* Contains all the notes and limits their movement: */
    margin:0 auto;
    position:relative;
    width:980px;
    height:500px;
    z-index:10;
    background:url(img/add_a_note_help.gif) no-repeat left top;
}

La segunda parte del archivo define la clase del botón verde, completa con un estado de desplazamiento y una sombra de texto CSS3. Estos son algunos pequeños detalles que pueden no parecer gran cosa, pero dejan una buena impresión general para el usuario.

estilos.css - Parte 3

h3.popupTitle{
    border-bottom:1px solid #DDDDDD;
    color:#666666;
    font-size:24px;
    font-weight:normal;
    padding:0 0 5px;
}

#noteData{
    /* The input form in the pop-up: */
    height:200px;
    margin:30px 0 0 200px;
    width:350px;
}

.note-form label{
    display:block;
    font-size:10px;
    font-weight:bold;
    letter-spacing:1px;
    text-transform:uppercase;
    padding-bottom:3px;
}

.note-form textarea, .note-form input[type=text]{
    background-color:#FCFCFC;
    border:1px solid #AAAAAA;
    font-family:Arial,Verdana,sans-serif;
    font-size:16px;
    height:60px;
    padding:5px;
    width:300px;
    margin-bottom:10px;
}

.note-form input[type=text]{    height:auto; }

.color{
    /* The color swatches in the form: */
    cursor:pointer;
    float:left;
    height:10px;
    margin:0 5px 0 0;
    width:10px;
}

#note-submit{   margin:20px auto; }

En la última parte de styles.css, agregamos reglas CSS para el formulario de vista previa en vivo, comenzando desde el encabezado H3 y terminando con las muestras de color en la parte inferior.

Paso 4 - jQuery

jQuery administra el front-end y todas las solicitudes de AJAX. Para poder usar la biblioteca, primero debemos incluir algunas líneas en la sección principal de demo.php:

demo.php

<link rel="stylesheet" type="text/css" href="styles.css" />
<link rel="stylesheet" type="text/css" href="fancybox/jquery.fancybox-1.2.6.css" media="screen" />

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"></script>
<script type="text/javascript" src="fancybox/jquery.fancybox-1.2.6.pack.js"></script>

<script type="text/javascript" src="script.js"></script>

Incluimos jQuery y jQuery UI de la red de repositorios de contenido de Google, así como el resto de los archivos css y js necesarios para este tutorial. Ahora profundicemos un poco más en nuestro script jQuery.

script.js - Parte 1

$(document).ready(function(){
    /* This code is executed after the DOM has been completely loaded */

    var tmp;

    $('.note').each(function(){
        /* Finding the biggest z-index value of the notes */

        tmp = $(this).css('z-index');
        if(tmp>zIndex) zIndex = tmp;
    })

    /* A helper function for converting a set of elements to draggables: */
    make_draggable($('.note'));

    /* Configuring the fancybox plugin for the "Add a note" button: */
    $("#addButton").fancybox({
        'zoomSpeedIn'       : 600,
        'zoomSpeedOut'      : 500,
        'easingIn'          : 'easeOutBack',
        'easingOut'         : 'easeInBack',
        'hideOnContentClick': false,
        'padding'           : 15
    });

    /* Listening for keyup events on fields of the "Add a note" form: */
    $('.pr-body,.pr-author').live('keyup',function(e){

        if(!this.preview)
            this.preview=$('#previewNote');

        /* Setting the text of the preview to the contents of the input field, and stripping all the HTML tags: */
        this.preview.find($(this).attr('class').replace('pr-','.')).html($(this).val().replace(/<[^>]+>/ig,''));
    });

    /* Changing the color of the preview note: */
    $('.color').live('click',function(){

        $('#previewNote').removeClass('yellow green blue').addClass($(this).attr('class').replace('color',''));
    });

Primero, el script encuentra el índice z máximo valor, para que pueda almacenarlo en caché en el zIndex variable e incrementarla antes de asignarla a las notas al principio de cada movimiento de arrastre. De esta manera, cuando comience a arrastrar una nota, se moverá a la parte superior de la pila.

Otro momento interesante es que usamos jQuery live() método para escuchar eventos, en lugar del habitual bind() . Esto es así, porque los elementos de la página en los que estamos escuchando eventos se crean solo cuando se muestra el formulario y, una vez definidos, live() los detectores de eventos están activos en todos los elementos que aún no se han creado.

script.js - Parte 2

  /* The submit button: */
    $('#note-submit').live('click',function(e){

        if($('.pr-body').val().length<4)
        {
            alert("The note text is too short!")
            return false;
        }

        if($('.pr-author').val().length<1)
        {
            alert("You haven't entered your name!")
            return false;
        }

        $(this).replaceWith('<img src="img/ajax_load.gif" style="margin:30px auto;display:block" />');

        var data = {
            'zindex'    : ++zIndex,
            'body'      : $('.pr-body').val(),
            'author'        : $('.pr-author').val(),
            'color'     : $.trim($('#previewNote').attr('class').replace('note',''))
        };

        /* Sending an AJAX POST request: */
        $.post('ajax/post.php',data,function(msg){

            if(parseInt(msg))
            {
                /* msg contains the ID of the note, assigned by MySQL's auto increment: */
                var tmp = $('#previewNote').clone();

                tmp.find('span.data').text(msg).end().css({'z-index':zIndex,top:0,left:0});
                tmp.appendTo($('#main'));

                make_draggable(tmp)
            }

            $("#addButton").fancybox.close();
        });

        e.preventDefault();
    })
});

Aquí estamos escuchando el evento de clic en el enlace de envío del formulario. Una vez que se hace clic, los datos se validan y se envían con el $.post método. Si la inserción fue exitosa, la caja de luz se oculta y la nota recién creada se agrega a la página. Tenga en cuenta que estamos usando make_draggable función, que se incluye a continuación.

script.js - Parte 3

var zIndex = 0;

function make_draggable(elements)
{
    /* Elements is a jquery object: */
    elements.draggable({
        containment:'parent',
        start:function(e,ui){ ui.helper.css('z-index',++zIndex); },
        stop:function(e,ui){

            /* Sending the z-index and positon of the note to update_position.php via AJAX GET: */
            $.get('ajax/update_position.php',{
                x       : ui.position.left,
                y       : ui.position.top,
                z       : zIndex,
                id  : parseInt(ui.helper.find('span.data').html())
            });
        }
    });
}

En la última parte de script.js, tenemos el make_draggable función. Convierte un conjunto de elementos jQuery pasados ​​como parámetro en objetos que se pueden arrastrar. He movido esta funcionalidad a una función separada porque necesitamos crear arrastrables dos veces:una en la carga de la página inicial y otra cuando agregamos una nueva nota a la página.

Paso 5:MySQL

Si planea ejecutar y desarrollar esta demostración, deberá configurar una versión funcional en su servidor. Deberá ejecutar el código desde table.sql del archivo de descarga en phpMyAdmin y complete las credenciales de su base de datos en connect.php .

¡Con esto, nuestro sistema de notas adhesivas AJAX-ed está completo!

Conclusión

Hoy creamos un sistema de administración de notas adhesivas habilitado para Ajax y demostramos cómo podemos usar uno de los complementos disponibles para la biblioteca jQuery para crear una interfaz dinámica, completa con una vista previa en vivo.

¿Qué opinas? ¿Cómo mejorarías este código?