summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/block/block.api.php74
-rw-r--r--modules/block/block.module21
-rw-r--r--modules/block/block.tpl.php6
-rw-r--r--modules/comment/comment.module5
-rw-r--r--modules/comment/comment.tpl.php5
-rw-r--r--modules/locale/locale.test4
-rw-r--r--modules/menu/menu.api.php56
-rw-r--r--modules/menu/menu.module19
-rw-r--r--modules/node/node.module15
-rw-r--r--modules/node/node.tpl.php5
-rw-r--r--modules/system/system.install18
-rw-r--r--modules/system/system.module80
12 files changed, 300 insertions, 8 deletions
diff --git a/modules/block/block.api.php b/modules/block/block.api.php
index 4ea6844d5..b9147243f 100644
--- a/modules/block/block.api.php
+++ b/modules/block/block.api.php
@@ -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
diff --git a/modules/block/block.module b/modules/block/block.module
index 72356a500..9dd26e1a5 100644
--- a/modules/block/block.module
+++ b/modules/block/block.module
@@ -95,15 +95,20 @@ function block_menu() {
'type' => MENU_CALLBACK,
'file' => 'block.admin.inc',
);
- $items['admin/structure/block/manage/%block/%/configure'] = array(
+ $items['admin/structure/block/manage/%block/%'] = array(
'title' => 'Configure block',
'page callback' => 'drupal_get_form',
'page arguments' => array('block_admin_configure', 4),
'load arguments' => array(5),
'access arguments' => array('administer blocks'),
- 'type' => MENU_CALLBACK,
'file' => 'block.admin.inc',
);
+ $items['admin/structure/block/manage/%block/%/configure'] = array(
+ 'title' => 'Configure block',
+ 'load arguments' => array(5),
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_INLINE,
+ );
$items['admin/structure/block/manage/%block/%/delete'] = array(
'title' => 'Delete block',
'page callback' => 'drupal_get_form',
@@ -282,6 +287,12 @@ function _block_get_renderable_array($list = array()) {
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') {
+ $build[$key]['#contextual_links']['block'] = menu_contextual_links('admin/structure/block/manage', array($block->module, $block->delta));
+ }
+
$build[$key] += array(
'#block' => $block,
'#weight' => ++$weight,
@@ -785,6 +796,12 @@ function _block_render_blocks($region_blocks) {
}
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);
}
diff --git a/modules/block/block.tpl.php b/modules/block/block.tpl.php
index 961cb01b0..a1af14707 100644
--- a/modules/block/block.tpl.php
+++ b/modules/block/block.tpl.php
@@ -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 @@
*/
?>
<div id="block-<?php print $block->module . '-' . $block->delta; ?>" class="<?php print $classes; ?>"<?php print $attributes; ?>>
+
+<?php if ($contextual_links): ?>
+ <?php print render($contextual_links); ?>
+<?php endif; ?>
+
<?php if ($block->subject): ?>
<h2<?php print $title_attributes; ?>><?php print $block->subject ?></h2>
<?php endif;?>
diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index 9588633ea..ff88f6635 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -185,6 +185,7 @@ function comment_menu() {
'access callback' => 'comment_access',
'access arguments' => array('edit', 1),
'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'weight' => 0,
);
$items['comment/%comment/approve'] = array(
@@ -193,6 +194,7 @@ function comment_menu() {
'page arguments' => array(1),
'access arguments' => array('administer comments'),
'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_INLINE,
'file' => 'comment.pages.inc',
'weight' => 1,
);
@@ -202,6 +204,7 @@ function comment_menu() {
'page arguments' => array('comment_confirm_delete', 1),
'access arguments' => array('administer comments'),
'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'file' => 'comment.admin.inc',
'weight' => 2,
);
@@ -794,6 +797,8 @@ function comment_build($comment, $node, $build_mode = 'full') {
'#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;
diff --git a/modules/comment/comment.tpl.php b/modules/comment/comment.tpl.php
index 7b489aade..2777b3eda 100644
--- a/modules/comment/comment.tpl.php
+++ b/modules/comment/comment.tpl.php
@@ -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 @@
*/
?>
<div class="<?php print $classes; ?> clearfix"<?php print $attributes; ?>>
+ <?php if ($contextual_links): ?>
+ <?php print render($contextual_links); ?>
+ <?php endif; ?>
+
<?php print $picture ?>
<?php if ($new): ?>
diff --git a/modules/locale/locale.test b/modules/locale/locale.test
index 9a22b9abc..bb6a2de86 100644
--- a/modules/locale/locale.test
+++ b/modules/locale/locale.test
@@ -1089,7 +1089,7 @@ class LanguageSwitchingFunctionalTest extends DrupalWebTestCase {
$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 extends DrupalWebTestCase {
'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)) {
diff --git a/modules/menu/menu.api.php b/modules/menu/menu.api.php
index 1339bf04d..65170333c 100644
--- a/modules/menu/menu.api.php
+++ b/modules/menu/menu.api.php
@@ -199,6 +199,21 @@
* 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.
+ * - "context": (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 contexts:
+ * - MENU_CONTEXT_PAGE: (default) The tab is displayed as local task for the
+ * page context only.
+ * - MENU_CONTEXT_INLINE: The tab is displayed as contextual link outside of
+ * the primary page context only.
+ * Contexts can be combined. For example, to display a tab both on a page
+ * and inline, a menu router item may specify:
+ * @code
+ * 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ * @endcode
* - "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 +512,46 @@ function hook_menu_local_tasks_alter(&$data, $router_item, $root_path) {
}
/**
+ * Alter contextual links before they are rendered.
+ *
+ * This hook is invoked by menu_contextual_links(). The system-determined
+ * contextual links are passed in by reference. Additional links may be added
+ * or existing links can be altered.
+ *
+ * Each contextual link must at least 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 $links
+ * An associative array containing contextual links for the given $root_path,
+ * as described above. The array keys are used to build CSS class names for
+ * contextual links and must therefore be unique for each set of contextual
+ * links.
+ * @param $router_item
+ * The menu router item belonging to the $root_path being requested.
+ * @param $root_path
+ * The (parent) path that has been requested to build contextual links for.
+ * This is a normalized path, which means that an originally passed path of
+ * 'node/123' became 'node/%'.
+ *
+ * @see menu_contextual_links()
+ */
+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".
*/
diff --git a/modules/menu/menu.module b/modules/menu/menu.module
index 1e71297a5..824954d61 100644
--- a/modules/menu/menu.module
+++ b/modules/menu/menu.module
@@ -98,6 +98,7 @@ function menu_menu() {
'title' => 'List links',
'weight' => -10,
'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
);
$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,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'file' => 'menu.admin.inc',
);
$items['admin/structure/menu/manage/%menu/delete'] = array(
@@ -423,10 +425,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) {
diff --git a/modules/node/node.module b/modules/node/node.module
index 4c85affad..de59e22f7 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1112,6 +1112,9 @@ function node_build($node, $build_mode = 'full') {
'#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;
}
@@ -1806,11 +1809,13 @@ function node_menu() {
'page arguments' => array(1),
'access callback' => 'node_access',
'access arguments' => array('view', 1),
- 'type' => MENU_CALLBACK);
+ 'type' => MENU_CALLBACK,
+ );
$items['node/%node/view'] = array(
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,
- 'weight' => -10);
+ 'weight' => -10,
+ );
$items['node/%node/edit'] = array(
'title' => 'Edit',
'page callback' => 'node_page_edit',
@@ -1818,8 +1823,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,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'file' => 'node.pages.inc',
);
$items['node/%node/delete'] = array(
@@ -1829,7 +1835,8 @@ function node_menu() {
'access callback' => 'node_access',
'access arguments' => array('delete', 1),
'weight' => 1,
- 'type' => MENU_CALLBACK,
+ 'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_INLINE,
'file' => 'node.pages.inc',
);
$items['node/%node/revisions'] = array(
diff --git a/modules/node/node.tpl.php b/modules/node/node.tpl.php
index aa470f850..c05d7e8bf 100644
--- a/modules/node/node.tpl.php
+++ b/modules/node/node.tpl.php
@@ -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 @@
<?php print $user_picture; ?>
+ <?php if (!$page && $contextual_links): ?>
+ <?php print render($contextual_links); ?>
+ <?php endif; ?>
+
<?php if (!$page): ?>
<h2<?php print $title_attributes; ?>><a href="<?php print $node_url; ?>"><?php print $node_title; ?></a></h2>
<?php endif; ?>
diff --git a/modules/system/system.install b/modules/system/system.install
index bf73bda9b..66901ef4b 100644
--- a/modules/system/system.install
+++ b/modules/system/system.install
@@ -1026,6 +1026,12 @@ function system_schema() {
'default' => 0,
'size' => 'small',
),
+ 'context' => array(
+ 'description' => 'Only for local tasks (tabs) - the context of a local task to control its placement.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
'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 +2764,18 @@ function system_update_7042() {
}
/**
+ * Add a 'context' field to {menu_router} to control contextual placement of local tasks.
+ */
+function system_update_7043() {
+ db_add_field('menu_router', 'context', array(
+ 'description' => 'Only for local tasks (tabs) - the context of a local task to control its placement.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ ));
+}
+
+/**
* @} End of "defgroup updates-6.x-to-7.x"
* The next series of updates should start at 8000.
*/
diff --git a/modules/system/system.module b/modules/system/system.module
index 2bd5866ce..5c1abf524 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -3488,3 +3488,83 @@ 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;
+
+ if (!isset($hooks)) {
+ $hooks = theme_get_registry();
+ }
+
+ // 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'])) {
+ $variables['contextual_links'] = system_build_contextual_links($element);
+ if (!empty($variables['contextual_links'])) {
+ $variables['classes_array'][] = 'contextual-links-region';
+ }
+ }
+}
+
+/**
+ * Build a renderable array for contextual links.
+ *
+ * @param $element
+ * A renderable array containing a #contextual_links property.
+ *
+ * @return
+ * A renderable array representing contextual links.
+ */
+function system_build_contextual_links($element) {
+ static $destination;
+
+ // Transform contextual links into parameters suitable for theme_link().
+ $items = call_user_func_array('array_merge_recursive', $element['#contextual_links']);
+ $build = array();
+ if (empty($items)) {
+ return $build;
+ }
+
+ if (!isset($destination)) {
+ $destination = drupal_get_destination();
+ }
+
+ $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) {
+ $build = 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'),
+ ),
+ );
+ }
+ return $build;
+}
+