Translate to

Buscar

23 de marzo de 2011

Como modificar el breadcrumb para un nodo de cierto tipo

El breadcrumb es el conjunto de enlaces que suele aparecer en la parte superior de las páginas para indicar el camino seguido para llegar hasta allí.

Pero, por default, no siempre queda tal cual se quiere.

En este caso, mostraré cómo se puede modificar usando el archivo template.php del tema shamrock, que es un subtema que hice del tema zen.

Ejemplo
Tengo un nodo proyecto, que tiene un campo CCK field_proyecto_tipo, que puede ser 'Nuevo' o 'Entregado'.

Se desea que el breadcrumb pueda conducir a las página proyectos-nuevos o proyectos-entregados según si el nodo presentado es de tipo 'Nuevo' o 'Entregado'.

function shamrock_preprocess_node(&$vars, $hook) {
  if ($vars['type']=='proyecto') {
    $tipo = $vars['field_proyecto_tipo'][0]['value'];
    $bc = drupal_get_breadcrumb();
    if ($tipo==t('Nuevo')) {
      $bc[] = l(t('Proyectos Nuevos'), 'proyectos-nuevos');
    } else if ($tipo==t('Entregado')) {
      $bc[] = l(t('Proyectos Entregados'), 'proyectos-entregados');
    }
    drupal_set_breadcrumb($bc);
  }

  // Optionally, run node-type-specific preprocess functions, like
  // shamrock_preprocess_node_page() or shamrock_preprocess_node_story().
  $function = __FUNCTION__ . '_' . $vars['node']->type;
  if (function_exists($function)) {
    $function($vars, $hook);
  }
}

Referencia

18 de marzo de 2011

Cómo hacer un segundo botón de envío

Me resultó de ayuda este post: Additional submit button on node forms

14 de marzo de 2011

Una forma de usar Cufon

Cufon es una alternativa para reemplazar las fuentes de la página con otras no estandar.

Cufón es un script que traza las fuentes con ayuda de archivos .js generados (desde esta página http://cufon.shoqolate.com/generate/) a partir de una fuente .ttf, otf, o pfb.

En el formulario que aparece en la página del generador de coufon, pueder ser útil (particularmente para el español) indicar que incluya además los siguientes glifos:

“”‘’…_&-–—åäöæøàèìòùáéíóúâêîôûäëïöüãõñçÅÄÖÆØÀÈÌÒÙÁÉÍÓÚÂÊÎÔÛÄËÏÖÜÃÕÑÇ©®™′″´×⁺

Aunque existe el módulo cufon, aquí describo una forma de usarlo diréctamente.

Los archivos
Coloco cufon-yui.js y los archivos .js de las fuentes en un módulo. Por ejemplo el módulo misc.

El código
Creo un bloque (llamado Cufon, por ejemplo) que contenga el código php que requiero y se muestre en cada página:

<?php
drupal_add_js(drupal_get_path('module', 'misc') . '/js/cufon-yui.js');
drupal_add_js(drupal_get_path('module', 'misc') . '/js/MyFrutigerBold_700.font.js');
drupal_add_js("$(function() {
  Cufon.replace('h1.title, .views-field-title', { fontFamily: 'MyFrutigerBold' });
})", "inline");
?>

Donde MyFrutigerBold es un nombre indicado en el formulario del generador .js de cufon.

El módulo
El módulo cufon permite manejar esto con más comodidad.

Luego de instalar el módulo, es necesario copiar cufon-yui.js al directorio modules/cufon/js y colocar los .js de las fuentes un directorio como sites/all/libraries/cufon-fonts.

La configuración se hacen en Administer, Configuración del Sitio, Cufon Settings. En Selector, se coloca algo como h1.title, .views-field-title. En Font family, se elige de entre las fuentes disponibles.

Referencia

Cómo hacer un login AJAX alternativo

El login normal de Drupal es un formulario que, en caso de error, conduce a otra página. El objetivo es un formulario que use AJAX para el login y permita mostrar los mensajes de error sin cargar otra página.



El bloque
Creo un bloque (my-login) con este contenido:

<?php
global $user;
?>

<?php if ($user->uid): ?>

  <div id="block-my-login">
    <div class="title"><?php echo l(t('Login'), 'user', array('attributes'=>array('id'=>'btn-my-login'))) ?></div>
    <div class="content">
      <ul>
        <li>
          <?php echo l(t('Mi cuenta'), 'user') ?>
        </li>
        <li>
          <?php echo l(t('Salir'), 'logout') ?>
        </li>
      </ul>
    </div>
  </div>

