How to style a single-select dropdown?

Events happening in the community are now at Drupal community events on www.drupal.org.
ressa's picture

Hey,

I originally posted this question here: http://drupal.org/node/507724, but got no response, so I am trying in this group. I will of course post a write up of the solution in the original post if I get one here 8o)

Does anyone know how to style a single-select dropdown, which is based on a taxonomy vocabulary?

As it is now, the styling is a dash added in front of the child terms, like this:

Parent
-Child
--Grandchild
-Child
-Child
Parent
-Child

Ideally I would like to style the parent term bold, to really make it stand out and clarify where a new category begins.

Alternatively, adding a space in front of the dash would also be an improvement, or substituting it with another character (for example »), if the first option isn't possible.

Thank you.

Comments

Ressa: I've been pulling my

bangpound@drupal.org's picture

Ressa:

I've been pulling my hair out over this problem, too.

The fundamental problem is that there's no way I can see to pass any style or other attributes to the tags generated by form_select_options(). As such, the only way to represent indentation is with non-whitespace characters. If you use whitespace, it will collapse. We can't style things bold either, unless we use OPTGROUP tags, which cannot be nested and so are not a really viable avenue to pursue.

The only way you can change the hyphen is to change it in core. It's a minor change, and if it's very important to you, I would say it's a perfectly valid reason to hack core. If you use CVS to deploy Drupal, your changes will persist between upgrades. Otherwise you'll be relying on your memory to maintain the code.

form_select_options() is fundamentally a theme helper function, and that means you can override theme_select to alter the output for your theme. Of course, you'll also have to prune the hyphens yourself. Grr... http://drupal.org/node/188933

Hey bangpound, As you can

ressa's picture

Hey bangpound,

As you can see below, I found a function which does indeed facilitate inserting class tags inside an option tag, but most browsers ignore CSS styled select boxes, so it isn't really a solution. As you write, OPTGROUP is not a solution for most, but in my case, with only two levels -- parent and child -- it actually works out fine 8o)

I used this script, which exobuzz shared with me, to format my views generated taxonomy select box, making it look a bit like it was formatted with OPTGROUP tags , inserting === before and after the parent terms:

<?php
// override some exposed filter form data
function MYTHEME_preprocess_views_exposed_form(&$vars, $hook) {
 
// print $vars['form']['#id']; // uncomment the print command to get the value for YOURFORMID
 
switch($vars['form']['#id']) {
    case
'YOURFORMID':
      foreach (
$vars['form']['YOUR_FILTER_TID']['#options'] as $option) { // 'YOUR_FILTER_TID' is probably = 'tid'
       
$key = key($option->option);
       
// insert === before and after parent term, looking for no dash in first character
       
$value = &$option->option[$key];
       
$value = preg_replace('/^([a-zA-Z0-9æøåÆØÅ ]+)/','== $1 ==',$value);
       
// replace "-" with "--" for child items      
              // $value = &$option->option[$key];
             // $value = preg_replace('/^-/','--',$value);
     
}
      unset(
$vars['form']['YOUR_FILTER_TID']['#printed']);
     
$vars['widgets']['filter-YOUR_FILTER_TID']->widget = drupal_render($vars['form']['term_node_tid_depth']);
      break;
  }
}
?>

At first I thought this script provided me with the solution, until I realized I wanted to make the parent terms unselectable in the add node form, which is where OPTGROUP comes in handy. Only problem is how to format the mark up language of the form. After much digging I found this post: http://drupal.org/node/431950#comment-1474088

I couldn't make it work until I realized that myform_select_options was set to form_select_options in the second function. I have inserted the updated script below.

Since the parent terms of my category are in the range of 2001 to 2005 I only inserted the OPTGROUP tags if they validated and the form #id was edit-taxonomy-1. I couldn't figure out how to insert the close OPTGROUP tag after the last child term, but it doesn't seem to cause any problems, so far!

The class="level0", class="level1", etc. tags are not used, since Internet explorer, Safari and other browsers ignore them, but I included them just in case I want to use them later on.

