Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1023
diff -u -p -r1.1023 common.inc
--- includes/common.inc 16 Oct 2009 19:20:33 -0000 1.1023
+++ includes/common.inc 16 Oct 2009 21:45:27 -0000
@@ -3292,7 +3292,7 @@ function drupal_clear_css_cache() {
* @return
* The cleaned identifier.
*/
-function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_' => '-', '[' => '-', ']' => '')) {
+function drupal_clean_css_identifier($identifier, $filter = array(' ' => '-', '_' => '-', '/' => '-', '[' => '-', ']' => '')) {
// By default, we filter using Drupal's coding standards.
$identifier = strtr($identifier, $filter);
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.354
diff -u -p -r1.354 menu.inc
--- includes/menu.inc 16 Oct 2009 19:06:21 -0000 1.354
+++ includes/menu.inc 16 Oct 2009 23:12:15 -0000
@@ -1614,10 +1614,11 @@ function menu_local_tasks($level = 0) {
$result = db_select('menu_router', NULL, array('fetch' => PDO::FETCH_ASSOC))
->fields('menu_router')
->condition('tab_root', $router_item['tab_root'])
+ ->condition('tab_type', 'context', '<>')
->orderBy('weight')
->orderBy('title')
->execute();
- $map = arg();
+ $map = $router_item['original_map'];
$children = array();
$tasks = array();
$root_path = $router_item['path'];
@@ -1758,6 +1759,106 @@ function menu_local_tasks($level = 0) {
}
/**
+ * Retrieve contextual links for a system object based on registered local tasks.
+ *
+ * This leverages the menu system to retrieve the first layer of registered
+ * local tasks for a given system path. All local tasks of the tab type 'task'
+ * or 'context' are taken into account.
+ *
+ * @see hook_menu()
+ *
+ * For example, when considering the following registered local tasks:
+ * - node/%node/view (default local task) with no tab_type
+ * - node/%node/edit with tab_type "task"
+ * - node/%node/revisions with tab_type "view"
+ * - node/%node/report-as-spam with tab_type "context"
+ *
+ * If the path "node/123" is passed to this function, then it will return the
+ * links for 'edit' and 'report-as-spam'.
+ *
+ * @param $path
+ * The menu router path of the object to retrieve local tasks for, for example
+ * "node/123" or "admin/structure/menu/manage/[menu_name]".
+ *
+ * @return
+ * A list of menu router items that are local tasks for the passed in path.
+ *
+ * @see system_preprocess()
+ */
+function menu_contextual_links($parent_path, $args) {
+ static $path_empty = array();
+
+ // @todo This access check really doesn't belong into an API function. But as
+ // of now, there is no better location to entirely prevent the loading and
+ // building of contextual links in case they should not be rendered at all.
+ if (!user_access('access contextual links')) {
+ return array();
+ }
+
+ $links = array();
+ // Performance: In case a previous invocation for the same parent path did not
+ // return any links, we immediately return here.
+ if (isset($path_empty[$parent_path])) {
+ return $links;
+ }
+ $path = $parent_path . '/' . implode('/', $args);
+
+ // Get the router item for the given parent link path.
+ $router_item = menu_get_item($path);
+ if (!$router_item || !$router_item['access']) {
+ $path_empty[$parent_path] = TRUE;
+ return $links;
+ }
+ $data = &drupal_static(__FUNCTION__, array());
+ $root_path = $router_item['path'];
+
+ // Performance: For a single, normalized path (such as 'node/%') we only query
+ // available tasks once per request.
+ if (!isset($data[$root_path])) {
+ // Get all contextual links that are direct children of the router item and
+ // not of the tab type 'view'.
+ $data[$root_path] = db_select('menu_router', 'm')
+ ->fields('m')
+ ->condition('tab_parent', $router_item['tab_root'])
+ ->condition('tab_type', 'view', '<>')
+ ->orderBy('weight')
+ ->orderBy('title')
+ ->execute()
+ ->fetchAllAssoc('path', PDO::FETCH_ASSOC);
+ }
+ $parent_length = drupal_strlen($root_path) + 1;
+ $map = $router_item['original_map'];
+ foreach ($data[$root_path] as $item) {
+ // Extract the actual "task" string from the path argument.
+ $key = drupal_substr($item['path'], $parent_length);
+
+ // Denormalize and translate the contextual link.
+ _menu_translate($item, $map, TRUE);
+ if (!$item['access']) {
+ continue;
+ }
+ // All contextual links are keyed by the actual "task" path argument. The
+ // menu system does not allow for two local tasks with the same name, and
+ // since the key is also used as CSS class for the link item, which may be
+ // styled as icon, it wouldn't make sense to display the same icon for
+ // different tasks.
+ $links[$key] = $item;
+ }
+
+ // Allow modules to alter contextual links.
+ drupal_alter('menu_contextual_links', $links, $router_item, $root_path);
+
+ // Performance: If the current user does not have access to any links for this
+ // router path and no other module added further links, we assign FALSE here
+ // to skip the entire process the next time the same router path is requested.
+ if (empty($links)) {
+ $path_empty[$parent_path] = TRUE;
+ }
+
+ return $links;
+}
+
+/**
* Returns the rendered local tasks at the top level.
*/
function menu_primary_local_tasks() {
@@ -2829,6 +2930,10 @@ function _menu_router_build($callbacks)
$item['tab_parent'] = '';
$item['tab_root'] = $path;
}
+ // If not specified, assign the default tab type for local tasks.
+ elseif (!isset($item['tab_type'])) {
+ $item['tab_type'] = 'view';
+ }
for ($i = $item['_number_parts'] - 1; $i; $i--) {
$parent_path = implode('/', array_slice($item['_parts'], 0, $i));
if (isset($menu[$parent_path])) {
@@ -2901,6 +3006,7 @@ function _menu_router_build($callbacks)
'theme callback' => '',
'description' => '',
'position' => '',
+ 'tab_type' => '',
'tab_parent' => '',
'tab_root' => $path,
'path' => $path,
@@ -2944,6 +3050,7 @@ function _menu_router_save($menu, $masks
'delivery_callback',
'fit',
'number_parts',
+ 'tab_type',
'tab_parent',
'tab_root',
'title',
@@ -2972,6 +3079,7 @@ function _menu_router_save($menu, $masks
'delivery_callback' => $item['delivery callback'],
'fit' => $item['_fit'],
'number_parts' => $item['_number_parts'],
+ 'tab_type' => $item['tab_type'],
'tab_parent' => $item['tab_parent'],
'tab_root' => $item['tab_root'],
'title' => $item['title'],
Index: misc/contextual_links.css
===================================================================
RCS file: misc/contextual_links.css
diff -N misc/contextual_links.css
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ misc/contextual_links.css 16 Oct 2009 17:59:53 -0000
@@ -0,0 +1,38 @@
+/* $Id$ */
+
+/**
+ * Contextual links regions.
+ */
+.contextual-links-region {
+ outline: none;
+ position: relative;
+}
+.contextual-links-region-active {
+ outline: #000 dashed 1px;
+}
+
+/**
+ * Contextual links.
+ */
+ul.contextual-links {
+ float: right;
+ font-size: 90%;
+ margin: 0;
+ padding: 0;
+}
+ul.contextual-links li {
+ border-left: 1px solid #ccc;
+ display: inline;
+ line-height: 100%;
+ list-style: none;
+ margin: 0 0 0 0.3em;
+ padding: 0 0 0 0.6em;
+}
+ul.contextual-links li.first {
+ border-left: 0;
+ margin: 0;
+ padding: 0;
+}
+ul.contextual-links li a {
+ text-decoration: none;
+}
Index: misc/contextual_links.js
===================================================================
RCS file: misc/contextual_links.js
diff -N misc/contextual_links.js
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ misc/contextual_links.js 16 Oct 2009 18:01:08 -0000
@@ -0,0 +1,33 @@
+// $Id$
+(function ($) {
+
+Drupal.contextualLinks = Drupal.contextualLinks || {};
+
+/**
+ * Attach outline behavior for regions associated with contextual links.
+ */
+Drupal.behaviors.contextualLinks = {
+ attach: function (context) {
+ $('ul.contextual-links', context).once('contextual-links', function () {
+ $(this).hover(Drupal.contextualLinks.hover, Drupal.contextualLinks.hoverOut);
+ });
+ }
+};
+
+/**
+ * Enables outline for the region contextual links are associated with.
+ */
+Drupal.contextualLinks.hover = function () {
+ $(this).addClass('contextual-links-link-active')
+ .closest('.contextual-links-region').addClass('contextual-links-region-active');
+};
+
+/**
+ * Disables outline for the region contextual links are associated with.
+ */
+Drupal.contextualLinks.hoverOut = function () {
+ $(this).removeClass('contextual-links-link-active')
+ .closest('.contextual-links-region').removeClass('contextual-links-region-active');
+};
+
+})(jQuery);
Index: modules/block/block.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.api.php,v
retrieving revision 1.8
diff -u -p -r1.8 block.api.php
--- modules/block/block.api.php 31 Aug 2009 17:06:08 -0000 1.8
+++ modules/block/block.api.php 16 Oct 2009 17:50:23 -0000
@@ -140,6 +140,7 @@ function hook_block_view($delta = '') {
'content' => mymodule_display_block_exciting(),
);
break;
+
case 'amazing':
$block = array(
'subject' => t('Default title of the amazing block'),
@@ -151,6 +152,79 @@ function hook_block_view($delta = '') {
}
/**
+ * Perform alterations to the content of a block.
+ *
+ * This hook allows you to modify any data returned by hook_block_view().
+ *
+ * Note that instead of hook_block_view_alter(), which is called for all
+ * blocks, you can also use hook_block_view_MODULE_DELTA_alter() to alter a
+ * specific block.
+ *
+ * @param $data
+ * An array of data, as returned from the hook_block_view() implementation of
+ * the module that defined the block:
+ * - subject: The localized title of the block.
+ * - content: Either a string or a renderable array representing the content
+ * of the block. You should check that the content is an array before trying
+ * to modify parts of the renderable structure.
+ * @param $block
+ * The block object, as loaded from the database, having the main properties:
+ * - module: The name of the module that defined the block.
+ * - delta: The identifier for the block within that module, as defined within
+ * hook_block_info().
+ *
+ * @see hook_block_view_alter()
+ * @see hook_block_view()
+ */
+function hook_block_view_alter(&$data, $block) {
+ // Remove the contextual links on all blocks that provide them.
+ if (is_array($data['content']) && isset($data['content']['#contextual_links'])) {
+ unset($data['content']['#contextual_links']);
+ }
+ // Add a theme wrapper function defined by the current module to all blocks
+ // provided by the "somemodule" module.
+ if (is_array($data['content']) && $block->module == 'somemodule') {
+ $data['content']['#theme_wrappers'][] = 'mymodule_special_block';
+ }
+}
+
+/**
+ * Perform alterations to a specific block.
+ *
+ * Modules can implement hook_block_view_MODULE_DELTA_alter() to modify a
+ * specific block, rather than implementing hook_block_view_alter().
+ *
+ * Note that this hook fires before hook_block_view_alter(). Therefore, all
+ * implementations of hook_block_view_MODULE_DELTA_alter() will run before all
+ * implementations of hook_block_view_alter(), regardless of the module order.
+ *
+ * @param $data
+ * An array of data, as returned from the hook_block_view() implementation of
+ * the module that defined the block:
+ * - subject: The localized title of the block.
+ * - content: Either a string or a renderable array representing the content
+ * of the block. You should check that the content is an array before trying
+ * to modify parts of the renderable structure.
+ * @param $block
+ * The block object, as loaded from the database, having the main properties:
+ * - module: The name of the module that defined the block.
+ * - delta: The identifier for the block within that module, as defined within
+ * hook_block_info().
+ *
+ * @see hook_block_view_alter()
+ * @see hook_block_view()
+ */
+function hook_block_view_MODULE_DELTA_alter(&$data, $block) {
+ // This code will only run for a specific block. For example, if MODULE_DELTA
+ // in the function definition above is set to "mymodule_somedelta", the code
+ // will only run on the "somedelta" block provided by the "mymodule" module.
+
+ // Change the title of the "somedelta" block provided by the "mymodule"
+ // module.
+ $data['subject'] = t('New title of the block');
+}
+
+/**
* Act on blocks prior to rendering.
*
* This hook allows you to add, remove or modify blocks in the block list. The
Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.390
diff -u -p -r1.390 block.module
--- modules/block/block.module 16 Oct 2009 19:06:22 -0000 1.390
+++ modules/block/block.module 16 Oct 2009 21:45:28 -0000
@@ -280,6 +280,17 @@ function _block_get_renderable_array($li
foreach ($list as $key => $block) {
$build[$key] = $block->content;
unset($block->content);
+
+ // Add contextual links for this block; skipping the system main block.
+ if ($key != 'system_main') {
+ // @todo Implement proper path/subject/verb URL pattern for blocks.
+ // @see http://drupal.org/node/606640
+ $item = menu_get_item("admin/structure/block/configure/{$block->module}/{$block->delta}");
+ _menu_translate($item, $item['original_map'], TRUE);
+ $item['href'] = "admin/structure/block/configure/{$block->module}/{$block->delta}";
+ $build[$key]['#contextual_links']['block']['configure'] = $item;
+ }
+
$build[$key] += array(
'#block' => $block,
'#weight' => ++$weight,
@@ -753,6 +764,12 @@ function _block_render_blocks($region_bl
}
else {
$array = module_invoke($block->module, 'block_view', $block->delta);
+
+ // Allow modules to modify the block before it is viewed, via either
+ // hook_block_view_MODULE_DELTA_alter() or hook_block_view_alter().
+ drupal_alter("block_view_{$block->module}_{$block->delta}", $array, $block);
+ drupal_alter('block_view', $array, $block);
+
if (isset($cid)) {
cache_set($cid, $array, 'cache_block', CACHE_TEMPORARY);
}
Index: modules/block/block.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.tpl.php,v
retrieving revision 1.4
diff -u -p -r1.4 block.tpl.php
--- modules/block/block.tpl.php 11 Sep 2009 06:48:02 -0000 1.4
+++ modules/block/block.tpl.php 16 Oct 2009 17:52:58 -0000
@@ -11,6 +11,7 @@
* - $block->module: Module that generated the block.
* - $block->delta: An ID for the block, unique within each module.
* - $block->region: The block region embedding the current block.
+ * - $contextual_links (array): An array of contextual links for the block.
* - $classes: String of classes that can be used to style contextually through
* CSS. It can be manipulated through the variable $classes_array from
* preprocess functions. The default values can be one or more of the following:
@@ -36,6 +37,11 @@
*/
?>
>
+
+
+
+
+
subject): ?>
>subject ?>
Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.792
diff -u -p -r1.792 comment.module
--- modules/comment/comment.module 16 Oct 2009 20:40:05 -0000 1.792
+++ modules/comment/comment.module 16 Oct 2009 23:08:46 -0000
@@ -794,6 +794,8 @@ function comment_build($comment, $node,
'#node' => $node,
'#build_mode' => $build_mode,
);
+ // Add contextual links for this comment.
+ $build['#contextual_links']['comment'] = menu_contextual_links('comment', array($comment->cid));
$prefix = '';
$is_threaded = isset($comment->divs) && variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED) == COMMENT_MODE_THREADED;
Index: modules/comment/comment.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.tpl.php,v
retrieving revision 1.13
diff -u -p -r1.13 comment.tpl.php
--- modules/comment/comment.tpl.php 10 Oct 2009 13:37:10 -0000 1.13
+++ modules/comment/comment.tpl.php 16 Oct 2009 18:06:07 -0000
@@ -19,6 +19,7 @@
* - $status: Comment status. Possible values are:
* comment-unpublished, comment-published or comment-preview.
* - $title: Linked title.
+ * - $contextual_links (array): An array of contextual links for the comment.
* - $classes: String of classes that can be used to style contextually through
* CSS. It can be manipulated through the variable $classes_array from
* preprocess functions. The default values can be one or more of the following:
@@ -46,6 +47,10 @@
*/
?>
>
+
+
+
+
Index: modules/locale/locale.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/locale/locale.test,v
retrieving revision 1.47
diff -u -p -r1.47 locale.test
--- modules/locale/locale.test 16 Oct 2009 15:47:46 -0000 1.47
+++ modules/locale/locale.test 16 Oct 2009 21:45:28 -0000
@@ -1089,7 +1089,7 @@ class LanguageSwitchingFunctionalTest ex
$this->assertText(t('Languages'), t('Language switcher block found.'));
// Assert that only the current language is marked as active.
- list($language_switcher) = $this->xpath('//div[@id="block-locale-language"]');
+ list($language_switcher) = $this->xpath('//div[@id="block-locale-language"]/div[@class="content"]');
$links = array(
'active' => array(),
'inactive' => array(),
@@ -1098,7 +1098,7 @@ class LanguageSwitchingFunctionalTest ex
'active' => array(),
'inactive' => array(),
);
- foreach ($language_switcher->div->ul->li as $link) {
+ foreach ($language_switcher->ul->li as $link) {
$classes = explode(" ", (string) $link['class']);
list($language) = array_intersect($classes, array('en', 'fr'));
if (in_array('active', $classes)) {
Index: modules/menu/menu.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.api.php,v
retrieving revision 1.17
diff -u -p -r1.17 menu.api.php
--- modules/menu/menu.api.php 15 Oct 2009 14:07:29 -0000 1.17
+++ modules/menu/menu.api.php 16 Oct 2009 22:59:44 -0000
@@ -199,6 +199,18 @@
* this alone; the default alphabetical order is usually best.
* - "menu_name": Optional. Set this to a custom menu if you don't want your
* item to be placed in Navigation.
+ * - "tab_type": (optional) Defines the type of a tab to control its placement
+ * depending on the requested context. By default, all tabs are only
+ * displayed as local tasks when being rendered in a page context. All tabs
+ * that should be accessible as contextual links in page region containers
+ * outside of the parent menu item's primary page context, should be
+ * registered using one of the following types:
+ * - view: (default) The tab is displayed as local task for the page context
+ * only.
+ * - task: The tab is displayed both in the page context and as contextual
+ * link.
+ * - context: The tab is displayed as contextual link outside of the primary
+ * page context only.
* - "tab_parent": For local task menu items, the path of the task's parent
* item; defaults to the same path without the last component (e.g., the
* default parent for 'admin/people/create' is 'admin/people').
@@ -497,5 +509,40 @@ function hook_menu_local_tasks_alter(&$d
}
/**
+ * Alter contextual links before they are rendered.
+ *
+ * This hook is invoked by menu_contextual_links(). The system-determined tabs and
+ * actions are passed in by reference. Additional tabs or actions may be added,
+ * or existing items altered.
+ *
+ * Each tab or action is an associative array containing:
+ * - #link: An associative array containing:
+ * - 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 $data
+ * An associative array containing:
+ * - count: The amount of actions determined by the menu system, which can
+ * be ignored.
+ * - output: A list of of actions, each one being an associative array
+ * as described above.
+ */
+function hook_menu_contextual_links_alter(&$links, $router_item, $root_path) {
+ // Add a link to all contextual links for nodes.
+ if ($root_path == 'node/%') {
+ $links['foo'] = array(
+ 'title' => t('Do fu'),
+ 'href' => 'foo/do',
+ 'localized_options' => array(
+ 'query' => array(
+ 'foo' => 'bar',
+ ),
+ ),
+ );
+ }
+}
+
+/**
* @} End of "addtogroup hooks".
*/
Index: modules/menu/menu.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/menu/menu.module,v
retrieving revision 1.210
diff -u -p -r1.210 menu.module
--- modules/menu/menu.module 16 Oct 2009 19:06:23 -0000 1.210
+++ modules/menu/menu.module 16 Oct 2009 23:13:07 -0000
@@ -98,6 +98,7 @@ function menu_menu() {
'title' => 'List links',
'weight' => -10,
'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'tab_type' => 'task',
);
$items['admin/structure/menu/manage/%menu/add'] = array(
'title' => 'Add link',
@@ -113,6 +114,7 @@ function menu_menu() {
'page arguments' => array('menu_edit_menu', 'edit', 4),
'access arguments' => array('administer menu'),
'type' => MENU_LOCAL_TASK,
+ 'tab_type' => 'task',
'file' => 'menu.admin.inc',
);
$items['admin/structure/menu/manage/%menu/delete'] = array(
@@ -431,10 +433,27 @@ function menu_block_view($delta = '') {
$menus = menu_get_menus(FALSE);
$data['subject'] = check_plain($menus[$delta]);
$data['content'] = menu_tree($delta);
+ // Add contextual links for this block.
+ if (!empty($data['content'])) {
+ $data['content']['#contextual_links']['menu'] = menu_contextual_links('admin/structure/menu/manage', array($delta));
+ }
return $data;
}
/**
+ * Implement hook_block_view_alter().
+ */
+function menu_block_view_alter(&$data, $block) {
+ // Add contextual links for system menu blocks.
+ if ($block->module == 'system' && !empty($data['content'])) {
+ $system_menus = menu_list_system_menus();
+ if (isset($system_menus[$block->delta])) {
+ $data['content']['#contextual_links']['menu'] = menu_contextual_links('admin/structure/menu/manage', array($block->delta));
+ }
+ }
+}
+
+/**
* Implement hook_node_insert().
*/
function menu_node_insert($node) {
Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1149
diff -u -p -r1.1149 node.module
--- modules/node/node.module 16 Oct 2009 19:06:23 -0000 1.1149
+++ modules/node/node.module 16 Oct 2009 23:13:19 -0000
@@ -1112,6 +1112,9 @@ function node_build($node, $build_mode =
'#node' => $node,
'#build_mode' => $build_mode,
);
+ // Add contextual links for this node.
+ $build['#contextual_links']['node'] = menu_contextual_links('node', array($node->nid));
+
return $build;
}
@@ -1818,8 +1821,9 @@ function node_menu() {
'access callback' => 'node_access',
'access arguments' => array('update', 1),
'theme callback' => '_node_custom_theme',
- 'weight' => 1,
+ 'weight' => 0,
'type' => MENU_LOCAL_TASK,
+ 'tab_type' => 'task',
'file' => 'node.pages.inc',
);
$items['node/%node/delete'] = array(
@@ -1829,7 +1833,8 @@ function node_menu() {
'access callback' => 'node_access',
'access arguments' => array('delete', 1),
'weight' => 1,
- 'type' => MENU_CALLBACK,
+ 'type' => MENU_LOCAL_TASK,
+ 'tab_type' => 'context',
'file' => 'node.pages.inc',
);
$items['node/%node/revisions'] = array(
Index: modules/node/node.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.tpl.php,v
retrieving revision 1.24
diff -u -p -r1.24 node.tpl.php
--- modules/node/node.tpl.php 11 Oct 2009 06:43:33 -0000 1.24
+++ modules/node/node.tpl.php 16 Oct 2009 17:56:11 -0000
@@ -18,6 +18,7 @@
* - $node_url: Direct url of the current node.
* - $terms: the themed list of taxonomy term links output from theme_links().
* - $display_submitted: whether submission information should be displayed.
+ * - $contextual_links (array): An array of contextual links for the node.
* - $classes: String of classes that can be used to style contextually through
* CSS. It can be manipulated through the variable $classes_array from
* preprocess functions. The default values can be one or more of the following:
@@ -74,6 +75,10 @@
+
+
+
+
>
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.402
diff -u -p -r1.402 system.install
--- modules/system/system.install 16 Oct 2009 19:06:24 -0000 1.402
+++ modules/system/system.install 16 Oct 2009 21:45:29 -0000
@@ -1026,6 +1026,13 @@ function system_schema() {
'default' => 0,
'size' => 'small',
),
+ 'tab_type' => array(
+ 'description' => 'Only for local tasks (tabs) - the type of the local task to control its contextual placement.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
'tab_parent' => array(
'description' => 'Only for local tasks (tabs) - the router path of the parent page (which may also be a local task).',
'type' => 'varchar',
@@ -2758,6 +2765,19 @@ function system_update_7042() {
}
/**
+ * Add a 'tab_type' field to {menu_router} to control contextual placement of local tasks.
+ */
+function system_update_7043() {
+ db_add_field('menu_router', 'tab_type', array(
+ 'description' => 'Only for local tasks (tabs) - the type of the local task to control its contextual placement.',
+ 'type' => 'varchar',
+ 'length' => 255,
+ 'not null' => TRUE,
+ 'default' => '',
+ ));
+}
+
+/**
* @} End of "defgroup updates-6.x-to-7.x"
* The next series of updates should start at 8000.
*/
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.818
diff -u -p -r1.818 system.module
--- modules/system/system.module 16 Oct 2009 19:20:34 -0000 1.818
+++ modules/system/system.module 16 Oct 2009 21:45:30 -0000
@@ -243,6 +243,10 @@ function system_permission() {
'title' => t('Access administration pages'),
'description' => t('View the administration panel and browse the help system.'),
),
+ 'access contextual links' => array(
+ 'title' => t('Access contextual links'),
+ 'description' => t('Access contextual links associated with items on the page.'),
+ ),
'access site in maintenance mode' => array(
'title' => t('Access site in maintenance mode'),
'description' => t('Log in when the site is in maintenance mode.'),
@@ -3488,3 +3492,57 @@ function system_archiver_info() {
function theme_confirm_form($variables) {
return drupal_render_children($variables['form']);
}
+
+/**
+ * Template variable preprocessor for contextual links.
+ */
+function system_preprocess(&$variables, $hook) {
+ static $hooks, $destination;
+
+ if (!isset($hooks)) {
+ $hooks = theme_get_registry();
+ $destination = drupal_get_destination();
+ }
+
+ // Initialize contextual links template variable.
+ $variables['contextual_links'] = array();
+
+ // Determine the primary theme function argument.
+ $keys = array_keys($hooks[$hook]['arguments']);
+ $key = $keys[0];
+ if (isset($variables[$key])) {
+ $element = $variables[$key];
+ }
+
+ if (isset($element) && is_array($element) && isset($element['#contextual_links'])) {
+ // Transform contextual links into parameters suitable for theme_link().
+ $items = call_user_func_array('array_merge_recursive', $element['#contextual_links']);
+ $links = array();
+ foreach ($items as $class => $item) {
+ $class = drupal_html_class($class);
+ $links[$class] = array(
+ 'title' => $item['title'],
+ 'href' => $item['href'],
+ );
+ // @todo theme_links() should *really* use the same parameters as l()...
+ if (!isset($item['localized_options']['query'])) {
+ $item['localized_options']['query'] = array();
+ }
+ $item['localized_options']['query'] += $destination;
+ $links[$class] += $item['localized_options'];
+ }
+ if ($links) {
+ $variables['contextual_links'] = array(
+ '#theme' => 'links',
+ '#links' => $links,
+ '#attributes' => array('class' => array('contextual-links')),
+ '#attached' => array(
+ 'js' => array('misc/contextual_links.js'),
+ 'css' => array('misc/contextual_links.css'),
+ ),
+ );
+ $variables['classes_array'][] = 'contextual-links-region';
+ }
+ }
+}
+
Index: themes/garland/block.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/block.tpl.php,v
retrieving revision 1.9
diff -u -p -r1.9 block.tpl.php
--- themes/garland/block.tpl.php 11 Sep 2009 06:48:03 -0000 1.9
+++ themes/garland/block.tpl.php 16 Oct 2009 17:57:57 -0000
@@ -3,6 +3,10 @@
?>
>
+
+
+
+
subject)): ?>
>subject ?>
Index: themes/garland/comment.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/comment.tpl.php,v
retrieving revision 1.17
diff -u -p -r1.17 comment.tpl.php
--- themes/garland/comment.tpl.php 10 Oct 2009 13:37:11 -0000 1.17
+++ themes/garland/comment.tpl.php 16 Oct 2009 18:06:56 -0000
@@ -5,6 +5,10 @@
+
+
+
+
—
Index: themes/garland/node.tpl.php
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/node.tpl.php,v
retrieving revision 1.17
diff -u -p -r1.17 node.tpl.php
--- themes/garland/node.tpl.php 11 Oct 2009 03:07:21 -0000 1.17
+++ themes/garland/node.tpl.php 16 Oct 2009 17:58:21 -0000
@@ -3,6 +3,10 @@
?>
>
+
+
+
+
Index: themes/garland/style.css
===================================================================
RCS file: /cvs/drupal/drupal/themes/garland/style.css,v
retrieving revision 1.65
diff -u -p -r1.65 style.css
--- themes/garland/style.css 5 Oct 2009 02:43:01 -0000 1.65
+++ themes/garland/style.css 16 Oct 2009 17:58:41 -0000
@@ -650,8 +650,8 @@ ul.secondary li.active a {
*/
.node {
border-bottom: 1px solid #e9eff3;
- margin: 0 -26px 1.5em;
- padding: 1.5em 26px;
+ margin: 0 -16px 1.5em;
+ padding: 1.5em 16px;
}
ul.links li, ul.inline li {
@@ -809,6 +809,17 @@ tr.even td.menu-disabled {
}
/**
+ * Contextual links.
+ */
+.contextual-links-region-active {
+ outline: #027AC6 dashed 1px;
+}
+.block ul.contextual-links {
+ margin: 0;
+ padding: 0;
+}
+
+/**
* Collapsible fieldsets
*/
fieldset {