diff --git a/core/includes/menu.inc b/core/includes/menu.inc index dc70185..d223319 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -508,7 +508,13 @@ function menu_execute_active_handler($path = NULL, $deliver = TRUE) { if ($router_item['include_file']) { require_once DRUPAL_ROOT . '/' . $router_item['include_file']; } - $page_callback_result = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']); + if (function_exists($router_item['page_callback'])) { + $page_callback_result = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']); + } + else { + debug($router_item['page_callback'] . ' function does not exist.[1]'); + $page_callback_result = MENU_NOT_FOUND; + } } else { $page_callback_result = MENU_ACCESS_DENIED; @@ -627,7 +633,8 @@ function _menu_check_access(&$item, $map) { $item['access'] = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]); } else { - $item['access'] = call_user_func_array($callback, $arguments); + // if callback function does not exist, do not set $item['access'] to true + $item['access'] = function_exists($callback) ? call_user_func_array($callback, $arguments) : NULL; } } } diff --git a/core/modules/menu/menu.admin.inc b/core/modules/menu/menu.admin.inc index 2e1725d..d5f9898 100644 --- a/core/modules/menu/menu.admin.inc +++ b/core/modules/menu/menu.admin.inc @@ -476,6 +476,32 @@ function menu_edit_menu($form, &$form_state, $type, $menu = array()) { '#title' => t('Description'), '#default_value' => $menu['description'], ); + + // Add the option to add custom menus to a content type on menu + // creating/editing + if (module_exists('node')) { + $node_types = node_type_get_names(); + $default_value = array(); + // Ignore the add form case because there are no default values available. + if ($type == 'edit') { + // When editing a menu we need to collect all the node types that have + // this menu enabled. + foreach ($node_types as $node_type => $name) { + $menu_options = variable_get('menu_options_' . $node_type, array('main-menu')); + if (in_array($menu['menu_name'], $menu_options)) { + $default_value[] = $node_type; + } + } + } + // add checkboxes to the form for each content type + $form['menu_node_types'] = array( + '#type' => 'checkboxes', + '#title' => t('Available for these content types'), + '#default_value' => $default_value, + '#options' => $node_types, + ); + } + $form['actions'] = array('#type' => 'actions'); $form['actions']['submit'] = array( '#type' => 'submit', @@ -580,6 +606,11 @@ function menu_edit_menu_name_exists($value) { function menu_edit_menu_submit($form, &$form_state) { $menu = $form_state['values']; $path = 'admin/structure/menu/manage/'; + // Abort if menu values do not exist + if (!isset($menu['menu_name']) || !isset($menu['title'])) { + drupal_set_message(t('There was a problem. Your configuration was not saved.')); + $form_state['redirect'] = $path; + } if ($form['#insert']) { // Add 'menu-' to the menu name to help avoid name-space conflicts. $menu['menu_name'] = 'menu-' . $menu['menu_name']; @@ -605,6 +636,23 @@ function menu_edit_menu_submit($form, &$form_state) { menu_link_save($link); } } + + // Add or remove this menu from each available node type. + if (isset($menu['menu_node_types'])) { + $node_types = $menu['menu_node_types']; + foreach ($node_types as $node_type => $value) { + $menu_options = variable_get('menu_options_' . $node_type, array('main-menu')); + if (empty($value)) { + // Remove this menu from the content type. + $menu_options = array_diff($menu_options, array($menu['menu_name'])); + } + elseif (!empty($value) && !in_array($menu['menu_name'], $menu_options)) { + // Add this menu to the content type. + $menu_options[] = $menu['menu_name']; + } + variable_set('menu_options_' . $node_type, $menu_options); + } + } drupal_set_message(t('Your configuration has been saved.')); $form_state['redirect'] = $path . $menu['menu_name']; } diff --git a/core/modules/menu/menu.test b/core/modules/menu/menu.test index 14fe96b..c44bd7a 100644 --- a/core/modules/menu/menu.test +++ b/core/modules/menu/menu.test @@ -340,9 +340,9 @@ class MenuTestCase extends WebTestBase { * @param array $parent Parent menu link. * @param object $parent_node Parent menu link content node. */ - function verifyMenuLink($item, $item_node, $parent = NULL, $parent_node = NULL) { + function verifyMenuLink($item, $item_node = NULL, $parent = NULL, $parent_node = NULL) { // View home page. - $this->drupalGet(''); + $this->drupalGet('user'); $this->assertResponse(200); // Verify parent menu link. @@ -352,9 +352,11 @@ class MenuTestCase extends WebTestBase { $this->assertLink($title, 0, 'Parent menu link was displayed'); // Verify menu link link. - $this->clickLink($title); - $title = $parent_node->title; - $this->assertTitle(t("@title | Drupal", array('@title' => $title)), t('Parent menu link link target was correct')); + if (isset($parent_node)) { + $this->clickLink($title); + $title = $parent_node->title; + $this->assertTitle(t("@title | Drupal", array('@title' => $title)), t('Parent menu link link target was correct')); + } } // Verify menu link. @@ -362,9 +364,11 @@ class MenuTestCase extends WebTestBase { $this->assertLink($title, 0, 'Menu link was displayed'); // Verify menu link link. - $this->clickLink($title); - $title = $item_node->title; - $this->assertTitle(t("@title | Drupal", array('@title' => $title)), t('Menu link link target was correct')); + if (isset($item_node)) { + $this->clickLink($title); + $title = $item_node->title; + $this->assertTitle(t("@title | Drupal", array('@title' => $title)), t('Menu link link target was correct')); + } } /** @@ -419,7 +423,7 @@ class MenuTestCase extends WebTestBase { $this->assertRaw(t('The menu link was reset to its default settings.'), t('Menu link was reset')); // Verify menu link. - $this->drupalGet(''); + $this->drupalGet('user'); $this->assertNoText($title, 'Menu link was reset'); $this->assertText($old_title, 'Menu link was reset'); } @@ -453,12 +457,12 @@ class MenuTestCase extends WebTestBase { $this->disableMenuLink($item); // Verify menu link is absent. - $this->drupalGet(''); + $this->drupalGet('user'); $this->assertNoText($item['link_title'], 'Menu link was not displayed'); $this->enableMenuLink($item); // Verify menu link is displayed. - $this->drupalGet(''); + $this->drupalGet('user'); $this->assertText($item['link_title'], 'Menu link was displayed'); } @@ -580,6 +584,127 @@ class MenuTestCase extends WebTestBase { $this->assertText(t('Menus'), t('Add menu node was displayed')); } } + + /** + * Login users, add menus and menu links, and test menu functionality through the admin and user interfaces. + */ + function testMenuWithoutNode() { + // Disable node module to test menus. + module_disable(array('node')); + + // Login the user. + $this->drupalLogin($this->big_user); + $this->items = array(); + + // Do standard menu tests. + $this->doStandardMenuTestsWithoutNode(); + + // Do custom menu tests. + $this->doCustomMenuTestsWithoutNode(); + + // No standard user tests because there are no accessible menu links to $std_user. + + // Delete menu links. + foreach ($this->items as $item) { + $this->deleteMenuLink($item); + } + + // Delete custom menu. + $this->deleteCustomMenu($this->menu); + + // Modify and reset a standard menu link. + $item = $this->getStandardMenuLink(); + $old_title = $item['link_title']; + $this->modifyMenuLink($item); + $item = menu_link_load($item['mlid']); + + // Verify that a change to the description is saved. + $description = $this->randomName(16); + $item['options']['attributes']['title'] = $description; + menu_link_save($item); + $saved_item = menu_link_load($item['mlid']); + $this->assertEqual($description, $saved_item['options']['attributes']['title'], t('Saving an existing link updates the description (title attribute)')); + $this->resetMenuLink($item, $old_title); + } + + /** + * Test standard menu functionality using navigation menu. + * + */ + function doStandardMenuTestsWithoutNode() { + $this->doMenuTestsWithoutNode(); + $this->addInvalidMenuLink(); + } + + /** + * Test custom menu functionality using navigation menu. + * + */ + function doCustomMenuTestsWithoutNode() { + $this->menu = $this->addCustomMenu(); + $this->doMenuTestsWithoutNode($this->menu['menu_name']); + $this->addInvalidMenuLink($this->menu['menu_name']); + $this->addCustomMenuCRUD(); + } + + + /** + * Test menu functionality using navigation menu. + * + */ + function doMenuTestsWithoutNode($menu_name = 'navigation') { + + // Add menu links. + $item1 = $this->addMenuLink(0, 'admin', $menu_name); + $item2 = $this->addMenuLink($item1['mlid'], 'admin/structure', $menu_name); + $item3 = $this->addMenuLink($item2['mlid'], 'admin/structure/block', $menu_name); + $this->assertMenuLink($item1['mlid'], array('depth' => 1, 'has_children' => 1, 'p1' => $item1['mlid'], 'p2' => 0)); + $this->assertMenuLink($item2['mlid'], array('depth' => 2, 'has_children' => 1, 'p1' => $item1['mlid'], 'p2' => $item2['mlid'], 'p3' => 0)); + $this->assertMenuLink($item3['mlid'], array('depth' => 3, 'has_children' => 0, 'p1' => $item1['mlid'], 'p2' => $item2['mlid'], 'p3' => $item3['mlid'], 'p4' => 0)); + + // Verify menu links. + $this->verifyMenuLink($item1); + $this->verifyMenuLink($item2, NULL, $item1, NULL); + $this->verifyMenuLink($item3, NULL, $item2, NULL); + + // Add more menu links. + $item4 = $this->addMenuLink(0, 'admin/config', $menu_name); + $item5 = $this->addMenuLink($item4['mlid'], 'admin/config/system', $menu_name); + $this->assertMenuLink($item4['mlid'], array('depth' => 1, 'has_children' => 1, 'p1' => $item4['mlid'], 'p2' => 0)); + $this->assertMenuLink($item5['mlid'], array('depth' => 2, 'has_children' => 0, 'p1' => $item4['mlid'], 'p2' => $item5['mlid'], 'p3' => 0)); + + // Modify menu links. + $this->modifyMenuLink($item1); + $this->modifyMenuLink($item2); + + // Toggle menu links. + $this->toggleMenuLink($item1); + $this->toggleMenuLink($item2); + + // Move link and verify that descendants are updated. + $this->moveMenuLink($item2, $item5['mlid'], $menu_name); + $this->assertMenuLink($item1['mlid'], array('depth' => 1, 'has_children' => 0, 'p1' => $item1['mlid'], 'p2' => 0)); + $this->assertMenuLink($item4['mlid'], array('depth' => 1, 'has_children' => 1, 'p1' => $item4['mlid'], 'p2' => 0)); + $this->assertMenuLink($item5['mlid'], array('depth' => 2, 'has_children' => 1, 'p1' => $item4['mlid'], 'p2' => $item5['mlid'], 'p3' => 0)); + $this->assertMenuLink($item2['mlid'], array('depth' => 3, 'has_children' => 1, 'p1' => $item4['mlid'], 'p2' => $item5['mlid'], 'p3' => $item2['mlid'], 'p4' => 0)); + $this->assertMenuLink($item3['mlid'], array('depth' => 4, 'has_children' => 0, 'p1' => $item4['mlid'], 'p2' => $item5['mlid'], 'p3' => $item2['mlid'], 'p4' => $item3['mlid'], 'p5' => 0)); + + // Enable a link via the overview form. + $this->disableMenuLink($item1); + $edit = array(); + + // Note in the UI the 'mlid:x[hidden]' form element maps to enabled, or + // NOT hidden. + $edit['mlid:' . $item1['mlid'] . '[hidden]'] = TRUE; + $this->drupalPost('admin/structure/menu/manage/' . $item1['menu_name'], $edit, t('Save configuration')); + + // Verify in the database. + $this->assertMenuLink($item1['mlid'], array('hidden' => 0)); + + // Save menu links for later tests. + $this->items[] = $item1; + $this->items[] = $item2; + } } /**