Archivo de la etiqueta: javascript

Acordeón Javascript para el listado de artículos

[blog]

Esto es algo que tenía en el viejo blog, y me gustaba por la facilidad que da de ir a alguno de los artículos. Estuve buscando a ver si ya existía un plugin o widget que me ofreciera la funcionalidad, pero no encontré nada, así que lo vi como la oportunidad ideal de aprender a crear widgets para WordPress.

Buscando tutoriales, encontré unos cuantos, pero muchos están desfasados y solo cubren versiones anteriores de WordPress. Otros tantos están incompletos o dan información por supuesta, por lo que no son demasiados útiles para empezar. Al final encontré este que explica paso a paso la creación de un widget funcional.

Siguiendo el tutorial, la creación del widget es muy sencilla, y pude reutilizar la mayor parte del código PHP que tenía para el viejo blog (excepto la obtención de los datos de los artículos que ahora pasa a hacerse a través de la API de WordPress). Lo que no es tan inmediato es la carga del Javascript necesario para el acordeón, ya que hay que usar un hook.

Indicando la URL del script de manera relativa al plugin/widget tal y como se explica en el codex de WordPress:

El resultado sería algo similar a esto:

function load_into_head(){
    echo '<script type="text/javascript" src="'.plugins_url('accordion.js', __FILE__).'"></script>'."n";
    echo '<link rel="stylesheet" href="'.plugins_url('acc-styles.css', __FILE__).'" type="text/css" media="screen" />';
}

add_action('wp_head', 'load_into_head');

Donde estoy cargando tanto el script del acordeón como una hoja con sus estilos en la cabecera de la página donde aparezca el widget.

En cuanto tenga un poco de tiempo limpiaré y comentaré el código y compartiré el widget por si alguien lo quiere utilizar. También me hará falta darle un nombre. De momento se llama “Article Accordion” que no es muy original, aunque es bastante autoexplicativo :P. ¿A alguien se le ocurre un buen nombre?

Obtener datos de un Google Docs Spreadsheet mediante Javascript

[programación]

Aunque parezca mentira, google no ofrece una manera sencilla de leer datos de una hora de cálculo pública mediante Javascript. La única manera que he encontrado es publicar la hoja de cálculo como una página web y utilizar Javascript para parsear los datos. Hasta ahora estaba utilizando una API de Yahoo, que funcionaba bien pero con un ligero problema…. SÓLO funcionaba en Firefox. Ni Chrome, ni Safari, ni (sin sorprender a nadie) Explorer.

Pero bueno, en mi público objetivo todos tenían instalado Firefox, así que tan simple como decir “solo funciona en Firefox!!!” 😛

El problema fue cuando un amigo me dijo “NO FUNCIONA EN FIREFOX!!!”. ¿Tal vez era problema de la nueva versión? Efectivamente, en Firefox 4 ya no funcionaba. Siendo esto la gota que colmaba el vaso, me puse a buscar un nuevo script que me permitiera acceder a los datos, encontrando este.

Aquí se puede ver un sencillo ejemplo en funcionamiento y probar tu propia hoja de cálculo.

El ejemplo no es muy intuitivo en cuanto a como obtener los datos (al menos a mi no me lo pareció :P), pero básicamente el objeto “result” es un objeto de JSON, por lo que se puede recorrer el objeto “data” como si fuese un vector. Por ejemplo este código mostraría todos los datos de la hoja de cálculo:

googleSpreadsheet.load(function(result) {
    for(var i = 0; i < result.data.length; i++){
        alert(result.data[i]);
    }
});

El problema es que no hay manera de saber la fila o columna en la que te encuentras, por lo que hay que añadir algo de lógica para tener eso controlado. También me queda comprobar como se comporta cuando la hoja de cálculo tiene varias páginas, pero eso para más adelante 😛

Adaptar el editor para mostrar código HTML

[programación]

En muchos de mis artículos muestro código HTML. Esto no supone ningún problema para el editor a la hora de crear un nuevo artículo, pero cuando intento editar el contenido de un artículo anterior surgen complicaciones.

Esto ocurre por la manera en la que se está asignando el contenido HTML que se recupera de la base de datos. El contenido se está asignando al textarea de la siguiente manera:

$output.=" <textarea id="text" name="text">".$row[1]."</textarea>";

El problema de hacerlo así, es que si hay etiquetas HTML en el contenido, se están interpretando como parte del código de la página, por lo que empiezan a aparecer cajas de texto y otros elementos en medio del propio artículo.

La solución es por tanto asignar el contenido de forma dinámica con javascript, y hacer esto con CKEditor es sencillo:

$output.=" <textarea id="text" name="text"></textarea>";
$data = str_replace('"','"',$row[1]);
$data = str_replace(" ", "", $data);
$output.='<script type="text/javascript">'
.'var editor = CKEDITOR.replace( "text" );'
.'editor.setData("'.$data.'")'
.'</script>';

Con esto lo que estamos haciendo es, primero crear un textarea vacío. Después, en el contenido del artículo escapamos todas las comillas dobles, y añadimos una suma en los cambios de línea para que no salte un error de javascript. Por último definimos el CKEditor y le asignamos el contenido.

Acordeón multinivel para el listado de artículos

[programación]

Sigo cambiando cosas que no me gustaban de EggBlog.

El listado de artículos en la columna de la derecha me parecía un poco pobre. Solo mostraba los 10 últimos, por lo que los más antiguos iban quedando relegados al olvido. Se podía acceder a una página con el listado completo de artículos, pero me parecía muy feucha.

La idea era por tanto poder acceder al listado completo de artículos desde cualquier página. Quitar la limitación de 10 artículos es sencillo, pero claro, cuando tenga 100 el listado sería enorme. Hace tiempo trabaje en el curro con un acordeón en Prototype, y me gustaba su funcionalidad, por lo que pensé que sería buena idea tener un acordeón multinivel para los artículos, de forma que se pueda desplegar por años y por meses.

Aquél que usé recuerdo que era un poco “pesado” en cuanto a rendimiento, por lo que decidí usar JQuery en esta ocasión. Buscando un poco encontré este acordeón.

Tenía buena pinta, así que lo estuve probando, y me daba problema al intentar hacerlo multinivel (no realizaba correctamente las animaciones).

Buscando el enlace he encontrado este otro.

También tiene buena pinta, pero no dice nada de multinivel. Tendré que hacer la prueba un día a ver como se comporta.

El caso es que seguí buscando y al final encontré una implementación de un acordeón multinivel que no utiliza ninguna librería por debajo. La implementación es muy simple, el js es diminuto (1,35KB) y funciona a las mil maravillas.

Para implementar el acordeón, el método que hay que modificar es eb_articlelist en el fichero news.php. En principio pensé en adaptar el código existente, pero no me gustaba nada su implementación. Básicamente se hace una consulta SQL para cada mes. Esto puede tener sentido si como máximo se van a mostrar 10 artículos, pero si se quieren mostrar todos no lo veo muy eficiente. Por eso acabé modificando el código por completo:

/**
 * Compone un acordeón con todos los artículos publicados, agrupados por meses
 * y por años.
 * @param integer $n Si su valor es cero no se muestra el acordeón.
 */
