diff --git a/category_menu/category_menu.module b/category_menu/category_menu.module index 131e22bc970631507c5b2efbd0af96aae33c2d52..076ba88efbc51ba47eb5e3a515a4532ef7d7fec7 100644 --- a/category_menu/category_menu.module +++ b/category_menu/category_menu.module @@ -60,6 +60,15 @@ function category_menu_nodeapi(&$node, $op, $teaser, $page) { return $output; + case 'view': + if (!$teaser && $page) { + if (!empty($node->category_menu_map['mlid']) && $node->build_mode == NODE_BUILD_NORMAL) { + menu_set_active_trail(category_menu_build_active_trail($node->category_menu_map)); + menu_set_active_menu_name($node->category_menu_map['menu_name']); + } + } + break; + case 'prepare': $behavior = variable_get('category_behavior_'. $node->type, 0); if (!empty($behavior)) { @@ -701,7 +710,16 @@ function _category_menu_map_save_category($nid) { $parent = reset($parents); if (empty($parent->cid)) { - return 0; + // Special edge case of a category with one or more hidden containers as + // its ancestors, and with the top hidden container having a custom menu + // parent. In such cases, the category gets the custom menu parent as its + // menu parent. + if (($container = category_get_container($nid)) && $container->hidden_cont && ($container_menu = category_menu_get_container($nid)) && !empty($container_menu->plid_for_container) && ($parent_link = menu_link_load($container_menu->plid_for_container))) { + return $container_menu->plid_for_container; + } + else { + return 0; + } } $parent_category = category_get_category($parent->cid); @@ -738,6 +756,119 @@ function category_menu_menu_name($cnid) { return 'category-menu-toc-'. $cnid; } +/** + * Build an active trail to show in the breadcrumb. + */ +function category_menu_build_active_trail($menu_link) { + static $trail; + + if (!isset($trail)) { + $trail = array(); + $trail[] = array('title' => t('Home'), 'href' => '<front>', 'localized_options' => array()); + + $tree = category_menu_tree_all_data($menu_link['menu_name'], $menu_link); + $curr = array_shift($tree); + + while ($curr) { + if ($curr['link']['href'] == $menu_link['href']) { + $trail[] = $curr['link']; + $curr = FALSE; + } + else { + if ($curr['below'] && $curr['link']['in_active_trail']) { + $trail[] = $curr['link']; + $tree = $curr['below']; + } + $curr = array_shift($tree); + } + } + } + return $trail; +} + +/** + * Creates a tree that is able to recognise distant-parent menu items. + * This is done by finding top-level menu items with a parent defined (which + * technically should never exist in Drupal), and by extending the tree based + * on these items. The tree is also extended down, by searching for distant + * children of bottom-level menu items. + */ +function category_menu_tree_all_data($menu_name, &$item) { + // Start with a regular tree, based on the specified item, containing + // items local to the $menu_name menu. + $tree = menu_tree_all_data($menu_name, $item); + + // Next, find top-level items with defined parents, and extend the tree + // to include such parents and their ancestors. + $parent_link = reset($tree); + $parent_link_key = key($tree); + while ($parent_link['link']['plid']) { + $ancestor_link = menu_link_load($parent_link['link']['plid']); + if ($ancestor_link['menu_name'] != $menu_name) { + $tree = menu_tree_all_data($ancestor_link['menu_name'], $ancestor_link); + _category_menu_tree_above($tree, array( + 'key' => $parent_link_key, + 'value' => $parent_link, + )); + + $parent_link = reset($tree); + $parent_link_key = key($tree); + } + else { + $parent_link['link']['plid'] = 0; + } + }; + + // Finally, find distant children with the specified item as their parent, + // and extend the tree to include such children and their descendants. + $children = db_query("SELECT m.*, ml.* FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path WHERE ml.plid = %d AND ml.menu_name != '%s'", $item['mlid'], $menu_name); + $child_tree_prev = array(); + + while ($child_link = db_fetch_array($children)) { + _menu_link_translate($child_link); + $child_tree = menu_tree_all_data($child_link['menu_name'], $child_link); + if (!empty($child_tree) && $child_tree != $child_tree_prev) { + $item['has_children'] = 1; + _category_menu_tree_below($tree, $child_tree, $item); + $child_tree_prev = $child_tree; + } + } + + return $tree; +} + +/** + * Helper function for category_menu_tree_all_data(). Recursively searches the tree for + * the specified menu item, and appends the child tree below it. + */ +function _category_menu_tree_below(&$tree, $child_tree, $item) { + foreach (array_keys($tree) as $key) { + if ($tree[$key]['link']['mlid'] != $item['mlid']) { + if (!empty($tree[$key]['below'])) { + _category_menu_tree_below($tree[$key]['below'], $child_tree, $item); + } + } + else { + $tree[$key]['below'] = $child_tree; + } + } +} + +/** + * Helper function for category_menu_tree_all_data(). Recursively searches the tree for + * the specified parent item, and appends the rest of the tree below it. + */ +function _category_menu_tree_above(&$tree, $parent_link) { + foreach (array_keys($tree) as $key) { + if (!empty($tree[$key]['below'])) { + _category_menu_tree_above($tree[$key]['below'], $parent_link); + } + else { + $tree[$key]['below'] = array($parent_link['key'] => $parent_link['value']); + } + } +} + /** * Helper function to flatten the $node->category['menu'] array. */