views_ui.module 13.5 KB
Newer Older
merlinofchaos's avatar
merlinofchaos committed
1 2 3 4 5 6 7
<?php

/**
 * @file
 * Provide structure for the administrative interface to Views.
 */

8
use Drupal\views\Views;
9
use Drupal\views\ViewExecutable;
10
use Drupal\views\ViewStorageInterface;
11
use Drupal\views_ui\ViewUI;
12
use Drupal\views\Analyzer;
13 14
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
15
use Symfony\Component\HttpFoundation\Request;
16

17 18 19
/**
 * Implements hook_help().
 */
20 21 22
function views_ui_help($route_name, Request $request) {
  switch ($route_name) {
    case 'help.page.views_ui':
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Views UI module provides an interface for managing views for the <a href="@views">Views module</a>. For more information, see the <a href="@handbook">online documentation for the Views UI module</a>.', array('@views' => \Drupal::url('help.page', array('name' => 'views')), '@handbook' => 'https://drupal.org/documentation/modules/views_ui')) . '</p>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Creating and managing views.') . '</dt>';
      $output .= '<dd>' . t('Views can be created from the <a href="@list">Views list page</a> by using the "Add new view" action. Existing views can be managed from the <a href="@list">Views list page</a> by locating the view in the "Enabled" or "Disabled" list and selecting the desired operation action, for example "Edit".', array('@list' => \Drupal::url('views_ui.list', array('name' => 'views_ui')))) . '</dd>';
      $output .= '<dt>' . t('Enabling and disabling views.') . '<dt>';
      $output .= '<dd>' . t('Views can be enabled or disabled from the <a href="@list">Views list page</a>. To enable a view, find the view within the "Disabled" list and select the "Enable" operation. To disable a view find the view within the "Enabled" list and select the "Disable" operation.', array('@list' => \Drupal::url('views_ui.list', array('name' => 'views_ui')))) . '</dd>';
      $output .= '<dt>' . t('Exporting and importing views.') . '</dt>';
      $output .= '<dd>' . t('Views can be exported and imported as configuration files by using the <a href="@config">Configuration Manager module</a>.', array('@config' => \Drupal::url('help.page', array('name' => 'config')))) . '</dd>';
      $output .= '<dt>' . t('Theming views.') . '</dt>';
      $output .= '<dd>' . t('The template files used by views can be overridden from a custom theme. When editing a view, you can see the templates that are used and alternatives for overriding them by clicking on the "Templates" link, found in the Advanced &gt; Other section under "Output".') . '</dd>';
      $output .= '</dl>';
      return $output;
  }
}

41
/**
42
 * Implements hook_entity_type_build().
43
 */
44 45 46
function views_ui_entity_type_build(array &$entity_types) {
  /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
  $entity_types['view']
47 48 49 50 51
    ->setFormClass('edit', 'Drupal\views_ui\ViewEditForm')
    ->setFormClass('add', 'Drupal\views_ui\ViewAddForm')
    ->setFormClass('preview', 'Drupal\views_ui\ViewPreviewForm')
    ->setFormClass('clone', 'Drupal\views_ui\ViewCloneForm')
    ->setFormClass('delete', 'Drupal\views_ui\ViewDeleteForm')
52
    ->setFormClass('break_lock', 'Drupal\views_ui\Form\BreakLockForm')
53
    ->setListBuilderClass('Drupal\views_ui\ViewListBuilder')
54 55 56 57 58 59 60 61
    ->setLinkTemplate('edit-form', 'views_ui.edit')
    ->setLinkTemplate('edit-display-form', 'views_ui.edit_display')
    ->setLinkTemplate('preview-form', 'views_ui.preview')
    ->setLinkTemplate('clone', 'views_ui.clone')
    ->setLinkTemplate('delete-form', 'views_ui.delete')
    ->setLinkTemplate('enable', 'views_ui.enable')
    ->setLinkTemplate('disable', 'views_ui.disable')
    ->setLinkTemplate('break-lock', 'views_ui.break_lock');
62 63
}