<?php
/**
* Format a dropdown menu or scrolling selection box.
*/
function YOUR_THEME_NAME_select($element) {
 
$select = '';
 
$size = $element['#size'] ? ' size="'. $element['#size'] .'"' : '';
 
_form_set_class($element, array('form-select'));
 
$multiple = $element['#multiple'];
  return
theme('form_element', $element, '<select name="'. $element['#name'] .''. ($multiple ? '[]' : '') .'"'. ($multiple ? ' multiple="multiple" ' : '') . drupal_attributes($element['#attributes']) .' id="'. $element['#id'] .'" '. $size .'>'. myform_select_options($element) .'</select>');
}


function
myform_select_options($element, $choices = NULL) {

  if (!isset(
$choices)) {
   
$choices = $element['#options'];
  }
 
// array_key_exists() accommodates the rare event where $element['#value'] is NULL.
  // isset() fails in this situation.
 
$value_valid = isset($element['#value']) || array_key_exists('#value', $element);
 
$value_is_array = is_array($element['#value']);
 
$options = '';
  foreach (
$choices as $key => $choice) {
    if (
is_array($choice)) {
     
$options .= '<optgroup label="'. $key .'">';
     
$options .= myform_select_options($element, $choice);
     
$options .= '</optgroup>';
    }
    elseif (
is_object($choice)) {
     
$options .= myform_select_options($element, $choice->option);
    }
    else {
     
$key = (string)$key;
      if (
$value_valid && (!$value_is_array && (string)$element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) {
       
$selected = ' selected="selected"';
      }
      else {
       
$selected = '';
      }
// only enable for the form with #id of edit-taxonomy-1 and parent terms, in the range of 2001 to 2005 
              
if ( ( ($key == 2001) || ($key == 2002) || ($key == 2003) || ($key == 2004) || ($key == 2005) ) && ($element['#id'] == 'edit-taxonomy-1') ) {
         
$options .= '<optgroup label="'. check_plain($choice) . '">';
             
// print $element['#id'] . "<br>";
              
}
              else {
       
// replace "-" with " " for child items only -- don't replace dashes in - Please select -
       
$child_term_no_dash = preg_replace('/^-([a-zA-Z0-9æøåÆØÅ]+)/' ,'$1', check_plain($choice));
 
     
$options .= '<option value="'. check_plain($key) .'" class="level' . check_plain(substr_count($choice, '-')) . '"' . $selected .'>' . $child_term_no_dash .'</option>';
      }
    }
  }
  return
$options;
}
?>

Thanks for sharing your

bangpound@drupal.org's picture

Thanks for sharing your solution with the group, ressa!

New solution

ressa's picture

You're welcome 8o)

I couldn't get the exposed filter of my view to search through children of selected parent terms, so I have decided to skip the first script and use the second script to insert the === before and after parent terms in the views exposed filter.

In stead, I include the parent terms when entering new nodes and force the user to select the deepest term, using the Hierarchical Select module, which can be set up to do this.

I changed the code from

<?php
// only enable for the form with #id of edit-taxonomy-1 and parent terms, in the range of 2001 to 2005 
if ( ( ($key == 2001) || ($key == 2002) || ($key == 2003) || ($key == 2004) || ($key == 2005) ) && ($element['#id'] == 'edit-taxonomy-1') ) {
$options .= '<optgroup label="'. check_plain($choice) . '">';
?>

to
<?php
// only enable for forms with #id of edit-tid(views exposed filter) and parent terms in the range of 2001 to 2005 
if ( ( ($key >= 2001) && ($key <= 2005) ) && ($element['#id'] == 'edit-tid') ) {
$parent_term = preg_replace('/^([a-zA-Z0-9æøåÆØÅ ]+)/', '== $1 ==', check_plain($choice));
$options .= '<option value="'. check_plain($key) .'" class="level' . check_plain(substr_count($choice, '-')) . '"' . $selected .'>' . $parent_term .'</option>';
?>

Hopefully I wont have to look in to this too soon again!

Thanks also

mlncn's picture

Wim Leers' http://drupal.org/project/hierarchical_select - still in dev 3.x branch for Drupal 6 - certainly has established itself as a must-have module for improving taxonomy usability in many situations.

And what you've found to do with http://api.drupal.org/api/function/theme_select/6 is pretty amazing!

Thanks for sharing!

ben, agaric

benjamin, agaric

Taxonomy

Group organizers

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: