summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreffulgentsia2011-02-22 18:07:29 (GMT)
committer effulgentsia2011-02-22 18:07:29 (GMT)
commit63c157a23ea02439e976fbcc11dfa7364949c5e2 (patch)
tree74003a02d65854aa9964e5cbc6c336ae8681fded
parent1aba7055d9be2f6f3f6db1758cb7eb970c8dc4ac (diff)
parent613984f1e6abada58654a21690c5802abe803b65 (diff)
Merge remote branch 'origin/master'
-rw-r--r--css/views.css17
-rw-r--r--docs/docs.php17
-rw-r--r--includes/plugins.inc2
-rw-r--r--js/base.js28
-rw-r--r--js/views-contextual.js18
-rw-r--r--plugins/views_plugin_display.inc2
-rw-r--r--tests/templates/views-view--frontpage.tpl.php7
-rw-r--r--theme/theme.inc37
-rw-r--r--theme/views-ui-edit-view.tpl.php2
-rw-r--r--theme/views-view.tpl.php7
-rw-r--r--views.module212
-rw-r--r--views_ui.module32
12 files changed, 266 insertions, 115 deletions
diff --git a/css/views.css b/css/views.css
index b909f0b..763cc40 100644
--- a/css/views.css
+++ b/css/views.css
@@ -33,23 +33,6 @@
text-align: center;
}
-div.view div.views-hide {
- display: none;
-}
-
-/** For IE we add the class via js; for other browsers we rely on :hover **/
-div.view div.views-hide-hover,
-div.view:hover div.views-hide {
- display: block;
- position: absolute;
- z-index: 200;
-}
-
-/* don't do this one in IE */
-div.view:hover div.views-hide {
- margin-top: -1.5em;
-}
-
/* Remove the border on tbody that system puts in */
.views-view-grid tbody {
border-top: none;
diff --git a/docs/docs.php b/docs/docs.php
index c9ce039..53faf8c 100644
--- a/docs/docs.php
+++ b/docs/docs.php
@@ -679,23 +679,6 @@ function hook_views_query_alter(&$view, &$query) {
* This must either be in the same directory as the .module file or in a subdirectory
* named 'includes'.
*
- * Alter the links that appear over a view. They are in a format suitable for
- * theme('links').
- *
- * Warning: $view is not a reference in PHP4 and cannot be modified here. But it IS
- * a reference in PHP5, and can be modified. Please be careful with it.
- *
- * @see theme_links
- */
-function hook_views_admin_links_alter(&$links, $view) {
- // example code here
-}
-
-/**
- * This hook should be placed in MODULENAME.views.inc and it will be auto-loaded.
- * This must either be in the same directory as the .module file or in a subdirectory
- * named 'includes'.
- *
* Alter the rows that appear with a view preview, which include query and
* performance statistics. $rows is an associative array with two keys:
* - query: An array of rows suitable for theme('table'), containing information
diff --git a/includes/plugins.inc b/includes/plugins.inc
index 4742ae4..7afac0c 100644
--- a/includes/plugins.inc
+++ b/includes/plugins.inc
@@ -38,6 +38,7 @@ function views_views_plugins() {
'handler' => 'views_plugin_display_page',
'theme' => 'views_view',
'uses hook menu' => TRUE,
+ 'contextual links locations' => array('page'),
'use ajax' => TRUE,
'use pager' => TRUE,
'accept attachments' => TRUE,
@@ -50,6 +51,7 @@ function views_views_plugins() {
'handler' => 'views_plugin_display_block',
'theme' => 'views_view',
'uses hook block' => TRUE,
+ 'contextual links locations' => array('block'),
'use ajax' => TRUE,
'use pager' => TRUE,
'use more' => TRUE,
diff --git a/js/base.js b/js/base.js
index f437f5b..68ee7f4 100644
--- a/js/base.js
+++ b/js/base.js
@@ -41,34 +41,6 @@ Drupal.behaviors.viewsTabs = {
};
/**
- * For IE, attach some javascript so that our hovers do what they're supposed
- * to do.
- */
-Drupal.behaviors.viewsHoverlinks = function() {
- if ($.browser.msie) {
- // If IE, attach a hover event so we can see our admin links.
- $("div.view:not(.views-hover-processed)").addClass('views-hover-processed').hover(
- function() {
- $('div.views-hide', this).addClass("views-hide-hover"); return true;
- },
- function(){
- $('div.views-hide', this).removeClass("views-hide-hover"); return true;
- }
- );
- $("div.views-admin-links:not(.views-hover-processed)")
- .addClass('views-hover-processed')
- .hover(
- function() {
- $(this).addClass("views-admin-links-hover"); return true;
- },
- function(){
- $(this).removeClass("views-admin-links-hover"); return true;
- }
- );
- }
-}
-
-/**
* Helper function to parse a querystring.
*/
Drupal.Views.parseQueryString = function (query) {
diff --git a/js/views-contextual.js b/js/views-contextual.js
new file mode 100644
index 0000000..8dd6cf2
--- /dev/null
+++ b/js/views-contextual.js
@@ -0,0 +1,18 @@
+// $Id$
+
+/**
+ * @file
+ * Javascript related to contextual links.
+ */
+(function ($) {
+
+Drupal.behaviors.viewsContextualLinks = {
+ attach: function (context) {
+ // If there are views-related contextual links attached to the main page
+ // content, find the smallest region that encloses both the links and the
+ // view, and display it as a contextual links region.
+ $('.views-contextual-links-page', context).closest(':has(.view)').addClass('contextual-links-region');
+ }
+};
+
+})(jQuery);
diff --git a/plugins/views_plugin_display.inc b/plugins/views_plugin_display.inc
index 4f63669..6846e83 100644
--- a/plugins/views_plugin_display.inc
+++ b/plugins/views_plugin_display.inc
@@ -2399,7 +2399,7 @@ class views_plugin_display extends views_plugin {
function view_special_blocks($type) {
if ($type == '-exp') {
// avoid interfering with the admin forms.
- if (arg(0) == 'admin' && arg(1) == 'build' && arg(2) == 'views') {
+ if (arg(0) == 'admin' && arg(1) == 'structure' && arg(2) == 'views') {
return;
}
$this->view->init_handlers();
diff --git a/tests/templates/views-view--frontpage.tpl.php b/tests/templates/views-view--frontpage.tpl.php
index 7704c81..1741b95 100644
--- a/tests/templates/views-view--frontpage.tpl.php
+++ b/tests/templates/views-view--frontpage.tpl.php
@@ -23,18 +23,11 @@
* - $exposed: Exposed widget form/info to display
* - $feed_icon: Feed icon to display, if any
* - $more: A link to view more, if any
- * - $admin_links: A rendered list of administrative links
- * - $admin_links_raw: A list of administrative links suitable for theme('links')
*
* @ingroup views_templates
*/
?>
<div class="<?php print $classes; ?>">
- <?php if ($admin_links): ?>
- <div class="views-admin-links views-hide">
- <?php print $admin_links; ?>
- </div>
- <?php endif; ?>
<?php if ($header): ?>
<div class="view-header">
<?php print $header; ?>
diff --git a/theme/theme.inc b/theme/theme.inc
index c01fae3..72ff414 100644
--- a/theme/theme.inc
+++ b/theme/theme.inc
@@ -88,36 +88,13 @@ function template_preprocess_views_view(&$vars) {
$vars['attachment_before'] = !empty($view->attachment_before) ? $view->attachment_before : '';
$vars['attachment_after'] = !empty($view->attachment_after) ? $view->attachment_after : '';
- // if administrator, add some links. These used to be tabs, but this is better.
- if (user_access('administer views') && module_exists('views_ui') && module_exists('contextual') && empty($view->hide_admin_links)) {
- $links = array(
- 'views-edit' => array(
- 'title' => t('Edit view'),
- 'attributes' => array('title' => t("Edit this view")),
- 'href' => "admin/structure/views/view/$view->name",
- 'fragment' => 'views-tab-' . $view->current_display,
- 'query' => drupal_get_destination(),
- ),
- );
- drupal_alter('views_admin_links', $links, $view);
-
- $build = array(
- '#prefix' => '<div class="contextual-links-wrapper">',
- '#suffix' => '</div>',
- '#theme' => 'links__contextual',
- '#links' => $links,
- '#attributes' => array('class' => array('contextual-links')),
- '#attached' => array(
- 'library' => array(array('contextual', 'contextual-links')),
- ),
- );
- $vars['classes_array'][] = 'contextual-links-region';
- $vars['admin_links'] = drupal_render($build);
- }
- else {
- $vars['admin_links'] = '';
- $vars['admin_links_raw'] = array();
- }
+ // Add contextual links to the view. We need to attach them to the dummy
+ // $view_array variable, since contextual_preprocess() requires that they be
+ // attached to an array (not an object) in order to process them. For our
+ // purposes, it doesn't matter what we attach them to, since once they are
+ // processed by contextual_preprocess() they will appear in the $title_suffix
+ // variable (which we will then render in views-view.tpl.php).
+ views_add_contextual_links($vars['view_array'], 'view', $view, $view->current_display);
// Attachments are always updated with the outer view, never by themselves,
// so they do not have dom ids.
diff --git a/theme/views-ui-edit-view.tpl.php b/theme/views-ui-edit-view.tpl.php
index 5c515ab..67f0edd 100644
--- a/theme/views-ui-edit-view.tpl.php
+++ b/theme/views-ui-edit-view.tpl.php
@@ -11,7 +11,7 @@
<?php print t('This view is being edited by user !user, and is therefore locked from editing by others. This lock is !age old. Click here to <a href="!break">break this lock</a>.', array('!user' => $locked, '!age' => $lock_age, '!break' => $break)); ?>
</div>
<?php endif; ?>
- <div class="views-basic-info contextual-links-region clearfix<?php if (!empty($view->changed)) { print " changed"; }?>">
+ <div class="views-basic-info clearfix<?php if (!empty($view->changed)) { print " changed"; }?>">
<?php if (!is_numeric($view->vid)): ?>
<div class="view-changed view-new"><?php print t('New view'); ?></div>
<?php else: ?>
diff --git a/theme/views-view.tpl.php b/theme/views-view.tpl.php
index 003973e..ffd124f 100644
--- a/theme/views-view.tpl.php
+++ b/theme/views-view.tpl.php
@@ -23,19 +23,16 @@
* - $exposed: Exposed widget form/info to display
* - $feed_icon: Feed icon to display, if any
* - $more: A link to view more, if any
- * - $admin_links: A rendered list of administrative links
- * - $admin_links_raw: A list of administrative links suitable for theme('links')
*
* @ingroup views_templates
*/
?>
<div class="<?php print $classes; ?>">
+ <?php print render($title_prefix); ?>
<?php if ($title): ?>
<?php print $title; ?>
<?php endif; ?>
- <?php if ($admin_links): ?>
- <?php print $admin_links; ?>
- <?php endif; ?>
+ <?php print render($title_suffix); ?>
<?php if ($header): ?>
<div class="view-header">
<?php print $header; ?>
diff --git a/views.module b/views.module
index b8ccdae..c105179 100644
--- a/views.module
+++ b/views.module
@@ -43,7 +43,10 @@ function views_theme($existing, $type, $theme, $path) {
);
$arguments = array(
- 'display' => array('view' => NULL),
+ // For displays, we pass in a dummy array as the first parameter, since
+ // $view is an object but the core contextual_preprocess() function only
+ // attaches contextual links when the primary theme argument is an array.
+ 'display' => array('view_array' => array(), 'view' => NULL),
'style' => array('view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL),
'row' => array('view' => NULL, 'options' => NULL, 'row' => NULL, 'field_alias' => NULL),
);
@@ -395,13 +398,20 @@ function views_arg_load($value, $name, $display_id, $index) {
* passes control to the display handler.
*/
function views_page() {
+ // Determine the name and display ID of the view that will be rendered here,
+ // and save them in a static variable so we can use them in hook_page_alter()
+ // to affect the rest of the page.
+ $name = &drupal_static('views_page:name');
+ $display_id = &drupal_static('views_page:display_id');
$args = func_get_args();
$name = array_shift($args);
$display_id = array_shift($args);
- // Load the view
+ // Load the view and render it. Destory it before returning, to save memory.
if ($view = views_get_view($name)) {
- return $view->execute_display($display_id, $args);
+ $output = $view->execute_display($display_id, $args);
+ $view->destroy();
+ return $output;
}
// Fallback; if we get here no view was found or handler was not valid.
@@ -409,6 +419,61 @@ function views_page() {
}
/**
+ * Implements hook_page_alter().
+ */
+function views_page_alter(&$page) {
+ // Check the static variables that were set in views_page() to see if the
+ // main content of this page contains a view. If so, attach its contextual
+ // links to the overall page array. This allows them to be rendered directly
+ // next to the page title.
+ $name = drupal_static('views_page:name');
+ $display_id = drupal_static('views_page:display_id');
+ if (!empty($name) && !empty($display_id) && ($view = views_get_view($name))) {
+ views_add_contextual_links($page, 'page', $view, $display_id);
+ $view->destroy();
+ }
+}
+
+/**
+ * Implements MODULE_preprocess_HOOK().
+ */
+function views_preprocess_html(&$variables) {
+ // If the page contains a view as its main content, contextual links may have
+ // been attached to the page as a whole; for example, by views_page_alter().
+ // This allows them to be associated with the page and rendered by default
+ // next to the page title (which we want). However, it also causes the
+ // Contextual Links module to treat the wrapper for the entire page (i.e.,
+ // the <body> tag) as the HTML element that these contextual links are
+ // associated with. This we don't want; for better visual highlighting, we
+ // prefer a smaller region to be chosen. The region we prefer differs from
+ // theme to theme and depends on the details of the theme's markup in
+ // page.tpl.php, so we can only find it using JavaScript. We therefore remove
+ // the "contextual-links-region" class from the <body> tag here and add
+ // JavaScript that will insert it back in the correct place.
+ if (!empty($variables['page']['#views_contextual_links_info'])) {
+ $key = array_search('contextual-links-region', $variables['classes_array']);
+ if ($key !== FALSE) {
+ unset($variables['classes_array'][$key]);
+ // Add the JavaScript, with a group and weight such that it will run
+ // before modules/contextual/contextual.js.
+ drupal_add_js(drupal_get_path('module', 'views') . '/js/views-contextual.js', array('group' => JS_LIBRARY, 'weight' => -1));
+ }
+ }
+}
+
+/**
+ * Implements hook_contextual_links_view_alter().
+ */
+function views_contextual_links_view_alter(&$element, $items) {
+ // If we are rendering views-related contextual links attached to the overall
+ // page array, add a class to the list of contextual links. This will be used
+ // by the JavaScript added in views_preprocess_html().
+ if (!empty($element['#element']['#views_contextual_links_info']) && !empty($element['#element']['#type']) && $element['#element']['#type'] == 'page') {
+ $element['#attributes']['class'][] = 'views-contextual-links-page';
+ }
+}
+
+/**
* Implement hook_block_info().
*/
function views_block_info() {
@@ -501,6 +566,9 @@ function views_block_view($delta) {
$view->set_display($display_id);
if (isset($view->display_handler)) {
$output = $view->display_handler->view_special_blocks($type);
+ // Before returning the block output, convert it to a renderable
+ // array with contextual links.
+ views_add_block_contextual_links($output, $view, $display_id);
$view->destroy();
return $output;
}
@@ -514,6 +582,9 @@ function views_block_view($delta) {
if ($view = views_get_view($name)) {
if ($view->access($display_id)) {
$output = $view->execute_display($display_id);
+ // Before returning the block output, convert it to a renderable array
+ // with contextual links.
+ views_add_block_contextual_links($output, $view, $display_id);
$view->destroy();
return $output;
}
@@ -522,6 +593,141 @@ function views_block_view($delta) {
}
/**
+ * Converts Views block content to a renderable array with contextual links.
+ *
+ * @param $block
+ * An array representing the block, with the same structure as the return
+ * value of hook_block_view(). This will be modified so as to force
+ * $block['content'] to be a renderable array, containing the optional
+ * '#contextual_links' property (if there are any contextual links associated
+ * with the block).
+ * @param $view
+ * The view that was used to generate the block content.
+ * @param $display_id
+ * The ID of the display within the view that was used to generate the block
+ * content.
+ */
+function views_add_block_contextual_links(&$block, $view, $display_id) {
+ // Do not add contextual links to an empty block.
+ if (!empty($block['content'])) {
+ // Contextual links only work on blocks whose content is a renderable
+ // array, so if the block contains a string of already-rendered markup,
+ // convert it to an array.
+ if (is_string($block['content'])) {
+ $block['content'] = array('#markup' => $block['content']);
+ }
+ // Add the contextual links.
+ views_add_contextual_links($block['content'], 'block', $view, $display_id);
+ }
+}
+
+/**
+ * Adds contextual links associated with a view display to a renderable array.
+ *
+ * This function should be called when a view is being rendered in a particular
+ * location and you want to attach the appropriate contextual links (e.g.,
+ * links for editing the view) to it.
+ *
+ * The function operates by checking the view's display plugin to see if it has
+ * defined any contextual links that are intended to be displayed in the
+ * requested location; if so, it attaches them. The contextual links intended
+ * for a particular location are defined by the 'contextual links' and
+ * 'contextual links locations' properties in hook_views_plugins() and
+ * hook_views_plugins_alter(); as a result, these hook implementations have
+ * full control over where and how contextual links are rendered for each
+ * display.
+ *
+ * In addition to attaching the contextual links to the passed-in array (via
+ * the standard #contextual_links property), this function also attaches
+ * additional information via the #views_contextual_links_info property. This
+ * stores an array whose keys are the names of each module that provided
+ * views-related contextual links (same as the keys of the #contextual_links
+ * array itself) and whose values are themselves arrays whose keys ('location',
+ * 'view_name', and 'view_display_id') store the location, name of the view,
+ * and display ID that were passed in to this function. This allows you to
+ * access information about the contextual links and how they were generated in
+ * a variety of contexts where you might be manipulating the renderable array
+ * later on (for example, alter hooks which run later during the same page
+ * request).
+ *
+ * @param $render_element
+ * The renderable array to which contextual links will be added. This array
+ * should be suitable for passing in to drupal_render() and will normally
+ * contain a representation of the view display whose contextual links are
+ * being requested.
+ * @param $location
+ * The location in which the calling function intends to render the view and
+ * its contextual links. The core system supports three options for this
+ * parameter:
+ * - 'block': Used when rendering a block which contains a view. This
+ * retrieves any contextual links intended to be attached to the block
+ * itself.
+ * - 'page': Used when rendering the main content of a page which contains a
+ * view. This retrieves any contextual links intended to be attached to the
+ * page itself (for example, links which are displayed directly next to the
+ * page title).
+ * - 'view': Used when rendering the view itself, in any context. This
+ * retrieves any contextual links intended to be attached directly to the
+ * view.
+ * If you are rendering a view and its contextual links in another location,
+ * you can pass in a different value for this parameter. However, you will
+ * also need to use hook_views_plugins() or hook_views_plugins_alter() to
+ * declare, via the 'contextual links locations' array key, which view
+ * displays support having their contextual links rendered in the location
+ * you have defined.
+ * @param $view
+ * The view whose contextual links will be added.
+ * @param $display_id
+ * The ID of the display within $view whose contextual links will be added.
+ *
+ * @see hook_views_plugins()
+ * @see views_block_view()
+ * @see views_page_alter()
+ * @see template_preprocess_views_view()
+ */
+function views_add_contextual_links(&$render_element, $location, $view, $display_id) {
+ // Do not do anything if the view is configured to hide its administrative
+ // links.
+ if (empty($view->hide_admin_links)) {
+ // Also do not do anything if the display plugin has not defined any
+ // contextual links that are intended to be displayed in the requested
+ // location.
+ $plugin = views_fetch_plugin_data('display', $view->display[$display_id]->display_plugin);
+ $has_links = !empty($plugin['contextual links']) && !empty($plugin['contextual links locations']);
+ if ($has_links && in_array($location, $plugin['contextual links locations'])) {
+ foreach ($plugin['contextual links'] as $module => $link) {
+ $args = array();
+ $valid = TRUE;
+ if (!empty($link['argument properties'])) {
+ foreach ($link['argument properties'] as $property) {
+ // If the plugin is trying to create an invalid contextual link
+ // (for example, "path/to/{$view->property}", where $view->property
+ // does not exist), we cannot construct the link, so we skip it.
+ if (!property_exists($view, $property)) {
+ $valid = FALSE;
+ break;
+ }
+ else {
+ $args[] = $view->{$property};
+ }
+ }
+ }
+ // If the link was valid, attach information about it to the renderable
+ // array.
+ if ($valid) {
+ $render_element['#contextual_links'][$module] = array($link['parent path'], $args);
+ $render_element['#views_contextual_links_info'][$module] = array(
+ 'location' => $location,
+ 'view_name' => $view->name,
+ 'view_display_id' => $display_id,
+ );
+ }
+ }
+ }
+ }
+}
+
+/**
* Implements hook_flush_caches().
*/
function views_flush_caches() {
diff --git a/views_ui.module b/views_ui.module
index 41a08e0..814e153 100644
--- a/views_ui.module
+++ b/views_ui.module
@@ -75,8 +75,9 @@ function views_ui_menu() {
'page arguments' => array('views_ui_edit_form', 4),
) + $base;
$items['admin/structure/views/view/%views_ui_cache/edit'] = array(
- 'title' => 'Edit',
+ 'title' => 'Edit view',
'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'weight' => -10,
) + $base;
$items['admin/structure/views/view/%views_ui_cache/edit/ajax'] = array(
@@ -357,8 +358,6 @@ function views_ui_preprocess_views_view(&$vars) {
$view = $vars['view'];
if (!empty($view->views_ui_context)) {
$view->hide_admin_links = TRUE;
- $vars['admin_links'] = '';
- $vars['admin_links_raw'] = array();
foreach (array('title', 'header', 'exposed', 'rows', 'pager', 'more', 'footer', 'empty', 'attachment_after', 'attachment_before') as $section) {
if (!empty($vars[$section])) {
$vars[$section] = array(
@@ -639,15 +638,36 @@ function views_ui_get_form_wizard_instance($wizard) {
}
/**
+ * Implements hook_views_plugins_alter().
+ */
+function views_ui_views_plugins_alter(&$plugins) {
+ // Attach contextual links to each display plugin. The links will point to
+ // paths underneath "admin/structure/views/view/{$view->name}" (i.e., paths
+ // for editing and performing other contextual actions on the view).
+ foreach ($plugins['display'] as &$display) {
+ $display['contextual links']['views_ui'] = array(
+ 'parent path' => 'admin/structure/views/view',
+ 'argument properties' => array('name'),
+ );
+ }
+}
+
+/**
* Implements hook_contextual_links_view_alter().
- *
- * Removes contextual links from being rendered, when so desired, such as within
- * a View preview.
*/
function views_ui_contextual_links_view_alter(&$element, $items) {
+ // Remove contextual links from being rendered, when so desired, such as
+ // within a View preview.
if (views_ui_contextual_links_suppress()) {
$element['#links'] = array();
}
+ // Append the display ID to the Views UI edit links, so that clicking on the
+ // contextual link takes you directly to the correct display tab on the edit
+ // screen.
+ elseif (!empty($element['#links']['views-ui-edit']) && !empty($element['#element']['#views_contextual_links_info']['views_ui']['view_display_id'])) {
+ $display_id = $element['#element']['#views_contextual_links_info']['views_ui']['view_display_id'];
+ $element['#links']['views-ui-edit']['href'] .= '/' . $display_id;
+ }
}
/**