| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: menu_block.module,v 1.69.2.1 2010/03/24 12:13:01 johnalbin Exp $ 3 4 /** 5 * @file 6 * Provides configurable blocks of menu items. 7 */ 8 9 /** 10 * Denotes that the tree should use the menu picked by the curent page. 11 */ 12 define('MENU_TREE__CURRENT_PAGE_MENU', '_active'); 13 14 /** 15 * Implements hook_menu(). 16 */ 17 function menu_block_menu() { 18 $items['admin/build/block/add-menu-block'] = array( 19 'title' => 'Add menu block', 20 'description' => 'Add a new menu block.', 21 'access arguments' => array('administer blocks'), 22 'page callback' => 'drupal_get_form', 23 'page arguments' => array('menu_block_add_block_form'), 24 'type' => MENU_LOCAL_TASK, 25 'file' => 'menu_block.admin.inc', 26 ); 27 $items['admin/build/block/delete-menu-block'] = array( 28 'title' => 'Delete menu block', 29 'access arguments' => array('administer blocks'), 30 'page callback' => 'drupal_get_form', 31 'page arguments' => array('menu_block_delete'), 32 'type' => MENU_CALLBACK, 33 'file' => 'menu_block.admin.inc', 34 ); 35 $items['admin/settings/menu_block'] = array( 36 'title' => 'Menu block', 37 'description' => 'Configure menu block.', 38 'access arguments' => array('administer blocks'), 39 'page callback' => 'drupal_get_form', 40 'page arguments' => array('menu_block_admin_settings_form'), 41 'type' => MENU_NORMAL_ITEM, 42 'file' => 'menu_block.admin.inc', 43 ); 44 return $items; 45 } 46 47 /** 48 * Implements hook_help(). 49 */ 50 function menu_block_help($path, $arg) { 51 switch ($path) { 52 case 'admin/build/block/configure': 53 if ($arg[4] != 'menu_block') { 54 break; 55 } 56 case 'admin/help#menu_block': 57 case 'admin/build/block': 58 case 'admin/build/block/add-menu-block': 59 module_load_include('inc', 'menu_block', 'menu_block.pages'); 60 return _menu_block_help($path, $arg); 61 } 62 } 63 64 /** 65 * Implements hook_theme(). 66 */ 67 function menu_block_theme(&$existing, $type, $theme, $path) { 68 // Add theme hook suggestion patterns for the core theme functions used in 69 // this module. We can't add them during hook_theme_registry_alter() because 70 // we will already have missed the opportunity for the theme engine's 71 // theme_hook() to process the pattern. And we can't run the pattern ourselves 72 // because we aren't given the type, theme and path in that hook. 73 $existing['menu_tree']['pattern'] = 'menu_tree__'; 74 $existing['menu_item']['pattern'] = 'menu_item__'; 75 $existing['menu_item_link']['pattern'] = 'menu_item_link__'; 76 77 return array( 78 'menu_block_wrapper' => array( 79 'template' => 'menu-block-wrapper', 80 'arguments' => array('content' => NULL, 'settings' => NULL, 'delta' => NULL), 81 'pattern' => 'menu_block_wrapper__', 82 ), 83 'menu_block_menu_order' => array( 84 'arguments' => array('element' => NULL), 85 'file' => 'menu_block.admin.inc', 86 ), 87 ); 88 } 89 90 /** 91 * Implements hook_ctools_plugin_directory(). 92 */ 93 function menu_block_ctools_plugin_directory($module, $plugin) { 94 if ($plugin == 'content_types') { 95 return 'plugins/' . $plugin; 96 } 97 } 98 99 /** 100 * Process variables for menu-block-wrapper.tpl.php. 101 * 102 * @see menu-block-wrapper.tpl.php 103 */ 104 function template_preprocess_menu_block_wrapper(&$variables) { 105 $variables['classes_array'][] = 'menu-block-' . $variables['delta']; 106 $variables['classes_array'][] = 'menu-name-' . $variables['settings']['menu_name']; 107 $variables['classes_array'][] = 'parent-mlid-' . $variables['settings']['parent_mlid']; 108 $variables['classes_array'][] = 'menu-level-' . $variables['settings']['level']; 109 $variables['classes'] = check_plain(implode(' ', $variables['classes_array'])); 110 $variables['template_files'][] = 'menu-block-wrapper-' . $variables['settings']['menu_name']; 111 } 112 113 /** 114 * Alters the block admin form to add delete links next to menu blocks. 115 */ 116 function menu_block_form_block_admin_display_form_alter(&$form, $form_state) { 117 module_load_include('inc', 'menu_block', 'menu_block.admin'); 118 _menu_block_form_block_admin_display_form_alter($form, $form_state); 119 } 120 121 /** 122 * Returns a list of menu names implemented by all modules. 123 * 124 * @return 125 * array A list of menu names and titles. 126 */ 127 function menu_block_get_all_menus() { 128 static $all_menus; 129 130 if (!$all_menus) { 131 // Include book support. 132 if (module_exists('book')) { 133 module_load_include('inc', 'menu_block', 'menu_block.book'); 134 } 135 // We're generalizing menu's menu_get_menus() by making it into a hook. 136 // Retrieve all the menu names provided by hook_get_menus(). 137 $all_menus = module_invoke_all('get_menus'); 138 // Add an option to use the menu for the active menu item. 139 $all_menus[MENU_TREE__CURRENT_PAGE_MENU] = '<' . t('the menu selected by the page') . '>'; 140 asort($all_menus); 141 } 142 return $all_menus; 143 } 144 145 /** 146 * Implements hook_block(). 147 */ 148 function menu_block_block($op = 'list', $delta = NULL, $edit = NULL) { 149 $function = '_menu_block_block_' . $op; 150 if (function_exists($function)) { 151 return $function($delta, $edit); 152 } 153 else { 154 // "op"s besides "view" are seldom used, so we store them in a separate file. 155 module_load_include('inc', 'menu_block', 'menu_block.admin'); 156 if (function_exists($function)) { 157 return $function($delta, $edit); 158 } 159 } 160 } 161 162 /** 163 * Returns the configuration for the requested block delta. 164 * 165 * @param $delta 166 * string The delta that uniquely identifies the block in the block system. If 167 * not specified, the default configuration will be returned. 168 * @return 169 * array An associated array of configuration options. 170 */ 171 function menu_block_get_config($delta = NULL) { 172 $config = array( 173 'delta' => $delta, 174 'menu_name' => 'primary-links', 175 'parent_mlid' => 0, 176 'title_link' => 0, 177 'admin_title' => '', 178 'level' => 1, 179 'follow' => 0, 180 'depth' => 0, 181 'expanded' => 0, 182 'sort' => 0, 183 ); 184 185 // Get the block configuration options. 186 if ($delta) { 187 $config['title_link'] = variable_get("menu_block_{$delta}_title_link", $config['title_link']); 188 $config['admin_title'] = variable_get("menu_block_{$delta}_admin_title", $config['admin_title']); 189 $config['level'] = variable_get("menu_block_{$delta}_level", $config['level']); 190 $config['follow'] = variable_get("menu_block_{$delta}_follow", $config['follow']); 191 $config['depth'] = variable_get("menu_block_{$delta}_depth", $config['depth']); 192 $config['expanded'] = variable_get("menu_block_{$delta}_expanded", $config['expanded']); 193 $config['sort'] = variable_get("menu_block_{$delta}_sort", $config['sort']); 194 list($config['menu_name'], $config['parent_mlid']) = explode(':', variable_get("menu_block_{$delta}_parent", $config['menu_name'] . ':' . $config['parent_mlid'])); 195 } 196 197 return $config; 198 } 199 200 /** 201 * Returns the 'view' $op info for hook_block(). 202 * 203 * @param $delta 204 * string The name of the block to render. 205 */ 206 function _menu_block_block_view($delta) { 207 return menu_tree_build(menu_block_get_config($delta)); 208 } 209 210 /** 211 * Build a menu tree based on the provided configuration. 212 * 213 * @param $config 214 * array An array of configuration options that specifies how to build the 215 * menu tree and its title. 216 * - delta: (string) The menu_block's block delta. 217 * - menu_name: (string) The machine name of the requested menu. Can also be 218 * set to MENU_TREE__CURRENT_PAGE_MENU to use the menu selected by the page. 219 * - parent_mlid: (int) The mlid of the item that should root the tree. Use 0 220 * to use the menu's root. 221 * - title_link: (boolean) Specifies if the title should be rendered as a link 222 * or a simple string. 223 * - admin_title: (string) An optional title to uniquely identify the block on 224 * the administer blocks page. 225 * - level: (int) The starting level of the tree. 226 * - follow: (string) Specifies if the starting level should follow the 227 * active menu item. Should be set to 0, 'active' or 'child'. 228 * - depth: (int) The maximum depth the tree should contain, relative to the 229 * starting level. 230 * - expanded: (boolean) Specifies if the entire tree be expanded or not. 231 * - sort: (boolean) Specifies if the tree should be sorted with the active 232 * trail at the top of the tree. 233 * @return 234 * array An array containing the rendered tree in the 'content' key and the 235 * rendered title in the 'subject' key. 236 */ 237 function menu_tree_build($config) { 238 // Retrieve the active menu item from the database. 239 if ($config['menu_name'] == MENU_TREE__CURRENT_PAGE_MENU) { 240 // Retrieve the list of available menus. 241 $menu_order = variable_get('menu_block_menu_order', array('primary-links' => '', 'secondary-links' => '')); 242 243 // Retrieve all the menus containing a link to the current page. 244 $result = db_query("SELECT menu_name FROM {menu_links} WHERE link_path = '%s'", $_GET['q'] ? $_GET['q'] : '<front>'); 245 while ($item = db_fetch_array($result)) { 246 // Check if the menu is in the list of available menus. 247 if (isset($menu_order[$item['menu_name']])) { 248 // Mark the menu. 249 $menu_order[$item['menu_name']] = MENU_TREE__CURRENT_PAGE_MENU; 250 } 251 } 252 // Find the first marked menu. 253 $config['menu_name'] = array_search(MENU_TREE__CURRENT_PAGE_MENU, $menu_order); 254 $config['parent_mlid'] = 0; 255 256 // If no menu link was found, don't display the block. 257 if (empty($config['menu_name'])) { 258 return array(); 259 } 260 } 261 262 // Get the default block name. 263 $menu_names = menu_block_get_all_menus(); 264 menu_block_set_title(t($menu_names[$config['menu_name']])); 265 266 if ($config['expanded'] || $config['parent_mlid']) { 267 // Get the full, un-pruned tree. 268 $tree = menu_tree_all_data($config['menu_name']); 269 // And add the active trail data back to the full tree. 270 menu_tree_add_active_path($tree); 271 } 272 else { 273 // Get the tree pruned for just the active trail. 274 $tree = menu_tree_page_data($config['menu_name']); 275 } 276 277 // Allow other modules to alter the tree before we begin operations on it. 278 $alter_data = &$tree; 279 // Also allow modules to alter the config. 280 $alter_data['__drupal_alter_by_ref'] = array(&$config); 281 drupal_alter('menu_block_tree', $alter_data); 282 283 // Localize the tree. 284 if (module_exists('i18nmenu')) { 285 i18nmenu_localize_tree($tree); 286 } 287 288 // Prune the tree along the active trail to the specified level. 289 if ($config['level'] > 1 || $config['parent_mlid']) { 290 if ($config['parent_mlid']) { 291 $parent_item = menu_link_load($config['parent_mlid']); 292 menu_tree_prune_tree($tree, $config['level'], $parent_item); 293 } 294 else { 295 menu_tree_prune_tree($tree, $config['level']); 296 } 297 } 298 299 // Prune the tree to the active menu item. 300 if ($config['follow']) { 301 menu_tree_prune_active_tree($tree, $config['follow']); 302 } 303 304 // If the menu-item-based tree is not "expanded", trim the tree to the active path. 305 if ($config['parent_mlid'] && !$config['expanded']) { 306 menu_tree_trim_active_path($tree); 307 } 308 309 // Trim the branches that extend beyond the specified depth. 310 if ($config['depth'] > 0) { 311 menu_tree_depth_trim($tree, $config['depth']); 312 } 313 314 // Sort the active path to the top of the tree. 315 if ($config['sort']) { 316 menu_tree_sort_active_path($tree); 317 } 318 319 // Render the tree. 320 $data = array(); 321 $data['subject'] = menu_block_get_title($config['title_link'], $config); 322 $data['content'] = menu_block_tree_output($tree, $config); 323 if ($data['content']) { 324 $hooks = array(); 325 $hooks[] = 'menu_block_wrapper__' . $config['delta']; 326 $hooks[] = 'menu_block_wrapper__' . str_replace('-', '_', $config['menu_name']); 327 $hooks[] = 'menu_block_wrapper'; 328 $data['content'] = theme($hooks, $data['content'], $config, $config['delta']); 329 } 330 331 return $data; 332 } 333 334 /** 335 * Retrieves the menu item to use for the tree's title. 336 * 337 * @param $render_title_as_link 338 * boolean A boolean that says whether to render the title as a link or a 339 * simple string. 340 * @return 341 * string The tree's title rendered as a string. 342 */ 343 function menu_block_get_title($render_title_as_link = TRUE, $config = array()) { 344 $menu_item = menu_block_set_title(); 345 346 // The tree's title is a menu title, a normal string. 347 if (is_string($menu_item)) { 348 $title = check_plain($menu_item); 349 } 350 // The tree's title is a menu item with a link. 351 elseif ($render_title_as_link) { 352 if (!empty($menu_item['in_active_trail'])) { 353 if (!empty($menu_item['localized_options']['attributes']['class'])) { 354 $menu_item['localized_options']['attributes']['class'] .= ' active-trail'; 355 } 356 else { 357 $menu_item['localized_options']['attributes']['class'] = 'active-trail'; 358 } 359 } 360 $hooks = array(); 361 if (!empty($config['delta'])) { 362 $hooks[] = 'menu_item_link__menu_block__' . $config['delta']; 363 } 364 $hooks[] = 'menu_item_link__menu_block__' . str_replace('-', '_', $menu_item['menu_name']); 365 $hooks[] = 'menu_item_link__menu_block'; 366 $hooks[] = 'menu_item_link'; 367 $title = theme($hooks, $menu_item); 368 } 369 // The tree's title is a menu item. 370 else { 371 $title = check_plain($menu_item['title']); 372 } 373 return $title; 374 } 375 376 /** 377 * Sets the menu item to use for the tree's title. 378 * 379 * @param $item 380 * array The menu item (an array) or the menu item's title as a string. 381 */ 382 function menu_block_set_title($item = NULL) { 383 static $menu_item; 384 385 // Save the menu item. 386 if (!is_null($item)) { 387 $menu_item = $item; 388 } 389 390 return $menu_item; 391 } 392 393 /** 394 * Add the active trail indicators into the tree. 395 * 396 * The data returned by menu_tree_page_data() has link['in_active_trail'] set to 397 * TRUE for each menu item in the active trail. The data returned from 398 * menu_tree_all_data() does not contain the active trail indicators. This is a 399 * helper function that adds it back in. 400 * 401 * @param $tree 402 * array The menu tree. 403 * @return 404 * void 405 */ 406 function menu_tree_add_active_path(&$tree) { 407 // Grab any menu item to find the menu_name for this tree. 408 $menu_item = current($tree); 409 $tree_with_trail = menu_tree_page_data($menu_item['link']['menu_name']); 410 411 // To traverse the original tree down the active trail, we use a pointer. 412 $subtree_pointer =& $tree; 413 414 // Find each key in the active trail. 415 while ($tree_with_trail) { 416 foreach (array_keys($tree_with_trail) AS $key) { 417 if ($tree_with_trail[$key]['link']['in_active_trail']) { 418 // Set the active trail info in the original tree. 419 $subtree_pointer[$key]['link']['in_active_trail'] = TRUE; 420 // Continue in the subtree, if it exists. 421 $tree_with_trail =& $tree_with_trail[$key]['below']; 422 $subtree_pointer =& $subtree_pointer[$key]['below']; 423 break; 424 } 425 else { 426 unset($tree_with_trail[$key]); 427 } 428 } 429 } 430 } 431 432 /** 433 * Trim everything but the active trail in the tree. 434 * 435 * @param $tree 436 * array The menu tree to trim. 437 * @return 438 * void 439 */ 440 function menu_tree_trim_active_path(&$tree) { 441 foreach (array_keys($tree) AS $key) { 442 if (($tree[$key]['link']['in_active_trail'] || $tree[$key]['link']['expanded']) && $tree[$key]['below']) { 443 // Continue in the subtree, if it exists. 444 menu_tree_trim_active_path($tree[$key]['below']); 445 } 446 else { 447 // Trim anything not expanded or along the active trail. 448 $tree[$key]['below'] = FALSE; 449 } 450 } 451 } 452 453 /** 454 * Sort the active trail to the top of the tree. 455 * 456 * @param $tree 457 * array The menu tree to sort. 458 * @return 459 * void 460 */ 461 function menu_tree_sort_active_path(&$tree) { 462 module_load_include('inc', 'menu_block', 'menu_block.sort'); 463 _menu_tree_sort_active_path($tree); 464 } 465 466 /** 467 * Prune a tree so that it begins at the specified level. 468 * 469 * This function will follow the active menu trail to the specified level. 470 * 471 * @param $tree 472 * array The menu tree to prune. 473 * @param $level 474 * int The level of the original tree that will start the pruned tree. 475 * @param $parent_item 476 * array The menu item that should be used as the root of the tree. 477 * @return 478 * void 479 */ 480 function menu_tree_prune_tree(&$tree, $level, $parent_item = FALSE) { 481 if (!empty($parent_item)) { 482 // Prune the tree along the path to the menu item. 483 for ($i = 1; $i <= MENU_MAX_DEPTH && $parent_item["p$i"] != '0'; $i++) { 484 $plid = $parent_item["p$i"]; 485 $found_active_trail = FALSE; 486 // Examine each element at this level for the ancestor. 487 foreach (array_keys($tree) AS $key) { 488 if ($tree[$key]['link']['mlid'] == $plid) { 489 menu_block_set_title($tree[$key]['link']); 490 // Prune the tree to the children of this ancestor. 491 $tree = $tree[$key]['below'] ? $tree[$key]['below'] : array(); 492 $found_active_trail = TRUE; 493 break; 494 } 495 } 496 // If we don't find the ancestor, bail out. 497 if (!$found_active_trail) { 498 $tree = array(); 499 break; 500 } 501 } 502 } 503 504 // Trim the upper levels down to the one desired. 505 for ($i = 1; $i < $level; $i++) { 506 $found_active_trail = FALSE; 507 // Examine each element at this level for the active trail. 508 foreach (array_keys($tree) AS $key) { 509 if ($tree[$key]['link']['in_active_trail']) { 510 // Get the title for the pruned tree. 511 menu_block_set_title($tree[$key]['link']); 512 // Prune the tree to the children of the item in the active trail. 513 $tree = $tree[$key]['below'] ? $tree[$key]['below'] : array(); 514 $found_active_trail = TRUE; 515 break; 516 } 517 } 518 // If we don't find the active trail, the active item isn't in the tree we want. 519 if (!$found_active_trail) { 520 $tree = array(); 521 break; 522 } 523 } 524 } 525 526 /** 527 * Prune a tree so that it begins at the active menu item. 528 * 529 * @param $tree 530 * array The menu tree to prune. 531 * @param $level 532 * string The level which the tree will be pruned to: 'active' or 'child'. 533 * @return 534 * void 535 */ 536 function menu_tree_prune_active_tree(&$tree, $level) { 537 module_load_include('inc', 'menu_block', 'menu_block.follow'); 538 _menu_tree_prune_active_tree($tree, $level); 539 } 540 541 /** 542 * Prune a tree so it does not extend beyond the specified depth limit. 543 * 544 * @param $tree 545 * array The menu tree to prune. 546 * @param $depth_limit 547 * int The maximum depth of the returned tree; must be a positive integer. 548 * @return 549 * void 550 */ 551 function menu_tree_depth_trim(&$tree, $depth_limit) { 552 // Prevent invalid input from returning a trimmed tree. 553 if ($depth_limit < 1) { return; } 554 555 // Examine each element at this level to find any possible children. 556 foreach (array_keys($tree) AS $key) { 557 if ($tree[$key]['below']) { 558 if ($depth_limit > 1) { 559 menu_tree_depth_trim($tree[$key]['below'], $depth_limit-1); 560 } 561 else { 562 // Remove the children items. 563 $tree[$key]['below'] = FALSE; 564 } 565 } 566 if ($depth_limit == 1 && $tree[$key]['link']['has_children']) { 567 // Turn off the menu styling that shows there were children. 568 $tree[$key]['link']['has_children'] = FALSE; 569 $tree[$key]['link']['leaf_has_children'] = TRUE; 570 } 571 } 572 } 573 574 /** 575 * Returns a rendered menu tree. 576 * 577 * This is an optimized version of menu_tree_output() with additional classes 578 * added to the output. 579 * 580 * @param $tree 581 * array A data structure representing the tree as returned from menu_tree_data. 582 * @return 583 * string The rendered HTML of that data structure. 584 */ 585 function menu_block_tree_output(&$tree, $config = array()) { 586 $output = ''; 587 $items = array(); 588 589 // Create context if no config was provided. 590 if (empty($config)) { 591 $config['delta'] = 0; 592 // Grab any menu item to find the menu_name for this tree. 593 $menu_item = current($tree); 594 $config['menu_name'] = $menu_item['link']['menu_name']; 595 } 596 $hook_delta = $config['delta']; 597 $hook_menu_name = str_replace('-', '_', $config['menu_name']); 598 599 // Pull out just the menu items we are going to render so that we 600 // get an accurate count for the first/last classes. 601 foreach (array_keys($tree) as $key) { 602 if (!$tree[$key]['link']['hidden']) { 603 $items[$key] = array( 604 'link' => $tree[$key]['link'], 605 // To prevent copying the entire child array, we render it first. 606 'below' => !empty($tree[$key]['below']) ? menu_block_tree_output($tree[$key]['below'], $config) : '', 607 ); 608 } 609 } 610 611 $num_items = count($items); 612 $i = 1; 613 foreach (array_keys($items) as $key) { 614 // Render the link. 615 $link_class = array(); 616 if (!empty($items[$key]['link']['localized_options']['attributes']['class'])) { 617 $link_class[] = $items[$key]['link']['localized_options']['attributes']['class']; 618 } 619 if ($items[$key]['link']['in_active_trail']) { 620 $link_class[] = 'active-trail'; 621 } 622 if (!empty($link_class)) { 623 $items[$key]['link']['localized_options']['attributes']['class'] = implode(' ', $link_class); 624 } 625 $hooks = array(); 626 $hooks[] = 'menu_item_link__menu_block__' . $hook_delta; 627 $hooks[] = 'menu_item_link__menu_block__' . $hook_menu_name; 628 $hooks[] = 'menu_item_link__menu_block'; 629 $hooks[] = 'menu_item_link'; 630 $link = theme($hooks, $items[$key]['link']); 631 // Render the menu item. 632 $extra_class = array(); 633 if ($i == 1) { 634 $extra_class[] = 'first'; 635 } 636 if ($i == $num_items) { 637 $extra_class[] = 'last'; 638 } 639 $extra_class[] = 'menu-mlid-' . $items[$key]['link']['mlid']; 640 if (!empty($items[$key]['link']['leaf_has_children'])) { 641 $extra_class[] = 'has-children'; 642 } 643 if ($items[$key]['link']['href'] == $_GET['q'] || ($items[$key]['link']['href'] == '<front>' && drupal_is_front_page())) { 644 $extra_class[] = 'active'; 645 } 646 $extra_class = !empty($extra_class) ? implode(' ', $extra_class) : NULL; 647 $hooks = array(); 648 $hooks[] = 'menu_item__menu_block__' . $hook_delta; 649 $hooks[] = 'menu_item__menu_block__' . $hook_menu_name; 650 $hooks[] = 'menu_item__menu_block'; 651 $hooks[] = 'menu_item'; 652 $output .= theme($hooks, $link, $items[$key]['link']['has_children'], $items[$key]['below'], $items[$key]['link']['in_active_trail'], $extra_class); 653 $i++; 654 } 655 $hooks = array(); 656 $hooks[] = 'menu_tree__menu_block__' . $hook_delta; 657 $hooks[] = 'menu_tree__menu_block__' . $hook_menu_name; 658 $hooks[] = 'menu_tree__menu_block'; 659 $hooks[] = 'menu_tree'; 660 return $output ? theme($hooks, $output) : ''; 661 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |