Sección dinámica de preguntas frecuentes con jQuery, YQL y Google Docs

En este tutorial, estamos creando una sección dinámica de preguntas frecuentes. El script, con la ayuda de jQuery y YQL, extraerá el contenido de una hoja de cálculo compartida en su cuenta de Google Docs y usará los datos para completar la sección de preguntas frecuentes con preguntas y respuestas.

El mejor aspecto de esta solución es que puede cambiar el contenido de la sección de preguntas frecuentes desde Google Docs, simplemente edite la hoja de cálculo. Incluso puede aprovechar el resto de las funciones de Google Docs, como la edición colaborativa. De esta manera, un pequeño equipo puede respaldar la sección de preguntas frecuentes sin necesidad de una solución de CMS dedicada.

Gracias a Chris Ivarson por diseñar el ícono de Google Docs, que se usa en la ilustración destacada de este tutorial.

Documentos de Google

Antes de comenzar a trabajar en la sección de preguntas frecuentes, primero debemos crear una nueva hoja de cálculo de Google Docs. Como probablemente ya tenga una cuenta con Google (si no es así, cree una), pasaremos directamente a la parte interesante.

En una hoja de cálculo en blanco, comience a completar dos columnas de datos. La primera columna debe contener las preguntas y la segunda las respuestas, que se convertirán en entradas en su sección de preguntas frecuentes. Cada pregunta frecuente va en una línea separada. Puedes ver el que creé aquí.

Después de esto, haz clic en Compartir> Publicar como página web y elija CSV de la lista desplegable. Esto generará un enlace a su hoja de cálculo en forma de un archivo CSV normal, que usaremos más adelante.

El HTML

El primer paso en el desarrollo del guión es el marcado. La #página div es el elemento contenedor principal. Es el único div con un ancho explícito. También está centrado en el medio de la página con un margen:automático, como verás en la parte CSS del tut.

faq.html

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<link rel="stylesheet" type="text/css" href="styles.css" />

</head>

<body>

<div id="page">

    <div id="headingSection">
        <h1>Frequently Asked Questions</h1>
        <a class="button expand" href="#">Expand</a>
    </div>

    <div id="faqSection">
        <!-- The FAQs are inserted here -->
    </div>

</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="script.js"></script>
</body>
</html>

La hoja de estilo se incluye en el encabezado del documento, y la biblioteca jQuery y nuestro script.js se incluyen en la parte inferior. Todos estos se analizan en detalle en las siguientes secciones de este tutorial.

La #headingSection contiene el encabezado h1 y el botón expandir/contraer. Después viene la #faqSection div, donde se insertan las entradas de preguntas frecuentes después de que jQuery obtenga el contenido de su hoja de cálculo de Google Docs.

Las entradas de preguntas frecuentes están organizadas como una estructura de lista de definiciones (dl ). Este es uno de los elementos HTML menos utilizados, pero es perfecto para nuestra tarea. Así es como se ve una vez que jQuery lo agrega a la página.

faq.html

<dl>
    <dt><span class="icon"></span>How does this FAQ section work?</dt>
    <dd>With the help of jQuery and YQL, this script pulls the latest data ..</dd>

    <dt><span class="icon"></span>Can you modify it?</dt>
    <dd>This is the best part of it - you can change the contents ..</dd>
</dl>

El dl elemento contiene un dt para cada pregunta y un dd para cada respuesta. Los elementos dd están ocultos con display:none, y solo se muestran con un slideDown animación una vez que el respectivo dt se hace clic.

El CSS

Los estilos (que se encuentran en styles.css) son bastante sencillos y se explican por sí mismos. Como se mencionó anteriormente, solo la #página div, que actúa como el contenedor principal, se le asigna explícitamente un ancho. También está centrado en el medio de la página con un valor automático para los márgenes izquierdo/derecho.

estilos.css - Parte 1

#page{
    width:753px;
    margin:50px auto;
}

#headingSection{
    background-color:#7b8b98;
    padding:40px;
    padding-left:60px;
    position:relative;
    border:1px solid #8b9ba7;
    border-bottom:none;
}

#faqSection{
    background:url('img/faq_bg.jpg') repeat-y #fff;
    padding:20px 90px 60px 60px;
    border:1px solid white;
    text-shadow:1px 1px 0 white;
}

h1{
    color:#fff;
    font-size:36px;
    font-weight:normal;
}

/* The expand / collapse button */

a.button{
    background:url('img/buttons.png') no-repeat;
    width:80px;
    height:38px;
    position:absolute;
    right:50px;
    top:45px;
    text-indent:-9999px;
    overflow:hidden;
    border:none !important;
}

a.button.expand:hover{ background-position:0 -38px;}
a.button.collapse{ background-position:0 -76px;}
a.button.collapse:hover{ background-position:0 bottom;}

Estamos utilizando una sola etiqueta de ancla para el botón expandir y contraer, asignándole el botón expandir o el colapso clase CSS. Estas clases determinan qué partes de la imagen de fondo se desplazan a la vista. La imagen de fondo en sí es cuatro veces la altura del botón y contiene un estado normal y flotante para las versiones de botón de expansión y contracción.

estilos.css - Parte 2

/* Definition Lists */

