Chris 2pha Brown

Chris Brown

Drupal, Javascript, Three.js, 3D

website blog

Drupal 7 Bootstrap image field upload widget

When using the Bootstrap theme in Drupal 7, the image upload widget leaves a lot to be desired. I looks pretty crappy Below is how I overcame this.
It should probably work with file fields too but instead of overriding THEME_image_widget, you would override THEME_file_widget, though I haven't tried it yet.

First, add this to your css

.btn-file {
  position: relative;
  overflow: hidden;
}

.btn-file input[type=file] {
  position: absolute;
  top: 0;
  right: 0;
  min-width: 100%;
  min-height: 100%;
  font-size: 100px;
  text-align: right;
  filter: alpha(opacity = 0);
  opacity: 0;
  outline: none;
  background: white;
  cursor: inherit;
  display: block;
}

Then override the theme_image_widget in your template.php
A note on admin theme If your upload widget is on a node edit page (or any admin page) the active theme will be your admin theme. This means the code will need to go into your admin themes template.php and the css in your admin themes css.

function MYTHEME_image_widget($variables) {
  $element = $variables['element'];
  $output = '';
  $output .= '<div class="image-widget form-managed-file clearfix">';

  if (isset($element['preview'])) {
    $output .= '<div class="image-preview">';
    $output .= drupal_render($element['preview']);
    $output .= '</div>';
  }

  $output .= '<div class="image-widget-data">';
  if ($element['fid']['#value'] != 0) {
    $element['filename']['#markup'] = '<div class="form-group">' . $element['filename']['#markup'] . ' <span class="file-size badge">' . format_size($element['#file']->filesize) . '</span></div>';
  }
  else {
    $element['upload']['#prefix'] = '<div class="input-group"><span class="input-group-btn"><span class="btn btn-primary btn-file">Browse';
    $element['upload']['#suffix'] = '</span></span>';
    $element['upload_button']['#prefix'] = '<input class="form-control" type="text" readonly=""><span class="input-group-btn">';
    $element['upload_button']['#suffix'] = '</span></div>';
  }
  drupal_add_js("
    (function($) {
      Drupal.behaviors.bootstrapImages = {
        attach: function (context) {
              $('.btn-file :file', context).once().on('change', function() {
                var txt  = '';
                var input = $(this);
                var numFiles = input.get(0).files ? input.get(0).files.length : 1;
                if (numFiles > 1) {
                  txt = numFiles + ' Selected';
                } else {
                  txt = input.val();
                }
                input.closest('.input-group').children('input[type=text]:lt(1)').val(txt);
              });
        }
      };
    })(jQuery)
  ", 'inline');

  $output .= drupal_render_children($element);
  $output .= '</div>';
  $output .= '</div>';

  return $output;
}

I should mention that this was inspired by Cory LaViska's blog post HERE

To get it to work with file fields too, just add:

function MYTHEME_file_widget($variables) {
  return MYTHEME_image_widget($variables);
}

Original vs altered

filefield original filefield altered