Does anyone know how to theme the textarea so that the descriptive text associate with the textarea appear above the textarea rather than below.

I've been looking at theme_textarea() but can't see where the description gets set?

Essentially i'd like the textarea order to be:

Title
Description
Textarea

as opposed to

Title
Textarea
Description

I've looked at doing this with CSS and absolute positioning, but it's not ideal for all cases.

regards

Hix

Comments

Ellen Dee’s picture

Have a look at theme_form_element. I accomplished this by doing the following:

function yourtheme_form_element($element, $value) {
  // This is also used in the installer, pre-database setup.
  $t = get_t();

  $output = '<div class="form-item"';
  if (!empty($element['#id'])) {
    $output .= ' id="'. $element['#id'] .'-wrapper"';
  }
  $output .= ">\n";
  $required = !empty($element['#required']) ? '<span class="form-required" title="'. $t('This field is required.') .'">*</span>' : '';

  if (!empty($element['#title'])) {
    $title = $element['#title'];
    if (!empty($element['#id'])) {
      $output .= ' <label for="'. $element['#id'] .'">'. $t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
    else {
      $output .= ' <label>'. $t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) ."</label>\n";
    }
  }
  
  /* To move description: move these lines here:
   */
  if (!empty($element['#description'])) {
    $output .= ' <div class="description">'. $element['#description'] ."</div>\n";
  }

 $output .= " $value\n";

  $output .= "</div>\n";

  return $output;
}

Hope that helps!

hixster’s picture

thanks Gamutalarm,

I try that out and see how it goes. Thanks for the taking the time to reply , i've been searching all over for a solution.

rgds

Hix

Drupal Web Designers Surrey South East England www.lightflows.co.uk

hixster’s picture

Thanks Gamutalarm, you're a star that worked perfectly, many thanks :-)

H

Drupal Web Designers Surrey South East England www.lightflows.co.uk

Ellen Dee’s picture

No probs, I was curious about it myself. :)

mokargas’s picture

Doesn't appear to work for multi-value fields, such as a CCK Imagefield or Filefield with unlimited values. Different theming function?

artscoop’s picture

Hi,

The function for the multi-values is not the same : it's theme_content_multiple_values($element)
You can copy the function from /sites/all/modules/cck/content.module and paste it in template.php.
Replace the "theme" in function name

That's what I did and it works fine.
:)

mastoll’s picture

I have copied the content_multiple_values($element) function into my template.php file. I am able to move the description above the field title or below the field input by moving the statement
$output .= $element['#description'] ? '<div class="description">'. $element['#description'] .'</div>' : '';
But, I can't figure out how to place it after the title and before the input field.

In the multiple values function, the title is a part of the header row of a table. The header is formed by an array. My understanding of PHP is entirely learned by hacking, so I tried the following, not knowing whether they were appropriate strategies or not:
- I've tried adding the $element['description'] to the array.
- I've tried creating a new variable $description and defining it as in the $output, then adding the $description variable to the header array. I don't think I created the variable correctly.
- I tried putting the string $element['#description'] ? '<div class="description">'. $element['#description'] .'</div>' : ''; directly in the array.
None of these worked.

Here is the entire function with the description both above and below the table for illustration sake.

function apw_tsc_zen_content_multiple_values($element) {
  $field_name = $element['#field_name'];
  $field = content_fields($field_name);
  $output = '';

  if ($field['multiple'] >= 1) {
    $table_id = $element['#field_name'] .'_values';
    $order_class = $element['#field_name'] .'-delta-order';
    $required = !empty($element['#required']) ? '<span class="form-required" title="'. t('This field is required.') .'">*</span>' : '';
    $description = $element['#description'] ? '<div class="description">I want this one to appear INSIDE the output table'. $element['#description'] .'</div>' : '';
    $header = array(
      array(
        'data' => t('!title: !required', array('!title' => $element['#title'], '!required' => $required, '!description' => $description,)),
        'colspan' => 2
      ),
      t('Order'),
    );
    $rows = array();


    // Sort items according to '_weight' (needed when the form comes back after
    // preview or failed validation)
    $items = array();
    foreach (element_children($element) as $key) {
      if ($key !== $element['#field_name'] .'_add_more') {
        $items[] = &$element[$key];
      }
    }
    usort($items, '_content_sort_items_value_helper');

    // Add the items as table rows.
    foreach ($items as $key => $item) {
      $item['_weight']['#attributes']['class'] = $order_class;
      $delta_element = drupal_render($item['_weight']);
      $cells = array(
        array('data' => '', 'class' => 'content-multiple-drag'),
        drupal_render($item),
        array('data' => $delta_element, 'class' => 'delta-order'),
      );
      $rows[] = array(
        'data' => $cells,
        'class' => 'draggable',
      );
    }
    $output .= $element['#description'] ? '<div class="description">this one appears above the output table'. $element['#description'] .'</div>' : '';

    $output .= theme('table', $header, $rows, array('id' => $table_id, 'class' => 'content-multiple-table'));
	$output .= $element['#description'] ? '<div class="description">THIS one appears BELOW the output table'. $element['#description'] .'</div>' : '';
    $output .= drupal_render($element[$element['#field_name'] .'_add_more']);

    drupal_add_tabledrag($table_id, 'order', 'sibling', $order_class);
  }
  else {
    foreach (element_children($element) as $key) {
      $output .= drupal_render($element[$key]);
    }
  }

  return $output;
}
mastoll’s picture

