Make menu zebra coloring more robust.

Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>

diff -pruN framework/template.php framework_ao2/template.php
--- framework/template.php	2008-11-28 07:14:30.000000000 +0100
+++ framework_ao2/template.php	2009-03-07 17:58:48.000000000 +0100
@@ -104,22 +104,61 @@ function phptemplate_get_ie6_styles() {
 
 /**
  * Adds even and odd classes to <li> tags in ul.menu lists
+ *
+ * Detect menu depth changes, the zebra coloring "state machine" follows these 
+ * rules:
+ *  - An item with a 'first' class is always odd in its list, it starts a new 
+ *    submenu increasing menu depth.
+ *  - An item with a 'last' class decrease the menu depth.
+ *  - Items in the same submenu get alternating odd/even class.
+ *
+ *  This depth detection makes the processing more robust in case some other 
+ *  modules (namely dhtml_menu) preprocess the menu not following the original
+ *  item order (for instance dhtml_menu uses a recursive function to do its
+ *  preprocessing).
+ *
+ *  NOTE: this currently doesn't work well if a submenu has only one item, 
+ *  because this sigle element is labeled only as 'last' and not also as 
+ *  'first', see:
+ *  http://drupal.org/node/393632
  */ 
-function phptemplate_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) {
-  static $zebra = FALSE;
-  $zebra = !$zebra;
+function phptemplate_menu_item($link, $has_children, $menu = '', 
+  $in_active_trail = FALSE, $extra_class = NULL) {
+  static $zebra = array();
+  static $depth = 0;
+
+  /* A new sublist starts, increase menu depth */
+  if (preg_match('/first/', $extra_class)) {
+    $depth += 1;
+    $zebra[$depth] = FALSE;
+  } else {
+    $zebra[$depth] = ! $zebra[$depth];
+  }
+
   $class = ($menu ? 'expanded' : ($has_children ? 'collapsed' : 'leaf'));
+
   if (!empty($extra_class)) {
     $class .= ' '. $extra_class;
   }
   if ($in_active_trail) {
     $class .= ' active-trail';
   }
-  if ($zebra) {
-    $class .= ' even';
+  if ($zebra[$depth] == FALSE) {
+    $class .= ' odd';
   }
   else {
-    $class .= ' odd';
+    $class .= ' even';
   }
+
+  /* A sublist ends, do some cleanup and decrease menu depth */
+  if (preg_match('/last/', $extra_class)) {
+    $zebra[$depth] = TRUE;
+    unset($zebra[$depth]);
+    /* protect for underflow in the case of the NOTE above */
+    if ($depth > 0) {
+      $depth -= 1;
+    }
+  }
+
   return '<li class="'. $class .'">'. $link . $menu ."</li>\n";
 }
