Add "first" and "last" classes on list view LI's

Last modified: August 23, 2009 - 15:34

Much like HowTo: Have "first" and "last" classes on menu blocks sometimes you need to be able to address the first and last elements of lists, this howto allows you to have that for your LI's.

The processing of lists is done by function theme_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = NULL) which can be overridden in template.php. It only takes a few small changes to get this to work (adding $item_key to the foreach and checking it against count and 0 to determine if to apply the class).

Paste the code below into your template.php and you're done.

<?php

function phptemplate_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = NULL) {
 
$output = '<div class="item-list">';
  if (isset(
$title)) {
   
$output .= '<h3>'. $title .'</h3>';
  }

  if (!empty(
$items)) {
   
$output .= "<$type" . drupal_attributes($attributes) . '>';
    foreach (
$items as $item_key=>$item) {
     
$attributes = array();
     
$children = array();
      if (
is_array($item)) {
        foreach (
$item as $key => $value) {
          if (
$key == 'data') {
           
$data = $value;
          }
          elseif (
$key == 'children') {
           
$children = $value;
          }
          else {
           
$attributes[$key] = $value;
          }
        }
      }
      else {
       
$data = $item;
      }
      if (
count($children) > 0) {
       
$data .= theme_item_list($children, NULL, $type, $attributes); // Render nested list
     
}
     
      if(
$item_key == 0) {
       
$attributes['class'] = (isset($attributes['class'])? $attributes['class'] .= ' first' : 'first');
      } elseif(
$item_key == count($items)-1){
       
$attributes['class'] = (isset($attributes['class'])? $attributes['class'] .= ' last' : 'last');
      }
     
     
$output .= '<li' . drupal_attributes($attributes) . '>'. $data .'</li>';
    }
   
$output .= "</$type>";
  }
 
$output .= '</div>';
  return
$output;
}
?>

Bonus: Zebra

Add the following before $output .= '<li' . drupal_attributes($attributes) . '>'. $data .'</li>'; to add a zebra class to alternate list items (not the php tags).

<?php
if ($item_key % 2) { $attributes['class'] = (isset($attributes['class'])? $attributes['class'] .= ' zebra' : $attributes['class'] = 'zebra'); }
?>

How do you do this in 6x?

tchopshop - September 1, 2009 - 17:32

I need a solution to this in Drupal 6, to use with CCK fields that output multiples.

Elena

Try this code in your

GetLives - September 22, 2009 - 05:34

Try this code in your template.php:

<?php
function phptemplate_item_list($items = array(), $title = NULL, $type = 'ul', $attributes = NULL) {
  static
$zebra = FALSE;
 
$output = '<div class="item-list">';
  if (isset(
$title)) {
   
$output .= '<h3>'. $title .'</h3>';
  }

  if (!empty(
$items)) {
   
$output .= "<$type". drupal_attributes($attributes) .'>';
   
$num_items = count($items);
    foreach (
$items as $i => $item) {
     
$zebra = !$zebra;
     
$attributes = array();
     
$children = array();
      if (
is_array($item)) {
        foreach (
$item as $key => $value) {
          if (
$key == 'data') {
           
$data = $value;
          }
          elseif (
$key == 'children') {
           
$children = $value;
          }
          else {
           
$attributes[$key] = $value;
          }
        }
      }
      else {
       
$data = $item;
      }
      if (
count($children) > 0) {
       
$data .= theme_item_list($children, NULL, $type, $attributes); // Render nested list
     
}
      if (
$i == 0) {
       
$attributes['class'] = empty($attributes['class']) ? 'first' : ($attributes['class'] .' first');
      }
      if (
$i == $num_items - 1) {
       
$attributes['class'] = empty($attributes['class']) ? 'last' : ($attributes['class'] .' last');
      }
      if (
$zebra) {
       
$attributes['class'] = $attributes['class'].' even';
      } else {
       
$attributes['class'] = $attributes['class'].' odd';
      }
     
$output .= '<li'. drupal_attributes($attributes) .'>'. $data ."</li>\n";
    }
   
$output .= "</$type>";
  }
 
$output .= '</div>';
  return
$output;
}
?>

This wasn't copied from any other post. I was just in need of the same functionality, so I made my own edits to the theme_item_list function, which I found in the theme.inc file and in the API reference. The key to my change is in three parts. These are what I added:

<?php
static $zebra = FALSE;
?>

Set the "zebra" (as in alternating black and white stripes) variable to false. You may change this to true if you want to start with the "even" class instead.
<?php
$zebra
= !$zebra;
?>

This inverts the boolean value, making false true and true false. It's the simplest way I could think of to accomplish the goal.
<?php
      
if ($zebra) {
       
$attributes['class'] = $attributes['class'].' even';
      } else {
       
$attributes['class'] = $attributes['class'].' odd';
      }
?>

This is the basic checking of the "zebra" boolean. If true, it adds the "even" class. Otherwise, it adds the "odd" class. You could rewrite this to be much shorter, too...
<?php
      
if ($zebra) {
       
$attributes['class'] .= ' even';
      } else {
       
$attributes['class'] .= ' odd';
      }
?>

I just had some odd errors during testing, and I was trying a variety of changes to see what works. The short version works, mind you. I was too lazy to change it back. XD

Please consider joining my site: http://www.getlives.com
Thank you. -GetLives

Injecting first, last, odd, even

lodey - November 18, 2009 - 17:53

Hi.

Thanks for this template amendment. I actually had trouble getting this to work - but I think this was mainly due to me trying to adapt it into my node.tpl.php over ride file...... where I was using the below to output my cck field items :

<?php
foreach ((array)$node->field_proj_gallery as $item) {
?>

<?php
print $item['view']
?>

<?php
}
?>

I wanted each $item to have the odd, even, first and last classes added.

I am presuming that if my php skills were more up to scratch this might be easy - perhaps easy to just adapt your file...... but in the end I had a better idea and just used this really simple javascript to utiliise the inbuilt jquery...... and its very short.

Just thought that I would leave this info for anyone coming along after me with a similar problem.

So if you want to you can do the following.

In your javascript file, or inpage script block use similar code to this - i.e. you will need to edit the target selector :

//
// ZEBRA STRIPING
//
$(document).ready(function(){
$(".project-gallery > div:nth-child(even)").addClass("alt");
$(".project-gallery > div:first-child").addClass("first");
})

So to explain :

$(".project-gallery > ------- this points to the parent element (target selector) - so it might be a 'ul', or a 'div' etc.
The '>' means to treat each element individually in case of multiple uses. (so if you had two parent items it treats them individually rather than ending one on odd and starting the next on even....)

the div:first-child is the locator...... so in this instance the first div inside the parent. If it were a 'ul' you would use li:first-child.

nth-child(even) - this could be (odd) but should make sense.

.addClass("THIS IS THE CLASS THAT GETS ADDED")

Not the most detailed description, but it works for me and I think someone might find it useful.

I'd much rather understand how to get this hardcoded into the php output though..... so this is only a temp fix for me untill I can find better.

 
 

Drupal is a registered trademark of Dries Buytaert.