I can't tell you how good this feels!

Thank you, Lynda.com for php training and coincidentally including just the tidbits I needed in the first few videos after the installation lesson.

And to the CCK API website at http://api.audean.com/ where I finally learned what the t function is all about.

The beginning of the original function, with my theme-name replacing "theme" in the function name:

function apw_tsc_zen_content_multiple_values($element) {
  $field_name = $element['#field_name'];
  $field = content_fields($field_name);
  $output = '';

I added the variable $description:

  $description = $element['#description'] ? '<div class="description">'. $element['#description'] .'</div>' : '';

The original code:

  if ($field['multiple'] >= 1) {
    $table_id = $element['#field_name'] .'_values';
    $order_class = $element['#field_name'] .'-delta-order';
    $required = !empty($element['#required']) ? '<span class="form-required" title="'. t('This field is required.') .'">*</span>' : '';

Next the revised $header variable where I added !description to the data element's string parameter and '!description' =>$description to its array:

    $header = array(
      array(
'data' => t('!title: !required !description', array('!title' => $element['#title'], '!required' => $required, '!description' => $description)),        'colspan' => 2
      ),
      t('Order'),
    );

The rest of the function code. Notice that I removed the line that appended the description to the output variable.

    $rows = array();


    // Sort items according to '_weight' (needed when the form comes back after
    // preview or failed validation)
    $items = array();
    foreach (element_children($element) as $key) {
      if ($key !== $element['#field_name'] .'_add_more') {
        $items[] = &$element[$key];
      }
    }
    usort($items, '_content_sort_items_value_helper');

    // Add the items as table rows.
    foreach ($items as $key => $item) {
      $item['_weight']['#attributes']['class'] = $order_class;
      $delta_element = drupal_render($item['_weight']);
      $cells = array(
        array('data' => '', 'class' => 'content-multiple-drag'),
        drupal_render($item),
        array('data' => $delta_element, 'class' => 'delta-order'),
      );
      $rows[] = array(
        'data' => $cells,
        'class' => 'draggable',
      );
    }
   $output .= theme('table', $header, $rows, array('id' => $table_id, 'class' => 'content-multiple-table'));
	// $output .= $element['#description'] ? '<div class="description">THIS one is BELOW the output table'. $element['#description'] .'</div>' : '';
    $output .= drupal_render($element[$element['#field_name'] .'_add_more']);

    drupal_add_tabledrag($table_id, 'order', 'sibling', $order_class);
  }
  else {
    foreach (element_children($element) as $key) {
      $output .= drupal_render($element[$key]);
    }
  }

  return $output;
zwhalen’s picture

Any idea how this would work for Drupal 7? theme_form_element looks quite a bit different. I tried hacking a few things, but nothing seems to work.

I mean, I can move or remove the part of the form_element function that adds the description, but since textarea elements seem to get theirs from somewhere else, making changes just to this function doesn't have any effect on textarea display.

I know there's also a theme_textarea(), but that doesn't deal with the description either.

shendric’s picture

Hey, I've got a similar issue. I've been able to move the description below the label on most of my form elements, but textareas seem to still be a problem, if the text areas can use "Filtered HTML" or something else so that a WYSIWYG editor picks it up. Did you ever get a response to this?

Anonymous’s picture

I found that theme_textarea seemed to be the place to write the description under the title, but that the #description variable for the field was unavailable. I assume that it is not passed to theme_textarea but don't know how to trace this back.

To workaround this I've ended up inserting the description field into the HTML that has been generated by the time theme_text_format_wrapper is called as follows:

function <themename>_text_format_wrapper($variables) {
  $element = $variables['element'];
  $output = '<div class="text-format-wrapper">';
  $output .= $element['#children'];

  if (!empty($element['#description'])) { 
    // The string in the HTML to insert the description after
    $sstr = '<div class="form-textarea-wrapper resizable">';
    // The string to insert 
    $rstr = $sstr . '<div class="description">' . $element['#description'] . '</div>';
    $output = str_replace($sstr, $rstr, $output);
  }
  $output .= "</div>\n";

  return $output;
}

I can't believe that this is the best way to get the description above the input area, but it seems to work for me with the Adaptivetheme, Display Suite and the other modules I'm using.

Alan

Kojo Unsui’s picture

There's another way to do it, with function YOURTHEME_form_element($variables) (see this post).
Anyway, I couln't move the description above textareas when they are WYSIWYG enabled... Any idea ?

jrb’s picture

I've added a sandbox module to do this in D7.

https://drupal.org/sandbox/jrb/top_description

It should work for all fields including WYSIWYG text areas and multiple fields.

odegard’s picture

Another D7 module: https://www.drupal.org/project/better_field_descriptions

This module allows "description makers" to edit descriptions on a different page than the content type field management page. The descriptions are themeable and can be put over or under the field itself.

EDIT: typo