function eb_articlelist($n) {
    global $lang;
    settype( $n, "integer" );
    if( $n == 0 ){
        return "";
    }
    $output = '<div class="box"><strong>' . ucwords( $lang['articles'] ) . '</strong>';
    $output .= " " . '<ul class="acc acc_sup" id="acc_sup">';
    $lastYearShown = 0;
    $lastMonthShown = 0;
    $query = mysql_query( "SELECT article_id, article_title, article_date"
    ." FROM eb_articles WHERE article_flag != 0"
    ." ORDER BY article_date DESC" );
    $countNestedAcc = 0;
    while( $row = mysql_fetch_array( $query ) ) {
        $articleDate = $row['article_date'];
        $currentArticleYear = date( "Y", $articleDate );
        $currentArticleMonth  = date( "n", $articleDate );
        if( $currentArticleYear != $lastYearShown ) {
            if( $lastYearShown != 0 ) {
                // Cerramos el año anterior
                $output .= '</ul></div></div></li>';
            }
            // Abrimos el nuevo año
            $output .= " " . '<li><h3>' . $currentArticleYear . '</h3>'
            ." " . '<div class="acc-section"><div class="acc-content">'
            ." " . '<ul class="acc nested" id="nested_'.$countNestedAcc.'">';
            $countNestedAcc++;
            $lastYearShown = $currentArticleYear;
        }
        if( $currentArticleMonth != $lastMonthShown ) {
            if( $lastMonthShown != 0 ) {
                // Cerramos el mes anterior
                $output .= " " . '</ul></div></div></li>';
            }

            // Abrimos el nuevo mes
            $output .= " " . '<li><h3>' . ucwords( $lang['month' . $currentArticleMonth] )
            . " " . $currentArticleYear . '</h3>'
            . " " . '<div class="acc-section"><div class="acc-content"><ul>';
            $lastMonthShown = $currentArticleMonth;
        }

        $output .= " " . '<li><a href="'
        .eb_links_article( $row['article_title'], $row['article_id'] ) . '">'
        .$row[1] . '</a></li>';
    }

    // Cerramos el último mes, año y acordeon
    $output .= " " . '</ul></div></div></li>'
    ." " . '</ul></div></div></li>'
    ." " . '</ul>';

    // Inicializamos los acordeones con javascript
    $output .= " ".'<script type="text/javascript" src="_lib/scripts/script.js"></script>'
    ." " . '<script type="text/javascript">';

    // Acordeón superior
    $output.=" ".'var parentAccordion = new TINY.accordion.slider( "parentAccordion" );'
    ." " . 'parentAccordion.init( "acc_sup", "h3", 0, 0);';

    // Acordeones anidados
    for( $i = 0; $i < $countNestedAcc; $i++ ) {
        if( $i == 0 ) {
            $ex = 0;
        }
        else{
            $ex = -1;
        }
        $output .= " " . 'var nestedAcc' . $i . '=new TINY.accordion.slider( "nestedAcc' . $i . '" );'
        ." " . 'nestedAcc' . $i . ' . init( "nested_' . $i . '", "h3", 1,' . $ex . ', "acc-selected" );';
    }

    // Fin del script
    $output .= " " . '</script>';

    // Fin del div box
    $output .= '</div>';

    return $output;
}

Colocamos el script del acordeón (script.js) en la carpeta _lib/scripts, y añadimos las imágenes a themes/default/images.

Por último hay que modificar los estilos para el acordeón, por lo que añadimos los siguientes estilos a style.css:

/* ESTILOS PARA EL ACORDEÓN */
.acc_sup {
    width:205px;
    list-style:none;
    color:#033;
    margin:0 auto 40px -16px;
}

.acc_sup h3 {
    width:165px;
    border:1px solid #9ac1c9;
    padding:6px 6px 8px;
    font-weight:bold;
    margin-top:5px;
    cursor:pointer;
    background:url(images/header.gif);
    font-size: 9pt;
    margin: 0;
}

.acc_sup h3:hover { background:url( images/header_over.gif ) }
.acc_sup .acc-section {
    overflow:hidden;
    background:#fff;
    width: 180px;
}

.acc_sup .acc-content {
    width:162px;
    padding:15px;
    border:1px solid #9ac1c9;
    border-top:none;
    background:#fff;
    padding-left: 0px;
}

.nested {
    width:180px;
    list-style:none;
    color:#033;
    margin-bottom:15px;
    margin-left: -7px;
}

.nested h3 {
    width:145px;
    border:1px solid #9ac1c9;
    padding:6px 6px 8px;
    font-weight:bold;
    margin-top:5px;
    cursor:pointer;
    background:url(images/header.gif);
}

.nested h3:hover { background:url( images/header_over.gif ) }

.nested .acc-section {
    overflow:hidden;
    background:#fff;
    width: 160px;
}

.nested .acc-content {
    width:127px;
    padding:15px;
    border:1px solid #9ac1c9;
    border-top:none;
    background:#fff;
}

.nested .acc-selected { background:url( images/header_over.gif ) }

Con esto me cargo la página con el listado de artículos. Total, ya no aporta ninguna funcionalidad, y para mostrar el mismo acordeón que en el resto de las páginas, ya no tenía mucho sentido 😀