<?php else: ?>

  <div id="block-my-login">
    <div class="title"><?php echo l(t('Login'), 'user', array('attributes'=>array('id'=>'btn-my-login'))) ?></div>
    <div class="content">
      <form id="user-login">
        <div class="username">
          <label><?php echo t('Usuario') ?></label><input type="text" id="name" name="name" class="input text"/>
        </div>
        <div class="password">
          <label><?php echo t('Contraseña') ?></label><input type="password" id="password" name="password" class="input password"/>
        </div>
        <div class="submit">
          <input type="submit" id="submit" value="<?php echo t('Entrar') ?>" class="button submit"/>
        </div>
      </form>
      <div id="loginresult"></div>
      <div class="remember">
        <?php echo l(t('Olvidé mi contraseña'), 'user/password', array('attributes'=>array('id'=>'remember'))) ?>
      </div>
      <div class="register">
        <input type="button" id="register" value="<?php echo t('Registrarme') ?>" class="button register"/>
      </div>
    </div>
  </div>

<?php endif ?>

<?php
  drupal_add_js(drupal_get_path('module', 'misc') . '/js/login.js');
?>

El bloque muestra un formulario simple para el login y una lista de enlaces para el usuario ya logueado.

Javascript
misc/js/login.js contiene el javascript:

$(function() {
  $('#block-my-login .title')
    .click(function(e) {
      e.preventDefault();
      $('#botones-verdes .content').slideUp('slow');
      $('.content', $(this).parent()).slideToggle('slow');
      return false;
    });
  $('#user-login').submit(function() {
    var url = Drupal.settings.basePath + 'user/login.json';
    $.post(url, $(this).serialize(), function(data) {
      var result = Drupal.parseJson(data);
      if (!result.error || result.error == 0) {
        window.location.href = Drupal.settings.basePath + 'user';
      } else {
        $('#loginresult').show().html(result.result);
      }
    });
    return false;
  });
  $('#register').click(function(e) {
    e.preventDefault();
    window.location.href = Drupal.settings.basePath + 'user/register';
    return false;
  });
});

El script invoca a la acción user/login.json, definida en el módulo misc.

Acción
En el módulo misc, para la acción user/login.json:

/**
 * Implements hook_menu
 */
function misc_menu() {
  ...
  $items['user/login.json'] = array(
    'page callback' => 'misc_login_json',
    'access callback' => 'user_is_anonymous',
  );
  return $items;
}
...
function misc_login_json() {
  if (!isset($_POST['name']) && !isset($_POST['password'])) {
    echo json_encode(array('error'=>t('Se requiere $_POST[\'name\'] y $_POST[\'password\']')));
    return;
  }
  $name = $_POST['name'];
  $password = $_POST['password'];
  if ($msg = user_validate_name($name)) {
    echo json_encode(array('error'=>1, 'result'=>$msg));
    return;
  }
  $account = user_load(array('name' => $name, 'pass' => $password, 'status' => 1));
  if ($account) {
    user_external_login($account);
    echo json_encode(array('result'=>'OK'));
    return;
  } else {
    echo json_encode(array('error'=>1, 'result'=>t('Por favor verifique su nombre de usuario y contraseña.')));
    return;
  }
  return;
}

11 de marzo de 2011

Solucionando error con drush dl

Venía utilizando drush 4.2 con normalidad. Tanto en Linux (Centos 5, php 5.2.10) como en Windows 7 (xampp 1.7.1). Uno de estos días, me ocurrió, en ambos, que ya no funcionaba ejecutar algo como:

drush dl drupal-6.20

En Windows, obtenía un error como:

C:\bin\dev\xampp171\htdocs\>drush dl drupal-6.20
Source directory                                                         [error]

C:\Users\compaq\AppData\Local\Temp/drush_tmp_1299865530/drupal is not
readable or does not exist.
Project drupal (6.20) could not be downloaded to                         [error]

Investigando, se debe a un issue documentado en http://drupal.org/node/1078318.
Alli proveen también el parche http://drupal.org/files/issues/drush-1078318.patch:

