=== modified file 'includes/menu.inc' --- includes/menu.inc 2007-01-31 21:55:37 +0000 +++ includes/menu.inc 2007-02-06 09:39:09 +0000 @@ -172,22 +172,35 @@ define('MENU_SITE_OFFLINE', 4); */ /** + * @Name Menu operations + * @{ + * Menu helper possible operations. + */ + +define('MENU_HANDLE_REQUEST', 0); +define('MENU_RENDER_LINK', 1); + +/** + * @} End of "Menu helper directions + */ + +/** * Returns the ancestors (and relevant placeholders) for any given path. * * For example, the ancestors of node/12345/edit are: * * node/12345/edit - * node/12345/% - * node/%/edit - * node/%/% + * node/12345/[] + * node/[]/edit + * node/[]/[] * node/12345 - * node/% + * node/[] * node * * To generate these, we will use binary numbers. Each bit represents a * part of the path. If the bit is 1, then it represents the original * value while 0 means wildcard. If the path is node/12/edit/foo - * then the 1011 bitstring represents node/%/edit/foo where % means that + * then the 1011 bitstring represents node/[]/edit/foo where [] means that * any argument matches that part. * * @param $parts @@ -195,7 +208,7 @@ define('MENU_SITE_OFFLINE', 4); * array('node', '12345', 'edit'). * @return * An array which contains the ancestors and placeholders. Placeholders - * simply contain as many %s as the ancestors. + * simply contain as many '%s' as the ancestors. */ function menu_get_ancestors($parts) { $n1 = count($parts); @@ -212,7 +225,7 @@ function menu_get_ancestors($parts) { $current .= $parts[$length - $j]; } else { - $current .= '%'; + $current .= '[]'; } if ($j) { $current .= '/'; @@ -273,10 +286,10 @@ function menu_unserialize($data, $map) { * with keys like title, access callback, access arguments etc. */ function menu_set_item($path, $item) { - menu_get_item($path, TRUE, $item); + menu_get_item($path, $item); } -function menu_get_item($path = NULL, $execute = TRUE, $item = NULL) { +function menu_get_item($path = NULL, $item = NULL) { static $items; if (!isset($path)) { $path = $_GET['q']; @@ -289,14 +302,13 @@ function menu_get_item($path = NULL, $ex $parts = array_slice($map, 0, 6); list($ancestors, $placeholders) = menu_get_ancestors($parts); if ($item = db_fetch_object(db_query_range('SELECT * FROM {menu} WHERE path IN ('. implode (',', $placeholders) .') ORDER BY fit DESC', $ancestors, 0, 1))) { - $item->access = _menu_access($item, $map); + list($item->access, $map) = _menu_access($item, $map); if ($map === FALSE) { $items[$path] = FALSE; return FALSE; } - if ($execute) { - $item->page_arguments = array_merge(menu_unserialize($item->page_arguments, $map), array_slice($parts, $item->number_parts)); - } + $item->map = $map; + $item->page_arguments = array_merge(menu_unserialize($item->page_arguments, $map), array_slice($parts, $item->number_parts)); } $items[$path] = $item; } @@ -313,24 +325,78 @@ function menu_execute_active_handler() { return MENU_NOT_FOUND; } -function _menu_access($item, &$map) { - if ($item->map_callback) { - $map = call_user_func_array($item->map_callback, array_merge(array($map), unserialize($item->map_arguments))); - if ($map === FALSE) { - return FALSE; +/** + * Handles dynamic path translation and menu access control. + * + * When a user arrives on a page such as node/5, this function determines + * what "5" corresponds to, by inspecting the page's menu path definition, + * node/[node_from_arg]. This will call node_form_arg(MENU_HANDLE_REQUEST, 5) + * and get back the corresponding node object. + * + * It also works in reverse, to allow the display of tabs and menu items which + * contain these dynamic arguments, translating node/[node_from_arg] to node/5. + * This operation is called MENU_RENDER_LINK. + * + * @param $item + * A menu item object + * @param $map + * An array of path arguments (ex: array('node', 5)) + * @param $operation + * The path translation operation to perform: + * - MENU_HANDLE_REQUEST: An incoming page reqest; map with appropriate callback. + * - MENU_RENDER_LINK: Render an internal path as a link. + * @return + * Returns an array. The first value is the access, the second is the map + * with objects loaded where appropriate and the third is the path ready for + * printing. + */ +function _menu_access($item, $map, $operation = MENU_HANDLE_REQUEST) { + $path = ''; + + // Check if there are dynamic arguments in the path that need to be calculated. + if ($item->functions) { + $functions = unserialize($item->functions); + $path_map = ($operation == MENU_HANDLE_REQUEST) ? $map : explode('/', $item->path); + foreach ($functions as $index => $function) { + // Translate place-holders into real values. + if ($operation != MENU_HANDLE_REQUEST) { + $return = $function($operation, !empty($map[$index]) ? $map[$index] : ''); + if (!empty($map[$index]) || $return) { + $path_map[$index] = $return; + } + } + // We now have a real path regardless of operation, map it. + $return = $function(MENU_HANDLE_REQUEST, !empty($path_map[$index]) ? $path_map[$index] : ''); + // If callback returned an error, trigger 404. + if ($return === FALSE) { + return array(FALSE, FALSE, ''); + } + $map[$index] = $return; + } + if ($operation != MENU_HANDLE_REQUEST) { + // Re-join the path with the new replacement value. + $path = implode('/', $path_map); } } + else { + $path = $item->path; + } + + // Determine access callback, which will decide whether or not the current user has + // access to this path. $callback = $item->access_callback; + // Check for a TRUE or FALSE value. if (is_numeric($callback)) { - return $callback; + return array($callback, $map, $path); } $arguments = menu_unserialize($item->access_arguments, $map); // As call_user_func_array is quite slow and user_access is a very common // callback, it is worth making a special case for it. if ($callback == 'user_access') { - return (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]); + $access = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]); + return array($access, $map, $path); } - return call_user_func_array($callback, $arguments); + return array(call_user_func_array($callback, $arguments), $map, $path); } /** @@ -346,12 +412,13 @@ function _menu_tree($result = NULL, $dep static $original_map; $remnant = array('link' => '', 'has_children' => FALSE); $tree = ''; + $map = arg(NULL); while ($item = db_fetch_object($result)) { - $map = arg(NULL, $item->path); - if (!_menu_access($item, $map)) { + list($access, , $path) = _menu_access($item, $map, MENU_RENDER_LINK); + if (!$access) { continue; } - $menu_link = array('link' => $item->menu_link, 'has_children' => $item->has_children); + $menu_link = array('link' => l($item->title, $path), 'has_children' => $item->has_children); if ($item->depth > $depth) { list($remnant, $menu) = _menu_tree($result, $item->depth, $menu_link); $tree .= theme('menu_tree', $link, $menu); @@ -430,47 +497,80 @@ function menu_rebuild() { $function($menu); } $mid = 1; - // First pass. + // First pass: separate callbacks from pathes, making pathes ready for + // matching. Calculate fitness, and fill some default values. foreach ($menu as $path => $item) { - $item = &$menu[$path]; $parts = explode('/', $path, 6); $number_parts = count($parts); - // We store the highest index of parts here to save some work in the weight + // We store the highest index of parts here to save some work in the fit // calculation loop. $slashes = $number_parts - 1; - // If there is no %, it fits maximally. - if (strpos($path, '%') === FALSE) { + $fit = 0; + $functions = array(); + // extract functions + foreach ($parts as $k => $part) { + if (preg_match('/\[([a-z_]*)\]/', $part, $matches) && (!$matches[1] || function_exists($matches[1]))) { + if ($matches[1]) { + $functions[$k] = $matches[1]; + } + $parts[$k] = '[]'; + } + else { + $fit |= 1 << ($slashes - $k); + } + } + $functions = empty($functions) ? '' : serialize($functions); + $item['functions'] = $functions; + // If there is no [], it fits maximally. + if (!$fit) { $fit = (1 << $number_parts) - 1; + $move = FALSE; } else { - // We need to calculate the fitness. - $fit = 0; - foreach ($parts as $k => $part) { - // ($part != '%') is the bit we want and we shift it to its place - // by shifting to left by ($slashes - $k) bits. - $fit |= ($part != '%') << ($slashes - $k); - } + $move = TRUE; } - if (!isset($item['_visible'])) { - $item['_visible'] = (!isset($item['type']) || ($item['type'] & MENU_VISIBLE_IN_TREE)) ? 1 : 0; + $item += array( + 'title' => '', + 'weight' => 0, + 'type' => MENU_NORMAL_ITEM, + 'functions' => $functions, + '_number_parts' => $number_parts, + '_parts' => $parts, + '_fit' => $fit, + '_mid' => $mid++, + ); + $item += array( + '_visible' => (bool)($item['type'] & MENU_VISIBLE_IN_TREE), + '_tab' => (bool)($item['type'] & MENU_IS_LOCAL_TASK), + ); + if ($move) { + $new_path = implode('/', $item['_parts']); + unset($menu[$path]); } - $depth = 1; - if (!isset($item['_mid'])) { - $item['_mid'] = $mid++; + else { + $new_path = $path; } + $menu[$new_path] = $item; + } + // Second pass: find visible parents and prepare for sorting. + foreach ($menu as $path => $item) { + $item = &$menu[$path]; + $number_parts = $item['_number_parts']; $parents = array($item['_mid']); + if ($item['_visible'] && isset($item['parent'])) { + $parent_parts = explode('/', $item['parent'], 6); + $slashes = count($parent_parts) - 1; + } + else { + $parent_parts = $item['_parts']; + $slashes = $number_parts -1; + } + $depth = 1; for ($i = $slashes; $i; $i--) { - $parent_path = implode('/', array_slice($parts, 0, $i)); + $parent_path = implode('/', array_slice($parent_parts, 0, $i)); // We need to calculate depth to be able to sort. depth needs visibility. if (isset($menu[$parent_path])) { $parent = &$menu[$parent_path]; - // It's possible that the parent was not processed yet. - if (!isset($parent['_mid'])) { - $parent['_mid'] = $mid++; - } - if (!isset($parent['_visible'])) { - $parent['_visible'] = (!isset($parent['type']) || ($parent['type'] & MENU_VISIBLE_IN_TREE)) ? 1 : 0; - } if ($item['_visible'] && $parent['_visible']) { $parent['_has_children'] = 1; $depth++; @@ -487,22 +587,16 @@ function menu_rebuild() { $parents = implode(',', array_reverse($parents)); // Store variables and set defaults. $item += array( - '_fit' => $fit, - '_number_parts' => $number_parts, - '_parts' => $parts, '_pid' => 0, - '_depth' => $depth, + '_depth' => $item['_visible'] ? $depth : $number_parts, '_parents' => $parents, '_has_children' => 0, - 'title' => '', - 'weight' => 0, - 'type' => MENU_NORMAL_ITEM, ); - $sort[$path] = ($item['_visible'] ? $depth : $number_parts) . sprintf('%05d', $item['weight']) . $item['title']; + $sort[$path] = $item['_depth'] . sprintf('%05d', $item['weight']) . $item['title']; unset($item); } array_multisort($sort, $menu); - // Second pass: calculate ancestors, vancode and store into the database. + // Third pass: calculate ancestors, vancode and store into the database. foreach ($menu as $path => $item) { $item = &$menu[$path]; for ($i = $item['_number_parts'] - 1; $i; $i--) { @@ -512,7 +606,7 @@ function menu_rebuild() { // If a callback is not found, we try to find the first parent that // has this callback. When found, its callback argument will also be // copied but only if there is none in the current item. - foreach (array('access', 'map', 'page') as $type) { + foreach (array('access', 'page') as $type) { if (!isset($item["$type callback"]) && isset($parent["$type callback"])) { $item["$type callback"] = $parent["$type callback"]; if (!isset($item["$type arguments"]) && isset($parent["$type arguments"])) { @@ -525,9 +619,6 @@ function menu_rebuild() { if (!isset($item['access callback'])) { $menu[$path]['access callback'] = isset($item['access arguments']) ? 'user_access' : 0; } - if (!isset($item['map callback']) && isset($item['map arguments'])) { - $item['map callback'] = 'menu_map'; - } if (is_bool($item['access callback'])) { $item['access callback'] = intval($item['access callback']); } @@ -538,42 +629,38 @@ function menu_rebuild() { } $vancode = $prefix . int2vancode($next[$prefix]++); $menu[$path]['_prefix'] = $vancode .'.'; - $link = l($item['title'], $path, isset($item['attributes']) ? $item['attributes'] : array(), isset($item['query']) ? $item['query'] : NULL, isset($item['fragment']) ? $item['fragment'] : NULL); } else { $vancode = ''; - $link = ''; } - $tab = ($item['type'] & MENU_IS_LOCAL_TASK) ? 1 : 0; - $default_tab = $item['type'] == MENU_DEFAULT_LOCAL_TASK; - if (!isset($item['parent'])) { - if ($tab) { + if ($item['_tab']) { + if (!isset($item['parent'])) { $item['parent'] = implode('/', array_slice($item['_parts'], 0, $item['_number_parts'] - 1)); } - else { - $item['parent'] = $path; - } + } + else { + // Non-tab items specified the parent for visible links, and it's + // stored in parents, parent stores the tab parent. + $item['parent'] = $path; } $insert_item = $item + array( 'access arguments' => array(), 'access callback' => '', 'page arguments' => array(), 'page callback' => '', - 'map arguments' => array(), - 'map callback' => '', ); db_query("INSERT INTO {menu} ( - mid, pid, path, - access_callback, access_arguments, page_callback, page_arguments, map_callback, map_arguments, fit, - number_parts, vancode, menu_link, visible, parents, depth, has_children, tab, default_tab, title, parent) - VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', %d, '%s', %d, %d, %d, %d, '%s', '%s')", - $insert_item['_mid'], $insert_item['_pid'], $path, $insert_item['access callback'], - serialize($insert_item['access arguments']), $insert_item['page callback'], - serialize($insert_item['page arguments']), $insert_item['map callback'], - serialize($insert_item['map arguments']), $insert_item['_fit'], - $insert_item['_number_parts'], $vancode .'+', $link, $insert_item['_visible'], - $insert_item['_parents'], $insert_item['_depth'], $insert_item['_has_children'], - $tab, $default_tab, $insert_item['title'], $insert_item['parent']); + mid, pid, path, functions, + access_callback, access_arguments, page_callback, page_arguments, fit, + number_parts, vancode, visible, parents, depth, has_children, tab, title, parent, type) + VALUES (%d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, %d, '%s', '%s', '%s')", + $insert_item['_mid'], $insert_item['_pid'], $path, $item['functions'], + $insert_item['access callback'], serialize($insert_item['access arguments']), + $insert_item['page callback'], serialize($insert_item['page arguments']), + $insert_item['_fit'], $insert_item['_number_parts'], $vancode .'+', + $insert_item['_visible'], $insert_item['_parents'], $insert_item['_depth'], + $insert_item['_has_children'], $item['_tab'], $insert_item['title'], + $insert_item['parent'], $insert_item['type']); unset($item); } } @@ -590,32 +677,89 @@ function menu_primary_links() { function menu_secondary_links() { } -function menu_primary_local_tasks() { - $router_item = menu_get_item(); - $result = db_query("SELECT * FROM {menu} WHERE parent = '%s' AND tab = 1 ORDER BY vancode", $router_item->parent); - $tabs = array(); - while ($item = db_fetch_object($result)) { - $map = explode('/', $item->path); - foreach ($map as $key => $value) { - if ($value == '%') { - $map[$key] = arg($key); +/** + * Collects the local tasks (tabs) for a given level. + * + * @param $level + The level of tasks you ask for. Primary tasks are 0, secondary are 1... + * @return + * An array of links to the tabs. + */ +function menu_local_tasks($level = 0) { + static $tabs = array(), $parents = array(), $parents_done = array(); + if (empty($tabs)) { + $router_item = menu_get_item(); + $map = arg(NULL); + do { + // Tabs are router items that have the same parent. If there is a new + // parent, let's add it the queue. + if (!empty($router_item->parent)) { + $parents[] = $router_item->parent; + // Do not add the same item twice. + $router_item->parent = ''; + } + $parent = array_shift($parents); + // Do not process the same parent twice. + if (isset($parents_done[$parent])) { + continue; + } + // This loads all the tabs. + $result = db_query("SELECT * FROM {menu} WHERE parent = '%s' AND tab = 1 ORDER BY vancode", $parent); + $tabs_current = array(); + unset($next_router_item); + while ($item = db_fetch_object($result)) { + // This call changes the path from for example user/[] to user/123 and + // also determines whether we are allowed to access it. + list($access, , $path) = _menu_access($item, $map, MENU_RENDER_LINK); + if ($access) { + // MENU_DEFAULT_LOCAL_TASK links to its parent. + $link = l($item->title, $item->type == MENU_DEFAULT_LOCAL_TASK ? substr($path, 0, strrpos($path, '/')) : $path); + $depth = $item->depth; + // We check for the active tab. + if ($item->path == $router_item->path || (!$router_item->tab && $item->type == MENU_DEFAULT_LOCAL_TASK) || $path == $_GET['q']) { + $tabs_current[] = array('class' => 'active', 'data' => $link); + if ($item->parent) { + // Let's try to find the router item one level up. + $next_router_item = db_fetch_object(db_query("SELECT path, tab, parent FROM {menu} WHERE path = '%s'", $item->parent)); + } + // We will need to inspect one level down. + $parents[] = $item->path; + } + else { + $tabs_current[] = $link; + } + } } - } - $path = implode('/', $map); - if (_menu_access($item, $map, TRUE)) { - $link = l($item->title, $path); - if ((!$router_item->tab && $item->default_tab) || ($path == $_GET['q'])) { - $tabs[] = array('class' => 'active', 'data' => $link); + // If there are tabs, let's add them + if ($tabs_current) { + $tabs[$depth] = $tabs_current; + } + $parents_done[$parent] = TRUE; + if (isset($next_router_item)) { + $router_item = $next_router_item; } else { - $tabs[] = $link; + unset($router_item); } - } + } while ($parents); + // Sort by depth + ksort($tabs); + // Remove the depth, we are interested only in their relative placement. + $tabs = array_values($tabs); + } + return isset($tabs[$level]) ? $tabs[$level] : array(); +} + +function menu_primary_local_tasks() { + if ($tasks = menu_local_tasks()) { + return theme('item_list', $tasks, NULL, 'ul', array('class' => 'tabs primary')); } - return theme('item_list', $tabs, NULL, 'ul', array('class' => 'tabs primary')); } function menu_secondary_local_tasks() { + if ($tasks = menu_local_tasks(1)) { + return theme('item_list', $tasks, NULL, 'ul', array('class' => 'tabs secondary')); + } } function menu_set_active_item() { @@ -631,4 +775,4 @@ function menu_get_active_breadcrumb() { function menu_get_active_title() { $item = menu_get_item(); return $item->title; -} \ No newline at end of file +} === modified file 'index.php' --- index.php 2006-12-12 09:32:18 +0000 +++ index.php 2007-02-05 23:41:48 +0000 @@ -34,4 +34,4 @@ elseif (isset($return)) { } -drupal_page_footer(); \ No newline at end of file +drupal_page_footer(); === modified file 'modules/aggregator/aggregator.module' --- modules/aggregator/aggregator.module 2007-01-31 21:26:55 +0000 +++ modules/aggregator/aggregator.module 2007-02-05 15:09:55 +0000 @@ -51,19 +51,17 @@ function aggregator_menu() { 'type' => MENU_LOCAL_TASK, 'parent' => 'admin/content/aggregator', ); - $items['admin/content/aggregator/remove/%'] = array( + $items['admin/content/aggregator/remove/[aggregator_feed_from_arg]'] = array( 'title' => t('Remove items'), 'page callback' => 'aggregator_admin_remove_feed', 'page arguments' => array(4), - 'map arguments' => array('aggregator_get_feed', 4), 'access arguments' => array('administer news feeds'), 'type' => MENU_CALLBACK, ); - $items['admin/content/aggregator/update/%'] = array( + $items['admin/content/aggregator/update/[aggregator_feed_from_arg]'] = array( 'title' => t('Update items'), 'page callback' => 'aggregator_admin_refresh_feed', 'page arguments' => array(4), - 'map arguments' => array('aggregator_get_feed', 4), 'access arguments' => array('administer news feeds'), 'type' => MENU_CALLBACK, ); @@ -137,24 +135,23 @@ function aggregator_menu() { 'weight' => 1, ); } - $items['aggregator/sources/%'] = array( + $items['aggregator/sources/[aggregator_feed_from_arg]'] = array( 'page callback' => 'aggregator_page_source', - 'map arguments' => array('aggregator_get_feed', 2), 'type' => MENU_CALLBACK, ); - $items['aggregator/sources/%/view'] = array( + $items['aggregator/sources/[aggregator_feed_from_arg]/view'] = array( 'title' => t('View'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); - $items['aggregator/sources/%/categorize'] = array( + $items['aggregator/sources/[aggregator_feed_from_arg]/categorize'] = array( 'title' => t('Categorize'), 'page callback' => 'drupal_get_form', 'page arguments' => array('aggregator_page_source'), 'access arguments' => array('administer news feeds'), 'type' => MENU_LOCAL_TASK, ); - $items['aggregator/sources/%/configure'] = array( + $items['aggregator/sources/[aggregator_feed_from_arg]/configure'] = array( 'title' => t('Configure'), 'page callback' => 'drupal_get_form', 'page arguments' => array('aggregator_form_feed', 2), @@ -162,20 +159,18 @@ function aggregator_menu() { 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); - $items['admin/content/aggregator/edit/feed/%'] = array( + $items['admin/content/aggregator/edit/feed/[aggregator_feed_from_arg]'] = array( 'title' => t('Edit feed'), 'page callback' => 'drupal_get_form', 'page arguments' => array('aggregator_form_feed', 5), 'access arguments' => array('administer news feeds'), - 'map arguments' => array('aggregator_get_feed', 5), 'type' => MENU_CALLBACK, ); - $items['admin/content/aggregator/edit/category/%'] = array( + $items['admin/content/aggregator/edit/category/[aggregator_category_from_arg]'] = array( 'title' => t('Edit category'), 'page callback' => 'drupal_get_form', 'page arguments' => array('aggregator_form_category', 5), 'access arguments' => array('administer news feeds'), - 'map arguments' => array('aggregator_get_category', 5), 'type' => MENU_CALLBACK, ); @@ -186,6 +181,20 @@ function aggregator_init() { drupal_add_css(drupal_get_path('module', 'aggregator') .'/aggregator.css'); } +function aggregator_feed_from_arg($operation, $arg) { + if ($operation == MENU_HANDLE_REQUEST) { + return is_numeric($arg) ? aggregator_get_feed($arg) : FALSE; + } + return $arg; +} + +function aggregator_category_from_arg($operation, $arg) { + if ($operation == MENU_HANDLE_REQUEST) { + return is_numeric($arg) ? aggregator_get_category($arg) : FALSE; + } + return $arg; +} + function aggregator_admin_settings() { $items = array(0 => t('none')) + drupal_map_assoc(array(3, 5, 10, 15, 20, 25), '_aggregator_items'); $period = drupal_map_assoc(array(3600, 10800, 21600, 32400, 43200, 86400, 172800, 259200, 604800, 1209600, 2419200, 4838400, 9676800), 'format_interval'); @@ -1035,7 +1044,7 @@ function aggregator_page_last() { */ function aggregator_page_source() { $feed = db_fetch_object(db_query('SELECT * FROM {aggregator_feed} WHERE fid = %d', arg(2))); - drupal_set_title($feed->title); + drupal_set_title(check_plain($feed->title)); $info = theme('aggregator_feed', $feed); return _aggregator_page_list('SELECT * FROM {aggregator_item} WHERE fid = '. $feed->fid .' ORDER BY timestamp DESC, iid DESC', arg(3), $info); === modified file 'modules/blog/blog.module' --- modules/blog/blog.module 2007-01-31 15:49:22 +0000 +++ modules/blog/blog.module 2007-02-05 15:09:55 +0000 @@ -105,6 +105,9 @@ function blog_feed_last() { * Menu callback; displays a Drupal page containing recent blog entries. */ function blog_page($a = NULL, $b = NULL) { + if (is_object($a)) { + $a = $a->uid; + } if (is_numeric($a)) { // $a is a user ID if ($b == 'feed') { @@ -256,7 +259,7 @@ function blog_menu() { 'access arguments' => array('access content'), 'type' => MENU_SUGGESTED_ITEM, ); - $items['blog/%'] = array( + $items['blog/[user_from_arg]'] = array( 'title' => t('My blog'), 'page arguments' => array(1), 'access arguments' => array('edit own blog'), === modified file 'modules/book/book.module' --- modules/book/book.module 2007-01-31 15:49:22 +0000 +++ modules/book/book.module 2007-02-05 15:09:55 +0000 @@ -109,18 +109,17 @@ function book_menu() { 'access arguments' => array('access content'), 'type' => MENU_SUGGESTED_ITEM, ); - $items['book/export/%/%'] = array( + $items['book/export/[]/[]'] = array( 'page callback' => 'book_export', 'page arguments' => array(2, 3), 'type' => MENU_CALLBACK, ); - $items['node/%/outline'] = array( + $items['node/[node_from_arg]/outline'] = array( 'title' => t('Outline'), 'page callback' => 'drupal_get_form', 'page arguments' => array('book_outline', 1), 'access callback' => '_book_outline_access', 'access arguments' => array(1), - 'map arguments' => array('node_load', 1), 'type' => MENU_LOCAL_TASK, 'weight' => 2, ); === modified file 'modules/comment/comment.module' --- modules/comment/comment.module 2007-01-31 15:49:22 +0000 +++ modules/comment/comment.module 2007-02-05 15:09:55 +0000 @@ -195,15 +195,14 @@ function comment_menu() { 'access arguments' => array('post comments'), 'type' => MENU_CALLBACK, ); - $items['comment/reply'] = array( + $items['comment/reply/[node_from_arg]'] = array( 'title' => t('Reply to comment'), 'page callback' => 'comment_reply', 'access callback' => 'node_access', 'access arguments' => array('view', 2), - 'map arguments' => array('node_load', 2), 'type' => MENU_CALLBACK, ); - $items['node/%/%'] = array( + $items['node/[node_from_arg]/[]'] = array( 'title' => t('View'), 'page callback' => 'node_page_view', 'page arguments' => array(1, 2), === modified file 'modules/contact/contact.module' --- modules/contact/contact.module 2007-01-31 15:49:22 +0000 +++ modules/contact/contact.module 2007-02-05 15:09:55 +0000 @@ -84,14 +84,13 @@ function contact_menu() { 'access arguments' => array('access site-wide contact form'), 'type' => MENU_SUGGESTED_ITEM, ); - $items['user/%/contact'] = array( + $items['user/[user_from_arg]/contact'] = array( 'title' => t('Contact'), 'page callback' => 'contact_user_page', 'page arguments' => array(1), 'type' => MENU_LOCAL_TASK, 'access callback' => '_contact_user_tab_access', 'access arguments' => array(1), - 'map arguments' => array('user_load', 1), 'weight' => 2, ); return $items; === modified file 'modules/filter/filter.module' --- modules/filter/filter.module 2007-01-31 15:49:22 +0000 +++ modules/filter/filter.module 2007-02-05 15:09:55 +0000 @@ -81,26 +81,25 @@ function filter_menu() { 'access callback' => TRUE, 'type' => MENU_SUGGESTED_ITEM, ); - $items['admin/settings/filters/%'] = array( + $items['admin/settings/filters/[filter_from_arg]'] = array( 'type' => MENU_CALLBACK, 'page arguments' => array('filter_admin_format_form', 3), 'access arguments' => array('administer filters'), - 'map arguments' => array('filter_formats', 3), ); - $items['admin/settings/filters/%/list'] = array( + $items['admin/settings/filters/[filter_from_arg]/list'] = array( 'title' => t('View'), 'page arguments' => array('filter_admin_format_form', 3), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => 0, ); - $items['admin/settings/filters/%/configure'] = array( + $items['admin/settings/filters/[filter_from_arg]/configure'] = array( 'title' => t('Configure'), 'page arguments' => array('filter_admin_configure', 3), 'type' => MENU_LOCAL_TASK, 'weight' => 1, ); - $items['admin/settings/filters/%/order'] = array( + $items['admin/settings/filters/[filter_from_arg]/order'] = array( 'title' => t('Rearrange'), 'page arguments' => array('filter_admin_order', 3), 'type' => MENU_LOCAL_TASK, @@ -109,6 +108,13 @@ function filter_menu() { return $items; } +function filter_from_arg($operation, $arg) { + if ($operation == MENU_HANDLE_REQUEST) { + return is_numeric($arg) ? filter_formats($arg) : FALSE; + } + return $arg; +} + /** * Implementation of hook_perm(). */ === modified file 'modules/forum/forum.module' --- modules/forum/forum.module 2007-02-01 21:44:36 +0000 +++ modules/forum/forum.module 2007-02-05 15:09:55 +0000 @@ -75,19 +75,21 @@ function forum_menu() { 'type' => MENU_LOCAL_TASK, 'parent' => 'admin/content/forum', ); - $items['admin/content/forum/edit'] = array( + $items['admin/content/forum/edit/[forum_from_arg]'] = array( 'page callback' => 'forum_form_main', - 'map arguments' => array('_forum_get_term', 5, array()), 'type' => MENU_CALLBACK, ); - $items['admin/content/forum/edit/container/%'] = array( + $items['admin/content/forum/edit/container/[forum_from_arg]'] = array( 'title' => t('Edit container'), + 'page callback' => 'forum_form_main', 'page arguments' => array('container', 5), + 'type' => MENU_CALLBACK, ); - $items['admin/content/forum/edit/forum/%'] = array( + $items['admin/content/forum/edit/forum/[forum_from_arg]'] = array( 'title' => t('Edit forum'), 'page callback' => 'forum_form_main', 'page arguments' => array('forum', 5), + 'type' => MENU_CALLBACK, ); return $items; } @@ -96,8 +98,11 @@ function forum_init() { drupal_add_css(drupal_get_path('module', 'forum') .'/forum.css'); } -function _forum_get_term($tid) { - return (array)taxonomy_get_term($tid); +function forum_from_arg($operation, $tid) { + if ($operation == MENU_HANDLE_REQUEST) { + return is_numeric($tid) ? (array)taxonomy_get_term($tid) : FALSE; + } + return $tid; } /** === modified file 'modules/locale/locale.module' --- modules/locale/locale.module 2007-01-31 21:26:55 +0000 +++ modules/locale/locale.module 2007-02-05 15:09:55 +0000 @@ -97,13 +97,13 @@ function locale_menu() { 'type' => MENU_CALLBACK, ); // String related callbacks - $items['admin/settings/locale/string/edit/%'] = array( + $items['admin/settings/locale/string/edit/[]'] = array( 'title' => t('Edit string'), 'page callback' => 'drupal_get_form', 'page arguments' => array('locale_admin_string_edit', 5), 'type' => MENU_CALLBACK, ); - $items['admin/settings/locale/string/delete/%'] = array( + $items['admin/settings/locale/string/delete/[]'] = array( 'title' => t('Delete string'), 'page callback' => 'locale_admin_string_delete', 'page arguments' => array(5), === modified file 'modules/node/node.module' --- modules/node/node.module 2007-01-31 15:49:22 +0000 +++ modules/node/node.module 2007-02-05 15:09:55 +0000 @@ -1166,33 +1166,32 @@ function node_menu() { } } - $items['node/%'] = array( + $items['node/[node_from_arg]'] = array( 'title' => t('View'), 'page callback' => 'node_page_view', 'page arguments' => array(1), 'access callback' => 'node_access', 'access arguments' => array('view', 1), - 'map arguments' => array('node_load', 1), 'type' => MENU_CALLBACK); - $items['node/%/view'] = array( + $items['node/[node_from_arg]/view'] = array( 'title' => t('View'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10); - $items['node/%/edit'] = array( + $items['node/[node_from_arg]/edit'] = array( 'title' => t('Edit'), 'page callback' => 'node_page_edit', 'page arguments' => array(1), 'access arguments' => array('update', 1), 'weight' => 1, 'type' => MENU_LOCAL_TASK); - $items['node/%/delete'] = array( + $items['node/[node_from_arg]/delete'] = array( 'title' => t('Delete'), 'page callback' => 'drupal_get_form', 'page arguments' => array('node_delete_confirm', 1), 'access arguments' => array('delete', 1), 'weight' => 1, 'type' => MENU_CALLBACK); - $items['node/%/revisions'] = array( + $items['node/[node_from_arg]/revisions'] = array( 'title' => t('Revisions'), 'page callback' => 'node_revisions', 'access callback' => '_node_revision_access', @@ -1210,6 +1209,13 @@ function node_init() { drupal_add_css(drupal_get_path('module', 'node') .'/node.css'); } +function node_from_arg($direction, $arg) { + if ($direction == MENU_HANDLE_REQUEST) { + return is_numeric($arg) ? node_load($arg) : FALSE; + } + return $arg; +} + function node_last_changed($nid) { $node = db_fetch_object(db_query('SELECT changed FROM {node} WHERE nid = %d', $nid)); return ($node->changed); @@ -2464,7 +2470,7 @@ function node_update_index() { */ function node_form_alter($form_id, &$form) { // Advanced node search form - if ($form_id == 'search_form' && arg(1) == 'node' && user_access('use advanced search')) { + if ($form_id == 'search_form' && $form['module']['#value'] == 'node' && user_access('use advanced search')) { // Keyword boxes: $form['advanced'] = array( '#type' => 'fieldset', === modified file 'modules/poll/poll.module' --- modules/poll/poll.module 2007-01-24 14:48:35 +0000 +++ modules/poll/poll.module 2007-02-05 15:09:56 +0000 @@ -239,14 +239,14 @@ function poll_menu() { 'type' => MENU_SUGGESTED_ITEM, ); - $items['poll/cancel/%'] = array( + $items['poll/cancel/[node_from_arg]'] = array( 'title' => t('Cancel'), 'page callback' => 'poll_cancel', 'page arguments' => array(2), 'access arguments' => array('cancel own vote'), 'type' => MENU_CALLBACK, ); - $items['node/%/votes'] = array( + $items['node/[node_from_arg]/votes'] = array( 'title' => t('Votes'), 'page callback' => 'poll_votes', 'access callback' => '_poll_menu_access', @@ -254,7 +254,7 @@ function poll_menu() { 'weight' => 3, 'type' => MENU_LOCAL_TASK, ); - $items['node/%/results'] = array( + $items['node/[node_from_arg]/results'] = array( 'title' => t('Results'), 'page callback' => 'poll_results', 'access callback' => '_poll_menu_access', === modified file 'modules/search/search.module' --- modules/search/search.module 2007-01-31 21:26:55 +0000 +++ modules/search/search.module 2007-02-05 15:09:56 +0000 @@ -140,7 +140,6 @@ function search_menu() { $items['search'] = array( 'title' => t('Search'), 'page callback' => 'search_view', - 'page arguments' => array('node'), 'access arguments' => array('search content'), 'type' => MENU_SUGGESTED_ITEM, ); @@ -167,13 +166,14 @@ function search_menu() { ); foreach (module_implements('search') as $name) { - $items['search/'. $name] = array( + $items['search/'. $name .'/[search_get_keys]'] = array( 'title' => module_invoke($name, 'search', 'name', TRUE), 'page callback' => 'search_view', 'page arguments' => array($name), 'access callback' => '_search_menu', 'access arguments' => array($name), 'type' => $name == 'node' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, + 'parent' => 'search', ); } return $items; @@ -882,16 +882,21 @@ function do_search($keywords, $type, $jo * Helper function for grabbing search keys. */ function search_get_keys() { - // Extract keys as remainder of path - // Note: support old GET format of searches for existing links. - $path = explode('/', $_GET['q'], 3); - return count($path) == 3 ? $path[2] : $_REQUEST['keys']; + static $return; + if (!isset($return)) { + // Extract keys as remainder of path + // Note: support old GET format of searches for existing links. + $path = explode('/', $_GET['q'], 3); + $keys = empty($_REQUEST['keys']) ? '' : $_REQUEST['keys']; + $return = count($path) == 3 ? $path[2] : $keys; + } + return $return; } /** * Menu callback; presents the search form and/or search results. */ -function search_view($type = '') { +function search_view($type = 'node') { // Search form submits with POST but redirects to GET. This way we can keep // the search query URL clean as a whistle: // search/type/keyword+keyword @@ -905,6 +910,7 @@ function search_view($type = '') { $keys = search_get_keys(); // Only perform search if there is non-whitespace search term: + $results = ''; if (trim($keys)) { // Log the search keys: watchdog('search', t('%keys (@type).', array('%keys' => $keys, '@type' => module_invoke($type, 'search', 'name'))), WATCHDOG_NOTICE, l(t('results'), 'search/'. $type .'/'. $keys)); === modified file 'modules/statistics/statistics.module' --- modules/statistics/statistics.module 2007-01-31 15:49:22 +0000 +++ modules/statistics/statistics.module 2007-02-05 15:09:56 +0000 @@ -126,7 +126,7 @@ function statistics_menu() { 'page callback' => 'statistics_top_referrers', 'access arguments' => array('access statistics'), ); - $items['admin/logs/access/%'] = array( + $items['admin/logs/access/[]'] = array( 'title' => t('Details'), 'description' => t('View access log.'), 'page callback' => 'statistics_access_log', @@ -143,14 +143,15 @@ function statistics_menu() { 'type' => MENU_NORMAL_ITEM, 'weight' => 3, ); - $items['user/%/track/navigation'] = array( + $items['user/[user_from_arg]/track/navigation'] = array( 'title' => t('Track page visits'), 'page callback' => 'statistics_user_tracker', + 'access callback' => 'user_access', 'access arguments' => array('access statistics'), 'type' => MENU_LOCAL_TASK, 'weight' => 2, ); - $items['node/%/track'] = array( + $items['node/[node_from_arg]/track'] = array( 'title' => t('Track'), 'page callback' => 'statistics_node_tracker', 'access callback' => 'user_access', === modified file 'modules/system/system.install' --- modules/system/system.install 2007-01-31 21:26:55 +0000 +++ modules/system/system.install 2007-02-05 15:09:56 +0000 @@ -327,31 +327,31 @@ function system_install() { ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); db_query("CREATE TABLE {menu} ( + mid int NOT NULL default '0', + pid int NOT NULL default '0', path varchar(255) NOT NULL default '', + functions varchar(255) NOT NULL default '', access_callback varchar(255) NOT NULL default '', access_arguments text, page_callback varchar(255) NOT NULL default '', page_arguments text, - map_callback varchar(255) NOT NULL default '', - map_arguments text, fit int NOT NULL default '0', number_parts int NOT NULL default '0', vancode varchar(255) NOT NULL default '', - mid int NOT NULL default '0', - pid int NOT NULL default '0', visible int NOT NULL default '0', - menu_link varchar(255) NOT NULL default '', parents varchar(255) NOT NULL default '', depth int NOT NULL default '0', has_children int NOT NULL default '0', tab int NOT NULL default 0, title varchar(255) NOT NULL default '', - default_tab int NOT NULL default '0', parent varchar(255) NOT NULL default '', + type int NOT NULL default 0, PRIMARY KEY (path), KEY vancode (vancode), KEY fit (fit), - KEY visible (visible) + KEY visible (visible), + KEY pid (pid), + KEY parent (parent) ) /*!40100 DEFAULT CHARACTER SET UTF8 */ "); db_query("CREATE TABLE {node} ( @@ -802,30 +802,30 @@ function system_install() { mid int NOT NULL default '0', pid int NOT NULL default '0', path varchar(255) NOT NULL default '', + functions varchar(255) NOT NULL default '', access_callback varchar(255) NOT NULL default '', access_arguments text, page_callback varchar(255) NOT NULL default '', page_arguments text, - map_callback varchar(255) NOT NULL default '', - map_arguments text, - fit int NOT NULL default 0, - number_parts int NOT NULL default 0, + fit int NOT NULL default '0', + number_parts int NOT NULL default '0', vancode varchar(255) NOT NULL default '', visible int NOT NULL default '0', - menu_link varchar(255) NOT NULL default '', parents varchar(255) NOT NULL default '', depth int NOT NULL default '0', has_children int NOT NULL default '0', - tab int NOT NULL default '0', + tab int NOT NULL default 0, title varchar(255) NOT NULL default '', - default_tab int NOT NULL default '0', parent varchar(255) NOT NULL default '', + type int NOT NULL default 0, PRIMARY KEY (path) )"); db_query("CREATE INDEX {menu}_vancode_idx ON {menu} (vancode)"); db_query("CREATE INDEX {menu}_fit_idx ON {menu} (fit)"); db_query("CREATE INDEX {menu}_visible_idx ON {menu} (visible)"); + db_query("CREATE INDEX {menu}_parent_idx ON {menu} (parent)"); + db_query("CREATE INDEX {menu}_pid_idx ON {menu} (parent)"); db_query("CREATE TABLE {node} ( nid serial CHECK (nid >= 0), === modified file 'modules/taxonomy/taxonomy.module' --- modules/taxonomy/taxonomy.module 2007-01-31 21:26:55 +0000 +++ modules/taxonomy/taxonomy.module 2007-02-05 15:09:56 +0000 @@ -91,7 +91,7 @@ function taxonomy_menu() { 'parent' => 'admin/content/taxonomy', ); - $items['admin/content/taxonomy/edit/vocabulary/%'] = array( + $items['admin/content/taxonomy/edit/vocabulary/[taxonomy_vocabulary_from_arg]'] = array( 'title' => t('Edit vocabulary'), 'page callback' => 'taxonomy_admin_vocabulary_edit', 'page arguments' => array(5), @@ -117,32 +117,39 @@ function taxonomy_menu() { 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, ); - $items['admin/content/taxonomy/%'] = array( + $items['admin/content/taxonomy/[taxonomy_vocabulary_from_arg]'] = array( 'title' => t('List terms'), 'page callback' => 'taxonomy_overview_terms', 'page arguments' => array(3), 'access arguments' => array('administer taxonomy'), - 'map arguments' => array('taxonomy_get_vocabulary', 3), 'type' => MENU_CALLBACK, ); - $items['admin/content/taxonomy/%/list'] = array( + $items['admin/content/taxonomy/[taxonomy_vocabulary_from_arg]/list'] = array( 'title' => t('List'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); - $items['admin/content/taxonomy/%/add/term'] = array( + $items['admin/content/taxonomy/[taxonomy_vocabulary_from_arg]/add/term'] = array( 'title' => t('Add term'), 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_form_term', 3), 'type' => MENU_LOCAL_TASK, - 'parent' => 'admin/content/taxonomy/%', + 'parent' => 'admin/content/taxonomy/[taxonomy_vocabulary_from_arg]', ); return $items; } +function taxonomy_vocabulary_from_arg($operation, $arg) { + if ($operation == MENU_HANDLE_REQUEST) { + return is_numeric($arg) ? taxonomy_get_vocabulary($arg) : FALSE; + } + return $arg; +} + + /** * List and manage vocabularies. */ @@ -1388,14 +1395,11 @@ function taxonomy_term_page($str_tids = /** * Page to edit a vocabulary. */ -function taxonomy_admin_vocabulary_edit($vid = NULL) { +function taxonomy_admin_vocabulary_edit($vocabulary) { if ($_POST['op'] == t('Delete') || $_POST['confirm']) { - return drupal_get_form('taxonomy_vocabulary_confirm_delete', $vid); - } - if ($vocabulary = (array)taxonomy_get_vocabulary($vid)) { - return drupal_get_form('taxonomy_form_vocabulary', $vocabulary); + return drupal_get_form('taxonomy_vocabulary_confirm_delete', $vocabulary->vid); } - return drupal_not_found(); + return drupal_get_form('taxonomy_form_vocabulary', (array)$vocabulary); } /** === modified file 'modules/tracker/tracker.module' --- modules/tracker/tracker.module 2007-01-24 14:48:35 +0000 +++ modules/tracker/tracker.module 2007-02-05 15:09:56 +0000 @@ -35,18 +35,22 @@ function tracker_menu() { 'type' => MENU_DEFAULT_LOCAL_TASK, 'access callback' => 'user_is_logged_in', ); - $items['tracker/%'] = array( + + $items['tracker/[user_current]'] = array( 'title' => t('My recent posts'), 'type' => MENU_LOCAL_TASK, 'access callback' => 'user_is_logged_in', + 'access arguments' => array(1), ); - $items['user/%/track'] = array( + + $items['user/[user_from_arg]/track'] = array( 'title' => t('Track'), 'page callback' => 'tracker_track_user', + 'access callback' => 'user_access', 'access arguments' => array('access content'), 'type' => MENU_LOCAL_TASK, ); - $items['user/%/track/posts'] = array( + $items['user/[user_from_arg]/track/posts'] = array( 'title' => t('Track posts'), 'type' => MENU_DEFAULT_LOCAL_TASK, ); === modified file 'modules/user/user.module' --- modules/user/user.module 2007-02-02 15:25:25 +0000 +++ modules/user/user.module 2007-02-05 23:40:31 +0000 @@ -730,11 +730,15 @@ function user_menu() { ); // Registration and login pages. - $items['user/login'] = array( + $items['user'] = array( 'title' => t('Log in'), 'page callback' => 'drupal_get_form', 'page arguments' => array('user_login'), 'access callback' => 'user_is_anonymous', + ); + + $items['user/login'] = array( + 'title' => t('Log in'), 'type' => MENU_DEFAULT_LOCAL_TASK, ); @@ -753,7 +757,7 @@ function user_menu() { 'access callback' => 'user_is_anonymous', 'type' => MENU_LOCAL_TASK, ); - $items['user/reset/%/%/%'] = array( + $items['user/reset/[]/[]/[]'] = array( 'title' => t('Reset password'), 'page callback' => 'drupal_get_form', 'page arguments' => array('user_pass_reset', 2, 3, 4), @@ -857,7 +861,6 @@ function user_menu() { 'page callback' => 'user_admin', 'page arguments' => array('search'), 'access arguments' => array('administer users'), - 'type' => MENU_NORMAL_ITEM, ); } @@ -868,32 +871,22 @@ function user_menu() { 'weight' => 10, ); - $items['user'] = array( - 'title' => t('My account'), - 'page callback' => 'user_view', - 'page arguments' => array(1), - 'access callback' => 'user_view_access', - 'access arguments' => array(1), - 'map callback' => 'user_load_self', - ); - - $items['user/%'] = array( + $items['user/[user_current]'] = array( 'title' => t('My account'), 'page callback' => 'user_view', 'page arguments' => array(1), 'access callback' => 'user_view_access', 'access arguments' => array(1), - 'map arguments' => array('user_load', 1), - 'type' => MENU_CALLBACK, + 'parent' => '', ); - $items['user/%/view'] = array( + $items['user/[user_from_arg]/view'] = array( 'title' => t('View'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); - $items['user/%/delete'] = array( + $items['user/[user_from_arg]/delete'] = array( 'title' => t('Delete'), 'page callback' => 'user_edit', 'access callback' => 'user_access', @@ -901,7 +894,7 @@ function user_menu() { 'type' => MENU_CALLBACK, ); - $items['user/%/edit'] = array( + $items['user/[user_from_arg]/edit'] = array( 'title' => t('Edit'), 'page callback' => 'drupal_get_form', 'page arguments' => array('user_edit'), @@ -913,7 +906,7 @@ function user_menu() { $empty_account = new stdClass(); if (($categories = _user_categories($empty_account)) && (count($categories) > 1)) { foreach ($categories as $key => $category) { - $items['user/%/edit/'. $category['name']] = array( + $items['user/[user_from_arg]/edit/'. $category['name']] = array( 'title' => $category['title'], 'page arguments' => array('user_edit', 3), 'type' => $category['name'] == 'account' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, @@ -928,6 +921,20 @@ function user_init() { drupal_add_css(drupal_get_path('module', 'user') .'/user.css', 'module'); } +function user_from_arg($operation, $arg) { + if ($operation == MENU_HANDLE_REQUEST) { + return is_numeric($arg) ? user_load($arg) : FALSE; + } + return $arg; +} + +function user_current($operation, $arg) { + if ($operation == MENU_HANDLE_REQUEST) { + return is_numeric($arg) ? user_load($arg) : FALSE; + } + return $GLOBALS['user']->uid; +} + /** * Accepts an user object, $account, or a DA name and returns an associative * array of modules and DA names. Called at external login. @@ -1588,6 +1595,7 @@ function user_edit_submit($form_id, $for function user_view($account) { global $user; + drupal_set_title(check_plain($account->name)); // Retrieve and merge all profile fields: $fields = array(); foreach (module_list() as $module) { === modified file 'modules/watchdog/watchdog.module' --- modules/watchdog/watchdog.module 2007-01-31 15:49:22 +0000 +++ modules/watchdog/watchdog.module 2007-02-05 15:09:56 +0000 @@ -49,7 +49,7 @@ function watchdog_menu() { 'page callback' => 'watchdog_top', 'page arguments' => array('access denied'), ); - $items['admin/logs/event/%'] = array( + $items['admin/logs/event/[]'] = array( 'title' => t('Details'), 'page callback' => 'watchdog_event', 'page arguments' => array(3),