977da24ae5d7c8fa390faa2adca3b6b0dbd8e757
[yaffs-website] / web / core / modules / media_library / media_library.module
1 <?php
2
3 /**
4  * @file
5  * Contains hook implementations for the media_library module.
6  */
7
8 use Drupal\Component\Utility\UrlHelper;
9 use Drupal\Component\Serialization\Json;
10 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
11 use Drupal\Core\Form\FormStateInterface;
12 use Drupal\Core\Render\Element;
13 use Drupal\Core\Routing\RouteMatchInterface;
14 use Drupal\Core\Template\Attribute;
15 use Drupal\Core\Url;
16 use Drupal\views\Form\ViewsForm;
17 use Drupal\views\Plugin\views\cache\CachePluginBase;
18 use Drupal\views\Plugin\views\query\QueryPluginBase;
19 use Drupal\views\Plugin\views\query\Sql;
20 use Drupal\views\ViewExecutable;
21
22 /**
23  * Implements hook_help().
24  *
25  * @todo Update in https://www.drupal.org/project/drupal/issues/2964789
26  */
27 function media_library_help($route_name, RouteMatchInterface $route_match) {
28   switch ($route_name) {
29     case 'help.page.media_library':
30       $output = '<h3>' . t('About') . '</h3>';
31       $output .= '<p>' . t('The Media library module overrides the /admin/content/media view to provide a rich visual interface for performing administrative operations on media. For more information, see the <a href=":media">online documentation for the Media library module</a>.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '</p>';
32       return $output;
33   }
34 }
35
36 /**
37  * Implements hook_theme().
38  */
39 function media_library_theme() {
40   return [
41     'media__media_library' => [
42       'base hook' => 'media',
43     ],
44   ];
45 }
46
47 /**
48  * Implements hook_preprocess_view().
49  *
50  * Adds a link to add media above the view.
51  */
52 function media_library_preprocess_views_view(&$variables) {
53   $view = $variables['view'];
54   if ($view->id() === 'media_library' && $view->current_display === 'widget') {
55     $url = Url::fromRoute('media_library.upload');
56     if ($url->access()) {
57       $url->setOption('query', \Drupal::request()->query->all());
58       $variables['header']['add_media'] = [
59         '#type' => 'link',
60         '#title' => t('Add media'),
61         '#url' => $url,
62         '#attributes' => [
63           'class' => ['button', 'button-action', 'button--primary', 'use-ajax'],
64           'data-dialog-type' => 'modal',
65           'data-dialog-options' => Json::encode([
66             'dialogClass' => 'media-library-widget-modal',
67             'height' => '75%',
68             'width' => '75%',
69             'title' => t('Add media'),
70           ]),
71         ],
72       ];
73     }
74   }
75 }
76
77 /**
78  * Implements hook_views_post_render().
79  */
80 function media_library_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
81   if ($view->id() === 'media_library') {
82     $output['#attached']['library'][] = 'media_library/view';
83     if ($view->current_display === 'widget') {
84       $query = array_intersect_key(\Drupal::request()->query->all(), array_flip([
85         'media_library_widget_id',
86         'media_library_allowed_types',
87         'media_library_remaining',
88       ]));
89       // If the current query contains any parameters we use to contextually
90       // filter the view, ensure they persist across AJAX rebuilds.
91       // The ajax_path is shared for all AJAX views on the page, but our query
92       // parameters are prefixed and should not interfere with any other views.
93       // @todo Rework or remove this in https://www.drupal.org/node/2983451
94       if (!empty($query)) {
95         $ajax_path = &$output['#attached']['drupalSettings']['views']['ajax_path'];
96         $parsed_url = UrlHelper::parse($ajax_path);
97         $query = array_merge($query, $parsed_url['query']);
98         $ajax_path = $parsed_url['path'] . '?' . UrlHelper::buildQuery($query);
99         if (isset($query['media_library_remaining'])) {
100           $output['#attached']['drupalSettings']['media_library']['selection_remaining'] = (int) $query['media_library_remaining'];
101         }
102       }
103     }
104   }
105 }
106
107 /**
108  * Implements hook_preprocess_media().
109  */
110 function media_library_preprocess_media(&$variables) {
111   if ($variables['view_mode'] === 'media_library') {
112     /** @var \Drupal\media\MediaInterface $media */
113     $media = $variables['media'];
114     $variables['#cache']['contexts'][] = 'user.permissions';
115     $rel = $media->access('edit') ? 'edit-form' : 'canonical';
116     $variables['url'] = $media->toUrl($rel, [
117       'language' => $media->language(),
118     ]);
119     $variables['preview_attributes'] = new Attribute();
120     $variables['preview_attributes']->addClass('media-library-item__preview', 'js-media-library-item-preview', 'js-click-to-select-trigger');
121     $variables['metadata_attributes'] = new Attribute();
122     $variables['metadata_attributes']->addClass('media-library-item__attributes');
123     $variables['status'] = $media->isPublished();
124   }
125 }
126
127 /**
128  * Alter the bulk form to add a more accessible label.
129  *
130  * @param array $form
131  *   An associative array containing the structure of the form.
132  * @param \Drupal\Core\Form\FormStateInterface $form_state
133  *   The current state of the form.
134  *
135  * @todo Remove in https://www.drupal.org/node/2983454
136  */
137 function media_library_form_views_form_media_library_page_alter(array &$form, FormStateInterface $form_state) {
138   if (isset($form['media_bulk_form']) && isset($form['output'])) {
139     /** @var \Drupal\views\ViewExecutable $view */
140     $view = $form['output'][0]['#view'];
141     foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
142       if (isset($view->result[$key])) {
143         $media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
144         $form['media_bulk_form'][$key]['#title'] = t('Select @label', [
145           '@label' => $media->label(),
146         ]);
147       }
148     }
149   }
150 }
151
152 /**
153  * Implements hook_form_alter().
154  */
155 function media_library_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
156   $form_object = $form_state->getFormObject();
157   if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_media_library') === 0) {
158     $form['#attributes']['class'][] = 'media-library-views-form';
159     if (isset($form['header'])) {
160       $form['header']['#attributes']['class'][] = 'media-library-views-form__header';
161       $form['header']['media_bulk_form']['#attributes']['class'][] = 'media-library-views-form__bulk_form';
162     }
163   }
164
165   // Add after build to fix media library views exposed filter's submit button.
166   if ($form_id === 'views_exposed_form' && $form['#id'] === 'views-exposed-form-media-library-widget') {
167     $form['#after_build'][] = '_media_library_views_form_media_library_after_build';
168   }
169 }
170
171 /**
172  * After build callback for views form media library.
173  */
174 function _media_library_views_form_media_library_after_build(array $form, FormStateInterface $form_state) {
175   // Remove .form-actions from media library views exposed filter actions
176   // and replace with .media-library-view--form-actions.
177   //
178   // This prevents the views exposed filter's 'Apply filter' submit button from
179   // being moved into the dialog's buttons.
180   // @see \Drupal\Core\Render\Element\Actions::processActions
181   // @see Drupal.behaviors.dialog.prepareDialogButtons
182   if (($key = array_search('form-actions', $form['actions']['#attributes']['class'])) !== FALSE) {
183     unset($form['actions']['#attributes']['class'][$key]);
184   }
185   $form['actions']['#attributes']['class'][] = 'media-library-view--form-actions';
186   return $form;
187 }
188
189 /**
190  * Implements hook_views_query_alter().
191  *
192  * Alters the widget view's query to only show media that can be selected,
193  * based on what types are allowed in the field settings.
194  *
195  * @todo Remove in https://www.drupal.org/node/2983454
196  */
197 function media_library_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
198   if ($query instanceof Sql && $view->id() === 'media_library' && $view->current_display === 'widget') {
199     $types = _media_library_get_allowed_types();
200     if ($types) {
201       $entity_type = \Drupal::entityTypeManager()->getDefinition('media');
202       $group = $query->setWhereGroup();
203       $query->addWhere($group, $entity_type->getDataTable() . '.' . $entity_type->getKey('bundle'), $types, 'in');
204     }
205   }
206 }
207
208 /**
209  * Implements hook_form_FORM_ID_alter().
210  *
211  * Limits the types available in the exposed filter to avoid users trying to
212  * filter by a type that is un-selectable.
213  *
214  * @see media_library_views_query_alter()
215  *
216  * @todo Remove in https://www.drupal.org/node/2983454
217  */
218 function media_library_form_views_exposed_form_alter(array &$form, FormStateInterface $form_state) {
219   if (isset($form['#id']) && $form['#id'] === 'views-exposed-form-media-library-widget') {
220     $types = _media_library_get_allowed_types();
221     if ($types && isset($form['type']['#options'])) {
222       $keys = array_flip($types);
223       // Ensure that the default value (by default "All") persists.
224       if (isset($form['type']['#default_value'])) {
225         $keys[$form['type']['#default_value']] = TRUE;
226       }
227       $form['type']['#options'] = array_intersect_key($form['type']['#options'], $keys);
228     }
229   }
230 }
231
232 /**
233  * Implements hook_field_ui_preconfigured_options_alter().
234  */
235 function media_library_field_ui_preconfigured_options_alter(array &$options, $field_type) {
236   // If the field is not an "entity_reference"-based field, bail out.
237   $class = \Drupal::service('plugin.manager.field.field_type')->getPluginClass($field_type);
238   if (!is_a($class, EntityReferenceItem::class, TRUE)) {
239     return;
240   }
241
242   // Set the default field widget for media to be the Media library.
243   if (!empty($options['media'])) {
244     $options['media']['entity_form_display']['type'] = 'media_library_widget';
245   }
246 }
247
248 /**
249  * Implements hook_local_tasks_alter().
250  *
251  * Removes tasks for the Media library if the view display no longer exists.
252  */
253 function media_library_local_tasks_alter(&$local_tasks) {
254   /** @var \Symfony\Component\Routing\RouteCollection $route_collection */
255   $route_collection = \Drupal::service('router')->getRouteCollection();
256   foreach (['media_library.grid', 'media_library.table'] as $key) {
257     if (isset($local_tasks[$key]) && !$route_collection->get($local_tasks[$key]['route_name'])) {
258       unset($local_tasks[$key]);
259     }
260   }
261 }
262
263 /**
264  * Determines what types are allowed based on the current request.
265  *
266  * @return array
267  *   An array of allowed types.
268  */
269 function _media_library_get_allowed_types() {
270   $types = \Drupal::request()->query->get('media_library_allowed_types');
271   if ($types && is_array($types)) {
272     return array_filter($types, 'is_string');
273   }
274   return [];
275 }