this glob of code goes in template.php. I wrote it in order to 'tidy-up' node-editing pages, but it could be modified to make it much more powerful (the form-item DIV seems to be used everywhere!). This is my first really useful hack & I'm sure it can be improved upon (eg it has no useful identifiers for form-items which do not include some kind of input field).

What it does is generate an ID tag from the name-attribute of the input field. The tag is inserted into the <DIV class="form-item"> tag so that it encloses the whole form-item: $title (the label) $description (the help text) and $value (the input field itself). This makes instances of the ubiquitous <DIV class="form-item"> less anonymous and more themeable via CSS. Eg. <DIV class="form-item" id="css_edit_title"> and <DIV class="form-item" id="css_edit_flexinode_4">(which is a flexinode field, not a flexinode!).

/* ------------------------------------------------------*/
/* re-organise presentation of form elements / form-item */
/* ------------------------------------------------------*/
/* first we need this function locally? */
function form_clean_id($id = NULL) {
  $id = str_replace('][', '-', $id);
  return $id;
} 

/* then we need to get our $idname */

function form_item_get_idname($value) {
  $nameregexp = '/name=\"(.*?)\"/i';
  preg_match ($nameregexp, $value, $matches);
  $sensitive = array ('@\[@si','@\]@si','@:@si');
  $replace = array ('_','','');
  $idname0 = preg_replace($sensitive, $replace, $matches[1]);
  $idname = 'css_'.$idname0;
    return $idname;
} 


/* Catch the theme_form_element function, and redirect through the template api */
function phptemplate_form_element($title, $value, $description = NULL, $id = NULL, $required = FALSE, $error = FALSE) {

  $output  = '<div class="form-item" id="'. form_item_get_idname($value) .'">'."\n" ;
//  $output  = '<div class="form-item" id="'. 'idname' .'">'."\n";

  $required = $required ? '<span class="form-required">*</span>' : '';
  if ($title) {
    if ($id) {
      $output .= ' <label for="'. form_clean_id($id) .'">'. $title .':</label>'. $required ."\n";
   }
    else {
      $output .= ' <label>'. $title .':</label>'. $required ."\n";
   }

  }
  if ($description) {
    $output .= ' <span class="description">('. $description .")</span><br />\n";
  }
  $output .= " $value\n";
  $output .= "</div>\n";

  return $output;
} 
/** note on CSS definitions:
  * When there is no name= attrubute to the element, the generic id will be id="css_".
  * These are common on ordinary node pages eg .node #css_ {} so be careful!
  * I used .node-form #css_ {display: none} to hide the 'formatting guidelines' that 
  * normally appear under textareas (WYSIWYG editor makes them redundant). 
  **/
/* --------------------------------------*/

BTW It also (by introducing <span>tags) tweeks the html layout of these elements within the form item, from

$label :
[ $value ]
$description

to

$label : $description
[ $value ]

Any and all feedback welcome.

Comments

chud’s picture

this is exactly what I needed in order to hide certain fields by loading in different CMS based on the current user role

chud’s picture

...sorry, that's CSS not CMS :)

stella’s picture

I really find the addition of the id attribute to the <div class='form-item'> very useful and think that it should be added to the core drupal code rather than having specify it per theme. I prefer my theme's default form layout however.

grrajeshkumar’s picture

it doesnt seem to work in drupal5+.. in default garland theme...

any help?

JohnG-1’s picture

Version: 4.6.x-1.x-dev » master
Status: Needs work » Needs review

I'm not really surprised this patch applies to D5 & garland theme ... it's a long time ago !!! There's been a new Forms API and a lot of code under the bridge since then :-P

Recently I was playing with Nedjo's new Formfilter module which is still quite a young module but a very good starting place if you are trying to tidy-up the UI on your D5 input forms.

A quick look at theme_form_element in Drupal APIs shows that it still exists and still does a similar job ;-) It looks a lot easier to do this id-trick in D5 ... I just tried this in D5 Garland template.php and as far as I can see it works just fine:

<?php

/**********************************************************************/
/** Put form-element id into form-item div tag - http://drupal.org/node/33850 **/
/**********************************************************************/

function phptemplate_form_element($element, $value) {
//   $output  = '<div class="form-item">'."\n"; 
  $output  = '<div class="form-item" id="' . $element['#id'] . '">'."\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";
    }
  }

  $output .= " $value\n";

  if (!empty($element['#description'])) {
    $output .= ' <div class="description">'. $element['#description'] ."</div>\n";
  }

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

  return $output;
} 
/**********************************************************************/
?>

Now that we have these fieldsets everywhere, I guess we might want to give them the same treatment ... but we'll use the fieldset title as the tag:

<?php

/**********************************************************************/
/** Do the same to the fieldset tag - http://drupal.org/node/33850 **/
/**********************************************************************/

function phptemplate_fieldset($element) {
  if ($element['#collapsible']) {
    drupal_add_js('misc/collapse.js');

    if (!isset($element['#attributes']['class'])) {
      $element['#attributes']['class'] = '';
    }

    $element['#attributes']['class'] .= ' collapsible';
    if ($element['#collapsed']) {
     $element['#attributes']['class'] .= ' collapsed';
    }
  }

  return '<fieldset' . drupal_attributes($element['#attributes']) . ' id="' . $element['#title'] . '">' . ($element['#title'] ? '<legend>'. $element['#title'] .'</legend>' : '') . ($element['#description'] ? '<div class="description">'. $element['#description'] .'</div>' : '') . $element['#children'] . $element['#value'] . "</fieldset>\n";
}
/**********************************************************************/
?>

I have not tested these extensively ... they seem OK but feedback would be very welcome.