Hero

Como modificar el aspecto a un campo tipo Image en Drupal 7

Junio 04, 2013

nightwalkr
JavaScript
jQuery
PHP
Programación
Drupal
Desarrollo de Modulos

Hola hoy les mostrare como cambiar el aspecto de campo tipo File que usa el control Imagen, con el fin de que se visualize igual en todos los navegadores.

  1. Alterar el control.

Para iniciar en un módulo personalizado implementaremos el hook hook_field_widget_form_alter(), con este hook identificamos los campos o elementos de tipo imagen, para poder agregar otro proceso al elemento como se muestra en el siguiente código.

/**
 * Implements hook_field_widget_form_alter().

 */
function MIMODULO(&$element, &$form_state, $context) {

  $field_type = $context['field']['type'];

  if($field_type == 'image'){
    $element[0]['#process'][] = 'MIMODULO_field_image_custom_process';
  }
}

En este caso #process es una función en la cual creamos los elementos que reemplazaran la apariencia gráfica en nuestro campo.

Antes que todo hay que tener en cuenta el comportamiento original del campo, ya que al cargar o subir la imagen se hace un proceso por ajax, para luego mostrarnos la imagen, el nombre del archivo con su extensión y el botón remover.

Si no tenemos en cuenta esto al momento de cargar la imagen, nos seguirá apareciendo la estructura que reemplazara al campo original y la nueva interface que hemos agregado, como se muestra en las siguientes imágenes.

campo imagen upload campo imagen remove

Para evitar este problema realizamos una validacion en la cual debemos identificar que el campo al momento de realizar el ajax o al momento de editar el formulario no cargue el archivo ya guardado o que deseamos subir.

$fid = isset($element['#value']['fid']) ? $element['#value']['fid'] : 0; //Archivo Guardado
$file = $element['#file']; // Archivo por Guardar

Teniendo lo anterior en cuenta nuestra funcion quedara asi:

/**
 *  Custom Field Widget Image
 *
 * @return array
 *   Drupal's form.
 */

function MIMODULO_field_image_custom_process($element, &$form_state, $form){

  $fid = isset($element['#value']['fid']) ? $element['#value']['fid'] : 0;

  $file = $element['#file'];

  if(!$fid && !$file){
    $element['field_imagen_custom'] = array(
      '#markup' => '<span class="namefile">Select to Imagen File</span>
                    <a class="browser-image-file button">Browser</a>',
      '#attached' => array(
          'js' => array(drupal_get_path('module', 'mimodulo') . '/js/mimodulo_field_image_custom.js'),
          'css' => array(drupal_get_path('module', 'mimodulo') . '/css/mimodulo_field_image_custom.css'),
        ),
      '#weight' => -6,
    );
  }

  return $element;
}

En este caso hago uso de un ‘#markup’ para indicar la estructura para la nueva apariencia.

El uso de la propiedad ‘#attached’ nos permitira agregar o asignar que archivos trabajaran cada vez que nuestro campo sea llamado en un formulario, se puede decir que funciona igual que las funciones de drupal_add_css(), drupal_add_js() y drupal_add_library() entre otros.

El uso de la propiedad ‘#weight’ es opcional, en este ejemplo se desea que el nuevo elemento este antes del boton de “Upload”

  1. Implementación de JS personalizado para el control.

Ahora damos paso a la implementación del archivo mimodulo_field_image_custom.js, esto con el fin de cambiar el funcionamiento y comportamiendo del control Image.

Como primera medida identificaremos todos los campos de tipo “file” que utilizen el control Image, utilizando selectores de jQuery.

var $input_files = $('.field-type-image .image-widget input[type="file"]');

Despues necesitaremos un disparador para el enlace de “Browser” creado en la funcion mimodulo_field_image_custom_process(), el cual nos permitira llamar a la ventana de busqueda de archivos. Se debe tener en cuenta que pueden existir multiples campos del mismo tipo en un mismo formulario por esto creamos el evento click de forma general.

$('.image-widget .image-widget-data .browser-image-file').live('click',function(){
    var input_file = $(this).parent('.image-widget-data').find('.form-file');
    input_file.trigger('click');
  });

Se preguntaran porque uso el evento .live() y no el .bind(), esto es porque nuestro elemento esta ligado al funcionamiento del campo original, al momento de cargar un archivo se procesa por ajax y dado que los elementos se crean desde este metodo, el evento bind() no identifica elementos creados dinamicamente por llamados Ajax.

Para terminar debemos aplicar a todo posibles campos de este control en nuestro formulario la acción change, para mostrar el nombre del archivo + la .extencion, dentro de la estructura de “<span class=“namefile”>Select to Imagen File</span>“.

$input_files.live('change',function(){
    var imagename = $(this).val().split(/\\/).pop();
    $(this).parent('.image-widget-data').find('.namefile').text(imagename);
  });

Unificando todo lo anterior nos queda:

$ = jQuery.noConflict();
$(function(){

  var $input_files = $('.field-type-image .image-widget input[type="file"]');

  $('.image-widget .image-widget-data .browser-image-file').live('click',function(){
    var input_file = $(this).parent('.image-widget-data').find('.form-file');
    input_file.trigger('click');
  });

  $input_files.live('change',function(){
    var imagename = $(this).val().split(/\\/).pop();
    $(this).parent('.image-widget-data').find('.namefile').text(imagename);
  });
});
  1. Implementación de CSS personalizado para el control.

Para terminar un poco de estilo en nuestro archivo mimodulo_field_image_custom.css.

.image-widget .image-widget-data input[type="file"]{
  display: none;
}

.image-widget .image-widget-data .namefile{
  background: #eee;
  border: 1px solid #e4e4e4;
  padding: 4px 10px;
}

Al finalizar nuestro control tendra una apariencia similar al la siguiente imagen.

Muchas gracias espero les sirva de mucho y nos vemos en otra próxima contribución xD

Recibe consejos y oportunidades de trabajo 100% remotas y en dólares de weKnow Inc.