creates CSS hooks (ID tags) for each .form-item

JohnG - October 12, 2005 - 14:01
Project:FriendsElectric
Version:HEAD
Component:Suggestions
Category:feature request
Priority:normal
Assigned:Unassigned
Status:needs review
Description

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.

#1

chud - March 11, 2006 - 00:29

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

#2

chud - March 11, 2006 - 00:29

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

#3

stella - July 8, 2006 - 14:44

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.

#4

grrajeshkumar - April 20, 2007 - 03:25

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

any help?

#5

JohnG - April 20, 2007 - 11:32
Version:4.6.x-1.x-dev» HEAD
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 - <a href="http://drupal.org/node/33850" title="http://drupal.org/node/33850" rel="nofollow">http://drupal.org/node/33850</a> **/
/**********************************************************************/

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 - <a href="http://drupal.org/node/33850" title="http://drupal.org/node/33850" rel="nofollow">http://drupal.org/node/33850</a> **/
/**********************************************************************/

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.

 
 

Drupal is a registered trademark of Dries Buytaert.