Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /**
|
Chris@0
|
4 * @file
|
Chris@0
|
5 * Provide structure for the administrative interface to Views.
|
Chris@0
|
6 */
|
Chris@0
|
7
|
Chris@0
|
8 use Drupal\Core\Routing\RouteMatchInterface;
|
Chris@0
|
9 use Drupal\Core\Url;
|
Chris@0
|
10 use Drupal\views\ViewExecutable;
|
Chris@0
|
11 use Drupal\views\Analyzer;
|
Chris@0
|
12
|
Chris@0
|
13 /**
|
Chris@0
|
14 * Implements hook_help().
|
Chris@0
|
15 */
|
Chris@0
|
16 function views_ui_help($route_name, RouteMatchInterface $route_match) {
|
Chris@0
|
17 switch ($route_name) {
|
Chris@0
|
18 case 'help.page.views_ui':
|
Chris@0
|
19 $output = '';
|
Chris@0
|
20 $output .= '<h3>' . t('About') . '</h3>';
|
Chris@18
|
21 $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>.', [':views' => Url::fromRoute('help.page', ['name' => 'views'])->toString(), ':handbook' => 'https://www.drupal.org/documentation/modules/views_ui']) . '</p>';
|
Chris@0
|
22 $output .= '<h3>' . t('Uses') . '</h3>';
|
Chris@0
|
23 $output .= '<dl>';
|
Chris@0
|
24 $output .= '<dt>' . t('Creating and managing views') . '</dt>';
|
Chris@18
|
25 $output .= '<dd>' . t('Views can be created from the <a href=":list">Views list page</a> by using the "Add 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".', [':list' => Url::fromRoute('entity.view.collection', ['name' => 'views_ui'])->toString()]) . '</dd>';
|
Chris@0
|
26 $output .= '<dt>' . t('Enabling and disabling views') . '<dt>';
|
Chris@18
|
27 $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.', [':list' => Url::fromRoute('entity.view.collection', ['name' => 'views_ui'])->toString()]) . '</dd>';
|
Chris@0
|
28 $output .= '<dt>' . t('Exporting and importing views') . '</dt>';
|
Chris@18
|
29 $output .= '<dd>' . t('Views can be exported and imported as configuration files by using the <a href=":config">Configuration Manager module</a>.', [':config' => (\Drupal::moduleHandler()->moduleExists('config')) ? Url::fromRoute('help.page', ['name' => 'config'])->toString() : '#']) . '</dd>';
|
Chris@0
|
30 $output .= '</dl>';
|
Chris@0
|
31 return $output;
|
Chris@0
|
32 }
|
Chris@0
|
33 }
|
Chris@0
|
34
|
Chris@0
|
35 /**
|
Chris@0
|
36 * Implements hook_entity_type_build().
|
Chris@0
|
37 */
|
Chris@0
|
38 function views_ui_entity_type_build(array &$entity_types) {
|
Chris@0
|
39 /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
|
Chris@0
|
40 $entity_types['view']
|
Chris@0
|
41 ->setFormClass('edit', 'Drupal\views_ui\ViewEditForm')
|
Chris@0
|
42 ->setFormClass('add', 'Drupal\views_ui\ViewAddForm')
|
Chris@0
|
43 ->setFormClass('preview', 'Drupal\views_ui\ViewPreviewForm')
|
Chris@0
|
44 ->setFormClass('duplicate', 'Drupal\views_ui\ViewDuplicateForm')
|
Chris@0
|
45 ->setFormClass('delete', 'Drupal\Core\Entity\EntityDeleteForm')
|
Chris@0
|
46 ->setFormClass('break_lock', 'Drupal\views_ui\Form\BreakLockForm')
|
Chris@0
|
47 ->setListBuilderClass('Drupal\views_ui\ViewListBuilder')
|
Chris@0
|
48 ->setLinkTemplate('edit-form', '/admin/structure/views/view/{view}')
|
Chris@0
|
49 ->setLinkTemplate('edit-display-form', '/admin/structure/views/view/{view}/edit/{display_id}')
|
Chris@0
|
50 ->setLinkTemplate('preview-form', '/admin/structure/views/view/{view}/preview/{display_id}')
|
Chris@0
|
51 ->setLinkTemplate('duplicate-form', '/admin/structure/views/view/{view}/duplicate')
|
Chris@0
|
52 ->setLinkTemplate('delete-form', '/admin/structure/views/view/{view}/delete')
|
Chris@0
|
53 ->setLinkTemplate('enable', '/admin/structure/views/view/{view}/enable')
|
Chris@0
|
54 ->setLinkTemplate('disable', '/admin/structure/views/view/{view}/disable')
|
Chris@0
|
55 ->setLinkTemplate('break-lock-form', '/admin/structure/views/view/{view}/break-lock')
|
Chris@0
|
56 ->setLinkTemplate('collection', '/admin/structure/views');
|
Chris@0
|
57 }
|
Chris@0
|
58
|
Chris@0
|
59 /**
|
Chris@0
|
60 * Implements hook_theme().
|
Chris@0
|
61 */
|
Chris@0
|
62 function views_ui_theme() {
|
Chris@0
|
63 return [
|
Chris@0
|
64 // edit a view
|
Chris@0
|
65 'views_ui_display_tab_setting' => [
|
Chris@0
|
66 'variables' => ['description' => '', 'link' => '', 'settings_links' => [], 'overridden' => FALSE, 'defaulted' => FALSE, 'description_separator' => TRUE, 'class' => []],
|
Chris@0
|
67 'file' => 'views_ui.theme.inc',
|
Chris@0
|
68 ],
|
Chris@0
|
69 'views_ui_display_tab_bucket' => [
|
Chris@0
|
70 'render element' => 'element',
|
Chris@0
|
71 'file' => 'views_ui.theme.inc',
|
Chris@0
|
72 ],
|
Chris@0
|
73 'views_ui_rearrange_filter_form' => [
|
Chris@0
|
74 'render element' => 'form',
|
Chris@0
|
75 'file' => 'views_ui.theme.inc',
|
Chris@0
|
76 ],
|
Chris@0
|
77 'views_ui_expose_filter_form' => [
|
Chris@0
|
78 'render element' => 'form',
|
Chris@0
|
79 'file' => 'views_ui.theme.inc',
|
Chris@0
|
80 ],
|
Chris@0
|
81
|
Chris@0
|
82 // Legacy theme hook for displaying views info.
|
Chris@0
|
83 'views_ui_view_info' => [
|
Chris@0
|
84 'variables' => ['view' => NULL, 'displays' => NULL],
|
Chris@0
|
85 'file' => 'views_ui.theme.inc',
|
Chris@0
|
86 ],
|
Chris@0
|
87
|
Chris@0
|
88 // List views.
|
Chris@0
|
89 'views_ui_views_listing_table' => [
|
Chris@0
|
90 'variables' => [
|
Chris@0
|
91 'headers' => NULL,
|
Chris@0
|
92 'rows' => NULL,
|
Chris@0
|
93 'attributes' => [],
|
Chris@0
|
94 ],
|
Chris@0
|
95 'file' => 'views_ui.theme.inc',
|
Chris@0
|
96 ],
|
Chris@0
|
97 'views_ui_view_displays_list' => [
|
Chris@0
|
98 'variables' => ['displays' => []],
|
Chris@0
|
99 ],
|
Chris@0
|
100
|
Chris@0
|
101 // Group of filters.
|
Chris@0
|
102 'views_ui_build_group_filter_form' => [
|
Chris@0
|
103 'render element' => 'form',
|
Chris@0
|
104 'file' => 'views_ui.theme.inc',
|
Chris@0
|
105 ],
|
Chris@0
|
106
|
Chris@0
|
107 // On behalf of a plugin
|
Chris@0
|
108 'views_ui_style_plugin_table' => [
|
Chris@0
|
109 'render element' => 'form',
|
Chris@0
|
110 'file' => 'views_ui.theme.inc',
|
Chris@0
|
111 ],
|
Chris@0
|
112
|
Chris@0
|
113 // When previewing a view.
|
Chris@0
|
114 'views_ui_view_preview_section' => [
|
Chris@0
|
115 'variables' => ['view' => NULL, 'section' => NULL, 'content' => NULL, 'links' => ''],
|
Chris@0
|
116 'file' => 'views_ui.theme.inc',
|
Chris@0
|
117 ],
|
Chris@0
|
118
|
Chris@0
|
119 // Generic container wrapper, to use instead of theme_container when an id
|
Chris@0
|
120 // is not desired.
|
Chris@0
|
121 'views_ui_container' => [
|
Chris@0
|
122 'variables' => ['children' => NULL, 'attributes' => []],
|
Chris@0
|
123 'file' => 'views_ui.theme.inc',
|
Chris@0
|
124 ],
|
Chris@0
|
125 ];
|
Chris@0
|
126 }
|
Chris@0
|
127
|
Chris@0
|
128 /**
|
Chris@0
|
129 * Implements hook_preprocess_HOOK() for views templates.
|
Chris@0
|
130 */
|
Chris@0
|
131 function views_ui_preprocess_views_view(&$variables) {
|
Chris@0
|
132 $view = $variables['view'];
|
Chris@0
|
133
|
Chris@0
|
134 // Render title for the admin preview.
|
Chris@0
|
135 if (!empty($view->live_preview)) {
|
Chris@0
|
136 $variables['title'] = [
|
Chris@17
|
137 '#markup' => $view->getTitle(),
|
Chris@0
|
138 ];
|
Chris@0
|
139 }
|
Chris@0
|
140
|
Chris@0
|
141 if (!empty($view->live_preview) && \Drupal::moduleHandler()->moduleExists('contextual')) {
|
Chris@0
|
142 $view->setShowAdminLinks(FALSE);
|
Chris@0
|
143 foreach (['title', 'header', 'exposed', 'rows', 'pager', 'more', 'footer', 'empty', 'attachment_after', 'attachment_before'] as $section) {
|
Chris@0
|
144 if (!empty($variables[$section])) {
|
Chris@0
|
145 $variables[$section] = [
|
Chris@0
|
146 '#theme' => 'views_ui_view_preview_section',
|
Chris@0
|
147 '#view' => $view,
|
Chris@0
|
148 '#section' => $section,
|
Chris@0
|
149 '#content' => $variables[$section],
|
Chris@0
|
150 '#theme_wrappers' => ['views_ui_container'],
|
Chris@0
|
151 '#attributes' => ['class' => ['contextual-region']],
|
Chris@0
|
152 ];
|
Chris@0
|
153 }
|
Chris@0
|
154 }
|
Chris@0
|
155 }
|
Chris@0
|
156 }
|
Chris@0
|
157
|
Chris@0
|
158 /**
|
Chris@12
|
159 * Implements hook_theme_suggestions_HOOK().
|
Chris@12
|
160 */
|
Chris@12
|
161 function views_ui_theme_suggestions_views_ui_view_preview_section(array $variables) {
|
Chris@12
|
162 return ['views_ui_view_preview_section__' . $variables['section']];
|
Chris@12
|
163 }
|
Chris@12
|
164
|
Chris@12
|
165 /**
|
Chris@0
|
166 * Returns contextual links for each handler of a certain section.
|
Chris@0
|
167 *
|
Chris@0
|
168 * @TODO
|
Chris@0
|
169 * Bring in relationships
|
Chris@0
|
170 * Refactor this function to use much stuff of views_ui_edit_form_get_bucket.
|
Chris@0
|
171 *
|
Chris@0
|
172 * @param $title
|
Chris@0
|
173 * Add a bolded title of this section.
|
Chris@0
|
174 */
|
Chris@0
|
175 function views_ui_view_preview_section_handler_links(ViewExecutable $view, $type, $title = FALSE) {
|
Chris@0
|
176 $display = $view->display_handler->display;
|
Chris@0
|
177 $handlers = $view->display_handler->getHandlers($type);
|
Chris@0
|
178 $links = [];
|
Chris@0
|
179
|
Chris@0
|
180 $types = ViewExecutable::getHandlerTypes();
|
Chris@0
|
181 if ($title) {
|
Chris@0
|
182 $links[$type . '-title'] = [
|
Chris@0
|
183 'title' => $types[$type]['title'],
|
Chris@0
|
184 ];
|
Chris@0
|
185 }
|
Chris@0
|
186
|
Chris@0
|
187 foreach ($handlers as $id => $handler) {
|
Chris@0
|
188 $field_name = $handler->adminLabel(TRUE);
|
Chris@0
|
189 $links[$type . '-edit-' . $id] = [
|
Chris@0
|
190 'title' => t('Edit @section', ['@section' => $field_name]),
|
Chris@0
|
191 'url' => Url::fromRoute('views_ui.form_handler', ['js' => 'nojs', 'view' => $view->storage->id(), 'display_id' => $display['id'], 'type' => $type, 'id' => $id]),
|
Chris@0
|
192 'attributes' => ['class' => ['views-ajax-link']],
|
Chris@0
|
193 ];
|
Chris@0
|
194 }
|
Chris@0
|
195 $links[$type . '-add'] = [
|
Chris@0
|
196 'title' => t('Add new'),
|
Chris@0
|
197 'url' => Url::fromRoute('views_ui.form_add_handler', ['js' => 'nojs', 'view' => $view->storage->id(), 'display_id' => $display['id'], 'type' => $type]),
|
Chris@0
|
198 'attributes' => ['class' => ['views-ajax-link']],
|
Chris@0
|
199 ];
|
Chris@0
|
200
|
Chris@0
|
201 return $links;
|
Chris@0
|
202 }
|
Chris@0
|
203
|
Chris@0
|
204 /**
|
Chris@0
|
205 * Returns a link to editing a certain display setting.
|
Chris@0
|
206 */
|
Chris@0
|
207 function views_ui_view_preview_section_display_category_links(ViewExecutable $view, $type, $title) {
|
Chris@0
|
208 $display = $view->display_handler->display;
|
Chris@0
|
209 $links = [
|
Chris@0
|
210 $type . '-edit' => [
|
Chris@0
|
211 'title' => t('Edit @section', ['@section' => $title]),
|
Chris@0
|
212 'url' => Url::fromRoute('views_ui.form_display', ['js' => 'nojs', 'view' => $view->storage->id(), 'display_id' => $display['id'], 'type' => $type]),
|
Chris@0
|
213 'attributes' => ['class' => ['views-ajax-link']],
|
Chris@0
|
214 ],
|
Chris@0
|
215 ];
|
Chris@0
|
216
|
Chris@0
|
217 return $links;
|
Chris@0
|
218 }
|
Chris@0
|
219
|
Chris@0
|
220 /**
|
Chris@0
|
221 * Returns all contextual links for the main content part of the view.
|
Chris@0
|
222 */
|
Chris@0
|
223 function views_ui_view_preview_section_rows_links(ViewExecutable $view) {
|
Chris@0
|
224 $links = [];
|
Chris@0
|
225 $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'filter', TRUE));
|
Chris@0
|
226 $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'field', TRUE));
|
Chris@0
|
227 $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'sort', TRUE));
|
Chris@0
|
228 $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'argument', TRUE));
|
Chris@0
|
229 $links = array_merge($links, views_ui_view_preview_section_handler_links($view, 'relationship', TRUE));
|
Chris@0
|
230
|
Chris@0
|
231 return $links;
|
Chris@0
|
232 }
|
Chris@0
|
233
|
Chris@0
|
234 /**
|
Chris@0
|
235 * Implements hook_views_plugins_display_alter().
|
Chris@0
|
236 */
|
Chris@0
|
237 function views_ui_views_plugins_display_alter(&$plugins) {
|
Chris@0
|
238 // Attach contextual links to each display plugin. The links will point to
|
Chris@0
|
239 // paths underneath "admin/structure/views/view/{$view->id()}" (i.e., paths
|
Chris@0
|
240 // for editing and performing other contextual actions on the view).
|
Chris@0
|
241 foreach ($plugins as &$display) {
|
Chris@0
|
242 $display['contextual links']['entity.view.edit_form'] = [
|
Chris@0
|
243 'route_name' => 'entity.view.edit_form',
|
Chris@0
|
244 'route_parameters_names' => ['view' => 'id'],
|
Chris@0
|
245 ];
|
Chris@0
|
246 }
|
Chris@0
|
247 }
|
Chris@0
|
248
|
Chris@0
|
249 /**
|
Chris@0
|
250 * Implements hook_contextual_links_view_alter().
|
Chris@0
|
251 */
|
Chris@0
|
252 function views_ui_contextual_links_view_alter(&$element, $items) {
|
Chris@0
|
253 // Remove contextual links from being rendered, when so desired, such as
|
Chris@0
|
254 // within a View preview.
|
Chris@0
|
255 if (views_ui_contextual_links_suppress()) {
|
Chris@0
|
256 $element['#links'] = [];
|
Chris@0
|
257 }
|
Chris@0
|
258 // Append the display ID to the Views UI edit links, so that clicking on the
|
Chris@0
|
259 // contextual link takes you directly to the correct display tab on the edit
|
Chris@0
|
260 // screen.
|
Chris@0
|
261 elseif (!empty($element['#links']['entityviewedit-form'])) {
|
Chris@0
|
262 $display_id = $items['entity.view.edit_form']['metadata']['display_id'];
|
Chris@0
|
263 $route_parameters = $element['#links']['entityviewedit-form']['url']->getRouteParameters() + ['display_id' => $display_id];
|
Chris@0
|
264 $element['#links']['entityviewedit-form']['url'] = Url::fromRoute('entity.view.edit_display_form', $route_parameters);
|
Chris@0
|
265 }
|
Chris@0
|
266 }
|
Chris@0
|
267
|
Chris@0
|
268 /**
|
Chris@0
|
269 * Sets a static variable for controlling whether contextual links are rendered.
|
Chris@0
|
270 *
|
Chris@0
|
271 * @see views_ui_contextual_links_view_alter()
|
Chris@0
|
272 */
|
Chris@0
|
273 function views_ui_contextual_links_suppress($set = NULL) {
|
Chris@0
|
274 $suppress = &drupal_static(__FUNCTION__);
|
Chris@0
|
275 if (isset($set)) {
|
Chris@0
|
276 $suppress = $set;
|
Chris@0
|
277 }
|
Chris@0
|
278 return $suppress;
|
Chris@0
|
279 }
|
Chris@0
|
280
|
Chris@0
|
281 /**
|
Chris@0
|
282 * Increments the views_ui_contextual_links_suppress() static variable.
|
Chris@0
|
283 *
|
Chris@0
|
284 * When this function is added to the #pre_render of an element, and
|
Chris@0
|
285 * 'views_ui_contextual_links_suppress_pop' is added to the #post_render of the
|
Chris@0
|
286 * same element, then all contextual links within the element and its
|
Chris@0
|
287 * descendants are suppressed from being rendered. This is used, for example,
|
Chris@0
|
288 * during a View preview, when it is not desired for nodes in the Views result
|
Chris@0
|
289 * to have contextual links.
|
Chris@0
|
290 *
|
Chris@0
|
291 * @see views_ui_contextual_links_suppress_pop()
|
Chris@0
|
292 */
|
Chris@0
|
293 function views_ui_contextual_links_suppress_push() {
|
Chris@0
|
294 views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress()) + 1);
|
Chris@0
|
295 }
|
Chris@0
|
296
|
Chris@0
|
297 /**
|
Chris@0
|
298 * Decrements the views_ui_contextual_links_suppress() static variable.
|
Chris@0
|
299 *
|
Chris@0
|
300 * @see views_ui_contextual_links_suppress_push()
|
Chris@0
|
301 */
|
Chris@0
|
302 function views_ui_contextual_links_suppress_pop() {
|
Chris@0
|
303 views_ui_contextual_links_suppress(((int) views_ui_contextual_links_suppress()) - 1);
|
Chris@0
|
304 }
|
Chris@0
|
305
|
Chris@0
|
306 /**
|
Chris@0
|
307 * Implements hook_views_analyze().
|
Chris@0
|
308 *
|
Chris@0
|
309 * This is the basic views analysis that checks for very minimal problems.
|
Chris@0
|
310 * There are other analysis tools in core specific sections, such as
|
Chris@0
|
311 * node.views.inc as well.
|
Chris@0
|
312 */
|
Chris@0
|
313 function views_ui_views_analyze(ViewExecutable $view) {
|
Chris@0
|
314 $ret = [];
|
Chris@0
|
315 // Check for something other than the default display:
|
Chris@0
|
316 if (count($view->displayHandlers) < 2) {
|
Chris@0
|
317 $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');
|
Chris@0
|
318 }
|
Chris@0
|
319 // You can give a page display the same path as an alias existing in the
|
Chris@0
|
320 // system, so the alias will not work anymore. Report this to the user,
|
Chris@0
|
321 // because he probably wanted something else.
|
Chris@0
|
322 foreach ($view->displayHandlers as $display) {
|
Chris@0
|
323 if (empty($display)) {
|
Chris@0
|
324 continue;
|
Chris@0
|
325 }
|
Chris@0
|
326 if ($display->hasPath() && $path = $display->getOption('path')) {
|
Chris@0
|
327 $normal_path = \Drupal::service('path.alias_manager')->getPathByAlias($path);
|
Chris@0
|
328 if ($path != $normal_path) {
|
Chris@0
|
329 $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.', ['%display' => $display->display['display_title']]), 'warning');
|
Chris@0
|
330 }
|
Chris@0
|
331 }
|
Chris@0
|
332 }
|
Chris@0
|
333
|
Chris@0
|
334 return $ret;
|
Chris@0
|
335 }
|
Chris@0
|
336
|
Chris@0
|
337 /**
|
Chris@0
|
338 * Truncate strings to a set length and provide a '...' if they truncated.
|
Chris@0
|
339 *
|
Chris@0
|
340 * This is often used in the UI to ensure long strings fit.
|
Chris@0
|
341 */
|
Chris@0
|
342 function views_ui_truncate($string, $length) {
|
Chris@17
|
343 if (mb_strlen($string) > $length) {
|
Chris@17
|
344 $string = mb_substr($string, 0, $length);
|
Chris@0
|
345 $string .= '...';
|
Chris@0
|
346 }
|
Chris@0
|
347
|
Chris@0
|
348 return $string;
|
Chris@0
|
349 }
|