dt{
    color:#8F9AA3;
    font-size:25px;
    margin-top:30px;
    padding-left:25px;
    position:relative;
    cursor:pointer;
    border:1px solid transparent;
}

dt:hover{ color:#5f6a73;}

dt .icon{
    background:url('img/bullets.png') no-repeat;
    height:12px;
    left:0;
    position:absolute;
    top:11px;
    width:12px;
}

dt.opened .icon{ background-position:left bottom;}

dd{
    font-size:14px;
    color:#717f89;
    line-height:1.5;
    padding:20px 0 0 25px;
    width:580px;
    display:none;
}

Cuando se hace clic en el título de una definición (dt), su respectivo dd se expande a la vista (como verá en la siguiente sección). Con esto, al dt también se le asigna un abierto clase. Esta clase ayuda a jQuery a determinar qué preguntas frecuentes se abren y, al mismo tiempo, afecta el estilo de la viñeta pequeña a la izquierda del título.

JQuery

Pasando probablemente a la parte más interesante del tutorial. Si ha estado siguiendo los tutoriales en este sitio, probablemente haya notado que YQL encuentra su camino en muchos de los tutoriales aquí. La razón principal detrás de esto es que YQL hace posible que los desarrolladores lo usen como un proxy para una amplia gama de API e implementen una funcionalidad diversa completamente en JavaScript.

Hoy estamos usando YQL para obtener nuestra hoja de cálculo de Google como CSV y analizarla, de modo que esté disponible como un objeto JSON normal. De esta manera, obtenemos un almacenamiento de datos gratuito y fácil de actualizar para nuestra sencilla aplicación.

secuencia de comandos.js

$(document).ready(function(){

    // The published URL of your Google Docs spreadsheet as CSV:
    var csvURL = 'https://spreadsheets.google.com/pub?key='+
            '0Ahe1-YRnPKQ_dEI0STVPX05NVTJuNENhVlhKZklNUlE&hl=en&output=csv';

    // The YQL address:
    var yqlURL =    "http://query.yahooapis.com/v1/public/yql?q="+
            "select%20*%20from%20csv%20where%20url%3D'"+encodeURIComponent(csvURL)+
            "'%20and%20columns%3D'question%2Canswer'&format=json&callback=?";

    $.getJSON(yqlURL,function(msg){

        var dl = $('<dl>');

        // Looping through all the entries in the CSV file:
        $.each(msg.query.results.row,function(){

            // Sometimes the entries are surrounded by double quotes. This is why
            // we strip them first with the replace method:

            var answer = this.answer.replace(/""/g,'"').replace(/^"|"$/g,'');
            var question = this.question.replace(/""/g,'"').replace(/^"|"$/g,'');

            // Formatting the FAQ as a definition list: dt for the question
            // and a dd for the answer.

            dl.append('<dt><span class="icon"></span>'+
            question+'</dt><dd>'+answer+'</dd>');
        });

        // Appending the definition list:
        $('#faqSection').append(dl);

        $('dt').live('click',function(){
            var dd = $(this).next();

            // If the title is clicked and the dd is not currently animated,
            // start an animation with the slideToggle() method.

            if(!dd.is(':animated')){
                dd.slideToggle();
                $(this).toggleClass('opened');
            }

        });

        $('a.button').click(function(){

            // To expand/collapse all of the FAQs simultaneously,
            // just trigger the click event on the DTs

            if($(this).hasClass('collapse')){
                $('dt.opened').click();
            }
            else $('dt:not(.opened)').click();

            $(this).toggleClass('expand collapse');

            return false;
        });

    });
});

Puede que no quede claro en el código anterior, pero jQuery envía una solicitud JSONP a los servidores de YQL con la siguiente consulta de YQL:

SELECT * FROM csv
WHERE url='https://spreadsheets.google.com/...'
AND columns='question,answer'

CSV es una tabla YQL, que toma la URL de un archivo csv y una lista de nombres de columna. Devuelve un objeto JSON con los nombres de las columnas como sus propiedades. Luego, el script los filtra (eliminando las comillas dobles innecesarias) y los inserta como una lista de definiciones (DL) en la página.

¡Con esto, nuestra sección dinámica de preguntas frecuentes está completa!

Personalización

Para usar este script con su propia hoja de cálculo, solo necesita editar la variable csvURL en script.js y reemplácelo con la URL CSV de su hoja de cálculo. Puede obtener esta dirección desde Compartir> Publicar como página web> Menú desplegable CSV . Además, tenga en cuenta que cuando realiza cambios en la hoja de cálculo, los cambios pueden tardar unos minutos en surtir efecto. Puede acelerar esto haciendo clic en Volver a publicar ahora botón, que se encuentra en la misma ventana superpuesta.

Palabras finales

Puede usar la misma técnica para potenciar diferentes tipos de páginas dinámicas. Sin embargo, esta implementación tiene sus defectos. Todo el contenido se genera con JavaScript, lo que significa que no será visible para los motores de búsqueda.

Para garantizar que sus datos serán rastreados, puede tomar una ruta diferente. Puede usar PHP, u otro lenguaje de back-end, para obtener y mostrar los datos de YQL en un intervalo de tiempo fijo, digamos 30 minutos (o incluso con menos frecuencia, si no planea actualizar los datos con frecuencia).

Asegúrese de compartir sus sugerencias en la sección de comentarios a continuación.