merlinofchaos's avatar
merlinofchaos committed
64 65 66 67 68 69 70 71 72
/**
 * Implements hook_theme().
 */
function views_ui_theme() {
  return array(
    // edit a view
    'views_ui_display_tab_setting' => array(
      'variables' => array('description' => '', 'link' => '', 'settings_links' => array(), 'overridden' => FALSE, 'defaulted' => FALSE, 'description_separator' => TRUE, 'class' => array()),
      'template' => 'views-ui-display-tab-setting',
73
      'file' => 'views_ui.theme.inc',
merlinofchaos's avatar
merlinofchaos committed
74 75 76 77
    ),
    'views_ui_display_tab_bucket' => array(
      'render element' => 'element',
      'template' => 'views-ui-display-tab-bucket',
78
      'file' => 'views_ui.theme.inc',
merlinofchaos's avatar
merlinofchaos committed
79 80 81
    ),
    'views_ui_rearrange_filter_form' => array(
      'render element' => 'form',
82
      'file' => 'views_ui.theme.inc',
merlinofchaos's avatar
merlinofchaos committed
83 84 85
    ),
    'views_ui_expose_filter_form' => array(
      'render element' => 'form',
86
      'file' => 'views_ui.theme.inc',
merlinofchaos's avatar
merlinofchaos committed
87 88 89 90
    ),

    // list views
    'views_ui_view_info' => array(
91
      'variables' => array('view' => NULL, 'displays' => NULL),
92
      'file' => 'views_ui.theme.inc',
93
      'template' => 'views-ui-view-info',
merlinofchaos's avatar
merlinofchaos committed
94 95
    ),

96 97 98
    // Group of filters.
    'views_ui_build_group_filter_form' => array(
      'render element' => 'form',
99
      'file' => 'views_ui.theme.inc',
100 101
    ),

merlinofchaos's avatar
merlinofchaos committed
102 103 104
    // On behalf of a plugin
    'views_ui_style_plugin_table' => array(
      'render element' => 'form',
105
      'file' => 'views_ui.theme.inc',
106
      'template' => 'views-ui-style-plugin-table',
merlinofchaos's avatar
merlinofchaos committed
107 108 109 110 111
    ),

    // When previewing a view.
    'views_ui_view_preview_section' => array(
      'variables' => array('view' => NULL, 'section' => NULL, 'content' => NULL, 'links' => ''),
112
      'file' => 'views_ui.theme.inc',
113
      'template' => 'views-ui-view-preview-section',
merlinofchaos's avatar
merlinofchaos committed
114 115 116 117
    ),

    // Generic container wrapper, to use instead of theme_container when an id
    // is not desired.
118
    'views_ui_container' => array(
119 120
      'variables' => array('children' => NULL, 'attributes' => array()),
      'template' => 'views-ui-container',
121
      'file' => 'views_ui.theme.inc',
merlinofchaos's avatar
merlinofchaos committed
122 123 124 125
    ),
  );
}

126 127 128 129 130 131 132 133 134 135 136 137 138
/**
 * Implements hook_permission().
 */
function views_ui_permission() {
  return array(
    'administer views' => array(
      'title' => t('Administer views'),
      'description' => t('Access the views administration pages.'),
      'restrict access' => TRUE,
    ),
  );
}

merlinofchaos's avatar
merlinofchaos committed
139
/**
140
 * Implements hook_preprocess_HOOK() for views templates.
merlinofchaos's avatar
merlinofchaos committed
141
 */
