1

I'm using Drupal 7.23 with no core hacks. I have form element for logo:

'logo' => array(
  '#title' => t("Logo"),
  '#type' => 'managed_file',
  '#description' => t('Allowed extensions: gif png jpg jpeg.'),
  '#upload_validators' => array(
    'file_validate_extensions' => array('gif png jpg jpeg'),
  ),
  '#upload_location' => 'public://mymodule/logo',
),

I need to leave #theme as is - it gets altered by other modules to provide additional functionality. But for the sake of clean example I disabled them so they are not interfering. But it means I cannot use #theme, I need to use #theme_wrappers.

So I try this:

'logo' => array(
  '#title' => t("Logo"),
  '#type' => 'managed_file',
  '#description' => t('Allowed extensions: gif png jpg jpeg.'),
  '#upload_validators' => array(
    'file_validate_extensions' => array('gif png jpg jpeg'),
  ),
  '#upload_location' => 'public://mymodule/logo',
  '#theme_wrappers' => array('preview_upload'),
),

And in module file:

function mymodule_theme() {
  return array(
    'preview_upload' => array(
      'render element' => 'element',
      'file' => 'mymodule.module',
    ),
  );
}

function theme_preview_upload($variables) {
  $element = $variables['element'];
  $output = '<div class="form-item">';

  if (isset($element['#file']->uri)) {
      $output .= '<div class="managed-file-preview">';
      $output .= '<img src="' . image_style_url('thumbnail', $element['#file']->uri) . '" />';
      $output .= '</div>';
  }
  $output .= theme_file_managed_file($variables);
  $output .= "</div>";
  return $output;
}

And it works, but there is a problem: AJAX malfunction.

  • If field started having image in it, removing file works, but gives me this error in my JavaScript console:

    TypeError: element_settings.url.replace is not a function this.url = element_settings.url.replace(//nojs(/|$|\?|&|#)/g, '/ajax$1');

    Then uploading new one refreshes page - file is uploaded, but not with AJAX.

  • If field started blank, uploading image works without warnings, but removing it refreshes page. File stays removed.

So, where I went wrong? How to add wrapper, but not disturb built-in AJAX on this field?

Problem happens in ajax.js on line 132:

// Replacing 'nojs' with 'ajax' in the URL allows for an easy method to let
// the server detect when it needs to degrade gracefully.
// There are five scenarios to check for:
// 1. /nojs/
// 2. /nojs$ - The end of a URL string.
// 3. /nojs? - Followed by a query (with clean URLs enabled).
// E.g.: path/nojs?destination=foobar
// 4. /nojs& - Followed by a query (without clean URLs enabled).
// E.g.: ?q=path/nojs&destination=foobar
// 5. /nojs# - Followed by a fragment.
// E.g.: path/nojs#myfragment
this.url = element_settings.url.replace(/\/nojs(\/|$|\?|&|#)/g, '/ajax$1'); 

Worging of an error message suggest the problem is caused by element_settings not being obtained at line 98:

Drupal.ajax = function (base, element, element_settings) {

After that, I'm quite lost.

Best bet so far is that my $output .= theme_file_managed_file($variables); is insufficient and omits some kind of processing that would otherwise happened. If so, how to replace this line properly?


I could change the output the way I needed using this form element definition:

'logo' => array(
  '#title' => t("Logo"),
  '#type' => 'managed_file',
  '#description' => t('Allowed extensions: gif png jpg jpeg.'),
  '#upload_validators' => array(
    'file_validate_extensions' => array('gif png jpg jpeg'),
  ),
  '#upload_location' => 'public://mymodule/logo',
  '#theme' => 'preview_upload',
),

In module file I copied theme_file_managed_file, placed it under the name I wanted and altered as needed:

function theme_preview_upload($variables) {
  $element = $variables['element'];

  $attributes = array();
  if (isset($element['#id'])) {
    $attributes['id'] = $element['#id'];
  }
  if (!empty($element['#attributes']['class'])) {
    $attributes['class'] = (array) $element['#attributes']['class'];
  }
  $attributes['class'][] = 'form-managed-file';

  // This wrapper is required to apply JS behaviors and CSS styling.
  $output = '';
  $output .= '<div' . drupal_attributes($attributes) . '>';

  // START OF MY ADDITION
  if (isset($element['#file']->uri)) {
    $output .= '<img src="' . image_style_url('thumbnail', $element['#file']->uri) . '" />';
  }
  // END OF MY ADDITION

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

This works, and without JavaScript warnings or other side effects, but of course conflicts with all other modules and themes wanting to theme file_managed fields their own way.

  • 1
    Have you tried making your own managed_file type? It may be more work than you are willing to invest, but it would at least fix your theme conflict and therefore fix your issue. – Scott Joudry Sep 12 '13 at 23:03
  • @ScottJoudry Good idea, but I'm not that desperate. Yet. And I do believe wrappers are supposed to work. I hope someone can tell me how. – Mołot Sep 13 '13 at 6:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.