Index: custom_breadcrumbs.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/custom_breadcrumbs/custom_breadcrumbs.admin.inc,v
retrieving revision 1.1.2.3
diff -u -r1.1.2.3 custom_breadcrumbs.admin.inc
--- custom_breadcrumbs.admin.inc	11 Feb 2009 02:26:13 -0000	1.1.2.3
+++ custom_breadcrumbs.admin.inc	10 Apr 2009 16:59:42 -0000
@@ -72,15 +72,7 @@
     '#description' => t('A list of Drupal paths for the breadcrumb links, one on each line.'),
     '#default_value' => $bid ? $breadcrumb->paths : NULL
   );
-
-  $form['set_active_menu'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Override menu path'),
-    '#description' => t("If checked, the node's default location in the menu hierarchy will be forced to match the breadcrumb trail. This does not automatically add an entry for the node to existing menus, but will cause those menus to be displayed as 'active' when the node in question is viewed."),
-    '#return_value' => TRUE,
-    '#default_value' => $bid ? $breadcrumb->set_active_menu : FALSE
-  );
-  
+ 
   $form['help2'] = array(
     '#type' => 'fieldset',
     '#collapsible' => FALSE,
@@ -146,3 +138,25 @@
   _custom_breadcrumbs_delete_breadcrumb($form_state['values']['bid']);
   $form_state['redirect'] = 'admin/build/custom_breadcrumbs';
 }
+
+function custom_breadcrumbs_admin_settings() {
+  $form = array();
+  drupal_set_title(t('Custom Breadcrumbs Configuration'));
+
+  $form['custom_breadcrumbs_force_active_trail'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Force the active trail'),
+    '#description' => t('This options sets the active trail to match the custom breadcrumb trail and overrides the normal theme_links() implementation to add the active-trail class to links. This is experimental and may not work as expected. If this is of interest to you, please test and report back to the custom breadcrumbs issue queue.'),
+    '#default_value' => variable_get('custom_breadcrumbs_force_active_trail', FALSE),
+    '#weight' => -10,
+  );
+
+  $form['#submit'][] = 'custom_breadcrumbs_admin_settings_submit';
+  
+  return system_settings_form($form);
+}
+
+function custom_breadcrumbs_admin_settings_submit($form, &$form_state) {
+  drupal_rebuild_theme_registry();  // rebuild the theme registry
+  drupal_set_message('The theme registry has been rebuilt');
+}
Index: custom_breadcrumbs.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/custom_breadcrumbs/custom_breadcrumbs.module,v
retrieving revision 1.6.2.5
diff -u -r1.6.2.5 custom_breadcrumbs.module
--- custom_breadcrumbs.module	11 Feb 2009 02:26:13 -0000	1.6.2.5
+++ custom_breadcrumbs.module	10 Apr 2009 18:22:50 -0000
@@ -35,7 +35,16 @@
     'access arguments' => array('administer custom breadcrumbs'),
     'file' => 'custom_breadcrumbs.admin.inc',
   );
-
+  
+  $items['admin/settings/custom-breadcrumbs'] = array(
+    'title'            => 'Custom Breadcrumb Settings',
+    'page callback'    => 'drupal_get_form',
+    'page arguments'   => array('custom_breadcrumbs_admin_settings'),
+    'access arguments' => array('administer custom breadcrumbs'),
+    'file'             => 'custom_breadcrumbs.admin.inc',
+    'type'             => MENU_NORMAL_ITEM,
+  );
+  
   return $items;
 }
 
@@ -52,19 +61,19 @@
       $titles = module_exists('token') ? token_replace($titles, 'node', $node) : $titles;
       $paths = module_exists('token') ? token_replace($paths, 'node', $node) : $paths;
 
-      $trail = array(l(t('Home'), '<front>'));
       $location = array();
+      $trail = array(l(t('Home'), '<front>'));
+      $location[] = array('title' => t('Home'), 'href' => '<front>', 'localized_options' => array());
       for ($i = 0; $i < count($titles); $i++) {
         if ($title = trim($titles[$i])) { // create breadcrumb
-          $location[$i] = menu_get_item(drupal_get_normal_path($paths[$i]));
           $trail[] = _custom_breadcrumbs_create_crumb($title, trim($paths[$i]));
+          $location[] = array('title' => $title, 'href' => drupal_get_normal_path(trim($paths[$i])));
         }
       }