142 143
function views_ui_preprocess_views_view(&$variables) {
  $view = $variables['view'];
144
  if (!empty($view->live_preview) && \Drupal::moduleHandler()->moduleExists('contextual')) {
145
    $view->setShowAdminLinks(FALSE);
merlinofchaos's avatar
merlinofchaos committed
146
    foreach (array('title', 'header', 'exposed', 'rows', 'pager', 'more', 'footer', 'empty', 'attachment_after', 'attachment_before') as $section) {
147 148
      if (!empty($variables[$section])) {
        $variables[$section] = array(
merlinofchaos's avatar
merlinofchaos committed
149 150 151
          '#theme' => 'views_ui_view_preview_section',
          '#view' => $view,
          '#section' => $section,
152
          '#content' => $variables[$section],
153
          '#theme_wrappers' => array('views_ui_container'),
154
          '#attributes' => array('class' => 'contextual-region'),
merlinofchaos's avatar
merlinofchaos committed
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
        );
      }
    }
  }
}

/**
 * Returns contextual links for each handler of a certain section.
 *
 * @TODO
 *   Bring in relationships
 *   Refactor this function to use much stuff of views_ui_edit_form_get_bucket.
 *
 * @param $title
 *   Add a bolded title of this section.
 */
171 172 173
function views_ui_view_preview_section_handler_links(ViewExecutable $view, $type, $title = FALSE) {
  $display = $view->display_handler->display;
  $handlers = $view->display_handler->getHandlers($type);
merlinofchaos's avatar
merlinofchaos committed
174 175
  $links = array();

176
  $types = ViewExecutable::getHandlerTypes();
merlinofchaos's avatar
merlinofchaos committed
177 178 179 180 181 182 183
  if ($title) {
    $links[$type . '-title'] = array(
      'title' => $types[$type]['title'],
    );
  }

  foreach ($handlers as $id => $handler) {
184
    $field_name = $handler->adminLabel(TRUE);
merlinofchaos's avatar
merlinofchaos committed
185 186
    $links[$type . '-edit-' . $id] = array(
      'title' => t('Edit @section', array('@section' => $field_name)),
187
      'href' => "admin/structure/views/nojs/handler/{$view->storage->id()}/{$display['id']}/$type/$id",
merlinofchaos's avatar
merlinofchaos committed
188 189 190 191 192
      'attributes' => array('class' => array('views-ajax-link')),
    );
  }
  $links[$type . '-add'] = array(
    'title' => t('Add new'),
193
    'href' => "admin/structure/views/nojs/add-handler/{$view->storage->id()}/{$display['id']}/$type",
merlinofchaos's avatar
merlinofchaos committed
194 195 196 197 198 199 200 201 202
    'attributes' => array('class' => array('views-ajax-link')),
  );

  return $links;
}

/**
 * Returns a link to editing a certain display setting.
 */
203
function views_ui_view_preview_section_display_category_links(ViewExecutable $view, $type, $title) {
merlinofchaos's avatar
merlinofchaos committed
204 205 206 207
  $display = $view->display_handler->display;
  $links = array(
    $type . '-edit' => array(
      'title' => t('Edit @section', array('@section' => $title)),
208
      'href' => "admin/structure/views/nojs/display/{$view->storage->id()}/{$display['id']}/$type",
merlinofchaos's avatar
merlinofchaos committed
209 210 211 212 213 214 215 216 217 218
      'attributes' => array('class' => array('views-ajax-link')),
    ),
  );

  return $links;
}

/**
 * Returns all contextual links for the main content part of the view.
 */
219
function views_ui_view_preview_section_rows_links(ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
220 221 222 223 224 225 226 227 228 229 230
  $links = array();
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'filter', TRUE));
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'field', TRUE));
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'sort', TRUE));
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'argument', TRUE));
  $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'relationship', TRUE));

  return $links;
}

/**
231
 * Implements hook_views_plugins_display_alter().
merlinofchaos's avatar
merlinofchaos committed
232
 */
233
function views_ui_views_plugins_display_alter(&$plugins) {
merlinofchaos's avatar
merlinofchaos committed
234
  // Attach contextual links to each display plugin. The links will point to
235
  // paths underneath "admin/structure/views/view/{$view->id()}" (i.e., paths
merlinofchaos's avatar
merlinofchaos committed
236
  // for editing and performing other contextual actions on the view).
237
  foreach ($plugins as &$display) {
238 239 240
    $display['contextual links']['views_ui_edit'] = array(
      'route_name' => 'views_ui.edit',
      'route_parameters_names' => array('view' => 'id'),
merlinofchaos's avatar
merlinofchaos committed
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    );
  }
}