diff --git a/commands/pm/pm.drush.inc b/commands/pm/pm.drush.inc
index e39096a..18ec069 100644
--- a/commands/pm/pm.drush.inc
+++ b/commands/pm/pm.drush.inc
@@ -1858,7 +1858,7 @@ function pm_parse_project_version($requests) {
 function pm_project_types() {
   // Lookup the 'Project type' vocabulary to some standard strings.
   $types = array(
-    'core' => 'Drupal project', 
+    'core' => 'Drupal core',
     'profile' => 'Installation profiles',
     'module' => 'Modules',
     'theme' => 'Themes',

Es decir, ha habido un cambio en el valor del campo core, de 'Drupal project' a 'Drupal core', debido, segun entiendo, a un cambio en la taxonomia usada en el proyecto drupal. El issue es del 2 de marzo, pero yo recién lo he notado esta semana.

Para solucionarlo, aplique el parche al drush que tiene instalado. También puede hacerlo manualmente. Por ejemplo, en Windows, ubiqué el archivo pm.drush.inc:

C:\bin\dev\drush\commands\pm\pm.drush.inc:
function pm_project_types() {
  // Lookup the 'Project type' vocabulary to some standard strings.
  $types = array(
    'core' => 'Drupal project',
    'profile' => 'Installation profiles',
    'module' => 'Modules',
    'theme' => 'Themes',
    'theme engine' => 'Theme engines',
  );
  return $types;
}

1 de marzo de 2011

Audioplayer con drPlayer

Para hacer un player de archivos de audio (mp3, etc), ayuda el plugin audio. El problema es que está incompleto (el pase de Drupal 5 a Drupal 6 tiene varios pendientes). Uno puede ir completando las partes que no funcionan, como el playlist, pero es un poco complicado. Además, requiere varios módulos de apoyo. Me dije, a lo mejor, se puede resolver de manera más simple. ¿Cómo lo haría yo?

En este artículo no pretendo instruir sobre la mejor forma de hacer un player de audio. Simplemente, hablaré del camino que voy recorriendo (es un trabajo en marcha) en desarrollar una solución. Tal vez le ayude de algún modo a alguien.

La idea
La idea es poder subir archivos de audio (empecemos con mp3) que puedan ser organizados en playlists, o listas de reproducción.

Un usuario puede subir tantos archivos como quiera y definir sus propias listas.

De preferencia con software que no tenga restricciones de uso comercial, por si acaso.

El método
Empezar con lo imprescindible, lo minimo. Avanzar hacia el siguiente mínimo e imprescindible  paso. Y así sucesivamente. Aplicar la pauta con libertad.

Esbozando la solución
Subir archivos. Se puede usar el módulo filefield.

Playlist. No encontré un módulo para esto, aparte de audio. Busqué en plugins para jQuery. Quiero uno que permita dejar corriendo la lista de canciones. Encontré drplayer y flowplayer, entre otros. Flowplayer se ve muy prometedor. Drplayer es simple de usar. Luego de dar muchas vueltas, me pareció que me estaba distrayendo demasiado en la elección del player, que quizás hasta podría ser intercambiable.

Explorando drPlayer
Hago una demo simple sin usar Drupal, para comprobar lo que requiere:

<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <link rel="stylesheet" href="drplayer.css" type="text/css" />
    <script src="jquery.js" type="text/javascript"></script>
    <script src="drplayer.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(document).ready(function() {
            $("#playlist").playlist(
                {
                    playerurl: "swf/drplayer.swf"
                }
            );
        });
    </script>

</head>
<body>
    <div id="playlist">
        <div href="mp3/cancion-01.mp3" style="width: 400px;" class="item">
            <div>
                <div class="fr duration">03:00</div>
                <div class="btn play"></div>
                <div class="title"><b>Artista 1</b> - Canción 01</div>
            </div>
            <div class="player inactive"></div>
        </div>
        <div class="clear"></div>

        <div href="mp3/cancion-02.mp3" style="width: 400px;" class="item">
            <div>
                <div class="fr duration">04:00</div>
                <div class="btn play"></div>
                <div class="title"><b>Artista 2</b> - Canción 02</div>
            </div>
            <div class="player inactive"></div>
        </div>
        <div class="clear"></div>
        
    </div>
    <div class="clear"></div>
    
    <a href="javascript:void(0);" onClick="$('#playlist').playlist('prev');">Prev</a>
    <a href="javascript:void(0);" onClick="$('#playlist').playlist('next');">Next</a>
 
    <a href="javascript:void(0);" onClick="$('#playlist').playlist('pause');">Pause</a>
    <a href="javascript:void(0);" onClick="$('#playlist').playlist('play');">Play</a>
    
   
</body>
</html>

Es decir, la lista está contenida en un bloque #playlist. Cada item es un bloque .item. El campo de título es un bloque .title y el de duración es un bloque .duration.

Más tarde, encontré que es necesario considerar también un bloque .player .inactive por cada item.

Me parece que se podría usar el módulo views para construir html con esta estructura.

Usando id3
El módulo getid3 para permitir usar getid3 para obtener la metadata de un archivo.

La metadata de un archivo de audio contiene información como el título, el nombre del artista, la duración, el nombre y año del album, etc.

Una vez instalado getid3, los nodos que contengan un archivo subido tendrán un campo $node->field_audiofile[0] conteniendo esa metadata (puede leer un poco más sobre eso en el artículo Resolviendo Filefield Meta y usando Dynamic Field), que se podrán usar para llenar la estructura que se requiere para drplayer. Chévere.

Tipo de contenido Audio
Defino el tipo de contenido Audio (audio) con el campo Archivo (field_audio_file) de tipo File.

Indico además que no usará el campo Body (dejando en blanco el nombre de ese campo).

Para facilitar el llenado del campo Title, es útil el módulo auto_nodetitle, que se configura en la misma pestaña de edición del tipo de contenido. Allí, indico que el título se genere automáticamente si se deja en blanco (dando la opción al usuario de poner otra cosa, si desea). Teniendo además instalado el módulo token, indiqué que el patrón de los títulos automáticos fuera:

[field_audiofile-filefield-filename]

Es decir, el nombre del archivo subido.

Lista de audios
Defino la vista audios, que muestra nodos de tipo audio y los campos Nodo: Titulo, Contenido: Archivo. Para obtener la duración, requiero algo de código php que ingreso con ayuda del módulo views_customfield, permite usar php para generar el contenido de un campo.

Al comienzo, dejé a un lado el asunto de la duración e intenté proseguir con el nombre de archivo únicamente.

Intenté usar templates para crear la estructura que requería para drplayer. Con los view-xxx.tpl.php pude dar a cada bloque el id y la clase que requerían. #playlist conteniendo .item que contiene .title y .duration. Sin embargo, la estructura requiere que el nombre del archivo esté como href del elemento .item y no se me ocurría un modo de lograr eso con los templates, ya que el template que me permite personalizar el bloque .item no tiene disponible una variable con el nombre del archivo.

Supongo que hay algún modo de usar template.php para publicar la variable que necesita en ese caso, pero no domino mucho los hooks de la vista y se me hizo más natural imaginar que podría usar un Customfield: PHP para generar todo el html que se requiere a partir del $data->nid disponible:

<?php
echo misc_get_drplayer_html_audio($data->nid);
?>

La función misc_get_drplayer_html_audio la defino en el módulo misc:

function misc_get_drplayer_html_audio($nid) {
  $node = node_load($nid);
  $audiofile = $node->field_audiofile[0];
  $filename = base_path().$audiofile['filepath'];
  $duration = $audiofile['data']['duration'];
  $duration_h = sprintf('%02d:%02d', $duration/60, $duration%60);
  $artist = $audiofile['data']['tags']['artist'];
  $title = $audiofile['data']['tags']['title'];
  $html = '
'.$duration_h.'
'.$artist.' - '.$title.'
'; return $html; }

Lo bueno de usar este método es que me permitió acceder con más comodidad a la metadata del archivo, que no estaba directamente disponible en la vista.

Con esto, se puede conseguir que una vista que muestre las canciones con la estructura requerida por drplayer.

Módulo drPlayer
Para incorporar drPlayer a drupal, cree el módulo drplayer, vacío, simplemente para contener los archivos de esa biblioteca, en el subdirectorio modules/drplayer/drplayer/.

Luego, en la vista audios, en el display que muestra los archivos del playlist, Basic settings, Encabezado, indico el siguiente contenido php:

<?php
drupal_add_css(drupal_get_path('module', 'drplayer').'/drplayer/drplayer.css', 'module');
drupal_add_js(drupal_get_path('module', 'drplayer').'/drplayer/drplayer.js', 'module');
drupal_add_js('$(document).ready(function() {
    $("#playlist").playlist(
        {
            playerurl: "'.base_path().drupal_get_path('module', 'drplayer').'/drplayer/swf/drplayer.swf"
        }
    );
});', 'inline');
?>

Esto invoca a drplayer al momento de mostrar la vista.

Siguiente paso
Que el usuario pueda definir sus propios playlist.

Referencias

Más artículos