-      drupal_set_breadcrumb($trail);
-      if ($breadcrumb->set_active_menu) {
-        $location[] = menu_get_item();
+      if (variable_get('custom_breadcrumbs_force_active_trail', FALSE)) {
         menu_set_active_trail($location);
       }
+      drupal_set_breadcrumb($trail);
     }
   }
 }
@@ -187,3 +196,241 @@
   
   return theme('table', $headers, $rows, array('class' => 'description'));
  }
+
+/**
+ *  Implementation of hook_theme_registry_alter
+ */
+function custom_breadcrumbs_theme_registry_alter(&$theme_registry) {
+  if (variable_get('custom_breadcrumbs_force_active_trail', FALSE) && !empty($theme_registry['links'])) {
+    $theme_registry['links']['function'] = 'custom_breadcrumbs_override_links';
+    $theme_registry['menu_item_link']['function'] = 'custom_breadcrumbs_theme_menu_item_link';
+    $theme_registry['menu_item']['function'] = 'custom_breadcrumbs_theme_menu_item';
+  }
+}
+
+function custom_breadcrumbs_in_active_trail($link) {
+  if (!isset($link) || !isset($link['href'])) {
+    return FALSE;
+  }
+  $trail = menu_get_active_trail();
+  if (!isset($trail)) {
+    return FALSE;
+  }
+  foreach ($trail as $step) {
+    if ($step['href'] == drupal_get_path_alias($link['href'])) {
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+function custom_breadcrumbs_override_links($links, $attributes = array('class' => 'links')) {
+  $output = '';
+  if (count($links) > 0) {
+    $output = '<ul'. drupal_attributes($attributes) .'>';
+
+    $num_links = count($links);
+    $i = 1;
+
+    foreach ($links as $key => $link) {
+      $class = $key;
+
+      // Add first, last and active classes to the list of links to help out themers.
+      if ($i == 1) {
+        $class .= ' first';
+      }
+      if ($i == $num_links) {
+        $class .= ' last';
+      }
+      if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))) {
+        $class .= ' active';
+      }
+      if (custom_breadcrumbs_in_active_trail($link) && ($link['href'] != '<front>')) {
+        $class .= ' active-trail';
+      }
+      $output .= '<li'. drupal_attributes(array('class' => $class)) .'>';
+
+      if (isset($link['href'])) {
+        // Pass in $link as $options, they share the same keys.
+        $output .= l($link['title'], $link['href'], $link);
+      }
+      else if (!empty($link['title'])) {
+        // Some links are actually not links, but we wrap these in <span> for adding title and class attributes
+        if (empty($link['html'])) {
+          $link['title'] = check_plain($link['title']);
+        }
+        $span_attributes = '';
+        if (isset($link['attributes'])) {
+          $span_attributes = drupal_attributes($link['attributes']);
+        }
+        $output .= '<span'. $span_attributes .'>'. $link['title'] .'</span>';
+      }
+
+      $i++;
+      $output .= "</li>\n";
+    }
+
+    $output .= '</ul>';
+  }
+  return $output;
+}
+
+/* code below is taken from dhtml - modified to suit custom breadcrumbs */
+/**
+ * Preprocessor for menu_item_link.
+ * Adds an ID attribute to menu links and helps the module
+ * follow the recursion of menu_tree_output().
+ */
+function custom_breadcrumbs_theme_menu_item_link($link) {
+
+  $link['localized_options']['attributes']['id'] = 'custom_breadcrumbs_menu-' . _custom_breadcrumbs_menu_unique_id($link['mlid']);
+ 
+  // Each link in series is another level of recursion. Add it to the stack.
+  _custom_breadcrumbs_menu_stack($link);
+  if (custom_breadcrumbs_in_active_trail($link)) {  
+    $link['localized_options']['attributes']['class'] = 'active';
+  }
+  return theme_menu_item_link($link);   // Pass the altered variables to the normal menu themer.
+}
+
+function custom_breadcrumbs_theme_menu_item($link, $has_children, $menu = '', $in_active_trail = FALSE, $extra_class = NULL) {
+  /* When theme('menu_item') is called, the menu tree below it has been
+   * rendered already. Since we are done on this recursion level,
+   * one element must be popped off the stack.
+   */
+  $stack = _custom_breadcrumbs_menu_stack();
+
+  // Move to the last element in the stack (the current item).
+  end($stack);
+
+  // If there are children, but they were not loaded...
+  if ($has_children && !$menu) {
+    // Load the tree below the current position.
+    $tree = _custom_breadcrumbs_menu_subtree($stack);
+    $force_active_trail = FALSE;
+    foreach ($tree as $sub => $data) {
+      if (custom_breadcrumbs_in_active_trail($data['link'])) {
+        $force_active_trail = TRUE;
+      } 
+      else {
+        $belows = (array)$data['below'];
+        foreach ($belows as $id => $below) { //descend
+          if (custom_breadcrumbs_in_active_trail($below['link'])) {
+            $force_active_trail = TRUE;
+          }
+          else {
+            unset($tree[$sub]['below'][$id]);
+          }
+        }
+      }
+    }
+    if ($force_active_trail) {
+      // Render it...
+      $menu = menu_tree_output($tree);
+      $in_active_trail = TRUE;
+    }
+    if (!$menu) {
+      $has_children = FALSE; // Sanitize tree. If we found no children, the item has none.
+    }
+  }
+  // If the current item can expand, and is neither saved as open nor in the active trail, close it.
+  if ($menu && !$in_active_trail) {
+    $extra_class .= ' collapsed start-collapsed ';
+  }
+
+  return theme_menu_item($link, $has_children, $menu, $in_active_trail, $extra_class);
+}
+
+/**
+ * Traverses the menu tree and returns the sub-tree of the item
+ * indicated by the parameter.
+ *
+ * @param $stack
+ *   An array of menu item links that are nested in each other in the tree.
+ *
+ * @return
+ *   The items below the lowest item in the stack.
+ */
+function _custom_breadcrumbs_menu_subtree($stack) {
+  static $index = array();
+  static $indexed = array();
+
+  reset($stack);
+  $start = current($stack);
+
+  // This looks expensive, but menu_tree_all_data uses static caching.
+  $tree = menu_tree_all_data($start['menu_name']);
+
+  if (!isset($indexed[$start['menu_name']])) {
+    $index += _custom_breadcrumbs_menu_index($tree);
+    $indexed[$start['menu_name']] = TRUE;
+  }
+
+  // Traverse the tree.
+  foreach ($stack as $item) {
+    $key = $index[$item['mlid']];
+    if (!isset($tree[$key])) {
+      $tree = $tree[key($tree)]['below'];
+      if (!isset($tree[$key])) return array();
+    }
+    $tree = $tree[$key]['below'];
+  }
+  return $tree;
+}
+
+/**
+ * Indexes the menu tree by mlid. This is needed to identify the items
+ * without relying on titles. This function is recursive.
+ *
+ * @param $tree
+ *   A tree of menu items such as the return value of menu_tree_all_data()
+ *
+ * @return
+ *   An array associating mlid values with the internal keys of the menu tree.
+ */
+function _custom_breadcrumbs_menu_index($tree) {
+  $index = array();
+  foreach ($tree as $key => $item) {
+    $index[$item['link']['mlid']] = $key;
+    if (!empty($item['below'])) {
+      $index += _custom_breadcrumbs_menu_index($item['below']);
+    }
+  }
+  return $index;
+}
+
+/**
+ * Keeps track of ID attributes and adds a suffix to make it unique-when necessary.
+ */
+function _custom_breadcrumbs_menu_unique_id($id) {
+  static $ids = array();
+  if (!isset($ids[$id])) {
+    $ids[$id] = 1;
+    return $id;
+  }
+  else {
+    return $id . '-' . $ids[$id]++;
+  }
+}
+
+/**
+ * Helper function for storing recursion levels.
+ *
+ * @param $link
+ *   If a menu item link is passed, it will be appended to the stack.
+ *   If none is given, the stack will be returned and popped by one.
+ *
+ * @return
+ *   The stack, if no parameter is given.
+ */
+function _custom_breadcrumbs_menu_stack($link = FALSE) {
+  static $stack = array();
+  if ($link) {
+    $stack[$link['localized_options']['attributes']['id']] = $link;
+  }
+  else {
+    $copy = $stack;
+    array_pop($stack);
+    return $copy;
+  }
+}