/**
 * Implements hook_contextual_links_view_alter().
 */
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.
257 258 259 260
  elseif (!empty($element['#links']['views-uiedit'])) {
    $display_id = $items['views_ui.edit']['metadata']['display_id'];
    $element['#links']['views-uiedit']['route_parameters']['display_id'] = $display_id;
    $element['#links']['views-uiedit']['route_name'] = 'views_ui.edit_display';
merlinofchaos's avatar
merlinofchaos committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
  }
}

/**
 * Sets a static variable for controlling whether contextual links are rendered.
 *
 * @see views_ui_contextual_links_view_alter()
 */
function views_ui_contextual_links_suppress($set = NULL) {
  $suppress = &drupal_static(__FUNCTION__);
  if (isset($set)) {
    $suppress = $set;
  }
  return $suppress;
}

/**
 * Increments the views_ui_contextual_links_suppress() static variable.
 *
 * When this function is added to the #pre_render of an element, and
 * 'views_ui_contextual_links_suppress_pop' is added to the #post_render of the
 * same element, then all contextual links within the element and its
 * descendants are suppressed from being rendered. This is used, for example,
 * during a View preview, when it is not desired for nodes in the Views result
 * to have contextual links.
 *
 * @see views_ui_contextual_links_suppress_pop()
 */
function views_ui_contextual_links_suppress_push() {
  views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress())+1);
}

/**
 * Decrements the views_ui_contextual_links_suppress() static variable.
 *
 * @see views_ui_contextual_links_suppress_push()
 */
function views_ui_contextual_links_suppress_pop() {
  views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress())-1);
}

302 303 304 305 306 307 308
/**
 * Implements hook_views_analyze().
 *
 * This is the basic views analysis that checks for very minimal problems.
 * There are other analysis tools in core specific sections, such as
 * node.views.inc as well.
 */
309
function views_ui_views_analyze(ViewExecutable $view) {
310 311 312 313 314 315 316 317 318 319 320 321 322
  $ret = array();
  // Check for something other than the default display:
  if (count($view->displayHandlers) < 2) {
    $ret[] = Analyzer::formatMessage(t('This view has only a default display and therefore will not be placed anywhere on your site; perhaps you want to add a page or a block display.'), 'warning');
  }
  // You can give a page display the same path as an alias existing in the
  // system, so the alias will not work anymore. Report this to the user,
  // because he probably wanted something else.
  foreach ($view->displayHandlers as $display) {
    if (empty($display)) {
      continue;
    }
    if ($display->hasPath() && $path = $display->getOption('path')) {
323
      $normal_path = \Drupal::service('path.alias_manager')->getPathByAlias($path);
324
      if ($path != $normal_path) {
325
        $ret[] = Analyzer::formatMessage(t('You have configured display %display with a path which is an path alias as well. This might lead to unwanted effects so better use an internal path.', array('%display' => $display->display['display_title'])), 'warning');
326 327 328 329 330 331 332
      }
    }
  }

  return $ret;
}

merlinofchaos's avatar
merlinofchaos committed
333 334 335 336 337 338 339 340 341 342 343 344 345
/**
 * Truncate strings to a set length and provide a ... if they truncated.
 *
 * This is often used in the UI to ensure long strings fit.
 */
function views_ui_truncate($string, $length) {
  if (drupal_strlen($string) > $length) {
    $string = drupal_substr($string, 0, $length);
    $string .= '...';
  }

  return $string;
}
346 347 348 349

/**
 * Magic load function. Wrapper to load a view.
 */
350
function views_ui_load($name) {
351
  return Views::getView($name);
352
}