Commit b91a015b authored by catch's avatar catch

Issue #687842 by tim.plunkett et al: Added a 'description callback' property to menu items.

parent 78e88b77
......@@ -604,12 +604,13 @@ function _menu_check_access(&$item, $map) {
* $item['title'] is localized according to $item['title_callback'].
* If an item's callback is check_plain(), $item['options']['html'] becomes
* TRUE.
* $item['description'] is translated using t().
* $item['description'] is computed using $item['description_callback'] if
* specified; otherwise it is translated using t().
* When doing link translation and the $item['options']['attributes']['title']
* (link title attribute) matches the description, it is translated as well.
*/
function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
$callback = $item['title_callback'];
$title_callback = $item['title_callback'];
$item['localized_options'] = $item['options'];
// All 'class' attributes are assumed to be an array during rendering, but
// links stored in the database may use an old string value.
......@@ -628,7 +629,7 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
if (!$link_translate || ($item['title'] == $item['link_title'])) {
// t() is a special case. Since it is used very close to all the time,
// we handle it directly instead of using indirect, slower methods.
if ($callback == 't') {
if ($title_callback == 't') {
if (empty($item['title_arguments'])) {
$item['title'] = t($item['title']);
}
......@@ -636,15 +637,15 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
$item['title'] = t($item['title'], menu_unserialize($item['title_arguments'], $map));
}
}
elseif ($callback) {
elseif ($title_callback) {
if (empty($item['title_arguments'])) {
$item['title'] = $callback($item['title']);
$item['title'] = $title_callback($item['title']);
}
else {
$item['title'] = call_user_func_array($callback, menu_unserialize($item['title_arguments'], $map));
$item['title'] = call_user_func_array($title_callback, menu_unserialize($item['title_arguments'], $map));
}
// Avoid calling check_plain again on l() function.
if ($callback == 'check_plain') {
if ($title_callback == 'check_plain') {
$item['localized_options']['html'] = TRUE;
}
}
......@@ -656,10 +657,33 @@ function _menu_item_localize(&$item, $map, $link_translate = FALSE) {
// Translate description, see the motivation above.
if (!empty($item['description'])) {
$original_description = $item['description'];
$item['description'] = t($item['description']);
if ($link_translate && isset($item['options']['attributes']['title']) && $item['options']['attributes']['title'] == $original_description) {
$item['localized_options']['attributes']['title'] = $item['description'];
}
if (!empty($item['description_arguments']) || !empty($item['description'])) {
$description_callback = $item['description_callback'];
// If the description callback is t(), call it directly.
if ($description_callback == 't') {
if (empty($item['description_arguments'])) {
$item['description'] = t($item['description']);
}
else {
$item['description'] = t($item['description'], menu_unserialize($item['description_arguments'], $map));
}
}
elseif ($description_callback) {
// If there are no arguments, call the description callback directly.
if (empty($item['description_arguments'])) {
$item['description'] = $description_callback($item['description']);
}
// Otherwise, use call_user_func_array() to pass the arguments.
else {
$item['description'] = call_user_func_array($description_callback, menu_unserialize($item['description_arguments'], $map));
}
}
}
// If the title and description are the same, use the translated description
// as a localized title.
if ($link_translate && isset($original_description) && isset($item['options']['attributes']['title']) && $item['options']['attributes']['title'] == $original_description) {
$item['localized_options']['attributes']['title'] = $item['description'];
}
}
......@@ -1354,6 +1378,8 @@ function _menu_build_tree($menu_name, array $parameters = array()) {
'theme_arguments',
'type',
'description',
'description_callback',
'description_arguments',
));
for ($i = 1; $i <= MENU_MAX_DEPTH; $i++) {
$query->orderBy('p' . $i, 'ASC');
......@@ -3634,6 +3660,8 @@ function _menu_router_build($callbacks) {
'theme arguments' => array(),
'theme callback' => '',
'description' => '',
'description arguments' => array(),
'description callback' => 't',
'position' => '',
'context' => 0,
'tab_parent' => '',
......@@ -3688,6 +3716,8 @@ function _menu_router_save($menu, $masks) {
'theme_arguments',
'type',
'description',
'description_callback',
'description_arguments',
'position',
'weight',
'include_file',
......@@ -3718,6 +3748,8 @@ function _menu_router_save($menu, $masks) {
'theme_arguments' => serialize($item['theme arguments']),
'type' => $item['type'],
'description' => $item['description'],
'description_callback' => $item['description callback'],
'description_arguments' => ($item['description arguments'] ? serialize($item['description arguments']) : ''),
'position' => $item['position'],
'weight' => $item['weight'],
'include_file' => $item['include file'],
......
......@@ -52,7 +52,7 @@ function menu_overview_form($form, &$form_state, $menu) {
global $menu_admin;
$form['#attached']['css'] = array(drupal_get_path('module', 'menu') . '/menu.admin.css');
$sql = "
SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.type, m.description, ml.*
SELECT m.load_functions, m.to_arg_functions, m.access_callback, m.access_arguments, m.page_callback, m.page_arguments, m.delivery_callback, m.title, m.title_callback, m.title_arguments, m.type, m.description, m.description_callback, m.description_arguments, ml.*
FROM {menu_links} ml LEFT JOIN {menu_router} m ON m.path = ml.router_path
WHERE ml.menu_name = :menu
ORDER BY p1 ASC, p2 ASC, p3 ASC, p4 ASC, p5 ASC, p6 ASC, p7 ASC, p8 ASC, p9 ASC";
......
......@@ -71,6 +71,16 @@ function testTitleMenuCallback() {
$this->assertText(t('Menu Callback Title'));
}
/**
* Tests menu item descriptions.
*/
function testDescriptionMenuItems() {
// Verify that the menu router item title is output as page title.
$this->drupalGet('menu_callback_description');
$this->assertText(t('Menu item description text'));
$this->assertRaw(check_plain('<strong>Menu item description arguments</strong>'));
}
/**
* Test the theme callback when it is set to use an administrative theme.
*/
......
......@@ -694,6 +694,10 @@ function hook_menu_get_item_alter(&$router_item, $path, $original_map) {
* - "title arguments": Arguments to send to t() or your custom callback,
* with path component substitution as described above.
* - "description": The untranslated description of the menu item.
* - description callback: Function to generate the description; defaults to
* t(). If you require only the raw string to be output, set this to FALSE.
* - description arguments: Arguments to send to t() or your custom callback,
* with path component substitution as described above.
* - "page callback": The function to call to display a web page when the user
* visits the path. If omitted, the parent menu item's callback will be used
* instead.
......
......@@ -1161,6 +1161,20 @@ function system_schema() {
'type' => 'text',
'not null' => TRUE,
),
'description_callback' => array(
'description' => 'A function which will alter the description. Defaults to t().',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'description_arguments' => array(
'description' => 'A serialized array of arguments for the description callback. If empty, the description will be used as the sole argument for the description callback.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'position' => array(
'description' => 'The position of the block (left or right) on the system administration page for this item.',
'type' => 'varchar',
......@@ -1954,6 +1968,32 @@ function system_update_8012() {
));
}
/**
* Add description_callback and description_arguments fields to {menu_router}.
*/
function system_update_8013() {
if (!db_field_exists('menu_router', 'description_callback')) {
$spec = array(
'description' => 'A function which will alter the description. Defaults to t().',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
);
db_add_field('menu_router', 'description_callback', $spec);
}
if (!db_field_exists('menu_router', 'description_arguments')) {
$spec = array(
'description' => 'A serialized array of arguments for the description callback. If empty, the description will be used as the sole argument for the description callback.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
);
db_add_field('menu_router', 'description_arguments', $spec);
}
}
/**
* @} End of "defgroup updates-7.x-to-8.x".
* The next series of updates should start at 9000.
......
......@@ -22,6 +22,28 @@ function menu_test_menu() {
'type' => MENU_CALLBACK,
'access arguments' => array('access content'),
);
// This item uses system_admin_menu_block_page() to list child items.
$items['menu_callback_description'] = array(
'title' => 'Menu item title',
'page callback' => 'system_admin_menu_block_page',
'description' => 'Menu item description parent',
'access arguments' => array('access content'),
'file' => 'system.admin.inc',
'file path' => drupal_get_path('module', 'system'),
);
$items['menu_callback_description/description-plain'] = array(
'title' => 'Menu item with a regular description',
'page callback' => 'menu_test_callback',
'description' => 'Menu item description text',
'access arguments' => array('access content'),
);
$items['menu_callback_description/description-callback'] = array(
'title' => 'Menu item with a description set with a callback',
'page callback' => 'menu_test_callback',
'description callback' => 'check_plain',
'description arguments' => array('<strong>Menu item description arguments</strong>'),
'access arguments' => array('access content'),
);
// Use FALSE as 'title callback' to bypass t().
$items['menu_no_title_callback'] = array(
'title' => 'A title with @placeholder',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment