summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDries Buytaert <dries@buytaert.net>2010-09-24 00:37:45 +0000
committerDries Buytaert <dries@buytaert.net>2010-09-24 00:37:45 +0000
commitc9de4646c570a45de03d6e7ec470daf01a8d2cab (patch)
tree5d8781ec52d1cf25c5ca1a842d2a7a65bf0f7e95
parent4bd74a00668557ce827e4c51d7c278548518aaf8 (diff)
downloadbrdo-c9de4646c570a45de03d6e7ec470daf01a8d2cab.tar.gz
brdo-c9de4646c570a45de03d6e7ec470daf01a8d2cab.tar.bz2
- Patch #907690 by sun, pwolanin: breadcrumbs don't work for dynamic paths and local tasks #2.
-rw-r--r--includes/common.inc12
-rw-r--r--includes/menu.inc464
-rw-r--r--includes/theme.inc24
-rw-r--r--modules/aggregator/aggregator.module5
-rw-r--r--modules/book/book.module1
-rw-r--r--modules/comment/comment.module3
-rw-r--r--modules/contact/contact.module2
-rw-r--r--modules/dashboard/dashboard.module1
-rw-r--r--modules/dblog/dblog.module1
-rw-r--r--modules/field/modules/options/options.test52
-rw-r--r--modules/field/modules/text/text.test6
-rw-r--r--modules/field/tests/field.test22
-rw-r--r--modules/field/tests/field_test.entity.inc2
-rw-r--r--modules/field/tests/field_test.module4
-rw-r--r--modules/field_ui/field_ui.module1
-rw-r--r--modules/filter/filter.module2
-rw-r--r--modules/forum/forum.module2
-rw-r--r--modules/forum/forum.test22
-rw-r--r--modules/help/help.module1
-rw-r--r--modules/image/image.module6
-rw-r--r--modules/locale/locale.module6
-rw-r--r--modules/menu/menu.module7
-rw-r--r--modules/menu/menu.test4
-rw-r--r--modules/node/node.module6
-rw-r--r--modules/openid/openid.module1
-rw-r--r--modules/path/path.module2
-rw-r--r--modules/profile/profile.module3
-rw-r--r--modules/search/search.module1
-rw-r--r--modules/search/search.test26
-rw-r--r--modules/shortcut/shortcut.module4
-rw-r--r--modules/simpletest/drupal_web_test_case.php36
-rw-r--r--modules/simpletest/simpletest.module1
-rw-r--r--modules/simpletest/tests/menu.test552
-rw-r--r--modules/simpletest/tests/menu_test.module39
-rw-r--r--modules/statistics/statistics.module1
-rw-r--r--modules/statistics/statistics.test10
-rw-r--r--modules/system/system.api.php47
-rw-r--r--modules/system/system.module9
-rw-r--r--modules/system/system.test5
-rw-r--r--modules/taxonomy/taxonomy.module1
-rw-r--r--modules/taxonomy/taxonomy.pages.inc2
-rw-r--r--modules/taxonomy/taxonomy.test4
-rw-r--r--modules/trigger/trigger.module1
-rw-r--r--modules/user/user.module11
44 files changed, 1133 insertions, 279 deletions
diff --git a/includes/common.inc b/includes/common.inc
index e74d1c0a7..391878546 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -230,7 +230,7 @@ function drupal_get_profile() {
function drupal_set_breadcrumb($breadcrumb = NULL) {
$stored_breadcrumb = &drupal_static(__FUNCTION__);
- if (!is_null($breadcrumb)) {
+ if (isset($breadcrumb)) {
$stored_breadcrumb = $breadcrumb;
}
return $stored_breadcrumb;
@@ -242,7 +242,7 @@ function drupal_set_breadcrumb($breadcrumb = NULL) {
function drupal_get_breadcrumb() {
$breadcrumb = drupal_set_breadcrumb();
- if (is_null($breadcrumb)) {
+ if (!isset($breadcrumb)) {
$breadcrumb = menu_get_active_breadcrumb();
}
@@ -2267,9 +2267,9 @@ function l($text, $path, array $options = array()) {
// Merge in defaults.
$options += array(
- 'attributes' => array(),
- 'html' => FALSE,
- );
+ 'attributes' => array(),
+ 'html' => FALSE,
+ );
// Append active class.
if (($path == $_GET['q'] || ($path == '<front>' && drupal_is_front_page())) &&
@@ -6204,7 +6204,7 @@ function drupal_write_record($table, &$record, $primary_keys = array()) {
}
if (!property_exists($object, $field)) {
- // Skip fields that are not provided, default values are already known
+ // Skip fields that are not provided, default values are already known
// by the database.
continue;
}
diff --git a/includes/menu.inc b/includes/menu.inc
index 0119fb5b8..cc3c69e92 100644
--- a/includes/menu.inc
+++ b/includes/menu.inc
@@ -141,9 +141,9 @@ define('MENU_NORMAL_ITEM', MENU_VISIBLE_IN_TREE | MENU_VISIBLE_IN_BREADCRUMB);
* Menu type -- A hidden, internal callback, typically used for API calls.
*
* Callbacks simply register a path so that the correct function is fired
- * when the URL is accessed. They are not shown in the menu.
+ * when the URL is accessed. They do not appear in menus or breadcrumbs.
*/
-define('MENU_CALLBACK', MENU_VISIBLE_IN_BREADCRUMB);
+define('MENU_CALLBACK', 0x0000);
/**
* Menu type -- A normal menu item, hidden until enabled by an administrator.
@@ -728,12 +728,26 @@ function _menu_translate(&$router_item, $map, $to_arg = FALSE) {
// Generate the link path for the page request or local tasks.
$link_map = explode('/', $router_item['path']);
+ if (isset($router_item['tab_root'])) {
+ $tab_root_map = explode('/', $router_item['tab_root']);
+ }
+ if (isset($router_item['tab_parent'])) {
+ $tab_parent_map = explode('/', $router_item['tab_parent']);
+ }
for ($i = 0; $i < $router_item['number_parts']; $i++) {
if ($link_map[$i] == '%') {
$link_map[$i] = $path_map[$i];
}
+ if (isset($tab_root_map[$i]) && $tab_root_map[$i] == '%') {
+ $tab_root_map[$i] = $path_map[$i];
+ }
+ if (isset($tab_parent_map[$i]) && $tab_parent_map[$i] == '%') {
+ $tab_parent_map[$i] = $path_map[$i];
+ }
}
$router_item['href'] = implode('/', $link_map);
+ $router_item['tab_root_href'] = implode('/', $tab_root_map);
+ $router_item['tab_parent_href'] = implode('/', $tab_parent_map);
$router_item['options'] = array();
_menu_check_access($router_item, $map);
@@ -778,7 +792,11 @@ function menu_tail_to_arg($arg, $map, $index) {
* preparation such as always calling to_arg functions
*
* @param $item
- * A menu link
+ * A menu link.
+ * @param $translate
+ * (optional) Whether to try to translate a link containing dynamic path
+ * argument placeholders (%) based on the menu router item of the current
+ * path. Defaults to FALSE. Internally used for breadcrumbs.
*
* @return
* Returns the map of path arguments with objects loaded as defined in the
@@ -789,8 +807,10 @@ function menu_tail_to_arg($arg, $map, $index) {
* $item['options'] is unserialized; it is also changed within the call here
* to $item['localized_options'] by _menu_item_localize().
*/
-function _menu_link_translate(&$item) {
- $item['options'] = unserialize($item['options']);
+function _menu_link_translate(&$item, $translate = FALSE) {
+ if (!is_array($item['options'])) {
+ $item['options'] = unserialize($item['options']);
+ }
if ($item['external']) {
$item['access'] = 1;
$map = array();
@@ -799,13 +819,40 @@ function _menu_link_translate(&$item) {
$item['localized_options'] = $item['options'];
}
else {
+ // Complete the path of the menu link with elements from the current path,
+ // if it contains dynamic placeholders (%).
$map = explode('/', $item['link_path']);
- if (!empty($item['to_arg_functions'])) {
- _menu_link_map_translate($map, $item['to_arg_functions']);
+ if (strpos($item['link_path'], '%') !== FALSE) {
+ // Invoke registered to_arg callbacks.
+ if (!empty($item['to_arg_functions'])) {
+ _menu_link_map_translate($map, $item['to_arg_functions']);
+ }
+ // Or try to derive the path argument map from the current router item,
+ // if this $item's path is within the router item's path. This means
+ // that if we are on the current path 'foo/%/bar/%/baz', then
+ // menu_get_item() will have translated the menu router item for the
+ // current path, and we can take over the argument map for a link like
+ // 'foo/%/bar'. This inheritance is only valid for breadcrumb links.
+ // @see _menu_tree_check_access()
+ // @see menu_get_active_breadcrumb()
+ elseif ($translate && ($current_router_item = menu_get_item())) {
+ // If $translate is TRUE, then this link is in the active trail.
+ // Only translate paths within the current path.
+ if (strpos($current_router_item['path'], $item['link_path']) === 0) {
+ $count = count($map);
+ $map = array_slice($current_router_item['original_map'], 0, $count);
+ $item['original_map'] = $map;
+ if (isset($current_router_item['map'])) {
+ $item['map'] = array_slice($current_router_item['map'], 0, $count);
+ }
+ // Reset access to check it (for the first time).
+ unset($item['access']);
+ }
+ }
}
$item['href'] = implode('/', $map);
- // Note - skip callbacks without real values for their arguments.
+ // Skip links containing untranslated arguments.
if (strpos($item['href'], '%') !== FALSE) {
$item['access'] = FALSE;
return FALSE;
@@ -913,11 +960,12 @@ function menu_tree_output($tree) {
// Pull out just the menu links we are going to render so that we
// get an accurate count for the first/last classes.
foreach ($tree as $data) {
- if (!$data['link']['hidden']) {
+ if ($data['link']['access'] && !$data['link']['hidden']) {
$items[] = $data;
}
}
+ $router_item = menu_get_item();
$num_items = count($items);
foreach ($items as $i => $data) {
$class = array();
@@ -942,7 +990,14 @@ function menu_tree_output($tree) {
// Set a class if the link is in the active trail.
if ($data['link']['in_active_trail']) {
$class[] = 'active-trail';
- $data['localized_options']['attributes']['class'][] = 'active-trail';
+ $data['link']['localized_options']['attributes']['class'][] = 'active-trail';
+ }
+ // Normally, l() compares the href of every link with $_GET['q'] and sets
+ // the active class accordingly. But local tasks do not appear in menu
+ // trees, so if the current path is a local task, and this link is its
+ // tab root, then we have to set the class manually.
+ if ($data['link']['href'] == $router_item['tab_root_href'] && $data['link']['href'] != $_GET['q']) {
+ $data['link']['localized_options']['attributes']['class'][] = 'active';
}
// Allow menu-specific theme overrides.
@@ -993,7 +1048,7 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
// Use $mlid as a flag for whether the data being loaded is for the whole tree.
$mlid = isset($link['mlid']) ? $link['mlid'] : 0;
// Generate a cache ID (cid) specific for this $menu_name, $link, $language, and depth.
- $cid = 'links:' . $menu_name . ':all-cid:' . $mlid . ':' . $GLOBALS['language']->language . ':' . (int) $max_depth;
+ $cid = 'links:' . $menu_name . ':all:' . $mlid . ':' . $GLOBALS['language']->language . ':' . (int) $max_depth;
if (!isset($tree[$cid])) {
// If the static variable doesn't have the data, check {cache_menu}.
@@ -1042,9 +1097,13 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
* field, see http://drupal.org/node/141866 for more.
*
* @param $menu_name
- * The named menu links to return
+ * The named menu links to return.
* @param $max_depth
- * Optional maximum depth of links to retrieve.
+ * (optional) The maximum depth of links to retrieve.
+ * @param $only_active_trail
+ * (optional) Whether to only return the links in the active trail (TRUE)
+ * instead of all links on every level of the menu link tree (FALSE). Defaults
+ * to FALSE. Internally used for breadcrumbs only.
*
* @return
* An array of menu links, in the order they should be rendered. The array
@@ -1053,7 +1112,7 @@ function menu_tree_all_data($menu_name, $link = NULL, $max_depth = NULL) {
* submenu below the link if there is one, and it is a subtree that has the
* same structure described for the top-level array.
*/
-function menu_tree_page_data($menu_name, $max_depth = NULL) {
+function menu_tree_page_data($menu_name, $max_depth = NULL, $only_active_trail = FALSE) {
$tree = &drupal_static(__FUNCTION__, array());
// Load the menu item corresponding to the current page.
@@ -1062,7 +1121,18 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) {
$max_depth = min($max_depth, MENU_MAX_DEPTH);
}
// Generate a cache ID (cid) specific for this page.
- $cid = 'links:' . $menu_name . ':page-cid:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int) $item['access'] . ':' . (int) $max_depth;
+ $cid = 'links:' . $menu_name . ':page:' . $item['href'] . ':' . $GLOBALS['language']->language . ':' . (int) $item['access'] . ':' . (int) $max_depth;
+ // If we are asked for the active trail only, and $menu_name has not been
+ // built and cached for this page yet, then this likely means that it
+ // won't be built anymore, as this function is invoked from
+ // template_process_page(). So in order to not build a giant menu tree
+ // that needs to be checked for access on all levels, we simply check
+ // whether we have the menu already in cache, or otherwise, build a minimum
+ // tree containing the breadcrumb/active trail only.
+ // @see menu_set_active_trail()
+ if (!isset($tree[$cid]) && $only_active_trail) {
+ $cid .= ':trail';
+ }
if (!isset($tree[$cid])) {
// If the static variable doesn't have the data, check {cache_menu}.
@@ -1078,57 +1148,39 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) {
'min_depth' => 1,
'max_depth' => $max_depth,
);
+ // Parent mlids; used both as key and value to ensure uniqueness.
+ // We always want all the top-level links with plid == 0.
+ $active_trail = array(0 => 0);
+
// If the item for the current page is accessible, build the tree
// parameters accordingly.
if ($item['access']) {
- // Check whether a menu link exists that corresponds to the current path.
- $args[] = $item['href'];
- if (drupal_is_front_page()) {
- $args[] = '<front>';
- }
- $active_link = db_select('menu_links')
- ->fields('menu_links', array(
- 'p1',
- 'p2',
- 'p3',
- 'p4',
- 'p5',
- 'p6',
- 'p7',
- 'p8',
- ))
- ->condition('menu_name', $menu_name)
- ->condition('link_path', $args, 'IN')
- ->execute()->fetchAssoc();
-
- if (empty($active_link)) {
- // If no link exists, we may be on a local task that's not in the links.
- // TODO: Handle the case like a local task on a specific node in the menu.
- $active_link = db_select('menu_links')
- ->fields('menu_links', array(
- 'p1',
- 'p2',
- 'p3',
- 'p4',
- 'p5',
- 'p6',
- 'p7',
- 'p8',
- ))
- ->condition('menu_name', $menu_name)
- ->condition('link_path', $item['tab_root'])
- ->execute()->fetchAssoc();
+ // Find a menu link corresponding to the current path.
+ if ($active_link = menu_link_get_preferred()) {
+ // The active link may only be taken into account to build the
+ // active trail, if it resides in the requested menu. Otherwise,
+ // we'd needlessly re-run _menu_build_tree() queries for every menu
+ // on every page.
+ if ($active_link['menu_name'] == $menu_name) {
+ // Use all the coordinates, except the last one because there
+ // can be no child beyond the last column.
+ for ($i = 1; $i < MENU_MAX_DEPTH; $i++) {
+ if ($active_link['p' . $i]) {
+ $active_trail[$active_link['p' . $i]] = $active_link['p' . $i];
+ }
+ }
+ // If we are asked to build links for the active trail only, skip
+ // the entire 'expanded' handling.
+ if ($only_active_trail) {
+ $tree_parameters['only_active_trail'] = TRUE;
+ }
+ }
}
-
- // We always want all the top-level links with plid == 0.
- $active_link[] = '0';
-
- // Use array_values() so that the indices are numeric.
- $parents = $active_link = array_unique(array_values($active_link));
+ $parents = $active_trail;
$expanded = variable_get('menu_expanded', array());
// Check whether the current menu has any links set to be expanded.
- if (in_array($menu_name, $expanded)) {
+ if (!$only_active_trail && in_array($menu_name, $expanded)) {
// Collect all the links set to be expanded, and then add all of
// their children to the list as well.
do {
@@ -1142,19 +1194,19 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) {
->execute();
$num_rows = FALSE;
foreach ($result as $item) {
- $parents[] = $item['mlid'];
+ $parents[$item['mlid']] = $item['mlid'];
$num_rows = TRUE;
}
} while ($num_rows);
}
$tree_parameters['expanded'] = $parents;
- $tree_parameters['active_trail'] = $active_link;
+ $tree_parameters['active_trail'] = $active_trail;
}
- // Otherwise, only show the top-level menu items when access is denied.
+ // If access is denied, we only show top-level links in menus.
else {
- $tree_parameters['expanded'] = array(0);
+ $tree_parameters['expanded'] = $active_trail;
+ $tree_parameters['active_trail'] = $active_trail;
}
-
// Cache the tree building parameters using the page-specific cid.
cache_set($cid, $tree_parameters, 'cache_menu');
}
@@ -1178,9 +1230,12 @@ function menu_tree_page_data($menu_name, $max_depth = NULL) {
* (optional) An associative array of build parameters. Possible keys:
* - expanded: An array of parent link ids to return only menu links that are
* children of one of the plids in this list. If empty, the whole menu tree
- * is built.
+ * is built, unless 'only_active_trail' is TRUE.
* - active_trail: An array of mlids, representing the coordinates of the
* currently active menu link.
+ * - only_active_trail: Whether to only return links that are in the active
+ * trail. This option is ignored, if 'expanded' is non-empty. Internally
+ * used for breadcrumbs.
* - min_depth: The minimum depth of menu links in the resulting tree.
* Defaults to 1, which is the default to build a whole tree for a menu, i.e.
* excluding menu container itself.
@@ -1241,6 +1296,8 @@ function _menu_build_tree($menu_name, array $parameters = array()) {
'page_callback',
'page_arguments',
'delivery_callback',
+ 'tab_parent',
+ 'tab_root',
'title',
'title_callback',
'title_arguments',
@@ -1256,6 +1313,9 @@ function _menu_build_tree($menu_name, array $parameters = array()) {
if (!empty($parameters['expanded'])) {
$query->condition('ml.plid', $parameters['expanded'], 'IN');
}
+ elseif (!empty($parameters['only_active_trail'])) {
+ $query->condition('ml.mlid', $parameters['active_trail'], 'IN');
+ }
$min_depth = (isset($parameters['min_depth']) ? $parameters['min_depth'] : 1);
if ($min_depth != 1) {
$query->condition('ml.depth', $min_depth, '>=');
@@ -1269,8 +1329,8 @@ function _menu_build_tree($menu_name, array $parameters = array()) {
foreach ($query->execute() as $item) {
$links[] = $item;
}
- $active_link = (isset($parameters['active_trail']) ? $parameters['active_trail'] : array());
- $data['tree'] = menu_tree_data($links, $active_link, $min_depth);
+ $active_trail = (isset($parameters['active_trail']) ? $parameters['active_trail'] : array());
+ $data['tree'] = menu_tree_data($links, $active_trail, $min_depth);
$data['node_links'] = array();
menu_tree_collect_node_links($data['tree'], $data['node_links']);
@@ -1315,7 +1375,6 @@ function menu_tree_collect_node_links(&$tree, &$node_links) {
* menu_tree_collect_node_links().
*/
function menu_tree_check_access(&$tree, $node_links = array()) {
-
if ($node_links) {
$nids = array_keys($node_links);
$select = db_select('node', 'n');
@@ -1331,7 +1390,6 @@ function menu_tree_check_access(&$tree, $node_links = array()) {
}
}
_menu_tree_check_access($tree);
- return;
}
/**
@@ -1342,7 +1400,7 @@ function _menu_tree_check_access(&$tree) {
foreach ($tree as $key => $v) {
$item = &$tree[$key]['link'];
_menu_link_translate($item);
- if ($item['access']) {
+ if ($item['access'] || ($item['in_active_trail'] && strpos($item['href'], '%') !== FALSE)) {
if ($tree[$key]['below']) {
_menu_tree_check_access($tree[$key]['below']);
}
@@ -1675,6 +1733,7 @@ function menu_navigation_links($menu_name, $level = 0) {
}
// Create a single level of links.
+ $router_item = menu_get_item();
$links = array();
foreach ($tree as $item) {
if (!$item['link']['hidden']) {
@@ -1684,6 +1743,14 @@ function menu_navigation_links($menu_name, $level = 0) {
$l['title'] = $item['link']['title'];
if ($item['link']['in_active_trail']) {
$class = ' active-trail';
+ $l['attributes']['class'][] = 'active-trail';
+ }
+ // Normally, l() compares the href of every link with $_GET['q'] and sets
+ // the active class accordingly. But local tasks do not appear in menu
+ // trees, so if the current path is a local task, and this link is its
+ // tab root, then we have to set the class manually.
+ if ($item['link']['href'] == $router_item['tab_root_href'] && $item['link']['href'] != $_GET['q']) {
+ $l['attributes']['class'][] = 'active';
}
// Keyed with the unique mlid to generate classes in theme_links().
$links['menu-' . $item['link']['mlid'] . $class] = $l;
@@ -1729,7 +1796,7 @@ function menu_local_tasks($level = 0) {
// If this router item points to its parent, start from the parents to
// compute tabs and actions.
if ($router_item && ($router_item['type'] & MENU_LINKS_TO_PARENT)) {
- $router_item = menu_get_item($router_item['tab_parent']);
+ $router_item = menu_get_item($router_item['tab_parent_href']);
}
// If we failed to fetch a router item or the current user doesn't have
@@ -1790,6 +1857,16 @@ function menu_local_tasks($level = 0) {
for ($p = $item['tab_parent']; ($tasks[$p]['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT; $p = $tasks[$p]['tab_parent']);
// Use the path of the parent instead.
$link['href'] = $tasks[$p]['href'];
+ // Mark the link as active, if the current path happens to be the
+ // path of the default local task itself (i.e., instead of its
+ // tab_parent_href or tab_root_href). Normally, links for default
+ // local tasks link to their parent, but the path of default local
+ // tasks can still be accessed directly, in which case this link
+ // would not be marked as active, since l() only compares the href
+ // with $_GET['q'].
+ if ($link['href'] != $_GET['q']) {
+ $link['localized_options']['attributes']['class'][] = 'active';
+ }
$tabs_current[] = array(
'#theme' => 'menu_local_task',
'#link' => $link,
@@ -1859,6 +1936,13 @@ function menu_local_tasks($level = 0) {
}
// We check for the active tab.
if ($item['path'] == $path) {
+ // Mark the link as active, if the current path is a (second-level)
+ // local task of a default local task. Since this default local task
+ // links to its parent, l() will not mark it as active, as it only
+ // compares the link's href to $_GET['q'].
+ if ($link['href'] != $_GET['q']) {
+ $link['localized_options']['attributes']['class'][] = 'active';
+ }
$tabs_current[] = array(
'#theme' => 'menu_local_task',
'#link' => $link,
@@ -2103,7 +2187,7 @@ function menu_set_active_item($path) {
}
/**
- * Sets or gets the active trail (path to root menu root) of the current page.
+ * Sets or gets the active trail (path to menu tree root) of the current page.
*
* @param $new_trail
* Menu trail to set, or NULL to use previously-set or calculated trail. If
@@ -2132,77 +2216,161 @@ function menu_set_active_trail($new_trail = NULL) {
}
elseif (!isset($trail)) {
$trail = array();
- $trail[] = array('title' => t('Home'), 'href' => '<front>', 'localized_options' => array(), 'type' => 0);
- $item = menu_get_item();
-
- // Check whether the current item is a local task (displayed as a tab).
- if ($item['tab_parent']) {
- // The title of a local task is used for the tab, never the page title.
- // Thus, replace it with the item corresponding to the root path to get
- // the relevant href and title. For example, the menu item corresponding
- // to 'admin' is used when on the 'By module' tab at 'admin/by-module'.
- $parts = explode('/', $item['tab_root']);
- $args = arg();
- // Replace wildcards in the root path using the current path.
- foreach ($parts as $index => $part) {
- if ($part == '%') {
- $parts[$index] = $args[$index];
- }
- }
- // Retrieve the menu item using the root path after wildcard replacement.
- $root_item = menu_get_item(implode('/', $parts));
- if ($root_item && $root_item['access']) {
- $item = $root_item;
- }
+ $trail[] = array(
+ 'title' => t('Home'),
+ 'href' => '<front>',
+ 'link_path' => '',
+ 'localized_options' => array(),
+ 'type' => 0,
+ );
+
+ // Try to retrieve a menu link corresponding to the current path. If more
+ // than one exists, the link from the most preferred menu is returned.
+ $preferred_link = menu_link_get_preferred();
+ $current_item = menu_get_item();
+
+ // There is a link for the current path.
+ if ($preferred_link) {
+ // Pass TRUE for $only_active_trail to make menu_tree_page_data() build
+ // a stripped down menu tree containing the active trail only, in case
+ // the given menu has not been built in this request yet.
+ $tree = menu_tree_page_data($preferred_link['menu_name'], NULL, TRUE);
+ list($key, $curr) = each($tree);
}
- $menu_names = menu_get_active_menu_names();
- $curr = FALSE;
- // Determine if the current page is a link in any of the active menus.
- if ($menu_names) {
- $query = db_select('menu_links', 'ml');
- $query->fields('ml', array('menu_name'));
- $query->condition('ml.link_path', $item['href']);
- $query->condition('ml.menu_name', $menu_names, 'IN');
- $result = $query->execute();
- $found = array();
- foreach ($result as $menu) {
- $found[] = $menu->menu_name;
- }
- // The $menu_names array is ordered, so take the first one that matches.
- $found_menu_names = array_intersect($menu_names, $found);
- $name = current($found_menu_names);
- if ($name !== FALSE) {
- $tree = menu_tree_page_data($name);
- list($key, $curr) = each($tree);
- }
+ // There is no link for the current path.
+ else {
+ $preferred_link = $current_item;
+ $curr = FALSE;
}
while ($curr) {
- // Terminate the loop when we find the current path in the active trail.
- if ($curr['link']['href'] == $item['href']) {
- $trail[] = $curr['link'];
- $curr = FALSE;
- }
- else {
- // Add the link if it's in the active trail, then move to the link below.
- if ($curr['link']['in_active_trail']) {
- $trail[] = $curr['link'];
- $tree = $curr['below'] ? $curr['below'] : array();
+ $link = $curr['link'];
+ if ($link['in_active_trail']) {
+ // Add the link to the trail, unless it links to its parent.
+ if (!($link['type'] & MENU_LINKS_TO_PARENT)) {
+ // The menu tree for the active trail may contain additional links
+ // that have not been translated yet, since they contain dynamic
+ // argument placeholders (%). Such links are not contained in regular
+ // menu trees, and have only been loaded for the additional
+ // translation that happens here, so as to be able to display them in
+ // the breadcumb for the current page.
+ // @see _menu_tree_check_access()
+ // @see _menu_link_translate()
+ if (strpos($link['href'], '%') !== FALSE) {
+ _menu_link_translate($link, TRUE);
+ }
+ if ($link['access']) {
+ $trail[] = $link;
+ }
}
- list($key, $curr) = each($tree);
+ $tree = $curr['below'] ? $curr['below'] : array();
}
+ list($key, $curr) = each($tree);
}
// Make sure the current page is in the trail (needed for the page title),
- // but exclude tabs and the front page.
- $last = count($trail) - 1;
- if ($trail[$last]['href'] != $item['href'] && !(bool) ($item['type'] & MENU_IS_LOCAL_TASK) && !drupal_is_front_page()) {
- $trail[] = $item;
+ // if the link's type allows it to be shown in the breadcrumb. Also exclude
+ // it if we are on the front page.
+ $last = end($trail);
+ if ($last['href'] != $preferred_link['href'] && ($preferred_link['type'] & MENU_VISIBLE_IN_BREADCRUMB) == MENU_VISIBLE_IN_BREADCRUMB && !drupal_is_front_page()) {
+ $trail[] = $preferred_link;
}
}
return $trail;
}
/**
+ * Lookup the preferred menu link for a given system path.
+ *
+ * @param $path
+ * The path, for example 'node/5'. The function will find the corresponding
+ * menu link ('node/5' if it exists, or fallback to 'node/%').
+ *
+ * @return
+ * A fully translated menu link, or NULL if not matching menu link was
+ * found. The most specific menu link ('node/5' preferred over 'node/%') in
+ * the most preferred menu (as defined by menu_get_active_menu_names()) is
+ * returned.
+ */
+function menu_link_get_preferred($path = NULL) {
+ $preferred_links = &drupal_static(__FUNCTION__);
+
+ if (!isset($path)) {
+ $path = $_GET['q'];
+ }
+
+ if (!isset($preferred_links[$path])) {
+ $preferred_links[$path] = FALSE;
+
+ // Look for the correct menu link by building a list of candidate paths,
+ // which are ordered by priority (translated hrefs are preferred over
+ // untranslated paths). Afterwards, the most relevant path is picked from
+ // the menus, ordered by menu preference.
+ $item = menu_get_item($path);
+ $path_candidates = array();
+ // 1. The current item href.
+ $path_candidates[$item['href']] = $item['href'];
+ // 2. The tab root href of the current item (if any).
+ if ($item['tab_parent'] && ($tab_root = menu_get_item($item['tab_root_href']))) {
+ $path_candidates[$tab_root['href']] = $tab_root['href'];
+ }
+ // 3. The current item path (with wildcards).
+ $path_candidates[$item['path']] = $item['path'];
+ // 4. The tab root path of the current item (if any).
+ if (!empty($tab_root)) {
+ $path_candidates[$tab_root['path']] = $tab_root['path'];
+ }
+
+ // Retrieve a list of menu names, ordered by preference.
+ $menu_names = menu_get_active_menu_names();
+
+ $query = db_select('menu_links', 'ml', array('fetch' => PDO::FETCH_ASSOC));
+ $query->leftJoin('menu_router', 'm', 'm.path = ml.router_path');
+ $query->fields('ml');
+ // Weight must be taken from {menu_links}, not {menu_router}.
+ $query->fields('m', array_diff(drupal_schema_fields_sql('menu_router'), array('weight')));
+ $query->condition('ml.menu_name', $menu_names, 'IN');
+ $query->condition('ml.link_path', $path_candidates, 'IN');
+ // Include links
+ // - appearing in trees (MENU_VISIBLE_IN_TREE).
+ // - appearing in breadcrumbs (MENU_VISIBLE_IN_BREADCRUMB), since
+ // breadcrumbs are based on regular menu link trees.
+ // - not mapping to any router path (NULL).
+ $query->condition(db_or()
+ ->condition('m.type', MENU_VISIBLE_IN_TREE, '&')
+ ->condition('m.type', MENU_VISIBLE_IN_BREADCRUMB, '&')
+ ->isNull('m.type')
+ );
+
+ // Sort candidates by link path and menu name.
+ $candidates = array();
+ foreach ($query->execute() as $candidate) {
+ $candidates[$candidate['link_path']][$candidate['menu_name']] = $candidate;
+ }
+
+ // Pick the most specific link, in the most preferred menu.
+ foreach ($path_candidates as $link_path) {
+ if (!isset($candidates[$link_path])) {
+ continue;
+ }
+ foreach ($menu_names as $menu_name) {
+ if (!isset($candidates[$link_path][$menu_name])) {
+ continue;
+ }
+ $candidate_item = $candidates[$link_path][$menu_name];
+ $map = explode('/', $path);
+ _menu_translate($candidate_item, $map);
+ if ($candidate_item['access']) {
+ $preferred_links[$path] = $candidate_item;
+ }
+ break 2;
+ }
+ }
+ }
+
+ return $preferred_links[$path];
+}
+
+/**
* Gets the active trail (path to root menu root) of the current page.
*
* See menu_set_active_trail() for details of return value.
@@ -2213,6 +2381,8 @@ function menu_get_active_trail() {
/**
* Get the breadcrumb for the current page, as determined by the active trail.
+ *
+ * @see menu_set_active_trail()
*/
function menu_get_active_breadcrumb() {
$breadcrumb = array();
@@ -2223,17 +2393,38 @@ function menu_get_active_breadcrumb() {
}
$item = menu_get_item();
- if ($item && $item['access']) {
+ if (!empty($item['access'])) {
$active_trail = menu_get_active_trail();
- foreach ($active_trail as $parent) {
- $breadcrumb[] = l($parent['title'], $parent['href'], $parent['localized_options']);
- }
- $end = end($active_trail);
+ // Allow modules to alter the breadcrumb, if possible, as that is much
+ // faster than rebuilding an entirely new active trail.
+ drupal_alter('menu_breadcrumb', $active_trail, $item);
// Don't show a link to the current page in the breadcrumb trail.
- if ($item['href'] == $end['href'] || (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT && $end['href'] != '<front>')) {
- array_pop($breadcrumb);
+ $end = end($active_trail);
+ if ($item['href'] == $end['href']) {
+ array_pop($active_trail);
+ }
+
+ // Remove the tab root (parent) if the current path links to its parent.
+ // Normally, the tab root link is included in the breadcrumb, as soon as we
+ // are on a local task or any other child link. However, if we are on a
+ // default local task (e.g., node/%/view), then we do not want the tab root
+ // link (e.g., node/%) to appear, as it would be identical to the current
+ // page. Since this behavior also needs to work recursively (i.e., on
+ // default local tasks of default local tasks), and since the last non-task
+ // link in the trail is used as page title (see menu_get_active_title()),
+ // this condition cannot be cleanly integrated into menu_get_active_trail().
+ // menu_get_active_trail() already skips all links that link to their parent
+ // (commonly MENU_DEFAULT_LOCAL_TASK). In order to also hide the parent link
+ // itself, we always remove the last link in the trail, if the current
+ // router item links to its parent.
+ if (($item['type'] & MENU_LINKS_TO_PARENT) == MENU_LINKS_TO_PARENT) {
+ array_pop($active_trail);
+ }
+
+ foreach ($active_trail as $parent) {
+ $breadcrumb[] = l($parent['title'], $parent['href'], $parent['localized_options']);
}
}
return $breadcrumb;
@@ -2319,6 +2510,7 @@ function menu_reset_static_cache() {
drupal_static_reset('menu_tree_all_data');
drupal_static_reset('menu_tree_page_data');
drupal_static_reset('menu_load_all');
+ drupal_static_reset('menu_link_get_preferred');
}
/**
diff --git a/includes/theme.inc b/includes/theme.inc
index 832f8719d..35854d4a8 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -2240,7 +2240,6 @@ function template_preprocess_page(&$variables) {
$variables['base_path'] = base_path();
$variables['front_page'] = url();
- $variables['breadcrumb'] = theme('breadcrumb', array('breadcrumb' => drupal_get_breadcrumb()));
$variables['feed_icons'] = drupal_get_feeds();
$variables['language'] = $GLOBALS['language'];
$variables['language']->dir = $GLOBALS['language']->direction ? 'rtl' : 'ltr';
@@ -2252,7 +2251,6 @@ function template_preprocess_page(&$variables) {
$variables['site_name'] = (theme_get_setting('toggle_name') ? filter_xss_admin(variable_get('site_name', 'Drupal')) : '');
$variables['site_slogan'] = (theme_get_setting('toggle_slogan') ? filter_xss_admin(variable_get('site_slogan', '')) : '');
$variables['tabs'] = theme('menu_local_tasks');
- $variables['title'] = drupal_get_title();
if ($node = menu_get_object()) {
$variables['node'] = $node;
@@ -2265,6 +2263,28 @@ function template_preprocess_page(&$variables) {
}
/**
+ * Process variables for page.tpl.php
+ *
+ * Perform final addition of variables before passing them into the template.
+ * To customize these variables, simply set them in an earlier step.
+ *
+ * @see template_preprocess_page()
+ * @see page.tpl.php
+ */
+function template_process_page(&$variables) {
+ if (!isset($variables['breadcrumb'])) {
+ // Build the breadcrumb last, so as to increase the chance of being able to
+ // re-use the cache of an already rendered menu containing the active link
+ // for the current page.
+ // @see menu_tree_page_data()
+ $variables['breadcrumb'] = theme('breadcrumb', array('breadcrumb' => drupal_get_breadcrumb()));
+ }
+ if (!isset($variables['title'])) {
+ $variables['title'] = drupal_get_title();
+ }
+}
+
+/**
* Process variables for html.tpl.php
*
* Perform final addition and modification of variables before passing into
diff --git a/modules/aggregator/aggregator.module b/modules/aggregator/aggregator.module
index d9afbe66f..4d70102cc 100644
--- a/modules/aggregator/aggregator.module
+++ b/modules/aggregator/aggregator.module
@@ -134,7 +134,6 @@ function aggregator_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('aggregator_admin_remove_feed', 5),
'access arguments' => array('administer news feeds'),
- 'type' => MENU_CALLBACK,
'file' => 'aggregator.admin.inc',
);
$items['admin/config/services/aggregator/update/%aggregator_feed'] = array(
@@ -142,7 +141,6 @@ function aggregator_menu() {
'page callback' => 'aggregator_admin_refresh_feed',
'page arguments' => array(5),
'access arguments' => array('administer news feeds'),
- 'type' => MENU_CALLBACK,
'file' => 'aggregator.admin.inc',
);
$items['admin/config/services/aggregator/list'] = array(
@@ -227,7 +225,6 @@ function aggregator_menu() {
'page callback' => 'aggregator_page_source',
'page arguments' => array(2),
'access arguments' => array('access news feeds'),
- 'type' => MENU_CALLBACK,
'file' => 'aggregator.pages.inc',
);
$items['aggregator/sources/%aggregator_feed/view'] = array(
@@ -257,7 +254,6 @@ function aggregator_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('aggregator_form_feed', 6),
'access arguments' => array('administer news feeds'),
- 'type' => MENU_CALLBACK,
'file' => 'aggregator.admin.inc',
);
$items['admin/config/services/aggregator/edit/category/%aggregator_category'] = array(
@@ -265,7 +261,6 @@ function aggregator_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('aggregator_form_category', 6),
'access arguments' => array('administer news feeds'),
- 'type' => MENU_CALLBACK,
'file' => 'aggregator.admin.inc',
);
diff --git a/modules/book/book.module b/modules/book/book.module
index 053a14a06..7fd4ce57c 100644
--- a/modules/book/book.module
+++ b/modules/book/book.module
@@ -182,7 +182,6 @@ function book_menu() {
'access callback' => '_book_outline_remove_access',
'access arguments' => array(1),
'theme callback' => '_node_custom_theme',
- 'type' => MENU_CALLBACK,
'file' => 'book.pages.inc',
);
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index fd46cd7c0..5e4c34a99 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -241,7 +241,6 @@ function comment_menu() {
'page callback' => 'comment_permalink',
'page arguments' => array(1),
'access arguments' => array('access comments'),
- 'type' => MENU_CALLBACK,
);
$items['comment/%/view'] = array(
'title' => 'View comment',
@@ -264,7 +263,6 @@ function comment_menu() {
'page callback' => 'comment_approve',
'page arguments' => array(1),
'access arguments' => array('administer comments'),
- 'type' => MENU_CALLBACK,
'file' => 'comment.pages.inc',
'weight' => 1,
);
@@ -283,7 +281,6 @@ function comment_menu() {
'page arguments' => array(2),
'access callback' => 'node_access',
'access arguments' => array('view', 2),
- 'type' => MENU_CALLBACK,
'file' => 'comment.pages.inc',
);
diff --git a/modules/contact/contact.module b/modules/contact/contact.module
index 06103eae2..fc66f0519 100644
--- a/modules/contact/contact.module
+++ b/modules/contact/contact.module
@@ -77,7 +77,6 @@ function contact_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('contact_category_edit_form', 4),
'access arguments' => array('administer contact forms'),
- 'type' => MENU_CALLBACK,
'file' => 'contact.admin.inc',
);
$items['admin/structure/contact/delete/%contact'] = array(
@@ -85,7 +84,6 @@ function contact_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('contact_category_delete_form', 4),
'access arguments' => array('administer contact forms'),
- 'type' => MENU_CALLBACK,
'file' => 'contact.admin.inc',
);
$items['contact'] = array(
diff --git a/modules/dashboard/dashboard.module b/modules/dashboard/dashboard.module
index b1266ef88..8cf5a7e59 100644
--- a/modules/dashboard/dashboard.module
+++ b/modules/dashboard/dashboard.module
@@ -53,7 +53,6 @@ function dashboard_menu() {
'page callback' => 'dashboard_admin',
'page arguments' => array(TRUE),
'access arguments' => array('access dashboard'),
- 'type' => MENU_CALLBACK,
);
$items['admin/dashboard/drawer'] = array(
'page callback' => 'dashboard_show_disabled',
diff --git a/modules/dblog/dblog.module b/modules/dblog/dblog.module
index 0d149ec35..dac5387c4 100644
--- a/modules/dblog/dblog.module
+++ b/modules/dblog/dblog.module
@@ -67,7 +67,6 @@ function dblog_menu() {
'page callback' => 'dblog_event',
'page arguments' => array(3),
'access arguments' => array('access site reports'),
- 'type' => MENU_CALLBACK,
'file' => 'dblog.admin.inc',
);
diff --git a/modules/field/modules/options/options.test b/modules/field/modules/options/options.test
index 5fa444b66..cd85e6579 100644
--- a/modules/field/modules/options/options.test
+++ b/modules/field/modules/options/options.test
@@ -77,7 +77,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_test_entity_save($entity);
// With no field data, no buttons are checked.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertNoFieldChecked("edit-card-1-$langcode-0");
$this->assertNoFieldChecked("edit-card-1-$langcode-1");
$this->assertNoFieldChecked("edit-card-1-$langcode-2");
@@ -89,7 +89,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'card_1', $langcode, array(0));
// Check that the selected button is checked.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertFieldChecked("edit-card-1-$langcode-0");
$this->assertNoFieldChecked("edit-card-1-$langcode-1");
$this->assertNoFieldChecked("edit-card-1-$langcode-2");
@@ -104,7 +104,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_update_field($this->card_1);
$instance['required'] = TRUE;
field_update_instance($instance);
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertFieldChecked("edit-card-1-$langcode-99");
}
@@ -134,7 +134,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_test_entity_save($entity);
// Display form: with no field data, nothing is checked.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertNoFieldChecked("edit-card-2-$langcode-0");
$this->assertNoFieldChecked("edit-card-2-$langcode-1");
$this->assertNoFieldChecked("edit-card-2-$langcode-2");
@@ -150,7 +150,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'card_2', $langcode, array(0, 2));
// Display form: check that the right options are selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertFieldChecked("edit-card-2-$langcode-0");
$this->assertNoFieldChecked("edit-card-2-$langcode-1");
$this->assertFieldChecked("edit-card-2-$langcode-2");
@@ -165,7 +165,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
// Display form: check that the right options are selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertFieldChecked("edit-card-2-$langcode-0");
$this->assertNoFieldChecked("edit-card-2-$langcode-1");
$this->assertNoFieldChecked("edit-card-2-$langcode-2");
@@ -194,7 +194,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_update_field($this->card_2);
$instance['required'] = TRUE;
field_update_instance($instance);
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertFieldChecked("edit-card-2-$langcode-99");
}
@@ -222,7 +222,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_test_entity_save($entity);
// Display form.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
// A required field without any value has a "none" option.
$this->assertTrue($this->xpath('//select[@id=:id]//option[@value="_none" and text()=:label]', array(':id' => 'edit-card-1-' . $langcode, ':label' => t('- Select a value -'))), t('A required select list has a "Select a value" choice.'));
@@ -244,7 +244,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'card_1', $langcode, array(0));
// Display form: check that the right options are selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
// A required field with a value has no 'none' option.
$this->assertFalse($this->xpath('//select[@id=:id]//option[@value="_none"]', array(':id' => 'edit-card-1-' . $langcode)), t('A required select list with an actual value has no "none" choice.'));
$this->assertOptionSelected("edit-card-1-$langcode", 0);
@@ -256,12 +256,12 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_update_instance($instance);
// Display form.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
// A non-required field has a 'none' option.
$this->assertTrue($this->xpath('//select[@id=:id]//option[@value="_none" and text()=:label]', array(':id' => 'edit-card-1-' . $langcode, ':label' => t('- None -'))), t('A non-required select list has a "None" choice.'));
// Submit form: Unselect the option.
$edit = array("card_1[$langcode]" => '_none');
- $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+ $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
$this->assertFieldValues($entity_init, 'card_1', $langcode, array());
// Test optgroups.
@@ -271,7 +271,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_update_field($this->card_1);
// Display form: with no field data, nothing is selected
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertNoOptionSelected("edit-card-1-$langcode", 0);
$this->assertNoOptionSelected("edit-card-1-$langcode", 1);
$this->assertNoOptionSelected("edit-card-1-$langcode", 2);
@@ -284,14 +284,14 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'card_1', $langcode, array(0));
// Display form: check that the right options are selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertOptionSelected("edit-card-1-$langcode", 0);
$this->assertNoOptionSelected("edit-card-1-$langcode", 1);
$this->assertNoOptionSelected("edit-card-1-$langcode", 2);
// Submit form: Unselect the option.
$edit = array("card_1[$langcode]" => '_none');
- $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+ $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
$this->assertFieldValues($entity_init, 'card_1', $langcode, array());
}
@@ -318,7 +318,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_test_entity_save($entity);
// Display form: with no field data, nothing is selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertNoOptionSelected("edit-card-2-$langcode", 0);
$this->assertNoOptionSelected("edit-card-2-$langcode", 1);
$this->assertNoOptionSelected("edit-card-2-$langcode", 2);
@@ -330,7 +330,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'card_2', $langcode, array(0, 2));
// Display form: check that the right options are selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertOptionSelected("edit-card-2-$langcode", 0);
$this->assertNoOptionSelected("edit-card-2-$langcode", 1);
$this->assertOptionSelected("edit-card-2-$langcode", 2);
@@ -341,7 +341,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
// Display form: check that the right options are selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertOptionSelected("edit-card-2-$langcode", 0);
$this->assertNoOptionSelected("edit-card-2-$langcode", 1);
$this->assertNoOptionSelected("edit-card-2-$langcode", 2);
@@ -361,18 +361,18 @@ class OptionsWidgetsTestCase extends FieldTestCase {
// Check that the 'none' option has no efect if actual options are selected
// as well.
$edit = array("card_2[$langcode][]" => array('_none' => '_none', 0 => 0));
- $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+ $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
$this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
// Check that selecting the 'none' option empties the field.
$edit = array("card_2[$langcode][]" => array('_none' => '_none'));
- $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+ $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
$this->assertFieldValues($entity_init, 'card_2', $langcode, array());
// A required select list does not have an empty key.
$instance['required'] = TRUE;
field_update_instance($instance);
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertFalse($this->xpath('//select[@id=:id]//option[@value=""]', array(':id' => 'edit-card-2-' . $langcode)), t('A required select list does not have an empty key.'));
// We do not have to test that a required select list with one option is
@@ -388,7 +388,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_update_instance($instance);
// Display form: with no field data, nothing is selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertNoOptionSelected("edit-card-2-$langcode", 0);
$this->assertNoOptionSelected("edit-card-2-$langcode", 1);
$this->assertNoOptionSelected("edit-card-2-$langcode", 2);
@@ -401,14 +401,14 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'card_2', $langcode, array(0));
// Display form: check that the right options are selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertOptionSelected("edit-card-2-$langcode", 0);
$this->assertNoOptionSelected("edit-card-2-$langcode", 1);
$this->assertNoOptionSelected("edit-card-2-$langcode", 2);
// Submit form: Unselect the option.
$edit = array("card_2[$langcode][]" => array('_none' => '_none'));
- $this->drupalPost('test-entity/' . $entity->ftid .'/edit', $edit, t('Save'));
+ $this->drupalPost('test-entity/manage/' . $entity->ftid . '/edit', $edit, t('Save'));
$this->assertFieldValues($entity_init, 'card_2', $langcode, array());
}
@@ -435,7 +435,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
field_test_entity_save($entity);
// Display form: with no field data, option is unchecked.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertNoFieldChecked("edit-bool-$langcode");
$this->assertRaw('Some dangerous &amp; unescaped <strong>markup</strong>', t('Option text was properly filtered.'));
@@ -445,7 +445,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'bool', $langcode, array(0));
// Display form: check that the right options are selected.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertFieldChecked("edit-bool-$langcode");
// Submit form: uncheck the option.
@@ -454,7 +454,7 @@ class OptionsWidgetsTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, 'bool', $langcode, array(1));
// Display form: with 'off' value, option is unchecked.
- $this->drupalGet('test-entity/' . $entity->ftid .'/edit');
+ $this->drupalGet('test-entity/manage/' . $entity->ftid . '/edit');
$this->assertNoFieldChecked("edit-bool-$langcode");
}
}
diff --git a/modules/field/modules/text/text.test b/modules/field/modules/text/text.test
index 9256277d9..bfc9156e5 100644
--- a/modules/field/modules/text/text.test
+++ b/modules/field/modules/text/text.test
@@ -115,7 +115,7 @@ class TextFieldTestCase extends DrupalWebTestCase {
"{$this->field_name}[$langcode][0][value]" => $value,
);
$this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+ preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
$id = $match[1];
$this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Entity was created'));
@@ -184,7 +184,7 @@ class TextFieldTestCase extends DrupalWebTestCase {
"{$this->field_name}[$langcode][0][value]" => $value,
);
$this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+ preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
$id = $match[1];
$this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Entity was created'));
@@ -210,7 +210,7 @@ class TextFieldTestCase extends DrupalWebTestCase {
// Display edition form.
// We should now have a 'text format' selector.
- $this->drupalGet('test-entity/' . $id . '/edit');
+ $this->drupalGet('test-entity/manage/' . $id . '/edit');
$this->assertFieldByName("{$this->field_name}[$langcode][0][value]", '', t('Widget is displayed'));
$this->assertFieldByName("{$this->field_name}[$langcode][0][format]", '', t('Format selector is displayed'));
diff --git a/modules/field/tests/field.test b/modules/field/tests/field.test
index e865ac22d..43b6fe5bd 100644
--- a/modules/field/tests/field.test
+++ b/modules/field/tests/field.test
@@ -1259,14 +1259,14 @@ class FieldFormTestCase extends FieldTestCase {
$value = mt_rand(1, 127);
$edit = array("{$this->field_name}[$langcode][0][value]" => $value);
$this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+ preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
$id = $match[1];
$this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
$entity = field_test_entity_test_load($id);
$this->assertEqual($entity->{$this->field_name}[$langcode][0]['value'], $value, 'Field value was saved');
// Display edit form.
- $this->drupalGet('test-entity/' . $id . '/edit');
+ $this->drupalGet('test-entity/manage/' . $id . '/edit');
$this->assertFieldByName("{$this->field_name}[$langcode][0][value]", $value, 'Widget is displayed with the correct default value');
$this->assertNoField("{$this->field_name}[$langcode][1][value]", 'No extraneous widget is displayed');
@@ -1281,7 +1281,7 @@ class FieldFormTestCase extends FieldTestCase {
// Empty the field.
$value = '';
$edit = array("{$this->field_name}[$langcode][0][value]" => $value);
- $this->drupalPost('test-entity/' . $id . '/edit', $edit, t('Save'));
+ $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
$this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
$entity = field_test_entity_test_load($id);
$this->assertIdentical($entity->{$this->field_name}, array(), 'Field was emptied');
@@ -1306,7 +1306,7 @@ class FieldFormTestCase extends FieldTestCase {
$value = mt_rand(1, 127);
$edit = array("{$this->field_name}[$langcode][0][value]" => $value);
$this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+ preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
$id = $match[1];
$this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
$entity = field_test_entity_test_load($id);
@@ -1315,7 +1315,7 @@ class FieldFormTestCase extends FieldTestCase {
// Edit with missing required value.
$value = '';
$edit = array("{$this->field_name}[$langcode][0][value]" => $value);
- $this->drupalPost('test-entity/' . $id . '/edit', $edit, t('Save'));
+ $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
$this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
}
@@ -1384,7 +1384,7 @@ class FieldFormTestCase extends FieldTestCase {
// Submit the form and create the entity.
$this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+ preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
$id = $match[1];
$this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
$entity = field_test_entity_test_load($id);
@@ -1474,7 +1474,7 @@ class FieldFormTestCase extends FieldTestCase {
// Create entity with three values.
$edit = array("{$this->field_name}[$langcode]" => '1, 2, 3');
$this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+ preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
$id = $match[1];
// Check that the values were saved.
@@ -1482,7 +1482,7 @@ class FieldFormTestCase extends FieldTestCase {
$this->assertFieldValues($entity_init, $this->field_name, $langcode, array(1, 2, 3));
// Display the form, check that the values are correctly filled in.
- $this->drupalGet('test-entity/' . $id . '/edit');
+ $this->drupalGet('test-entity/manage/' . $id . '/edit');
$this->assertFieldByName("{$this->field_name}[$langcode]", '1, 2, 3', t('Widget is displayed.'));
// Submit the form with more values than the field accepts.
@@ -1529,7 +1529,7 @@ class FieldFormTestCase extends FieldTestCase {
// Create entity.
$edit = array("{$field_name}[$langcode][0][value]" => 1);
$this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+ preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
$id = $match[1];
// Check that the default value was saved.
@@ -1539,7 +1539,7 @@ class FieldFormTestCase extends FieldTestCase {
// Create a new revision.
$edit = array("{$field_name}[$langcode][0][value]" => 2, 'revision' => TRUE);
- $this->drupalPost('test-entity/' . $id . '/edit', $edit, t('Save'));
+ $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
// Check that the new revision has the expected values.
$entity = field_test_entity_test_load($id);
@@ -2721,7 +2721,7 @@ class FieldTranslationsTestCase extends FieldTestCase {
// Create a new revision.
$langcode = field_valid_language(NULL);
$edit = array("{$field_name}[$langcode][0][value]" => $entity->{$field_name}[$langcode][0]['value'], 'revision' => TRUE);
- $this->drupalPost('test-entity/' . $eid . '/edit', $edit, t('Save'));
+ $this->drupalPost('test-entity/manage/' . $eid . '/edit', $edit, t('Save'));
// Check translation revisions.
$this->checkTranslationRevisions($eid, $eid, $available_languages);
diff --git a/modules/field/tests/field_test.entity.inc b/modules/field/tests/field_test.entity.inc
index 149c09a2c..353bb3de0 100644
--- a/modules/field/tests/field_test.entity.inc
+++ b/modules/field/tests/field_test.entity.inc
@@ -392,7 +392,7 @@ function field_test_entity_form_submit($form, &$form_state) {
drupal_set_message($message);
if ($entity->ftid) {
- $form_state['redirect'] = 'test-entity/' . $entity->ftid . '/edit';
+ $form_state['redirect'] = 'test-entity/manage/' . $entity->ftid . '/edit';
}
else {
// Error on save.
diff --git a/modules/field/tests/field_test.module b/modules/field/tests/field_test.module
index 5adc3a4c1..3767a8014 100644
--- a/modules/field/tests/field_test.module
+++ b/modules/field/tests/field_test.module
@@ -52,10 +52,10 @@ function field_test_menu() {
'type' => MENU_NORMAL_ITEM,
);
}
- $items['test-entity/%field_test_entity_test/edit'] = array(
+ $items['test-entity/manage/%field_test_entity_test/edit'] = array(
'title' => 'Edit test entity',
'page callback' => 'field_test_entity_edit',
- 'page arguments' => array(1),
+ 'page arguments' => array(2),
'access arguments' => array('administer field_test content'),
'type' => MENU_NORMAL_ITEM,
);
diff --git a/modules/field_ui/field_ui.module b/modules/field_ui/field_ui.module
index 8ce1cdd14..cb4831f42 100644
--- a/modules/field_ui/field_ui.module
+++ b/modules/field_ui/field_ui.module
@@ -114,7 +114,6 @@ function field_ui_menu() {
'title arguments' => array($field_position),
'page callback' => 'drupal_get_form',
'page arguments' => array('field_ui_field_edit_form', $field_position),
- 'type' => MENU_LOCAL_TASK,
'file' => 'field_ui.admin.inc',
) + $access;
$items["$path/fields/%field_ui_menu/edit"] = array(
diff --git a/modules/filter/filter.module b/modules/filter/filter.module
index 85fb20fec..d726699c6 100644
--- a/modules/filter/filter.module
+++ b/modules/filter/filter.module
@@ -114,7 +114,6 @@ function filter_menu() {
'file' => 'filter.admin.inc',
);
$items['admin/config/content/formats/%filter_format'] = array(
- 'type' => MENU_CALLBACK,
'title callback' => 'filter_admin_format_title',
'title arguments' => array(4),
'page callback' => 'filter_admin_format_page',
@@ -128,7 +127,6 @@ function filter_menu() {
'page arguments' => array('filter_admin_disable', 4),
'access callback' => '_filter_disable_format_access',
'access arguments' => array(4),
- 'type' => MENU_CALLBACK,
'file' => 'filter.admin.inc',
);
return $items;
diff --git a/modules/forum/forum.module b/modules/forum/forum.module
index a0e8b4c97..ed7129c81 100644
--- a/modules/forum/forum.module
+++ b/modules/forum/forum.module
@@ -147,7 +147,6 @@ function forum_menu() {
'page callback' => 'forum_form_main',
'page arguments' => array('container', 5),
'access arguments' => array('administer forums'),
- 'type' => MENU_CALLBACK,
'file' => 'forum.admin.inc',
);
$items['admin/structure/forum/edit/forum/%taxonomy_term'] = array(
@@ -155,7 +154,6 @@ function forum_menu() {
'page callback' => 'forum_form_main',
'page arguments' => array('forum', 5),
'access arguments' => array('administer forums'),
- 'type' => MENU_CALLBACK,
'file' => 'forum.admin.inc',
);
return $items;
diff --git a/modules/forum/forum.test b/modules/forum/forum.test
index 786913ace..110dc3267 100644
--- a/modules/forum/forum.test
+++ b/modules/forum/forum.test
@@ -25,9 +25,25 @@ class ForumTestCase extends DrupalWebTestCase {
function setUp() {
parent::setUp('taxonomy', 'comment', 'forum');
// Create users.
- $this->admin_user = $this->drupalCreateUser(array('administer blocks', 'administer forums', 'administer menu', 'administer taxonomy', 'create forum content')); // 'access administration pages'));
- $this->edit_any_topics_user = $this->drupalCreateUser(array('create forum content', 'edit any forum content', 'delete any forum content', 'access administration pages'));
- $this->edit_own_topics_user = $this->drupalCreateUser(array('create forum content', 'edit own forum content', 'delete own forum content'));
+ $this->admin_user = $this->drupalCreateUser(array(
+ 'access administration pages',
+ 'administer blocks',
+ 'administer forums',
+ 'administer menu',
+ 'administer taxonomy',
+ 'create forum content',
+ ));
+ $this->edit_any_topics_user = $this->drupalCreateUser(array(
+ 'access administration pages',
+ 'create forum content',
+ 'edit any forum content',
+ 'delete any forum content',
+ ));
+ $this->edit_own_topics_user = $this->drupalCreateUser(array(
+ 'create forum content',
+ 'edit own forum content',
+ 'delete own forum content',
+ ));
$this->web_user = $this->drupalCreateUser(array());
}
diff --git a/modules/help/help.module b/modules/help/help.module
index 18357b4b4..2c964d7bf 100644
--- a/modules/help/help.module
+++ b/modules/help/help.module
@@ -25,7 +25,6 @@ function help_menu() {
'page callback' => 'help_page',
'page arguments' => array(2),
'access arguments' => array('access administration pages'),
- 'type' => MENU_CALLBACK,
'file' => 'help.admin.inc',
);
}
diff --git a/modules/image/image.module b/modules/image/image.module
index 36807a8e5..ccf21c73a 100644
--- a/modules/image/image.module
+++ b/modules/image/image.module
@@ -125,7 +125,6 @@ function image_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('image_style_form', 5),
'access arguments' => array('administer image styles'),
- 'type' => MENU_CALLBACK,
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/delete/%image_style'] = array(
@@ -135,7 +134,6 @@ function image_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('image_style_delete_form', 5),
'access arguments' => array('administer image styles'),
- 'type' => MENU_CALLBACK,
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/revert/%image_style'] = array(
@@ -145,7 +143,6 @@ function image_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('image_style_revert_form', 5),
'access arguments' => array('administer image styles'),
- 'type' => MENU_CALLBACK,
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/edit/%image_style/effects/%image_effect'] = array(
@@ -155,7 +152,6 @@ function image_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('image_effect_form', 5, 7),
'access arguments' => array('administer image styles'),
- 'type' => MENU_CALLBACK,
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/edit/%image_style/effects/%image_effect/delete'] = array(
@@ -165,7 +161,6 @@ function image_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('image_effect_delete_form', 5, 7),
'access arguments' => array('administer image styles'),
- 'type' => MENU_CALLBACK,
'file' => 'image.admin.inc',
);
$items['admin/config/media/image-styles/edit/%image_style/add/%image_effect_definition'] = array(
@@ -175,7 +170,6 @@ function image_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('image_effect_form', 5, 7),
'access arguments' => array('administer image styles'),
- 'type' => MENU_CALLBACK,
'file' => 'image.admin.inc',
);
diff --git a/modules/locale/locale.module b/modules/locale/locale.module
index 1f42abc6c..417528628 100644
--- a/modules/locale/locale.module
+++ b/modules/locale/locale.module
@@ -150,7 +150,6 @@ function locale_menu() {
'page arguments' => array('locale_languages_edit_form', 5),
'access arguments' => array('administer languages'),
'file' => 'locale.admin.inc',
- 'type' => MENU_CALLBACK,
);
$items['admin/config/regional/language/delete/%'] = array(
'title' => 'Confirm',
@@ -158,7 +157,6 @@ function locale_menu() {
'page arguments' => array('locale_languages_delete_form', 5),
'access arguments' => array('administer languages'),
'file' => 'locale.admin.inc',
- 'type' => MENU_CALLBACK,
);
// Translation functionality
@@ -205,7 +203,6 @@ function locale_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('locale_translate_edit_form', 5),
'access arguments' => array('translate interface'),
- 'type' => MENU_CALLBACK,
'file' => 'locale.admin.inc',
);
$items['admin/config/regional/translate/delete/%'] = array(
@@ -213,7 +210,6 @@ function locale_menu() {
'page callback' => 'locale_translate_delete_page',
'page arguments' => array(5),
'access arguments' => array('translate interface'),
- 'type' => MENU_CALLBACK,
'file' => 'locale.admin.inc',
);
@@ -233,7 +229,6 @@ function locale_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('locale_date_format_form', 5),
'access arguments' => array('administer site configuration'),
- 'type' => MENU_CALLBACK,
'file' => 'locale.admin.inc',
);
$items['admin/config/regional/date-time/locale/%/reset'] = array(
@@ -242,7 +237,6 @@ function locale_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('locale_date_format_reset_form', 5),
'access arguments' => array('administer site configuration'),
- 'type' => MENU_CALLBACK,
'file' => 'locale.admin.inc',
);
diff --git a/modules/menu/menu.module b/modules/menu/menu.module
index fc7a655b8..ded4bd21c 100644
--- a/modules/menu/menu.module
+++ b/modules/menu/menu.module
@@ -95,7 +95,6 @@ function menu_menu() {
'title callback' => 'menu_overview_title',
'title arguments' => array(4),
'access arguments' => array('administer menu'),
- 'type' => MENU_CALLBACK,
'file' => 'menu.admin.inc',
);
$items['admin/structure/menu/manage/%menu/list'] = array(
@@ -126,7 +125,6 @@ function menu_menu() {
'page callback' => 'menu_delete_menu_page',
'page arguments' => array(4),
'access arguments' => array('administer menu'),
- 'type' => MENU_CALLBACK,
'file' => 'menu.admin.inc',
);
$items['admin/structure/menu/item/%menu_link/edit'] = array(
@@ -134,7 +132,6 @@ function menu_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('menu_edit_item', 'edit', 4, NULL),
'access arguments' => array('administer menu'),
- 'type' => MENU_CALLBACK,
'file' => 'menu.admin.inc',
);
$items['admin/structure/menu/item/%menu_link/reset'] = array(
@@ -142,7 +139,6 @@ function menu_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('menu_reset_item_confirm', 4),
'access arguments' => array('administer menu'),
- 'type' => MENU_CALLBACK,
'file' => 'menu.admin.inc',
);
$items['admin/structure/menu/item/%menu_link/delete'] = array(
@@ -150,7 +146,6 @@ function menu_menu() {
'page callback' => 'menu_item_delete_page',
'page arguments' => array(4),
'access arguments' => array('administer menu'),
- 'type' => MENU_CALLBACK,
'file' => 'menu.admin.inc',
);
return $items;
@@ -707,7 +702,7 @@ function menu_form_node_type_form_alter(&$form, $form_state) {
$form['menu']['menu_options'] = array(
'#type' => 'checkboxes',
'#title' => t('Available menus'),
- '#default_value' => variable_get('menu_options_' . $type->type, array('main-menu' => 'main-menu')),
+ '#default_value' => variable_get('menu_options_' . $type->type, array('main-menu')),
'#options' => $menu_options,
'#description' => t('The menus available to place links in for this content type.'),
);
diff --git a/modules/menu/menu.test b/modules/menu/menu.test
index 1fa76f188..2c5900181 100644
--- a/modules/menu/menu.test
+++ b/modules/menu/menu.test
@@ -112,14 +112,14 @@ class MenuTestCase extends DrupalWebTestCase {
// Assert the new menu.
$this->drupalGet('admin/structure/menu/manage/' . $menu_name . '/edit');
- $this->assertText($title, t('Custom menu was added.'));
+ $this->assertRaw($title, t('Custom menu was added.'));
// Edit the menu.
$new_title = $this->randomName(16);
$menu['title'] = $new_title;
menu_save($menu);
$this->drupalGet('admin/structure/menu/manage/' . $menu_name . '/edit');
- $this->assertText($new_title, t('Custom menu was edited.'));
+ $this->assertRaw($new_title, t('Custom menu was edited.'));
}
/**
diff --git a/modules/node/node.module b/modules/node/node.module
index 4e94f5de9..b491e7469 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1844,12 +1844,10 @@ function node_menu() {
'title' => 'Delete',
'page arguments' => array('node_type_delete_confirm', 4),
'access arguments' => array('administer content types'),
- 'type' => MENU_CALLBACK,
'file' => 'content_types.inc',
);
$items['node'] = array(
- 'title' => 'Content',
'page callback' => 'node_page_default',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
@@ -1895,7 +1893,6 @@ function node_menu() {
'page arguments' => array(1),
'access callback' => 'node_access',
'access arguments' => array('view', 1),
- 'type' => MENU_CALLBACK,
);
$items['node/%node/view'] = array(
'title' => 'View',
@@ -1943,7 +1940,6 @@ function node_menu() {
'page arguments' => array(1, TRUE),
'access callback' => '_node_revision_access',
'access arguments' => array(1),
- 'type' => MENU_CALLBACK,
);
$items['node/%node/revisions/%/revert'] = array(
'title' => 'Revert to earlier revision',
@@ -1952,7 +1948,6 @@ function node_menu() {
'page arguments' => array('node_revision_revert_confirm', 1),
'access callback' => '_node_revision_access',
'access arguments' => array(1, 'update'),
- 'type' => MENU_CALLBACK,
'file' => 'node.pages.inc',
);
$items['node/%node/revisions/%/delete'] = array(
@@ -1962,7 +1957,6 @@ function node_menu() {
'page arguments' => array('node_revision_delete_confirm', 1),
'access callback' => '_node_revision_access',
'access arguments' => array(1, 'delete'),
- 'type' => MENU_CALLBACK,
'file' => 'node.pages.inc',
);
return $items;
diff --git a/modules/openid/openid.module b/modules/openid/openid.module
index 3412db45d..7e7ebfd05 100644
--- a/modules/openid/openid.module
+++ b/modules/openid/openid.module
@@ -32,7 +32,6 @@ function openid_menu() {
'page arguments' => array('openid_user_delete_form', 1),
'access callback' => 'user_edit_access',
'access arguments' => array(1),
- 'type' => MENU_CALLBACK,
'file' => 'openid.pages.inc',
);
return $items;
diff --git a/modules/path/path.module b/modules/path/path.module
index e0766f9e1..0e5874357 100644
--- a/modules/path/path.module
+++ b/modules/path/path.module
@@ -66,7 +66,6 @@ function path_menu() {
'page callback' => 'path_admin_edit',
'page arguments' => array(5),
'access arguments' => array('administer url aliases'),
- 'type' => MENU_CALLBACK,
'file' => 'path.admin.inc',
);
$items['admin/config/search/path/delete/%path'] = array(
@@ -74,7 +73,6 @@ function path_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('path_admin_delete_confirm', 5),
'access arguments' => array('administer url aliases'),
- 'type' => MENU_CALLBACK,
'file' => 'path.admin.inc',
);
$items['admin/config/search/path/list'] = array(
diff --git a/modules/profile/profile.module b/modules/profile/profile.module
index 7f3094051..a94c3c033 100644
--- a/modules/profile/profile.module
+++ b/modules/profile/profile.module
@@ -99,7 +99,6 @@ function profile_menu() {
'page arguments' => array('profile_field_form'),
'access arguments' => array('administer users'),
'file' => 'profile.admin.inc',
- 'type' => MENU_CALLBACK,
);
$items['admin/config/people/profile/autocomplete'] = array(
'title' => 'Profile category autocomplete',
@@ -114,7 +113,6 @@ function profile_menu() {
'page arguments' => array('profile_field_form'),
'access arguments' => array('administer users'),
'file' => 'profile.admin.inc',
- 'type' => MENU_CALLBACK,
);
$items['admin/config/people/profile/delete'] = array(
'title' => 'Delete field',
@@ -122,7 +120,6 @@ function profile_menu() {
'page arguments' => array('profile_field_delete'),
'access arguments' => array('administer users'),
'file' => 'profile.admin.inc',
- 'type' => MENU_CALLBACK,
);
$items['profile/autocomplete'] = array(
'title' => 'Profile autocomplete',
diff --git a/modules/search/search.module b/modules/search/search.module
index a66f1b96a..e4f4130ba 100644
--- a/modules/search/search.module
+++ b/modules/search/search.module
@@ -182,7 +182,6 @@ function search_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('search_reindex_confirm'),
'access arguments' => array('administer search'),
- 'type' => MENU_CALLBACK,
'file' => 'search.admin.inc',
);
diff --git a/modules/search/search.test b/modules/search/search.test
index 7e97640c3..29fa9ef3f 100644
--- a/modules/search/search.test
+++ b/modules/search/search.test
@@ -236,13 +236,16 @@ class SearchMatchTestCase extends DrupalWebTestCase {
}
}
-class SearchBikeShed extends DrupalWebTestCase {
+/**
+ * Tests the bike shed text on no results page, and text on the search page.
+ */
+class SearchPageText extends DrupalWebTestCase {
protected $searching_user;
public static function getInfo() {
return array(
- 'name' => 'Bike shed',
- 'description' => 'Tests the bike shed text on the no results page.',
+ 'name' => 'Search page text',
+ 'description' => 'Tests the bike shed text on the no results page, and various other text on search pages.',
'group' => 'Search'
);
}
@@ -251,18 +254,31 @@ class SearchBikeShed extends DrupalWebTestCase {
parent::setUp('search');
// Create user.
- $this->searching_user = $this->drupalCreateUser(array('search content'));
+ $this->searching_user = $this->drupalCreateUser(array('search content', 'access user profiles'));
}
- function testFailedSearch() {
+ /**
+ * Tests the failed search text, and various other text on the search page.
+ */
+ function testSearchText() {
$this->drupalLogin($this->searching_user);
$this->drupalGet('search/node');
$this->assertText(t('Enter your keywords'));
+ $this->assertText(t('Search'));
+ $title = t('Search') . ' | Drupal';
+ $this->assertTitle($title, 'Search page title is correct');
$edit = array();
$edit['keys'] = 'bike shed ' . $this->randomName();
$this->drupalPost('search/node', $edit, t('Search'));
$this->assertText(t('Consider loosening your query with OR. bike OR shed will often show more results than bike shed.'), t('Help text is displayed when search returns no results.'));
+ $this->assertText(t('Search'));
+ $this->assertTitle($title, 'Search page title is correct');
+
+ $edit['keys'] = $this->searching_user->name;
+ $this->drupalPost('search/user', $edit, t('Search'));
+ $this->assertText(t('Search'));
+ $this->assertTitle($title, 'Search page title is correct');
}
}
diff --git a/modules/shortcut/shortcut.module b/modules/shortcut/shortcut.module
index 6217d1ed4..348c6f725 100644
--- a/modules/shortcut/shortcut.module
+++ b/modules/shortcut/shortcut.module
@@ -91,7 +91,6 @@ function shortcut_menu() {
'title arguments' => array(4),
'access callback' => 'shortcut_set_edit_access',
'access arguments' => array(4),
- 'type' => MENU_CALLBACK,
'file' => 'shortcut.admin.inc',
);
$items['admin/config/user-interface/shortcut/%shortcut_set/links'] = array(
@@ -114,7 +113,6 @@ function shortcut_menu() {
'page arguments' => array('shortcut_set_delete_form', 4),
'access callback' => 'shortcut_set_delete_access',
'access arguments' => array(4),
- 'type' => MENU_CALLBACK,
'file' => 'shortcut.admin.inc',
);
$items['admin/config/user-interface/shortcut/%shortcut_set/add-link'] = array(
@@ -141,7 +139,6 @@ function shortcut_menu() {
'page arguments' => array('shortcut_link_edit', 5),
'access callback' => 'shortcut_link_access',
'access arguments' => array(5),
- 'type' => MENU_CALLBACK,
'file' => 'shortcut.admin.inc',
);
$items['admin/config/user-interface/shortcut/link/%menu_link/delete'] = array(
@@ -150,7 +147,6 @@ function shortcut_menu() {
'page arguments' => array('shortcut_link_delete', 5),
'access callback' => 'shortcut_link_access',
'access arguments' => array(5),
- 'type' => MENU_CALLBACK,
'file' => 'shortcut.admin.inc',
);
$items['user/%user/shortcuts'] = array(
diff --git a/modules/simpletest/drupal_web_test_case.php b/modules/simpletest/drupal_web_test_case.php
index 5b1849dd6..16076d766 100644
--- a/modules/simpletest/drupal_web_test_case.php
+++ b/modules/simpletest/drupal_web_test_case.php
@@ -2738,7 +2738,14 @@ class DrupalWebTestCase extends DrupalTestCase {
* TRUE on pass, FALSE on fail.
*/
protected function assertTitle($title, $message = '', $group = 'Other') {
- return $this->assertEqual(current($this->xpath('//title')), $title, $message, $group);
+ $actual = (string) current($this->xpath('//title'));
+ if (!$message) {
+ $message = t('Page title @actual is equal to @expected.', array(
+ '@actual' => var_export($actual, TRUE),
+ '@expected' => var_export($title, TRUE),
+ ));
+ }
+ return $this->assertEqual($actual, $title, $message, $group);
}
/**
@@ -2754,7 +2761,14 @@ class DrupalWebTestCase extends DrupalTestCase {
* TRUE on pass, FALSE on fail.
*/
protected function assertNoTitle($title, $message = '', $group = 'Other') {
- return $this->assertNotEqual(current($this->xpath('//title')), $title, $message, $group);
+ $actual = (string) current($this->xpath('//title'));
+ if (!$message) {
+ $message = t('Page title @actual is not equal to @unexpected.', array(
+ '@actual' => var_export($actual, TRUE),
+ '@unexpected' => var_export($title, TRUE),
+ ));
+ }
+ return $this->assertNotEqual($actual, $title, $message, $group);
}
/**
@@ -3092,6 +3106,24 @@ class DrupalWebTestCase extends DrupalTestCase {
}
/**
+ * Assert the page did not return the specified response code.
+ *
+ * @param $code
+ * Response code. For example 200 is a successful page request. For a list
+ * of all codes see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html.
+ * @param $message
+ * Message to display.
+ *
+ * @return
+ * Assertion result.
+ */
+ protected function assertNoResponse($code, $message = '') {
+ $curl_code = curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE);
+ $match = is_array($code) ? in_array($curl_code, $code) : $curl_code == $code;
+ return $this->assertFalse($match, $message ? $message : t('HTTP response not expected !code, actual !curl_code', array('!code' => $code, '!curl_code' => $curl_code)), t('Browser'));
+ }
+
+ /**
* Asserts that the most recently sent e-mail message has the given value.
*
* The field in $name must have the content described in $value.
diff --git a/modules/simpletest/simpletest.module b/modules/simpletest/simpletest.module
index d19cc04d5..e734fe1da 100644
--- a/modules/simpletest/simpletest.module
+++ b/modules/simpletest/simpletest.module
@@ -56,7 +56,6 @@ function simpletest_menu() {
'page arguments' => array('simpletest_result_form', 5),
'description' => 'View result of tests.',
'access arguments' => array('administer unit tests'),
- 'type' => MENU_CALLBACK,
'file' => 'simpletest.pages.inc',
);
return $items;
diff --git a/modules/simpletest/tests/menu.test b/modules/simpletest/tests/menu.test
index 1dccb6e60..5857247ff 100644
--- a/modules/simpletest/tests/menu.test
+++ b/modules/simpletest/tests/menu.test
@@ -525,3 +525,555 @@ class MenuTreeDataTestCase extends DrupalUnitTestCase {
return $this->assert($link1['mlid'] == $link2['mlid'], $message ? $message : t('First link is identical to second link'));
}
}
+
+/**
+ * Menu breadcrumbs related tests.
+ */
+class MenuBreadcrumbTestCase extends DrupalWebTestCase {
+ public static function getInfo() {
+ return array(
+ 'name' => 'Breadcrumbs',
+ 'description' => 'Tests breadcrumbs functionality.',
+ 'group' => 'Menu',
+ );
+ }
+
+ function setUp() {
+ parent::setUp(array('menu_test'));
+ $perms = array_keys(module_invoke_all('permission'));
+ $this->admin_user = $this->drupalCreateUser($perms);
+ $this->drupalLogin($this->admin_user);
+ }
+
+ /**
+ * Tests breadcrumbs on node and administrative paths.
+ */
+ function testBreadCrumbs() {
+ // Prepare common base breadcrumb elements.
+ $home = array('<front>' => 'Home');
+ $admin = $home + array('admin' => t('Administer'));
+ $config = $admin + array('admin/config' => t('Configuration'));
+ $type = 'article';
+ $langcode = LANGUAGE_NONE;
+
+ // Verify breadcrumbs for default local tasks.
+ $expected = array(
+ 'menu-test' => t('Menu test root'),
+ );
+ $title = t('Breadcrumbs test: Local tasks');
+ $trail = $home + $expected;
+ $tree = $expected + array(
+ 'menu-test/breadcrumb/tasks' => $title,
+ );
+ $this->assertBreadcrumb('menu-test/breadcrumb/tasks', $trail, $title, $tree);
+ $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first', $trail, $title, $tree);
+ $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first/first', $trail, $title, $tree);
+ $trail += array(
+ 'menu-test/breadcrumb/tasks' => t('Breadcrumbs test: Local tasks'),
+ );
+ $this->assertBreadcrumb('menu-test/breadcrumb/tasks/first/second', $trail, $title, $tree);
+ $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second', $trail, $title, $tree);
+ $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second/first', $trail, $title, $tree);
+ $trail += array(
+ 'menu-test/breadcrumb/tasks/second' => t('Second'),
+ );
+ $this->assertBreadcrumb('menu-test/breadcrumb/tasks/second/second', $trail, $title, $tree);
+
+ // Verify Taxonomy administration breadcrumbs.
+ $trail = $admin + array(
+ 'admin/structure' => t('Structure'),
+ );
+ $this->assertBreadcrumb('admin/structure/taxonomy', $trail);
+
+ $trail += array(
+ 'admin/structure/taxonomy' => t('Taxonomy'),
+ );
+ $this->assertBreadcrumb('admin/structure/taxonomy/tags', $trail);
+ $trail += array(
+ 'admin/structure/taxonomy/tags' => t('Tags'),
+ );
+ $this->assertBreadcrumb('admin/structure/taxonomy/tags/edit', $trail);
+ $this->assertBreadcrumb('admin/structure/taxonomy/tags/fields', $trail);
+ $this->assertBreadcrumb('admin/structure/taxonomy/tags/add', $trail);
+
+ // Verify Menu administration breadcrumbs.
+ $trail = $admin + array(
+ 'admin/structure' => t('Structure'),
+ );
+ $this->assertBreadcrumb('admin/structure/menu', $trail);
+
+ $trail += array(
+ 'admin/structure/menu' => t('Menus'),
+ );
+ $this->assertBreadcrumb('admin/structure/menu/manage/navigation', $trail);
+ $trail += array(
+ 'admin/structure/menu/manage/navigation' => t('Navigation'),
+ );
+ $this->assertBreadcrumb('admin/structure/menu/manage/navigation/edit', $trail);
+ $this->assertBreadcrumb('admin/structure/menu/manage/navigation/add', $trail);
+
+ // Verify Node administration breadcrumbs.
+ $trail = $admin + array(
+ 'admin/structure' => t('Structure'),
+ 'admin/structure/types' => t('Content types'),
+ );
+ $this->assertBreadcrumb('admin/structure/types/add', $trail);
+ $this->assertBreadcrumb("admin/structure/types/manage/$type", $trail);
+ $trail += array(
+ "admin/structure/types/manage/$type" => t('Article'),
+ );
+ $this->assertBreadcrumb("admin/structure/types/manage/$type/fields", $trail);
+ $this->assertBreadcrumb("admin/structure/types/manage/$type/display", $trail);
+ $trail_teaser = $trail + array(
+ "admin/structure/types/manage/$type/display" => t('Manage display'),
+ );
+ $this->assertBreadcrumb("admin/structure/types/manage/$type/display/teaser", $trail_teaser);
+ $this->assertBreadcrumb("admin/structure/types/manage/$type/comment/fields", $trail);
+ $this->assertBreadcrumb("admin/structure/types/manage/$type/comment/display", $trail);
+ $this->assertBreadcrumb("admin/structure/types/manage/$type/delete", $trail);
+ $trail += array(
+ "admin/structure/types/manage/$type/fields" => t('Manage fields'),
+ );
+ $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body", $trail);
+ $trail += array(
+ "admin/structure/types/manage/$type/fields/body" => t('Body'),
+ );
+ $this->assertBreadcrumb("admin/structure/types/manage/$type/fields/body/widget-type", $trail);
+
+ // Verify Filter text format administration breadcrumbs.
+ $format = db_query_range("SELECT format, name FROM {filter_format}", 1, 1)->fetch();
+ $format_id = $format->format;
+ $trail = $config + array(
+ 'admin/config/content' => t('Content authoring'),
+ );
+ $this->assertBreadcrumb('admin/config/content/formats', $trail);
+
+ $trail += array(
+ 'admin/config/content/formats' => t('Text formats'),
+ );
+ $this->assertBreadcrumb('admin/config/content/formats/add', $trail);
+ $this->assertBreadcrumb("admin/config/content/formats/$format_id", $trail);
+ $trail += array(
+ "admin/config/content/formats/$format_id" => $format->name,
+ );
+ $this->assertBreadcrumb("admin/config/content/formats/$format_id/disable", $trail);
+
+ // Verify node breadcrumbs (without menu link).
+ $node1 = $this->drupalCreateNode();
+ $nid1 = $node1->nid;
+ $trail = $home;
+ $this->assertBreadcrumb("node/$nid1", $trail);
+ // Also verify that the node does not appear elsewhere (e.g., menu trees).
+ $this->assertNoLink($node1->title);
+ // The node itself should not be contained in the breadcrumb on the default
+ // local task, since there is no difference between both pages.
+ $this->assertBreadcrumb("node/$nid1/view", $trail);
+ // Also verify that the node does not appear elsewhere (e.g., menu trees).
+ $this->assertNoLink($node1->title);
+
+ $trail += array(
+ "node/$nid1" => $node1->title,
+ );
+ $this->assertBreadcrumb("node/$nid1/edit", $trail);
+
+ // Verify that breadcrumb on node listing page contains "Home" only.
+ $trail = array();
+ $this->assertBreadcrumb('node', $trail);
+
+ // Verify node breadcrumbs (in menu).
+ // Do this separately for Main menu and Navigation menu, since only the
+ // latter is a preferred menu by default.
+ // @todo Also test all themes? Manually testing led to the suspicion that
+ // breadcrumbs may differ, possibly due to template.php overrides.
+ $menus = array('main-menu', 'navigation');
+ // Alter node type menu settings.
+ variable_set("menu_options_$type", $menus);
+ variable_set("menu_parent_$type", 'navigation:0');
+
+ foreach ($menus as $menu) {
+ // Create a parent node in the current menu.
+ $title = $this->randomName();
+ $node2 = $this->drupalCreateNode(array(
+ 'type' => $type,
+ 'title' => $title,
+ 'menu' => array(
+ 'enabled' => 1,
+ 'link_title' => 'Parent ' . $title,
+ 'description' => '',
+ 'menu_name' => $menu,
+ 'plid' => 0,
+ ),
+ ));
+ $nid2 = $node2->nid;
+
+ $trail = $home;
+ $tree = array(
+ "node/$nid2" => $node2->menu['link_title'],
+ );
+ $this->assertBreadcrumb("node/$nid2", $trail, $node2->title, $tree);
+ // The node itself should not be contained in the breadcrumb on the
+ // default local task, since there is no difference between both pages.
+ $this->assertBreadcrumb("node/$nid2/view", $trail, $node2->title, $tree);
+ $trail += array(
+ "node/$nid2" => $node2->menu['link_title'],
+ );
+ $this->assertBreadcrumb("node/$nid2/edit", $trail);
+
+ // Create a child node in the current menu.
+ $title = $this->randomName();
+ $node3 = $this->drupalCreateNode(array(
+ 'type' => $type,
+ 'title' => $title,
+ 'menu' => array(
+ 'enabled' => 1,
+ 'link_title' => 'Child ' . $title,
+ 'description' => '',
+ 'menu_name' => $menu,
+ 'plid' => $node2->menu['mlid'],
+ ),
+ ));
+ $nid3 = $node3->nid;
+
+ $this->assertBreadcrumb("node/$nid3", $trail, $node3->title, $tree, FALSE);
+ // The node itself should not be contained in the breadcrumb on the
+ // default local task, since there is no difference between both pages.
+ $this->assertBreadcrumb("node/$nid3/view", $trail, $node3->title, $tree, FALSE);
+ $trail += array(
+ "node/$nid3" => $node3->menu['link_title'],
+ );
+ $tree += array(
+ "node/$nid3" => $node3->menu['link_title'],
+ );
+ $this->assertBreadcrumb("node/$nid3/edit", $trail);
+
+ // Verify that node listing page still contains "Home" only.
+ $trail = array();
+ $this->assertBreadcrumb('node', $trail);
+
+ if ($menu == 'navigation') {
+ $parent = $node2;
+ $child = $node3;
+ }
+ }
+
+ // Create a Navigation menu link for 'node', move the last parent node menu
+ // link below it, and verify a full breadcrumb for the last child node.
+ $menu = 'navigation';
+ $edit = array(
+ 'link_title' => 'Root',
+ 'link_path' => 'node',
+ );
+ $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
+ $link = db_query('SELECT * FROM {menu_links} WHERE link_title = :title', array(':title' => 'Root'))->fetchAssoc();
+
+ $edit = array(
+ 'menu[parent]' => $link['menu_name'] . ':' . $link['mlid'],
+ );
+ $this->drupalPost("node/{$parent->nid}/edit", $edit, t('Save'));
+ $expected = array(
+ "node" => $link['link_title'],
+ );
+ $trail = $home + $expected;
+ $tree = $expected + array(
+ "node/{$parent->nid}" => $parent->menu['link_title'],
+ );
+ $this->assertBreadcrumb(NULL, $trail, $parent->title, $tree);
+ $trail += array(
+ "node/{$parent->nid}" => $parent->menu['link_title'],
+ );
+ $tree += array(
+ "node/{$child->nid}" => $child->menu['link_title'],
+ );
+ $this->assertBreadcrumb("node/{$child->nid}", $trail, $child->title, $tree);
+
+ // Add a taxonomy term/tag to last node, and add a link for that term to the
+ // Navigation menu.
+ $tags = array(
+ 'Drupal' => array(),
+ 'Breadcrumbs' => array(),
+ );
+ $edit = array(
+ "field_tags[$langcode]" => implode(',', array_keys($tags)),
+ );
+ $this->drupalPost("node/{$parent->nid}/edit", $edit, t('Save'));
+
+ // Put both terms into a hierarchy Drupal » Breadcrumbs. Required for both
+ // the menu links and the terms itself, since taxonomy_term_page() resets
+ // the breadcrumb based on taxonomy term hierarchy.
+ $parent_tid = 0;
+ foreach ($tags as $name => $null) {
+ $terms = taxonomy_term_load_multiple(NULL, array('name' => $name));
+ $term = reset($terms);
+ $tags[$name]['term'] = $term;
+ if ($parent_tid) {
+ $edit = array(
+ 'parent[]' => array($parent_tid),
+ );
+ $this->drupalPost("taxonomy/term/{$term->tid}/edit", $edit, t('Save'));
+ }
+ $parent_tid = $term->tid;
+ }
+ $parent_mlid = 0;
+ foreach ($tags as $name => $data) {
+ $term = $data['term'];
+ $edit = array(
+ 'link_title' => "$name link",
+ 'link_path' => "taxonomy/term/{$term->tid}",
+ 'parent' => "$menu:{$parent_mlid}",
+ );
+ $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
+ $tags[$name]['link'] = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array(
+ ':title' => $edit['link_title'],
+ ':href' => $edit['link_path'],
+ ))->fetchAssoc();
+ $tags[$name]['link']['link_path'] = $edit['link_path'];
+ $parent_mlid = $tags[$name]['link']['mlid'];
+ }
+
+ // Verify expected breadcrumbs for menu links.
+ $trail = $home;
+ $tree = array();
+ foreach ($tags as $name => $data) {
+ $term = $data['term'];
+ $link = $data['link'];
+
+ $tree += array(
+ $link['link_path'] => $link['link_title'],
+ );
+ // @todo Normally, you'd expect $term->name as page title here.
+ $this->assertBreadcrumb($link['link_path'], $trail, $link['link_title'], $tree);
+ $this->assertRaw(check_plain($parent->title), 'Tagged node found.');
+
+ // Additionally make sure that this link appears only once; i.e., the
+ // untranslated menu links automatically generated from menu router items
+ // ('taxonomy/term/%') should never be translated and appear in any menu
+ // other than the breadcrumb trail.
+ $elements = $this->xpath('//div[@id=:menu]/descendant::a[@href=:href]', array(
+ ':menu' => 'block-system-navigation',
+ ':href' => url($link['link_path']),
+ ));
+ $this->assertTrue(count($elements) == 1, "Link to {$link['link_path']} appears only once.");
+
+ // Next iteration should expect this tag as parent link.
+ // Note: Term name, not link name, due to taxonomy_term_page().
+ $trail += array(
+ $link['link_path'] => $term->name,
+ );
+ }
+
+ // Verify breadcrumbs on user and user/%.
+ // We need to log back in and out below, and cannot simply grant the
+ // 'administer users' permission, since user_page() makes your head explode.
+ user_role_grant_permissions(DRUPAL_ANONYMOUS_RID, array(
+ 'access user profiles',
+ ));
+ $this->drupalLogout();
+
+ // Verify breadcrumb on front page.
+ $this->assertBreadcrumb('<front>', array());
+
+ $trail = $home;
+ $this->assertBreadcrumb('user', $trail, t('User account'));
+ $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $this->admin_user->name);
+
+ $this->drupalLogin($this->admin_user);
+ $trail += array(
+ 'user/' . $this->admin_user->uid => $this->admin_user->name,
+ );
+ $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $this->admin_user->name);
+
+ // Add a Navigation menu links for 'user' and $this->admin_user.
+ // Although it may be faster to manage these links via low-level API
+ // functions, there's a lot that can go wrong in doing so.
+ $edit = array(
+ 'link_title' => 'User',
+ 'link_path' => 'user',
+ );
+ $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
+ $link_user = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array(
+ ':title' => $edit['link_title'],
+ ':href' => $edit['link_path'],
+ ))->fetchAssoc();
+
+ $edit = array(
+ 'link_title' => $this->admin_user->name . ' link',
+ 'link_path' => 'user/' . $this->admin_user->uid,
+ );
+ $this->drupalPost("admin/structure/menu/manage/$menu/add", $edit, t('Save'));
+ $link_admin_user = db_query('SELECT * FROM {menu_links} WHERE link_title = :title AND link_path = :href', array(
+ ':title' => $edit['link_title'],
+ ':href' => $edit['link_path'],
+ ))->fetchAssoc();
+
+ // Verify expected breadcrumbs for the two separate links.
+ $this->drupalLogout();
+ $trail = $home;
+ $tree = array(
+ $link_user['link_path'] => $link_user['link_title'],
+ );
+ $this->assertBreadcrumb('user', $trail, $link_user['link_title'], $tree);
+ $tree = array(
+ $link_admin_user['link_path'] => $link_admin_user['link_title'],
+ );
+ $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $link_admin_user['link_title'], $tree);
+
+ $this->drupalLogin($this->admin_user);
+ $trail += array(
+ $link_admin_user['link_path'] => $link_admin_user['link_title'],
+ );
+ $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $link_admin_user['link_title'], $tree, FALSE);
+
+ // Move 'user/%' below 'user' and verify again.
+ $edit = array(
+ 'parent' => "$menu:{$link_user['mlid']}",
+ );
+ $this->drupalPost("admin/structure/menu/item/{$link_admin_user['mlid']}/edit", $edit, t('Save'));
+
+ $this->drupalLogout();
+ $trail = $home;
+ $tree = array(
+ $link_user['link_path'] => $link_user['link_title'],
+ );
+ $this->assertBreadcrumb('user', $trail, $link_user['link_title'], $tree);
+ $trail += array(
+ $link_user['link_path'] => $link_user['link_title'],
+ );
+ $tree += array(
+ $link_admin_user['link_path'] => $link_admin_user['link_title'],
+ );
+ $this->assertBreadcrumb('user/' . $this->admin_user->uid, $trail, $link_admin_user['link_title'], $tree);
+
+ $this->drupalLogin($this->admin_user);
+ $trail += array(
+ $link_admin_user['link_path'] => $link_admin_user['link_title'],
+ );
+ $this->assertBreadcrumb('user/' . $this->admin_user->uid . '/edit', $trail, $link_admin_user['link_title'], $tree, FALSE);
+
+ // Create an only slightly privileged user being able to access site reports
+ // but not administration pages.
+ $this->web_user = $this->drupalCreateUser(array(
+ 'access site reports',
+ ));
+ $this->drupalLogin($this->web_user);
+
+ // Verify that we can access recent log entries, there is a corresponding
+ // page title, and that the breadcrumb is empty (because the user is not
+ // able to access "Administer", so the trail cannot recurse into it).
+ $trail = array();
+ $this->assertBreadcrumb('admin', $trail, t('Access denied'));
+ $this->assertResponse(403);
+
+ $trail = $home;
+ $this->assertBreadcrumb('admin/reports', $trail, t('Reports'));
+ $this->assertNoResponse(403);
+
+ $this->assertBreadcrumb('admin/reports/dblog', $trail, t('Recent log messages'));
+ $this->assertNoResponse(403);
+ }
+
+ /**
+ * Assert that a given path shows certain breadcrumb links.
+ *
+ * @param string $goto
+ * (optional) A system path to pass to DrupalWebTestCase::drupalGet().
+ * @param array $trail
+ * An associative array whose keys are expected breadcrumb link paths and
+ * whose values are expected breadcrumb link texts (not sanitized).
+ * @param string $page_title
+ * (optional) A page title to additionally assert via
+ * DrupalWebTestCase::assertTitle(). Without site name suffix.
+ * @param array $tree
+ * (optional) An associative array whose keys are link paths and whose
+ * values are link titles (not sanitized) of an expected active trail in a
+ * menu tree output on the page.
+ * @param $last_active
+ * (optional) Whether the last link in $tree is expected to be active (TRUE)
+ * or just to be in the active trail (FALSE).
+ */
+ protected function assertBreadcrumb($goto, array $trail, $page_title = NULL, array $tree = array(), $last_active = TRUE) {
+ if (isset($goto)) {
+ $this->drupalGet($goto);
+ }
+ // Compare paths with actual breadcrumb.
+ $parts = $this->getParts();
+ $pass = TRUE;
+ foreach ($trail as $path => $title) {
+ $url = url($path);
+ $part = array_shift($parts);
+ $pass = ($pass && $part['href'] === $url && $part['text'] === check_plain($title));
+ }
+ // No parts must be left, or an expected "Home" will always pass.
+ $pass = ($pass && empty($parts));
+
+ $this->assertTrue($pass, t('Breadcrumb %parts found on @path.', array(
+ '%parts' => implode(' » ', $trail),
+ '@path' => $this->getUrl(),
+ )));
+
+ // Additionally assert page title, if given.
+ if (isset($page_title)) {
+ $this->assertTitle(strtr('@title | Drupal', array('@title' => $page_title)));
+ }
+
+ // Additionally assert active trail in a menu tree output, if given.
+ if ($tree) {
+ end($tree);
+ $active_link_path = key($tree);
+ $active_link_title = array_pop($tree);
+ $xpath = '';
+ if ($tree) {
+ $i = 0;
+ foreach ($tree as $link_path => $link_title) {
+ $part_xpath = (!$i ? '//' : '/following-sibling::ul/descendant::');
+ $part_xpath .= 'li[contains(@class, :class)]/a[contains(@href, :href) and contains(text(), :title)]';
+ $part_args = array(
+ ':class' => 'active-trail',
+ ':href' => url($link_path),
+ ':title' => $link_title,
+ );
+ $xpath .= $this->buildXPathQuery($part_xpath, $part_args);
+ $i++;
+ }
+ $elements = $this->xpath($xpath);
+ $this->assertTrue(!empty($elements), t('Active trail to current page was found in menu tree.'));
+
+ // Append prefix for active link asserted below.
+ $xpath .= '/following-sibling::ul/descendant::';
+ }
+ else {
+ $xpath .= '//';
+ }
+ $xpath_last_active = ($last_active ? 'and contains(@class, :class-active)' : '');
+ $xpath .= 'li[contains(@class, :class-trail)]/a[contains(@href, :href) ' . $xpath_last_active . 'and contains(text(), :title)]';
+ $args = array(
+ ':class-trail' => 'active-trail',
+ ':class-active' => 'active',
+ ':href' => url($active_link_path),
+ ':title' => $active_link_title,
+ );
+ $elements = $this->xpath($xpath, $args);
+ $this->assertTrue(!empty($elements), t('Active link %title was found in menu tree, including active trail links %tree.', array(
+ '%title' => $active_link_title,
+ '%tree' => implode(' » ', $tree),
+ )));
+ }
+ }
+
+ /**
+ * Returns the breadcrumb contents of the current page in the internal browser.
+ */
+ protected function getParts() {
+ $parts = array();
+ $elements = $this->xpath('//div[@class="breadcrumb"]/a');
+ if (!empty($elements)) {
+ foreach ($elements as $element) {
+ $parts[] = array(
+ 'text' => (string) $element,
+ 'href' => (string) $element['href'],
+ 'title' => (string) $element['title'],
+ );
+ }
+ }
+ return $parts;
+ }
+}
diff --git a/modules/simpletest/tests/menu_test.module b/modules/simpletest/tests/menu_test.module
index 8bab8a208..340b8067a 100644
--- a/modules/simpletest/tests/menu_test.module
+++ b/modules/simpletest/tests/menu_test.module
@@ -77,7 +77,7 @@ function menu_test_menu() {
'access arguments' => array('access content'),
);
$items['menu-test/hidden'] = array(
- 'title' => 'Menu test parent',
+ 'title' => 'Hidden test root',
'page callback' => 'node_page_default',
'access arguments' => array('access content'),
);
@@ -110,7 +110,6 @@ function menu_test_menu() {
'title' => 'Customize menu',
'page callback' => 'node_page_default',
'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
);
$items['menu-test/hidden/menu/manage/%menu/list'] = array(
'title' => 'List links',
@@ -135,7 +134,6 @@ function menu_test_menu() {
'title' => 'Delete menu',
'page callback' => 'node_page_default',
'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
);
// Hidden tests; two dynamic arguments.
@@ -173,6 +171,41 @@ function menu_test_menu() {
'context' => MENU_CONTEXT_NONE,
);
+ // Breadcrumbs tests.
+ // @see MenuBreadcrumbTestCase
+ $base = array(
+ 'page callback' => 'menu_test_callback',
+ 'access callback' => TRUE,
+ );
+ // Local tasks: Second level below default local task.
+ $items['menu-test/breadcrumb/tasks'] = array(
+ 'title' => 'Breadcrumbs test: Local tasks',
+ ) + $base;
+ $items['menu-test/breadcrumb/tasks/first'] = array(
+ 'title' => 'First',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ ) + $base;
+ $items['menu-test/breadcrumb/tasks/second'] = array(
+ 'title' => 'Second',
+ 'type' => MENU_LOCAL_TASK,
+ ) + $base;
+ $items['menu-test/breadcrumb/tasks/first/first'] = array(
+ 'title' => 'First first',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ ) + $base;
+ $items['menu-test/breadcrumb/tasks/first/second'] = array(
+ 'title' => 'First second',
+ 'type' => MENU_LOCAL_TASK,
+ ) + $base;
+ $items['menu-test/breadcrumb/tasks/second/first'] = array(
+ 'title' => 'Second first',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ ) + $base;
+ $items['menu-test/breadcrumb/tasks/second/second'] = array(
+ 'title' => 'Second second',
+ 'type' => MENU_LOCAL_TASK,
+ ) + $base;
+
// File inheritance tests. This menu item should inherit the page callback
// system_admin_menu_block_page() and therefore render its children as links
// on the page.
diff --git a/modules/statistics/statistics.module b/modules/statistics/statistics.module
index e40e16fd9..0e093fe5f 100644
--- a/modules/statistics/statistics.module
+++ b/modules/statistics/statistics.module
@@ -163,7 +163,6 @@ function statistics_menu() {
'page callback' => 'statistics_access_log',
'page arguments' => array(3),
'access arguments' => array('access statistics'),
- 'type' => MENU_CALLBACK,
'file' => 'statistics.admin.inc',
);
$items['admin/config/system/statistics'] = array(
diff --git a/modules/statistics/statistics.test b/modules/statistics/statistics.test
index 31b13b95a..cbc58ae13 100644
--- a/modules/statistics/statistics.test
+++ b/modules/statistics/statistics.test
@@ -10,7 +10,15 @@ class StatisticsTestCase extends DrupalWebTestCase {
parent::setUp('statistics');
// Create user.
- $this->blocking_user = $this->drupalCreateUser(array('block IP addresses', 'access statistics', 'administer blocks', 'administer statistics', 'administer users'));
+ $this->blocking_user = $this->drupalCreateUser(array(
+ 'access administration pages',
+ 'access site reports',
+ 'access statistics',
+ 'block IP addresses',
+ 'administer blocks',
+ 'administer statistics',
+ 'administer users',
+ ));
$this->drupalLogin($this->blocking_user);
// Enable access logging.
diff --git a/modules/system/system.api.php b/modules/system/system.api.php
index e7903e86d..3fc5bbfe2 100644
--- a/modules/system/system.api.php
+++ b/modules/system/system.api.php
@@ -1200,6 +1200,53 @@ function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) {
}
/**
+ * Alter links in the active trail before it is rendered as the breadcrumb.
+ *
+ * This hook is invoked by menu_get_active_breadcrumb() and allows alteration
+ * of the breadcrumb links for the current page, which may be preferred instead
+ * of setting a custom breadcrumb via drupal_set_breadcrumb().
+ *
+ * Implementations should take into account that menu_get_active_breadcrumb()
+ * subsequently performs the following adjustments to the active trail *after*
+ * this hook has been invoked:
+ * - The last link in $active_trail is removed, if its 'href' is identical to
+ * the 'href' of $item. This happens, because the breadcrumb normally does
+ * not contain a link to the current page.
+ * - The (second to) last link in $active_trail is removed, if the current $item
+ * is a MENU_DEFAULT_LOCAL_TASK. This happens in order to do not show a link
+ * to the current page, when being on the path for the default local task;
+ * e.g. when being on the path node/%/view, the breadcrumb should not contain
+ * a link to node/%.
+ *
+ * Each link in the active trail must contain:
+ * - title: The localized title of the link.
+ * - href: The system path to link to.
+ * - localized_options: An array of options to pass to url().
+ *
+ * @param $active_trail
+ * An array containing breadcrumb links for the current page.
+ * @param $item
+ * The menu router item of the current page.
+ *
+ * @see drupal_set_breadcrumb()
+ * @see menu_get_active_breadcrumb()
+ * @see menu_get_active_trail()
+ * @see menu_set_active_trail()
+ */
+function hook_menu_breadcrumb_alter(&$active_trail, $item) {
+ // Always display a link to the current page by duplicating the last link in
+ // the active trail. This means that menu_get_active_breadcrumb() will remove
+ // the last link (for the current page), but since it is added once more here,
+ // it will appear.
+ if (!drupal_is_front_page()) {
+ $end = end($active_trail);
+ if ($item['href'] == $end['href']) {
+ $active_trail[] = $end;
+ }
+ }
+}
+
+/**
* Alter contextual links before they are rendered.
*
* This hook is invoked by menu_contextual_links(). The system-determined
diff --git a/modules/system/system.module b/modules/system/system.module
index 134a51e5f..865eec1f1 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -648,7 +648,6 @@ function system_menu() {
$items['admin/modules/list/confirm'] = array(
'title' => 'List',
'access arguments' => array('administer modules'),
- 'type' => MENU_CALLBACK,
);
$items['admin/modules/uninstall'] = array(
'title' => 'Uninstall',
@@ -661,7 +660,6 @@ function system_menu() {
$items['admin/modules/uninstall/confirm'] = array(
'title' => 'Uninstall',
'access arguments' => array('administer modules'),
- 'type' => MENU_CALLBACK,
'file' => 'system.admin.inc',
);
@@ -688,7 +686,6 @@ function system_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('system_ip_blocking_delete', 5),
'access arguments' => array('block IP addresses'),
- 'type' => MENU_CALLBACK,
'file' => 'system.admin.inc',
);
@@ -829,7 +826,6 @@ function system_menu() {
$items['admin/config/regional/date-time/types/%/delete'] = array(
'title' => 'Delete date type',
'description' => 'Allow users to delete a configured date type.',
- 'type' => MENU_CALLBACK,
'page callback' => 'drupal_get_form',
'page arguments' => array('system_delete_date_format_type_form', 5),
'access arguments' => array('administer site configuration'),
@@ -857,7 +853,6 @@ function system_menu() {
$items['admin/config/regional/date-time/formats/%/edit'] = array(
'title' => 'Edit date format',
'description' => 'Allow users to edit a configured date format.',
- 'type' => MENU_CALLBACK,
'page callback' => 'drupal_get_form',
'page arguments' => array('system_configure_date_formats_form', 5),
'access arguments' => array('administer site configuration'),
@@ -866,7 +861,6 @@ function system_menu() {
$items['admin/config/regional/date-time/formats/%/delete'] = array(
'title' => 'Delete date format',
'description' => 'Allow users to delete a configured date format.',
- 'type' => MENU_CALLBACK,
'page callback' => 'drupal_get_form',
'page arguments' => array('system_date_delete_format_form', 5),
'access arguments' => array('administer site configuration'),
@@ -874,7 +868,6 @@ function system_menu() {
);
$items['admin/config/regional/date-time/formats/lookup'] = array(
'title' => 'Date and time lookup',
- 'type' => MENU_CALLBACK,
'page callback' => 'system_date_time_lookup',
'access arguments' => array('administer site configuration'),
'file' => 'system.admin.inc',
@@ -938,7 +931,6 @@ function system_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('system_actions_configure'),
'access arguments' => array('administer actions'),
- 'type' => MENU_CALLBACK,
'file' => 'system.admin.inc',
);
$items['admin/config/system/actions/delete/%actions'] = array(
@@ -947,7 +939,6 @@ function system_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('system_actions_delete_form', 5),
'access arguments' => array('administer actions'),
- 'type' => MENU_CALLBACK,
'file' => 'system.admin.inc',
);
$items['admin/config/system/actions/orphan'] = array(
diff --git a/modules/system/system.test b/modules/system/system.test
index 5e75910d1..3fe9ac11d 100644
--- a/modules/system/system.test
+++ b/modules/system/system.test
@@ -653,8 +653,7 @@ class AccessDeniedTestCase extends DrupalWebTestCase {
parent::setUp();
// Create an administrative user.
- $this->admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer blocks'));
- $this->drupalLogin($this->admin_user);
+ $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'administer site configuration', 'administer blocks'));
}
function testAccessDenied() {
@@ -662,6 +661,7 @@ class AccessDeniedTestCase extends DrupalWebTestCase {
$this->assertText(t('Access denied'), t('Found the default 403 page'));
$this->assertResponse(403);
+ $this->drupalLogin($this->admin_user);
$edit = array(
'title' => $this->randomName(10),
'body' => array(LANGUAGE_NONE => array(array('value' => $this->randomName(100)))),
@@ -671,6 +671,7 @@ class AccessDeniedTestCase extends DrupalWebTestCase {
// Use a custom 403 page.
$this->drupalPost('admin/config/system/site-information', array('site_403' => 'node/' . $node->nid), t('Save configuration'));
+ $this->drupalLogout();
$this->drupalGet('admin');
$this->assertText($node->title, t('Found the custom 403 page'));
diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module
index 3d06f111f..ae3debc19 100644
--- a/modules/taxonomy/taxonomy.module
+++ b/modules/taxonomy/taxonomy.module
@@ -287,7 +287,6 @@ function taxonomy_menu() {
'page callback' => 'taxonomy_term_page',
'page arguments' => array(2),
'access arguments' => array('access content'),
- 'type' => MENU_CALLBACK,
'file' => 'taxonomy.pages.inc',
);
$items['taxonomy/term/%taxonomy_term/view'] = array(
diff --git a/modules/taxonomy/taxonomy.pages.inc b/modules/taxonomy/taxonomy.pages.inc
index 1af17db7e..47433a6a8 100644
--- a/modules/taxonomy/taxonomy.pages.inc
+++ b/modules/taxonomy/taxonomy.pages.inc
@@ -19,6 +19,8 @@ function taxonomy_term_page($term) {
$current = (object) array(
'tid' => $term->tid,
);
+ // @todo This overrides any other possible breadcrumb and is a pure hard-coded
+ // presumption. Make this behavior configurable per vocabulary or term.
$breadcrumb = array();
while ($parents = taxonomy_get_parents($current->tid)) {
$current = array_shift($parents);
diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test
index a9938b087..b71cc62c5 100644
--- a/modules/taxonomy/taxonomy.test
+++ b/modules/taxonomy/taxonomy.test
@@ -557,7 +557,7 @@ class TaxonomyTermTestCase extends TaxonomyWebTestCase {
// the first edit link found on the listing page is to our term.
$this->clickLink(t('edit'));
- $this->assertText($edit['name'], t('The randomly generated term name is present.'));
+ $this->assertRaw($edit['name'], t('The randomly generated term name is present.'));
$this->assertText($edit['description[value]'], t('The randomly generated term description is present.'));
$edit = array(
@@ -939,7 +939,7 @@ class TaxonomyTermFieldTestCase extends TaxonomyWebTestCase {
"{$this->field_name}[$langcode]" => array($term->tid),
);
$this->drupalPost(NULL, $edit, t('Save'));
- preg_match('|test-entity/(\d+)/edit|', $this->url, $match);
+ preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
$id = $match[1];
$this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Entity was created'));
diff --git a/modules/trigger/trigger.module b/modules/trigger/trigger.module
index 7a55e623e..852c23d9c 100644
--- a/modules/trigger/trigger.module
+++ b/modules/trigger/trigger.module
@@ -80,7 +80,6 @@ function trigger_menu() {
'page callback' => 'drupal_get_form',
'page arguments' => array('trigger_unassign'),
'access arguments' => array('administer actions'),
- 'type' => MENU_CALLBACK,
'file' => 'trigger.admin.inc',
);
diff --git a/modules/user/user.module b/modules/user/user.module
index b43b689fd..53172a83c 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -1522,7 +1522,12 @@ function user_menu() {
'title' => 'User account',
'page callback' => 'user_page',
'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
+ // Edge-case: No menu links should be auto-generated for this and below
+ // items, which makes it a MENU_CALLBACK. However, this item's title is
+ // expected to appear on user login, register, and password pages, so we
+ // need to use MENU_VISIBLE_IN_BREADCRUMB to make
+ // menu_get_active_breadcrumb() account for it.
+ 'type' => MENU_VISIBLE_IN_BREADCRUMB,
'file' => 'user.pages.inc',
);
@@ -1617,7 +1622,6 @@ function user_menu() {
'page arguments' => array('user_admin_role', 5),
'access callback' => 'user_role_edit_access',
'access arguments' => array(5),
- 'type' => MENU_CALLBACK,
);
$items['admin/people/permissions/roles/delete/%user_role'] = array(
'title' => 'Delete role',
@@ -1625,7 +1629,6 @@ function user_menu() {
'page arguments' => array('user_admin_role_delete_confirm', 5),
'access callback' => 'user_role_edit_access',
'access arguments' => array(5),
- 'type' => MENU_CALLBACK,
'file' => 'user.admin.inc',
);
@@ -1688,7 +1691,6 @@ function user_menu() {
'page arguments' => array('user_cancel_confirm_form', 1),
'access callback' => 'user_cancel_access',
'access arguments' => array(1),
- 'type' => MENU_CALLBACK,
'file' => 'user.pages.inc',
);
@@ -1698,7 +1700,6 @@ function user_menu() {
'page arguments' => array(1, 4, 5),
'access callback' => 'user_cancel_access',
'access arguments' => array(1),
- 'type' => MENU_CALLBACK,
'file' => 'user.pages.inc',
);