From 946835f45f14f6091dccb7da3d7d491cb767d5c5 Mon Sep 17 00:00:00 2001 From: xjm Date: Mon, 4 Nov 2019 18:00:11 +0100 Subject: [PATCH] =?UTF-8?q?Issue=20#3082690=20by=20phenaproxima,=20bnjmnm,?= =?UTF-8?q?=20oknate,=20JeroenT,=20effulgentsia,=20xjm,=20lauriii,=20webch?= =?UTF-8?q?ick,=20seanB,=20andrewmacpherson,=20Wim=20Leers,=20DyanneNova,?= =?UTF-8?q?=20G=C3=A1bor=20Hojtsy,=20cboyden,=20peterx,=20rainbreaw,=20jan?= =?UTF-8?q?.stoeckler,=20shaal,=20annagaz,=20FeyP,=20chr.fritsch,=20marcos?= =?UTF-8?q?cano,=20samuel.mortenson,=20Berdir,=20webflo:=20Mark=20Media=20?= =?UTF-8?q?Library=20as=20a=20stable=20core=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/MAINTAINERS.txt | 4 + .../install/views.view.media_library.yml | 126 ++++++------ .../css/media_library.module.css | 118 ----------- .../js/media_library.view.es6.js | 7 +- .../media_library/js/media_library.view.js | 2 +- .../media_library/media_library.info.yml | 2 +- .../media_library/media_library.libraries.yml | 10 - .../media_library/media_library.module | 136 ++++++++++--- .../src/Ajax/UpdateSelectionCommand.php | 5 +- .../media_library/src/Form/AddFormBase.php | 120 +++++------ .../media_library/src/Form/FileUploadForm.php | 16 +- .../media_library/src/Form/OEmbedForm.php | 20 +- .../media_library/src/Form/SettingsForm.php | 3 + .../src/MediaLibraryEditorOpener.php | 4 +- .../src/MediaLibraryFieldWidgetOpener.php | 3 + .../media_library/src/MediaLibraryState.php | 5 - .../src/MediaLibraryUiBuilder.php | 21 +- .../media_library/src/OpenerResolver.php | 4 + .../src/OpenerResolverInterface.php | 5 + .../Field/FieldWidget/MediaLibraryWidget.php | 127 +++++++----- .../views/field/MediaLibrarySelectForm.php | 13 +- .../src/Routing/RouteSubscriber.php | 3 + .../templates/media--media-library.html.twig | 9 +- .../templates/media-library-item.html.twig | 22 ++ .../templates/media-library-wrapper.html.twig | 21 ++ .../FunctionalJavascript/MediaLibraryTest.php | 49 ++--- ...form_display.media.audio.media_library.yml | 0 ...m_display.media.document.media_library.yml | 0 ...form_display.media.image.media_library.yml | 0 ...splay.media.remote_video.media_library.yml | 0 ...form_display.media.video.media_library.yml | 0 ...view_display.media.audio.media_library.yml | 0 ...w_display.media.document.media_library.yml | 0 ...view_display.media.image.media_library.yml | 0 ...splay.media.remote_video.media_library.yml | 0 ...view_display.media.video.media_library.yml | 0 core/themes/classy/classy.info.yml | 4 + core/themes/classy/classy.libraries.yml | 6 + core/themes/classy/classy.theme | 34 ++++ .../classy/css/layout/media-library.css | 28 +++ ...container--media-library-content.html.twig | 28 +++ ...--media-library-widget-selection.html.twig | 28 +++ .../links--media-library-menu.html.twig | 36 ++++ .../media--media-library.html.twig | 55 +++++ .../media-library-item--small.html.twig | 31 +++ .../media-library-item.html.twig | 28 +++ .../media-library-wrapper.html.twig | 21 ++ ...-view-unformatted--media-library.html.twig | 35 ++++ .../seven/css/theme/media-library.css} | 184 ++++++++++------- core/themes/seven/seven.info.yml | 8 + core/themes/seven/seven.libraries.yml | 6 + core/themes/seven/seven.theme | 188 ++++++++++++++++++ ...-library-add-form-selected-media.html.twig | 20 ++ .../fieldset--media-library-widget.html.twig | 64 ++++++ ...edia-library-add-form-media-list.html.twig | 33 +++ .../views-view--media_library.html.twig | 95 +++++++++ ...-view-unformatted--media-library.html.twig | 34 ++++ .../media--media-library.html.twig | 49 +++++ .../media-library-item.html.twig | 22 ++ .../media-library-wrapper.html.twig | 21 ++ 60 files changed, 1427 insertions(+), 486 deletions(-) delete mode 100644 core/modules/media_library/css/media_library.module.css create mode 100644 core/modules/media_library/templates/media-library-item.html.twig create mode 100644 core/modules/media_library/templates/media-library-wrapper.html.twig rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_form_display.media.audio.media_library.yml (100%) rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_form_display.media.document.media_library.yml (100%) rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_form_display.media.image.media_library.yml (100%) rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_form_display.media.remote_video.media_library.yml (100%) rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_form_display.media.video.media_library.yml (100%) rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_view_display.media.audio.media_library.yml (100%) rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_view_display.media.document.media_library.yml (100%) rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_view_display.media.image.media_library.yml (100%) rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_view_display.media.remote_video.media_library.yml (100%) rename core/{modules/media_library => profiles/standard}/config/optional/core.entity_view_display.media.video.media_library.yml (100%) create mode 100644 core/themes/classy/classy.theme create mode 100644 core/themes/classy/css/layout/media-library.css create mode 100644 core/themes/classy/templates/media-library/container--media-library-content.html.twig create mode 100644 core/themes/classy/templates/media-library/container--media-library-widget-selection.html.twig create mode 100644 core/themes/classy/templates/media-library/links--media-library-menu.html.twig create mode 100644 core/themes/classy/templates/media-library/media--media-library.html.twig create mode 100644 core/themes/classy/templates/media-library/media-library-item--small.html.twig create mode 100644 core/themes/classy/templates/media-library/media-library-item.html.twig create mode 100644 core/themes/classy/templates/media-library/media-library-wrapper.html.twig create mode 100644 core/themes/classy/templates/media-library/views-view-unformatted--media-library.html.twig rename core/{modules/media_library/css/media_library.theme.css => themes/seven/css/theme/media-library.css} (83%) create mode 100644 core/themes/seven/templates/media-library/details--media-library-add-form-selected-media.html.twig create mode 100644 core/themes/seven/templates/media-library/fieldset--media-library-widget.html.twig create mode 100644 core/themes/seven/templates/media-library/item-list--media-library-add-form-media-list.html.twig create mode 100644 core/themes/seven/templates/media-library/views-view--media_library.html.twig create mode 100644 core/themes/seven/templates/media-library/views-view-unformatted--media-library.html.twig create mode 100644 core/themes/stable/templates/media-library/media--media-library.html.twig create mode 100644 core/themes/stable/templates/media-library/media-library-item.html.twig create mode 100644 core/themes/stable/templates/media-library/media-library-wrapper.html.twig diff --git a/core/MAINTAINERS.txt b/core/MAINTAINERS.txt index b05de53a0fe..e93c71b10e8 100644 --- a/core/MAINTAINERS.txt +++ b/core/MAINTAINERS.txt @@ -283,6 +283,10 @@ Media - Christian Fritsch 'chr.fritsch' https://www.drupal.org/u/chr.fritsch - Adam Globus-Hoenich 'phenaproxima' https://www.drupal.org/u/phenaproxima + Media Library + - Sean Blommaert 'seanB' https://www.drupal.org/u/seanb + - Adam Globus-Hoenich 'phenaproxima' https://www.drupal.org/u/phenaproxima + Menu - Daniel Wehner 'dawehner' https://www.drupal.org/u/dawehner - Peter Wolanin 'pwolanin' https://www.drupal.org/u/pwolanin diff --git a/core/modules/media_library/config/install/views.view.media_library.yml b/core/modules/media_library/config/install/views.view.media_library.yml index d2799f92968..32fdbe4a3d0 100644 --- a/core/modules/media_library/config/install/views.view.media_library.yml +++ b/core/modules/media_library/config/install/views.view.media_library.yml @@ -73,7 +73,7 @@ display: type: default options: grouping: { } - row_class: 'media-library-item media-library-item--grid js-media-library-item js-click-to-select' + row_class: '' default_row_class: true row: type: fields @@ -120,7 +120,7 @@ display: preserve_tags: '' html: false element_type: '' - element_class: js-click-to-select-checkbox media-library-item__click-to-select-checkbox + element_class: '' element_label_type: '' element_label_class: '' element_label_colon: false @@ -173,7 +173,7 @@ display: preserve_tags: '' html: false element_type: '' - element_class: media-library-item__content + element_class: '' element_label_type: '' element_label_class: '' element_label_colon: false @@ -468,7 +468,7 @@ display: relationships: { } display_extenders: { } use_ajax: true - css_class: 'media-library-view js-media-library-view' + css_class: '' cache_metadata: max-age: 0 contexts: @@ -525,7 +525,7 @@ display: preserve_tags: '' html: false element_type: '' - element_class: js-click-to-select-checkbox media-library-item__click-to-select-checkbox + element_class: '' element_label_type: '' element_label_class: '' element_label_colon: false @@ -627,7 +627,7 @@ display: trim_whitespace: false alt: 'Edit {{ name }}' rel: '' - link_class: media-library-item__edit + link_class: '' prefix: '' suffix: '' target: '' @@ -680,7 +680,7 @@ display: trim_whitespace: false alt: 'Delete {{ name }}' rel: '' - link_class: media-library-item__remove + link_class: '' prefix: '' suffix: '' target: '' @@ -749,7 +749,7 @@ display: preserve_tags: '' html: false element_type: '' - element_class: media-library-item__content + element_class: '' element_label_type: '' element_label_class: '' element_label_colon: false @@ -786,57 +786,6 @@ display: display_extenders: { } path: admin/content/media-widget fields: - rendered_entity: - id: rendered_entity - table: media - field: rendered_entity - relationship: none - group_type: group - admin_label: '' - label: '' - exclude: false - alter: - alter_text: false - text: '' - make_link: false - path: '' - absolute: false - external: false - replace_spaces: false - path_case: none - trim_whitespace: false - alt: '' - rel: '' - link_class: '' - prefix: '' - suffix: '' - target: '' - nl2br: false - max_length: 0 - word_boundary: true - ellipsis: true - more_link: false - more_link_text: '' - more_link_path: '' - strip_tags: false - trim: false - preserve_tags: '' - html: false - element_type: '' - element_class: media-library-item__content - element_label_type: '' - element_label_class: '' - element_label_colon: false - element_wrapper_type: '' - element_wrapper_class: '' - element_default_classes: true - empty: '' - hide_empty: false - empty_zero: false - hide_alter_empty: true - view_mode: media_library - entity_type: media - plugin_id: rendered_entity media_library_select_form: id: media_library_select_form table: media @@ -879,7 +828,7 @@ display: element_label_class: '' element_label_colon: false element_wrapper_type: '' - element_wrapper_class: js-click-to-select-checkbox media-library-item__click-to-select-checkbox + element_wrapper_class: '' element_default_classes: true empty: '' hide_empty: false @@ -887,6 +836,57 @@ display: hide_alter_empty: true entity_type: media plugin_id: media_library_select_form + rendered_entity: + id: rendered_entity + table: media + field: rendered_entity + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + view_mode: media_library + entity_type: media + plugin_id: rendered_entity defaults: fields: false access: false @@ -1086,7 +1086,7 @@ display: label: 'Table' plugin_id: display_link empty: true - css_class: 'media-library-view js-media-library-view media-library-view--widget' + css_class: '' rendering_language: '***LANGUAGE_language_interface***' cache_metadata: max-age: -1 @@ -1131,7 +1131,7 @@ display: relationship: none entity_type: media plugin_id: media_library_select_form - element_wrapper_class: js-click-to-select-checkbox media-library-item__click-to-select-checkbox + element_wrapper_class: '' element_class: '' thumbnail__target_id: id: thumbnail__target_id @@ -1374,7 +1374,7 @@ display: label: 'Table' plugin_id: display_link empty: true - css_class: 'media-library-view js-media-library-view media-library-view--widget' + css_class: '' rendering_language: '***LANGUAGE_language_interface***' cache_metadata: max-age: -1 diff --git a/core/modules/media_library/css/media_library.module.css b/core/modules/media_library/css/media_library.module.css deleted file mode 100644 index 968cba67f52..00000000000 --- a/core/modules/media_library/css/media_library.module.css +++ /dev/null @@ -1,118 +0,0 @@ -/** -* @file media_library.module.css -*/ - -/** - * By default, the dialog is too narrow to be usable. - * @see Drupal.ckeditor.openDialog() - */ -.ui-dialog--narrow.media-library-widget-modal { - max-width: 75%; -} - -.media-library-wrapper { - display: flex; -} - -.media-library-menu { - margin: 0; - padding: 0; -} - -/* @todo Use a class instead of the li element. - https://www.drupal.org/project/drupal/issues/3029227 */ -.media-library-menu li { - padding: 0; - list-style: none; -} - -.media-library-views-form > .form-actions { - flex-basis: 100%; -} - -.media-library-views-form, -.media-library-selection, -.media-library-add-form__selected-media .details-wrapper, -.media-library-views-form__bulk_form, -.media-library-view .form--inline { - display: flex; - flex-wrap: wrap; -} - -.media-library-views-form__header { - flex-basis: 100%; -} - -.media-library-item { - position: relative; -} - -.media-library-item__click-to-select-trigger { - overflow: hidden; - height: 100%; - cursor: pointer; -} - -.media-library-view .form-actions { - align-self: flex-end; -} - -.media-library-item__click-to-select-checkbox { - position: absolute; - z-index: 1; - top: 16px; - left: 16px; /* LTR */ - display: block; -} -[dir="rtl"] .media-library-item__click-to-select-checkbox { - right: 16px; - left: auto; -} - -.media-library-item__status { - position: absolute; - top: 40px; - left: 5px; /* LTR */ - pointer-events: none; -} -[dir="rtl"] .media-library-item__status { - right: 5px; - left: auto; -} - -.media-library-select-all { - flex-basis: 100%; - width: 100%; -} - -.media-library-view--widget .media-library-select-all { - display: none; -} - -.media-library-item--disabled { - pointer-events: none; -} - -.media-library-selection .media-library-item__preview { - cursor: move; -} - -.media-library-widget-modal .ui-dialog-buttonpane { - display: flex; - align-items: center; -} - -.media-library-widget-modal .ui-dialog-buttonpane .form-actions { - flex: 1; -} - -@media screen and (max-width: 600px) { - .media-library-view .form-actions { - flex-basis: 100%; - } -} - -/* @todo Remove in https://www.drupal.org/project/drupal/issues/3064914 */ -.views-live-preview .media-library-view div.views-row + div.views-row { - margin-top: 0; -} diff --git a/core/modules/media_library/js/media_library.view.es6.js b/core/modules/media_library/js/media_library.view.es6.js index 9b28c72f482..311968ccd12 100644 --- a/core/modules/media_library/js/media_library.view.es6.js +++ b/core/modules/media_library/js/media_library.view.es6.js @@ -12,9 +12,10 @@ */ Drupal.behaviors.MediaLibrarySelectAll = { attach(context) { - const $view = $('.js-media-library-view', context).once( - 'media-library-select-all', - ); + const $view = $( + '.js-media-library-view[data-view-display-id="page"]', + context, + ).once('media-library-select-all'); if ($view.length && $view.find('.js-media-library-item').length) { const $checkbox = $(Drupal.theme('checkbox')).on( 'click', diff --git a/core/modules/media_library/js/media_library.view.js b/core/modules/media_library/js/media_library.view.js index b3c21e9eb8c..099991a32a7 100644 --- a/core/modules/media_library/js/media_library.view.js +++ b/core/modules/media_library/js/media_library.view.js @@ -8,7 +8,7 @@ (function ($, Drupal) { Drupal.behaviors.MediaLibrarySelectAll = { attach: function attach(context) { - var $view = $('.js-media-library-view', context).once('media-library-select-all'); + var $view = $('.js-media-library-view[data-view-display-id="page"]', context).once('media-library-select-all'); if ($view.length && $view.find('.js-media-library-item').length) { var $checkbox = $(Drupal.theme('checkbox')).on('click', function (_ref) { var currentTarget = _ref.currentTarget; diff --git a/core/modules/media_library/media_library.info.yml b/core/modules/media_library/media_library.info.yml index 41b1e1eb304..dc6e63e4f8f 100644 --- a/core/modules/media_library/media_library.info.yml +++ b/core/modules/media_library/media_library.info.yml @@ -1,7 +1,7 @@ name: 'Media Library' type: module description: 'Enhances the media list with additional features to more easily find and use existing media items.' -package: Core (Experimental) +package: Core version: VERSION core: 8.x dependencies: diff --git a/core/modules/media_library/media_library.libraries.yml b/core/modules/media_library/media_library.libraries.yml index 02ecd2a6e18..b548e425498 100644 --- a/core/modules/media_library/media_library.libraries.yml +++ b/core/modules/media_library/media_library.libraries.yml @@ -1,11 +1,3 @@ -style: - version: VERSION - css: - component: - css/media_library.module.css: {} - theme: - css/media_library.theme.css: {} - click_to_select: version: VERSION js: @@ -21,7 +13,6 @@ view: dependencies: - core/drupal.announce - core/drupal.checkbox - - media_library/style - media_library/click_to_select widget: @@ -31,7 +22,6 @@ widget: dependencies: - core/drupal.dialog.ajax - core/jquery.once - - media_library/style - core/sortable ui: diff --git a/core/modules/media_library/media_library.module b/core/modules/media_library/media_library.module index 6822601f987..84c0f67732f 100644 --- a/core/modules/media_library/media_library.module +++ b/core/modules/media_library/media_library.module @@ -24,7 +24,6 @@ use Drupal\media\MediaTypeInterface; use Drupal\media_library\Form\FileUploadForm; use Drupal\media_library\Form\OEmbedForm; use Drupal\media_library\MediaLibraryState; -use Drupal\views\Form\ViewsForm; use Drupal\views\Plugin\views\cache\CachePluginBase; use Drupal\views\ViewExecutable; use Drupal\Core\StringTranslation\TranslatableMarkup; @@ -60,11 +59,21 @@ function media_library_help($route_name, RouteMatchInterface $route_match) { $output .= ''; $output .= '

' . t('Customize') . '

'; $output .= ''; @@ -91,9 +100,84 @@ function media_library_theme() { 'media__media_library' => [ 'base hook' => 'media', ], + 'media_library_wrapper' => [ + 'render element' => 'element', + ], + 'media_library_item' => [ + 'render element' => 'element', + ], ]; } +/** + * Prepares variables for the media library modal dialog. + * + * Default template: media-library-wrapper.html.twig. + * + * @param array $variables + * An associative array containing: + * - element: An associative array containing the properties of the element. + * Properties used: #menu, #content. + */ +function template_preprocess_media_library_wrapper(array &$variables) { + $variables['menu'] = &$variables['element']['menu']; + $variables['content'] = &$variables['element']['content']; +} + +/** + * Prepares variables for a selected media item. + * + * Default template: media-library-item.html.twig. + * + * @param array $variables + * An associative array containing: + * - element: An associative array containing the properties and children of + * the element. + */ +function template_preprocess_media_library_item(array &$variables) { + $element = &$variables['element']; + foreach (Element::children($element) as $key) { + $variables['content'][$key] = $element[$key]; + } +} + +/** + * Implements hook_views_pre_render(). + */ +function media_library_views_pre_render(ViewExecutable $view) { + $add_classes = function (&$option, array $classes_to_add) { + $classes = $option ? preg_split('/\s+/', trim($option)) : []; + $classes = array_filter($classes); + $classes = array_merge($classes, $classes_to_add); + $option = implode(' ', array_unique($classes)); + }; + + if ($view->id() === 'media_library') { + if ($view->current_display === 'page') { + $add_classes($view->style_plugin->options['row_class'], ['js-media-library-item', 'js-click-to-select']); + + if (array_key_exists('media_bulk_form', $view->field)) { + $add_classes($view->field['media_bulk_form']->options['element_class'], ['js-click-to-select-checkbox']); + } + } + elseif (strpos($view->current_display, 'widget') === 0) { + if (array_key_exists('media_library_select_form', $view->field)) { + $add_classes($view->field['media_library_select_form']->options['element_wrapper_class'], ['js-click-to-select-checkbox']); + } + $add_classes($view->display_handler->options['css_class'], ['js-media-library-view']); + } + + $add_classes($view->style_plugin->options['row_class'], ['js-media-library-item', 'js-click-to-select']); + + if ($view->display_handler->options['defaults']['css_class']) { + $add_classes($view->displayHandlers->get('default')->options['css_class'], ['js-media-library-view']); + } + else { + $add_classes($view->display_handler->options['css_class'], ['js-media-library-view']); + } + } +} + /** * Implements hook_views_post_render(). */ @@ -143,23 +227,30 @@ function media_library_preprocess_media(&$variables) { $variables['url'] = $media->toUrl($rel, [ 'language' => $media->language(), ]); - $variables['preview_attributes'] = new Attribute(); - $variables['preview_attributes']->addClass('media-library-item__preview', 'js-media-library-item-preview'); - $variables['metadata_attributes'] = new Attribute(); - $variables['metadata_attributes']->addClass('media-library-item__attributes'); + $variables += [ + 'preview_attributes' => new Attribute(), + 'metadata_attributes' => new Attribute(), + ]; $variables['status'] = $media->isPublished(); } } +/** + * Implements hook_preprocess_views_view() for the 'media_library' view. + */ +function media_library_preprocess_views_view__media_library(array &$variables) { + $variables['attributes']['data-view-display-id'] = $variables['view']->current_display; +} + /** * Implements hook_preprocess_views_view_fields(). */ function media_library_preprocess_views_view_fields(&$variables) { // Add classes to media rendered entity field so it can be targeted for - // styling and JavaScript mouseover and click events. + // JavaScript mouseover and click events. if ($variables['view']->id() === 'media_library' && isset($variables['fields']['rendered_entity'])) { if (isset($variables['fields']['rendered_entity']->wrapper_attributes)) { - $variables['fields']['rendered_entity']->wrapper_attributes->addClass('js-click-to-select-trigger media-library-item__click-to-select-trigger'); + $variables['fields']['rendered_entity']->wrapper_attributes->addClass('js-click-to-select-trigger'); } } } @@ -193,41 +284,32 @@ function media_library_form_views_form_media_library_page_alter(array &$form, Fo * Implements hook_form_alter(). */ function media_library_form_alter(array &$form, FormStateInterface $form_state, $form_id) { - $form_object = $form_state->getFormObject(); - if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_media_library') === 0) { - $form['#attributes']['class'][] = 'media-library-views-form'; - if (isset($form['header'])) { - $form['header']['#attributes']['class'][] = 'media-library-views-form__header'; - $form['header']['media_bulk_form']['#attributes']['class'][] = 'media-library-views-form__bulk_form'; - } - } - - // Add after build to fix media library views exposed filter's submit button. + // Add a process callback to ensure that the media library view's exposed + // filters submit button is not moved to the modal dialog's button area. if ($form_id === 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-media-library-widget') === 0) { $form['#after_build'][] = '_media_library_views_form_media_library_after_build'; } // Configures media_library displays when a type is submitted. - if ($form_object instanceof MediaTypeForm) { + if ($form_state->getFormObject() instanceof MediaTypeForm) { $form['actions']['submit']['#submit'][] = '_media_library_media_type_form_submit'; } } /** - * After build callback for views form media library. + * Form #after_build callback for media_library view's exposed filters form. */ function _media_library_views_form_media_library_after_build(array $form, FormStateInterface $form_state) { - // Remove .form-actions from media library views exposed filter actions - // and replace with .media-library-view--form-actions. - // - // This prevents the views exposed filter's 'Apply filter' submit button from - // being moved into the dialog's buttons. + // Remove .form-actions from the view's exposed filter actions. This prevents + // the "Apply filters" submit button from being moved into the dialog's + // button area. // @see \Drupal\Core\Render\Element\Actions::processActions // @see Drupal.behaviors.dialog.prepareDialogButtons + // @todo Remove this after + // https://www.drupal.org/project/drupal/issues/3089751 is fixed. if (($key = array_search('form-actions', $form['actions']['#attributes']['class'])) !== FALSE) { unset($form['actions']['#attributes']['class'][$key]); } - $form['actions']['#attributes']['class'][] = 'media-library-view--form-actions'; return $form; } diff --git a/core/modules/media_library/src/Ajax/UpdateSelectionCommand.php b/core/modules/media_library/src/Ajax/UpdateSelectionCommand.php index c9f329ce6bc..1f6e7e047b4 100644 --- a/core/modules/media_library/src/Ajax/UpdateSelectionCommand.php +++ b/core/modules/media_library/src/Ajax/UpdateSelectionCommand.php @@ -18,9 +18,8 @@ use Drupal\Core\Ajax\CommandInterface; * @ingroup ajax * * @internal - * Media Library is an experimental module and its internal code may be - * subject to change in minor releases. External code should not instantiate - * or extend this class. + * This is an internal part of Media Library and may be subject to change in + * minor releases. External code should not instantiate or extend this class. */ class UpdateSelectionCommand implements CommandInterface { diff --git a/core/modules/media_library/src/Form/AddFormBase.php b/core/modules/media_library/src/Form/AddFormBase.php index 331fec0b84e..497d83346bb 100644 --- a/core/modules/media_library/src/Form/AddFormBase.php +++ b/core/modules/media_library/src/Form/AddFormBase.php @@ -9,8 +9,11 @@ use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\Entity\Entity\EntityFormDisplay; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\Form\BaseFormIdInterface; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Render\Element; +use Drupal\Core\Security\TrustedCallbackInterface; use Drupal\Core\Url; use Drupal\media\MediaInterface; use Drupal\media\MediaTypeInterface; @@ -21,13 +24,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** * Provides a base class for creating media items from within the media library. - * - * @internal - * Media Library is an experimental module and its internal code may be - * subject to change in minor releases. External code should not instantiate - * or extend this class. */ -abstract class AddFormBase extends FormBase { +abstract class AddFormBase extends FormBase implements BaseFormIdInterface, TrustedCallbackInterface { /** * The entity type manager. @@ -99,7 +97,7 @@ abstract class AddFormBase extends FormBase { /** * {@inheritdoc} */ - public function getFormId() { + public function getBaseFormId() { return 'media_library_add_form'; } @@ -137,9 +135,8 @@ abstract class AddFormBase extends FormBase { public function buildForm(array $form, FormStateInterface $form_state) { // @todo Remove the ID when we can use selectors to replace content via // AJAX in https://www.drupal.org/project/drupal/issues/2821793. - $form['#prefix'] = '
'; + $form['#prefix'] = '
'; $form['#suffix'] = '
'; - $form['#attached']['library'][] = 'media_library/style'; // The media library is loaded via AJAX, which means that the form action // URL defaults to the current URL. However, to add media, we always need to @@ -157,27 +154,37 @@ abstract class AddFormBase extends FormBase { ]; $form['#attributes']['class'] = [ - 'media-library-add-form', 'js-media-library-add-form', ]; $added_media = $this->getAddedMediaItems($form_state); if (empty($added_media)) { - $form['#attributes']['class'][] = 'media-library-add-form--without-input'; $form = $this->buildInputElement($form, $form_state); } else { - $form['#attributes']['class'][] = 'media-library-add-form--with-input'; + $form['#attributes']['data-input'] = 'true'; + + // This deserves to be themeable, but it doesn't need to be its own "real" + // template. + $form['description'] = [ + '#type' => 'inline_template', + '#template' => '

{{ text }}

', + '#context' => [ + 'text' => $this->formatPlural(count($added_media), 'The media item has been created but has not yet been saved. Fill in any required fields and save to add it to the media library.', 'The media items have been created but have not yet been saved. Fill in any required fields and save to add them to the media library.'), + ], + ]; $form['media'] = [ - '#type' => 'container', + '#pre_render' => [ + [$this, 'preRenderAddedMedia'], + ], '#attributes' => [ 'class' => [ + // This needs to be focus-able by an AJAX response. + // @see ::updateFormCallback() 'js-media-library-add-form-added-media', - 'media-library-add-form__added-media', ], 'aria-label' => $this->t('Added media items'), - 'role' => 'list', // Add the tabindex '-1' to allow the focus to be shifted to the added // media wrapper when items are added. We set focus to the container // because a media item does not necessarily have required fields and @@ -186,18 +193,6 @@ abstract class AddFormBase extends FormBase { 'tabindex' => '-1', ], ]; - - $form['media']['description'] = [ - '#type' => 'html_tag', - '#tag' => 'p', - '#value' => $this->formatPlural(count($added_media), 'The media item has been created but has not yet been saved. Fill in any required fields and save to add it to the media library.', 'The media items have been created but have not yet been saved. Fill in any required fields and save to add them to the media library.'), - '#attributes' => [ - 'class' => [ - 'media-library-add-form__description', - ], - ], - ]; - foreach ($added_media as $delta => $media) { $form['media'][$delta] = $this->buildEntityFormElement($media, $form, $form_state, $delta); } @@ -267,13 +262,8 @@ abstract class AddFormBase extends FormBase { $id_suffix = $parents ? '-' . implode('-', $parents) : ''; $element = [ - '#type' => 'container', - '#attributes' => [ - 'class' => [ - 'media-library-add-form__media', - ], + '#wrapper_attributes' => [ 'aria-label' => $media->getName(), - 'role' => 'listitem', // Add the tabindex '-1' to allow the focus to be shifted to the next // media item when an item is removed. We set focus to the container // because a media item does not necessarily have required fields and we @@ -288,20 +278,10 @@ abstract class AddFormBase extends FormBase { 'preview' => [ '#type' => 'container', '#weight' => 10, - '#attributes' => [ - 'class' => [ - 'media-library-add-form__preview', - ], - ], ], 'fields' => [ '#type' => 'container', '#weight' => 20, - '#attributes' => [ - 'class' => [ - 'media-library-add-form__fields', - ], - ], // The '#parents' are set here because the entity form display needs it // to build the entity form fields. '#parents' => ['media', $delta, 'fields'], @@ -312,7 +292,6 @@ abstract class AddFormBase extends FormBase { '#name' => 'media-' . $delta . '-remove-button' . $id_suffix, '#weight' => 30, '#attributes' => [ - 'class' => ['media-library-add-form__remove-button'], 'aria-label' => $this->t('Remove @label', ['@label' => $media->getName()]), ], '#ajax' => [ @@ -349,13 +328,13 @@ abstract class AddFormBase extends FormBase { } $form_display->buildForm($media, $element['fields'], $form_state); - // We hide the preview of the uploaded file in the image widget with CSS. + // We hide the preview of the uploaded file in the image widget with CSS, so + // set a property so themes and form_alter hooks can easily identify the + // source field. // @todo Improve hiding file widget elements in // https://www.drupal.org/project/drupal/issues/2987921 - $source_field_name = $this->getSourceFieldName($media->bundle->entity); - if (isset($element['fields'][$source_field_name])) { - $element['fields'][$source_field_name]['#attributes']['class'][] = 'media-library-add-form__source-field'; - } + $element['fields']['#source_field_name'] = $this->getSourceFieldName($media->bundle->entity); + // The revision log field is currently not configurable from the form // display, so hide it by changing the access. // @todo Make the revision_log_message field configurable in @@ -366,6 +345,34 @@ abstract class AddFormBase extends FormBase { return $element; } + /** + * {@inheritdodc} + */ + public static function trustedCallbacks() { + return ['preRenderAddedMedia']; + } + + /** + * Converts the set of newly added media into an item list for rendering. + * + * @param array $element + * The render element to transform. + * + * @return array + * The transformed render element. + */ + public function preRenderAddedMedia(array $element) { + // Transform the element into an item list for rendering. + $element['#theme'] = 'item_list__media_library_add_form_media_list'; + $element['#list_type'] = 'ul'; + + foreach (Element::children($element) as $delta) { + $element['#items'][$delta] = $element[$delta]; + unset($element[$delta]); + } + return $element; + } + /** * Returns a render array containing the current selection. * @@ -386,13 +393,11 @@ abstract class AddFormBase extends FormBase { $selection = [ '#type' => 'details', + '#theme_wrappers' => [ + 'details__media_library_add_form_selected_media', + ], '#open' => FALSE, '#title' => $this->t('Additional selected media'), - '#attributes' => [ - 'class' => [ - 'media-library-add-form__selected-media', - ], - ], ]; foreach ($pre_selected_items as $media_id => $media) { $selection[$media_id] = $this->buildSelectedItemElement($media, $form, $form_state); @@ -416,12 +421,9 @@ abstract class AddFormBase extends FormBase { */ protected function buildSelectedItemElement(MediaInterface $media, array $form, FormStateInterface $form_state) { return [ - '#type' => 'container', + '#theme' => 'media_library_item__small', '#attributes' => [ 'class' => [ - 'media-library-item', - 'media-library-item--grid', - 'media-library-item--small', 'js-media-library-item', 'js-click-to-select', ], @@ -430,7 +432,7 @@ abstract class AddFormBase extends FormBase { '#type' => 'container', '#attributes' => [ 'class' => [ - 'js-click-to-select-checkbox media-library-item__click-to-select-checkbox', + 'js-click-to-select-checkbox', ], ], 'select_checkbox' => [ diff --git a/core/modules/media_library/src/Form/FileUploadForm.php b/core/modules/media_library/src/Form/FileUploadForm.php index 81367821c25..d9b377d4a1b 100644 --- a/core/modules/media_library/src/Form/FileUploadForm.php +++ b/core/modules/media_library/src/Form/FileUploadForm.php @@ -27,9 +27,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; * Creates a form to create media entities from uploaded files. * * @internal - * Media Library is an experimental module and its internal code may be - * subject to change in minor releases. External code should not instantiate - * or extend this class. + * Form classes are internal. */ class FileUploadForm extends AddFormBase { @@ -106,6 +104,13 @@ class FileUploadForm extends AddFormBase { ); } + /** + * {@inheritdoc} + */ + public function getFormId() { + return $this->getBaseFormId() . '_upload'; + } + /** * {@inheritdoc} */ @@ -128,8 +133,6 @@ class FileUploadForm extends AddFormBase { * {@inheritdoc} */ protected function buildInputElement(array $form, FormStateInterface $form_state) { - $form['#attributes']['class'][] = 'media-library-add-form--upload'; - // Create a file item to get the upload validators. $media_type = $this->getMediaType($form_state); $item = $this->createFileItem($media_type); @@ -145,9 +148,6 @@ class FileUploadForm extends AddFormBase { // Add a container to group the input elements for styling purposes. $form['container'] = [ '#type' => 'container', - '#attributes' => [ - 'class' => ['media-library-add-form__input-wrapper'], - ], ]; $process = (array) $this->elementInfo->getInfoProperty('managed_file', '#process', []); diff --git a/core/modules/media_library/src/Form/OEmbedForm.php b/core/modules/media_library/src/Form/OEmbedForm.php index c31bc8e0dd3..8b70c896918 100644 --- a/core/modules/media_library/src/Form/OEmbedForm.php +++ b/core/modules/media_library/src/Form/OEmbedForm.php @@ -18,9 +18,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; * Creates a form to create media entities from oEmbed URLs. * * @internal - * Media Library is an experimental module and its internal code may be - * subject to change in minor releases. External code should not instantiate - * or extend this class. + * Form classes are internal. */ class OEmbedForm extends AddFormBase { @@ -71,6 +69,13 @@ class OEmbedForm extends AddFormBase { ); } + /** + * {@inheritdoc} + */ + public function getFormId() { + return $this->getBaseFormId() . '_oembed'; + } + /** * {@inheritdoc} */ @@ -90,17 +95,12 @@ class OEmbedForm extends AddFormBase { * {@inheritdoc} */ protected function buildInputElement(array $form, FormStateInterface $form_state) { - $form['#attributes']['class'][] = 'media-library-add-form--oembed'; - $media_type = $this->getMediaType($form_state); $providers = $media_type->getSource()->getProviders(); // Add a container to group the input elements for styling purposes. $form['container'] = [ '#type' => 'container', - '#attributes' => [ - 'class' => ['media-library-add-form__input-wrapper'], - ], ]; $form['container']['url'] = [ @@ -114,7 +114,6 @@ class OEmbedForm extends AddFormBase { '#required' => TRUE, '#attributes' => [ 'placeholder' => 'https://', - 'class' => ['media-library-add-form-oembed-url'], ], ]; @@ -139,9 +138,6 @@ class OEmbedForm extends AddFormBase { ], ], ], - '#attributes' => [ - 'class' => ['media-library-add-form-oembed-submit'], - ], ]; return $form; } diff --git a/core/modules/media_library/src/Form/SettingsForm.php b/core/modules/media_library/src/Form/SettingsForm.php index c171ece8088..68193583f58 100644 --- a/core/modules/media_library/src/Form/SettingsForm.php +++ b/core/modules/media_library/src/Form/SettingsForm.php @@ -7,6 +7,9 @@ use Drupal\Core\Form\FormStateInterface; /** * Defines a form for configuring the Media Library module. + * + * @internal + * Form classes are internal. */ class SettingsForm extends ConfigFormBase { diff --git a/core/modules/media_library/src/MediaLibraryEditorOpener.php b/core/modules/media_library/src/MediaLibraryEditorOpener.php index a31290fca60..0c0af98b419 100644 --- a/core/modules/media_library/src/MediaLibraryEditorOpener.php +++ b/core/modules/media_library/src/MediaLibraryEditorOpener.php @@ -14,9 +14,7 @@ use Drupal\editor\Ajax\EditorDialogSave; * @see \Drupal\media_library\Plugin\CKEditorPlugin\DrupalMediaLibrary * * @internal - * This is an internal part of the media system in Drupal core and may be - * subject to change in minor releases. This class should not be - * instantiated or extended by external code. + * This service is an internal part of Media Library's CKEditor integration. */ class MediaLibraryEditorOpener implements MediaLibraryOpenerInterface { diff --git a/core/modules/media_library/src/MediaLibraryFieldWidgetOpener.php b/core/modules/media_library/src/MediaLibraryFieldWidgetOpener.php index b34b8d308b9..84099ed3f60 100644 --- a/core/modules/media_library/src/MediaLibraryFieldWidgetOpener.php +++ b/core/modules/media_library/src/MediaLibraryFieldWidgetOpener.php @@ -12,6 +12,9 @@ use Drupal\Core\Session\AccountInterface; /** * The media library opener for field widgets. + * + * @internal + * This service is an internal part of Media Library's field widget. */ class MediaLibraryFieldWidgetOpener implements MediaLibraryOpenerInterface { diff --git a/core/modules/media_library/src/MediaLibraryState.php b/core/modules/media_library/src/MediaLibraryState.php index 258f19ded14..e1fd6e2e8b9 100644 --- a/core/modules/media_library/src/MediaLibraryState.php +++ b/core/modules/media_library/src/MediaLibraryState.php @@ -36,11 +36,6 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; * with them either. * * @see \Drupal\media_library\MediaLibraryOpenerInterface - * - * @internal - * Media Library is an experimental module and its internal code may be - * subject to change in minor releases. External code should not instantiate - * or extend this class. */ class MediaLibraryState extends ParameterBag { diff --git a/core/modules/media_library/src/MediaLibraryUiBuilder.php b/core/modules/media_library/src/MediaLibraryUiBuilder.php index b5e30c36f36..9c871a5be15 100644 --- a/core/modules/media_library/src/MediaLibraryUiBuilder.php +++ b/core/modules/media_library/src/MediaLibraryUiBuilder.php @@ -17,9 +17,8 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; * Service which builds the media library. * * @internal - * Media Library is an experimental module and its internal code may be - * subject to change in minor releases. External code should not instantiate - * or extend this class. + * This service is an internal part of the modal media library dialog and + * does not provide any extension points. */ class MediaLibraryUiBuilder { @@ -123,11 +122,9 @@ class MediaLibraryUiBuilder { } else { return [ - '#type' => 'html_tag', - '#tag' => 'div', + '#theme' => 'media_library_wrapper', '#attributes' => [ 'id' => 'media-library-wrapper', - 'class' => ['media-library-wrapper'], ], 'menu' => $this->buildMediaTypeMenu($state), 'content' => $this->buildLibraryContent($state), @@ -157,11 +154,12 @@ class MediaLibraryUiBuilder { */ protected function buildLibraryContent(MediaLibraryState $state) { return [ - '#type' => 'html_tag', - '#tag' => 'div', + '#type' => 'container', + '#theme_wrappers' => [ + 'container__media_library_content', + ], '#attributes' => [ 'id' => 'media-library-content', - 'class' => ['media-library-content'], ], 'form' => $this->buildMediaTypeAddForm($state), 'view' => $this->buildMediaLibraryView($state), @@ -234,10 +232,10 @@ class MediaLibraryUiBuilder { // @todo: Add a class to the li element. // https://www.drupal.org/project/drupal/issues/3029227 $menu = [ - '#theme' => 'links', + '#theme' => 'links__media_library_menu', '#links' => [], '#attributes' => [ - 'class' => ['media-library-menu', 'js-media-library-menu'], + 'class' => ['js-media-library-menu'], ], ]; @@ -267,7 +265,6 @@ class MediaLibraryUiBuilder { 'query' => $link_state->all(), ]), 'attributes' => [ - 'class' => ['media-library-menu__link'], 'role' => 'button', 'data-title' => $title, ], diff --git a/core/modules/media_library/src/OpenerResolver.php b/core/modules/media_library/src/OpenerResolver.php index 76a5acf6f7b..c164544aaed 100644 --- a/core/modules/media_library/src/OpenerResolver.php +++ b/core/modules/media_library/src/OpenerResolver.php @@ -11,6 +11,10 @@ use Symfony\Component\DependencyInjection\ContainerAwareTrait; * services which implement \Drupal\media_library\MediaLibraryOpenerInterface. * It is not an API and should not be extended or used by code that does not * interact with the Media Library module. + * + * @internal + * This service is an internal part of the modal media library dialog and + * does not provide any extension points or public API. */ class OpenerResolver implements OpenerResolverInterface { diff --git a/core/modules/media_library/src/OpenerResolverInterface.php b/core/modules/media_library/src/OpenerResolverInterface.php index 7854c17d38f..4a877f68ecc 100644 --- a/core/modules/media_library/src/OpenerResolverInterface.php +++ b/core/modules/media_library/src/OpenerResolverInterface.php @@ -9,6 +9,11 @@ namespace Drupal\media_library; * services which implement \Drupal\media_library\MediaLibraryOpenerInterface. * It is not an API and should not be extended or used by code that does not * interact with the Media Library module. + * + * @internal + * This interface is an internal part of the modal media library dialog and + * is only implemented by \Drupal\media_library\OpenerResolver. It is not a + * public API. */ interface OpenerResolverInterface { diff --git a/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php index f4ca70e16c4..5234c88d90d 100644 --- a/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php +++ b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php @@ -17,6 +17,7 @@ use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\Core\Field\WidgetBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; +use Drupal\Core\Security\TrustedCallbackInterface; use Drupal\Core\Session\AccountInterface; use Drupal\Core\Url; use Drupal\field_ui\FieldUI; @@ -40,11 +41,9 @@ use Symfony\Component\Validator\ConstraintViolationInterface; * ) * * @internal - * Media Library is an experimental module and its internal code may be - * subject to change in minor releases. External code should not instantiate - * or extend this class. + * Plugin classes are internal. */ -class MediaLibraryWidget extends WidgetBase implements ContainerFactoryPluginInterface { +class MediaLibraryWidget extends WidgetBase implements ContainerFactoryPluginInterface, TrustedCallbackInterface { /** * Entity type manager service. @@ -317,11 +316,17 @@ class MediaLibraryWidget extends WidgetBase implements ContainerFactoryPluginInt '#target_bundles' => isset($settings['target_bundles']) ? $settings['target_bundles'] : FALSE, '#attributes' => [ 'id' => $wrapper_id, - 'class' => ['js-media-library-widget', 'media-library-widget'], + 'class' => ['js-media-library-widget'], + ], + '#pre_render' => [ + [$this, 'preRenderWidget'], ], '#attached' => [ 'library' => ['media_library/widget'], ], + '#theme_wrappers' => [ + 'fieldset__media_library_widget', + ], ]; // When the list of allowed types in the field configuration is null, @@ -337,26 +342,21 @@ class MediaLibraryWidget extends WidgetBase implements ContainerFactoryPluginInt } if (empty($referenced_entities)) { - $element['empty_selection'] = [ - '#type' => 'html_tag', - '#tag' => 'p', - '#value' => $this->t('No media items are selected.'), - '#attributes' => [ - 'class' => [ - 'media-library-widget-empty-text', - ], - ], + $element['#field_prefix']['empty_selection'] = [ + '#markup' => $this->t('No media items are selected.'), ]; } else { - $element['weight_toggle'] = [ + // @todo Use a
{% if not status %} -
{{ "unpublished" | t }}
+ {{ "unpublished" | t }} {% endif %} -
- {{ name }} -
+ {{ name }} {% endif %} diff --git a/core/modules/media_library/templates/media-library-item.html.twig b/core/modules/media_library/templates/media-library-item.html.twig new file mode 100644 index 00000000000..a765d04c11b --- /dev/null +++ b/core/modules/media_library/templates/media-library-item.html.twig @@ -0,0 +1,22 @@ +{# +/** + * @file + * Default theme implementation of a media library item. + * + * This is used when displaying selected media items, either in the field + * widget or in the "Additional selected media" area when adding new + * media items in the media library modal dialog. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - content: The content of the media library item, plus any additional + * fields or elements surrounding it. + * + * @see template_preprocess_media_library_item() + * + * @ingroup themeable + */ +#} + + {{ content }} + diff --git a/core/modules/media_library/templates/media-library-wrapper.html.twig b/core/modules/media_library/templates/media-library-wrapper.html.twig new file mode 100644 index 00000000000..344637cd62c --- /dev/null +++ b/core/modules/media_library/templates/media-library-wrapper.html.twig @@ -0,0 +1,21 @@ +{# +/** + * @file + * Default theme implementation of a container used to wrap the media library's + * modal dialog interface. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - menu: The menu of availble media types to choose from. + * - content: The form to add new media items, followed by the grid or table of + * existing media items to choose from. + * + * @see template_preprocess_media_library_wrapper() + * + * @ingroup themeable + */ +#} + + {{ menu }} + {{ content }} + diff --git a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php index 5f9fb1df3b8..5604fa22d20 100644 --- a/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php +++ b/core/modules/media_library/tests/src/FunctionalJavascript/MediaLibraryTest.php @@ -128,16 +128,16 @@ class MediaLibraryTest extends WebDriverTestBase { // Test that users can filter by type. $page->selectFieldOption('Media type', 'Type One'); $page->pressButton('Apply filters'); - $this->waitForText('Dog'); $this->waitForNoText('Turtle'); + $assert_session->pageTextContains('Dog'); $page->selectFieldOption('Media type', 'Type Two'); $page->pressButton('Apply filters'); - $this->waitForNoText('Dog'); $this->waitForText('Turtle'); + $assert_session->pageTextNotContains('Dog'); // Test that selecting elements as a part of bulk operations works. $page->selectFieldOption('Media type', '- Any -'); - $page->pressButton('Apply filters'); + $assert_session->elementExists('css', '#views-exposed-form-media-library-page')->submit(); $this->waitForText('Dog'); // This tests that anchor tags clicked inside the preview are suppressed. @@ -145,14 +145,17 @@ class MediaLibraryTest extends WebDriverTestBase { $this->submitForm([], 'Apply to selected items'); $assert_session->pageTextContains('Dog'); $assert_session->pageTextNotContains('Cat'); - $this->submitForm([], 'Delete'); + // For reasons that are not clear, deleting media items by pressing the + // "Delete" button can fail (the button is found, but never actually pressed + // by the Mink driver). This workaround allows the delete form to be + // submitted. + $assert_session->elementExists('css', 'form')->submit(); $assert_session->pageTextNotContains('Dog'); $assert_session->pageTextContains('Cat'); // Test the 'Select all media' checkbox and assert that it makes the // expected announcements. - $select_all = $assert_session->waitForField('Select all media'); - $this->assertNotEmpty($select_all); + $select_all = $this->waitForFieldExists('Select all media'); $select_all->check(); $this->waitForText('All 7 items selected'); $select_all->uncheck(); @@ -160,7 +163,11 @@ class MediaLibraryTest extends WebDriverTestBase { $select_all->check(); $page->selectFieldOption('Action', 'media_delete_action'); $this->submitForm([], 'Apply to selected items'); - $page->pressButton('Delete'); + // For reasons that are not clear, deleting media items by pressing the + // "Delete" button can fail (the button is found, but never actually pressed + // by the Mink driver). This workaround allows the delete form to be + // submitted. + $assert_session->elementExists('css', 'form')->submit(); $assert_session->pageTextNotContains('Cat'); $assert_session->pageTextNotContains('Turtle'); @@ -439,7 +446,6 @@ class MediaLibraryTest extends WebDriverTestBase { // Assert generic media library elements. $this->openMediaLibraryForField('field_unlimited_media'); - $this->assertFalse($assert_session->elementExists('css', '.media-library-select-all')->isVisible()); $assert_session->elementExists('css', '.ui-dialog-titlebar-close')->click(); // Assert that the media type menu is available when more than 1 type is @@ -984,13 +990,11 @@ class MediaLibraryTest extends WebDriverTestBase { $assert_session->fieldExists('Add files'); // Assert we can upload a file to the default tab type_three. - $assert_session->elementExists('css', '.media-library-add-form--without-input'); - $assert_session->elementNotExists('css', '.media-library-add-form--with-input'); + $assert_session->elementNotExists('css', '.js-media-library-add-form[data-input]'); $this->addMediaFileToField('Add files', $this->container->get('file_system')->realpath($png_image->uri)); $this->assertMediaAdded(); - $assert_session->elementExists('css', '.media-library-add-form--with-input'); - $assert_session->elementNotExists('css', '.media-library-add-form--without-input'); - // We do not have a pre-selected items, so the container should not be added + $assert_session->elementExists('css', '.js-media-library-add-form[data-input]'); + // We do not have pre-selected items, so the container should not be added // to the form. $assert_session->pageTextNotContains('Additional selected media'); // Files are temporary until the form is saved. @@ -1326,12 +1330,10 @@ class MediaLibraryTest extends WebDriverTestBase { $assert_session->fieldExists('Add files'); // Assert we can upload a file to the default tab type_three. - $assert_session->elementExists('css', '.media-library-add-form--without-input'); - $assert_session->elementNotExists('css', '.media-library-add-form--with-input'); + $assert_session->elementNotExists('css', '.js-media-library-add-form[data-input]'); $this->addMediaFileToField('Add files', $this->container->get('file_system')->realpath($png_image->uri)); $this->assertMediaAdded(); - $assert_session->elementExists('css', '.media-library-add-form--with-input'); - $assert_session->elementNotExists('css', '.media-library-add-form--without-input'); + $assert_session->elementExists('css', '.js-media-library-add-form[data-input]'); // We do not have a pre-selected items, so the container should not be added // to the form. $assert_session->elementNotExists('css', 'details summary:contains(Additional selected media)'); @@ -2247,6 +2249,9 @@ class MediaLibraryTest extends WebDriverTestBase { $assert_session->linkExists('Grid'); $assert_session->linkExists('Table'); + // The "select all" checkbox should never be present in the modal. + $assert_session->elementNotExists('css', '.media-library-select-all'); + return $this->assertElementExistsAfterWait('css', $after_open_selector); } @@ -2379,18 +2384,16 @@ class MediaLibraryTest extends WebDriverTestBase { * Asserts that the grid display of the widget view is visible. */ protected function assertMediaLibraryGrid() { - $assert_session = $this->assertSession(); - $assert_session->elementExists('css', '.view-media-library.view-display-id-widget'); - $assert_session->elementNotExists('css', '.view-media-library.view-display-id-widget_table'); + $this->assertSession() + ->elementExists('css', '.js-media-library-view[data-view-display-id="widget"]'); } /** * Asserts that the table display of the widget view is visible. */ protected function assertMediaLibraryTable() { - $assert_session = $this->assertSession(); - $assert_session->elementExists('css', '.view-media-library.view-display-id-widget_table'); - $assert_session->elementNotExists('css', '.view-media-library.view-display-id-widget'); + $this->assertSession() + ->elementExists('css', '.js-media-library-view[data-view-display-id="widget_table"]'); } /** diff --git a/core/modules/media_library/config/optional/core.entity_form_display.media.audio.media_library.yml b/core/profiles/standard/config/optional/core.entity_form_display.media.audio.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_form_display.media.audio.media_library.yml rename to core/profiles/standard/config/optional/core.entity_form_display.media.audio.media_library.yml diff --git a/core/modules/media_library/config/optional/core.entity_form_display.media.document.media_library.yml b/core/profiles/standard/config/optional/core.entity_form_display.media.document.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_form_display.media.document.media_library.yml rename to core/profiles/standard/config/optional/core.entity_form_display.media.document.media_library.yml diff --git a/core/modules/media_library/config/optional/core.entity_form_display.media.image.media_library.yml b/core/profiles/standard/config/optional/core.entity_form_display.media.image.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_form_display.media.image.media_library.yml rename to core/profiles/standard/config/optional/core.entity_form_display.media.image.media_library.yml diff --git a/core/modules/media_library/config/optional/core.entity_form_display.media.remote_video.media_library.yml b/core/profiles/standard/config/optional/core.entity_form_display.media.remote_video.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_form_display.media.remote_video.media_library.yml rename to core/profiles/standard/config/optional/core.entity_form_display.media.remote_video.media_library.yml diff --git a/core/modules/media_library/config/optional/core.entity_form_display.media.video.media_library.yml b/core/profiles/standard/config/optional/core.entity_form_display.media.video.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_form_display.media.video.media_library.yml rename to core/profiles/standard/config/optional/core.entity_form_display.media.video.media_library.yml diff --git a/core/modules/media_library/config/optional/core.entity_view_display.media.audio.media_library.yml b/core/profiles/standard/config/optional/core.entity_view_display.media.audio.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_view_display.media.audio.media_library.yml rename to core/profiles/standard/config/optional/core.entity_view_display.media.audio.media_library.yml diff --git a/core/modules/media_library/config/optional/core.entity_view_display.media.document.media_library.yml b/core/profiles/standard/config/optional/core.entity_view_display.media.document.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_view_display.media.document.media_library.yml rename to core/profiles/standard/config/optional/core.entity_view_display.media.document.media_library.yml diff --git a/core/modules/media_library/config/optional/core.entity_view_display.media.image.media_library.yml b/core/profiles/standard/config/optional/core.entity_view_display.media.image.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_view_display.media.image.media_library.yml rename to core/profiles/standard/config/optional/core.entity_view_display.media.image.media_library.yml diff --git a/core/modules/media_library/config/optional/core.entity_view_display.media.remote_video.media_library.yml b/core/profiles/standard/config/optional/core.entity_view_display.media.remote_video.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_view_display.media.remote_video.media_library.yml rename to core/profiles/standard/config/optional/core.entity_view_display.media.remote_video.media_library.yml diff --git a/core/modules/media_library/config/optional/core.entity_view_display.media.video.media_library.yml b/core/profiles/standard/config/optional/core.entity_view_display.media.video.media_library.yml similarity index 100% rename from core/modules/media_library/config/optional/core.entity_view_display.media.video.media_library.yml rename to core/profiles/standard/config/optional/core.entity_view_display.media.video.media_library.yml diff --git a/core/themes/classy/classy.info.yml b/core/themes/classy/classy.info.yml index 161b5394752..5f46a6eaa65 100644 --- a/core/themes/classy/classy.info.yml +++ b/core/themes/classy/classy.info.yml @@ -25,6 +25,10 @@ libraries-extend: - classy/progress media/media_embed_ckeditor_theme: - classy/media_embed_ckeditor_theme + media_library/view: + - classy/media_library + media_library/widget: + - classy/media_library ckeditor_stylesheets: - css/components/media-embed-error.css diff --git a/core/themes/classy/classy.libraries.yml b/core/themes/classy/classy.libraries.yml index 975b64283a9..872b9738e4e 100644 --- a/core/themes/classy/classy.libraries.yml +++ b/core/themes/classy/classy.libraries.yml @@ -68,6 +68,12 @@ indented: component: css/components/indented.css: {} +media_library: + version: VERSION + css: + layout: + css/layout/media-library.css: {} + messages: version: VERSION css: diff --git a/core/themes/classy/classy.theme b/core/themes/classy/classy.theme new file mode 100644 index 00000000000..4407c9a5282 --- /dev/null +++ b/core/themes/classy/classy.theme @@ -0,0 +1,34 @@ +getFormObject(); + if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_media_library') === 0) { + $form['#attributes']['class'][] = 'media-library-views-form'; + } +} diff --git a/core/themes/classy/css/layout/media-library.css b/core/themes/classy/css/layout/media-library.css new file mode 100644 index 00000000000..84dee10daa5 --- /dev/null +++ b/core/themes/classy/css/layout/media-library.css @@ -0,0 +1,28 @@ +/** + * @file + * Contains minimal layout styling for the media library. + */ + +.media-library-wrapper { + display: flex; +} + +.media-library-menu { + flex-basis: 20%; + flex-shrink: 0; +} + +.media-library-content { + flex-grow: 1; +} + +.media-library-views-form { + display: flex; + flex-wrap: wrap; +} + +.media-library-views-form .media-library-item { + justify-content: space-between; + max-width: 23%; + margin: 1%; +} diff --git a/core/themes/classy/templates/media-library/container--media-library-content.html.twig b/core/themes/classy/templates/media-library/container--media-library-content.html.twig new file mode 100644 index 00000000000..7c930e2c7b6 --- /dev/null +++ b/core/themes/classy/templates/media-library/container--media-library-content.html.twig @@ -0,0 +1,28 @@ +{# +/** + * @file + * Theme implementation the content area of the modal media library dialog. + * + * The content area is everything that is not the menu of available media + * types. This includes the form to add new media items, if available, and + * the view of available media to select. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - children: The rendered child elements of the container. + * - has_parent: A flag to indicate that the container has one or more parent + containers. + * + * @see template_preprocess_container() + * + * @ingroup themeable + */ +#} +{% + set classes = [ + has_parent ? 'js-form-wrapper', + has_parent ? 'form-wrapper', + 'media-library-content', + ] +%} +{{ children }} diff --git a/core/themes/classy/templates/media-library/container--media-library-widget-selection.html.twig b/core/themes/classy/templates/media-library/container--media-library-widget-selection.html.twig new file mode 100644 index 00000000000..7c0af44307f --- /dev/null +++ b/core/themes/classy/templates/media-library/container--media-library-widget-selection.html.twig @@ -0,0 +1,28 @@ +{# +/** + * @file + * Theme implementation of a wrapper for selected media items. + * + * This is used to wrap around the set of media items that are currently + * selected in the media library widget (not the modal dialog), which may + * be used for entity reference fields that target media. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - children: The rendered child elements of the container. + * - has_parent: A flag to indicate that the container has one or more parent + containers. + * + * @see template_preprocess_container() + * + * @ingroup themeable + */ +#} +{% + set classes = [ + has_parent ? 'js-form-wrapper', + has_parent ? 'form-wrapper', + 'media-library-selection', + ] +%} +{{ children }} diff --git a/core/themes/classy/templates/media-library/links--media-library-menu.html.twig b/core/themes/classy/templates/media-library/links--media-library-menu.html.twig new file mode 100644 index 00000000000..dfc80f50f0c --- /dev/null +++ b/core/themes/classy/templates/media-library/links--media-library-menu.html.twig @@ -0,0 +1,36 @@ +{% extends "links.html.twig" %} +{# +/** + * @file + * Theme implementation of the media type menu in the media library dialog. + * + * Available variables: + * - attributes: Attributes for the UL containing the list of links. + * - links: Links to be output. + * Each link will have the following elements: + * - title: The link text. + * - href: The link URL. If omitted, the 'title' is shown as a plain text + * item in the links list. If 'href' is supplied, the entire link is passed + * to l() as its $options parameter. + * - attributes: (optional) HTML attributes for the anchor, or for the + * tag if no 'href' is supplied. + * - heading: (optional) A heading to precede the links. + * - text: The heading text. + * - level: The heading level (e.g. 'h2', 'h3'). + * - attributes: (optional) A keyed list of attributes for the heading. + * If the heading is a string, it will be used as the text of the heading and + * the level will default to 'h2'. + * + * Headings should be used on navigation menus and any list of links that + * consistently appears on multiple pages. To make the heading invisible use + * the 'visually-hidden' CSS class. Do not use 'display:none', which + * removes it from screen readers and assistive technology. Headings allow + * screen reader and keyboard only users to navigate to or skip the links. + * See http://juicystudio.com/article/screen-readers-display-none.php and + * http://www.w3.org/TR/WCAG-TECHS/H42.html for more information. + * + * @see classy_preprocess_links__media_library_menu() + * @see template_preprocess_links() + */ +#} +{% set attributes = attributes.addClass('media-library-menu') %} diff --git a/core/themes/classy/templates/media-library/media--media-library.html.twig b/core/themes/classy/templates/media-library/media--media-library.html.twig new file mode 100644 index 00000000000..e88635424fc --- /dev/null +++ b/core/themes/classy/templates/media-library/media--media-library.html.twig @@ -0,0 +1,55 @@ +{# +/** + * @file + * Theme override of a media item in the media library. + * + * This is used for media that the user can select from the grid of media + * items. It is not used for items that have already been selected in the + * corresponding field widget, or for items that have been previously selected + * before adding new media to the library. + * + * Available variables: + * - media: The entity with limited access to object properties and methods. + * Only method names starting with "get", "has", or "is" and a few common + * methods such as "id", "label", and "bundle" are available. For example: + * - entity.getEntityTypeId() will return the entity type ID. + * - entity.hasField('field_example') returns TRUE if the entity includes + * field_example. (This does not indicate the presence of a value in this + * field.) + * Calling other methods, such as entity.delete(), will result in an exception. + * See \Drupal\Core\Entity\EntityInterface for a full list of methods. + * - name: Name of the media. + * - content: Media content. + * - title_prefix: Additional output populated by modules, intended to be + * displayed in front of the main title tag that appears in the template. + * - title_suffix: Additional output populated by modules, intended to be + * displayed after the main title tag that appears in the template. + * - view_mode: View mode; for example, "teaser" or "full". + * - attributes: HTML attributes for the containing element. + * - title_attributes: Same as attributes, except applied to the main title + * tag that appears in the template. + * - url: Direct URL of the media. + * - preview_attributes: HTML attributes for the preview wrapper. + * - metadata_attributes: HTML attributes for the expandable metadata area. + * - status: Whether or not the Media is published. + * + * @see template_preprocess_media() + * + * @ingroup themeable + */ +#} + + {% if content %} + + {{ content|without('name') }} + + {% if not status %} +
{{ "unpublished" | t }}
+ {% endif %} + +
+ {{ name }} +
+ + {% endif %} + diff --git a/core/themes/classy/templates/media-library/media-library-item--small.html.twig b/core/themes/classy/templates/media-library/media-library-item--small.html.twig new file mode 100644 index 00000000000..ba03858b7f8 --- /dev/null +++ b/core/themes/classy/templates/media-library/media-library-item--small.html.twig @@ -0,0 +1,31 @@ +{# +/** + * @file + * Default theme implementation of a media library item. + * + * This is used when displaying selected media items, either in the field + * widget or in the "Additional selected media" area when adding new + * media items in the media library modal dialog. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - content: The content of the media library item, plus any additional + * fields or elements surrounding it. + * + * @see seven_preprocess_media_library_item__small() + * @see seven_preprocess_media_library_item__widget() + * @see template_preprocess_media_library_item() + * + * @ingroup themeable + */ +#} +{% + set classes = [ + 'media-library-item', + 'media-library-item--grid', + 'media-library-item--small', + ] +%} + + {{ content }} + diff --git a/core/themes/classy/templates/media-library/media-library-item.html.twig b/core/themes/classy/templates/media-library/media-library-item.html.twig new file mode 100644 index 00000000000..297780e0f73 --- /dev/null +++ b/core/themes/classy/templates/media-library/media-library-item.html.twig @@ -0,0 +1,28 @@ +{# +/** + * @file + * Default theme implementation of a media library item. + * + * This is used when displaying selected media items, either in the field + * widget or in the "Additional selected media" area when adding new + * media items in the media library modal dialog. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - content: The content of the media library item, plus any additional + * fields or elements surrounding it. + * + * @see template_preprocess_media_library_item() + * + * @ingroup themeable + */ +#} +{% + set classes = [ + 'media-library-item', + 'media-library-item--grid', + ] +%} + + {{ content }} + diff --git a/core/themes/classy/templates/media-library/media-library-wrapper.html.twig b/core/themes/classy/templates/media-library/media-library-wrapper.html.twig new file mode 100644 index 00000000000..850f63aa174 --- /dev/null +++ b/core/themes/classy/templates/media-library/media-library-wrapper.html.twig @@ -0,0 +1,21 @@ +{# +/** + * @file + * Theme override of a container used to wrap the media library's modal dialog + * interface. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - menu: The menu of availble media types to choose from. + * - content: The form to add new media items, followed by the grid or table of + * existing media items to choose from. + * + * @see template_preprocess_media_library_wrapper() + * + * @ingroup themeable + */ +#} + + {{ menu }} + {{ content }} + diff --git a/core/themes/classy/templates/media-library/views-view-unformatted--media-library.html.twig b/core/themes/classy/templates/media-library/views-view-unformatted--media-library.html.twig new file mode 100644 index 00000000000..a94d4e2b636 --- /dev/null +++ b/core/themes/classy/templates/media-library/views-view-unformatted--media-library.html.twig @@ -0,0 +1,35 @@ +{# +/** + * @file + * Theme override of the media library view. + * + * This is used to display a grid of media items, in both the administrative + * interface and in the modal media library dialog's grid layout. + * + * Available variables: + * - title: The title of this group of rows. May be empty. + * - rows: A list of the view's row items. + * - attributes: The row's HTML attributes. + * - content: The row's content. + * - view: The view object. + * - default_row_class: A flag indicating whether default classes should be + * used on rows. + * + * @see template_preprocess_views_view_unformatted() + */ +#} +{% if title %} +

{{ title }}

+{% endif %} +{% for row in rows %} + {% + set row_classes = [ + default_row_class ? 'views-row', + 'media-library-item', + 'media-library-item--grid', + ] + %} + + {{- row.content -}} + +{% endfor %} diff --git a/core/modules/media_library/css/media_library.theme.css b/core/themes/seven/css/theme/media-library.css similarity index 83% rename from core/modules/media_library/css/media_library.theme.css rename to core/themes/seven/css/theme/media-library.css index 0b698ffee3f..8c75fda49ff 100644 --- a/core/modules/media_library/css/media_library.theme.css +++ b/core/themes/seven/css/theme/media-library.css @@ -1,11 +1,11 @@ /** - * @file media_library.theme.css - * - * @todo Move into the Seven theme when this module is marked as stable. - * @see https://www.drupal.org/project/drupal/issues/2980769 + * @file media-library.css + + * Styling for Media Library. */ .media-library-wrapper { + display: flex; margin: -1em; } @@ -33,6 +33,8 @@ */ .media-library-menu li { display: block; + padding: 0; + list-style: none; } .media-library-menu__link { @@ -91,12 +93,14 @@ } /** - * Remove outline from added media container. + * Remove outline from added media list. * - * The added media container receives focus after adding new media, but since - * it is not an interactive element it does not need an outline. + * The added media list receives focus after adding new media, but since it is + * not an interactive element, it does not need an outline. */ .media-library-add-form__added-media { + margin: 0; + padding: 0; outline: none; } @@ -116,10 +120,6 @@ margin: 8px 0 0; } -.media-library-add-form__description { - margin: 0; -} - /* Style the media add oEmbed form. */ .media-library-add-form--oembed .media-library-add-form__input-wrapper { display: flex; @@ -163,21 +163,56 @@ /* Generic media library view styles. */ .media-library-select-all { - margin: 10px 0 10px 0; + flex-basis: 100%; + width: 100%; + margin: 10px 8px; } - .media-library-select-all input { margin-right: 10px; } +[dir="rtl"] .media-library-select-all input { + margin-left: 10px; +} + +.media-library-views-form, +.media-library-selection, +.media-library-add-form__selected-media .details-wrapper, +.media-library-views-form__bulk_form, +.media-library-view .form--inline { + display: flex; + flex-wrap: wrap; +} + +.media-library-views-form > .form-actions { + flex-basis: 100%; +} + +.media-library-views-form__header { + flex-basis: 100%; +} .media-library-views-form__header .form-item { margin-right: 8px; } +.media-library-views-form__rows { + display: flex; + flex-wrap: wrap; + flex-basis: 100%; + margin: 0 -8px; +} + .media-library-view .form-actions { + align-self: flex-end; margin: 0.75em 0; } +@media screen and (max-width: 600px) { + .media-library-view .form-actions { + flex-basis: 100%; + } +} + .media-library-view .media-library-view--form-actions { clear: left; align-self: flex-end; @@ -203,13 +238,8 @@ justify-content: space-between; } -/** - * @todo Remove order and reorder the views header and filters via a views - * template in https://www.drupal.org/project/drupal/issues/3035994 - */ .media-library-wrapper .view-header { align-self: flex-end; - order: 2; margin: 1em 0; text-align: right; /* LTR */ } @@ -217,29 +247,8 @@ text-align: left; } -/** - * @todo Remove order and reorder the views header and filters via a views - * template in https://www.drupal.org/project/drupal/issues/3035994 - */ -.media-library-wrapper .media-library-view .view-filters { - order: 1; -} - -/** - * @todo Remove order and reorder the views header and filters via a views - * template in https://www.drupal.org/project/drupal/issues/3035994 - */ .media-library-wrapper .media-library-view .view-content { flex: 0 0 100%; - order: 3; -} - -/** - * @todo Remove order and reorder the views header and filters via a views - * template in https://www.drupal.org/project/drupal/issues/3035994 - */ -.media-library-wrapper .media-library-view .pager { - order: 4; } .media-library-wrapper .views-display-link { @@ -260,46 +269,31 @@ .media-library-wrapper .views-display-link-widget { margin-right: 15px; - background: url(../../../misc/icons/333333/grid.svg) left 0 no-repeat; /* LTR */ + background: url(../../../../misc/icons/333333/grid.svg) left 0 no-repeat; /* LTR */ } [dir="rtl"] .media-library-wrapper .views-display-link-widget { background-position: right 0; } .media-library-wrapper .views-display-link-widget_table { - background: url(../../../misc/icons/333333/table.svg) left 0 no-repeat; /* LTR */ + background: url(../../../../misc/icons/333333/table.svg) left 0 no-repeat; /* LTR */ } [dir="rtl"] .media-library-wrapper .views-display-link-widget_table { background-position: right 0; } -/* Media library item grid styles. */ -.media-library-views-form { - margin: 0 -8px; -} - -/** - * Fix the negative margin of the grid. - * - * We need to fix the negative margin of the grid for table based displays and - * form elements that should not be part of the grid. - * - * @todo: Remove when new wrapper is added to apply negative margins in - * https://www.drupal.org/project/drupal/issues/3038489 - */ -.media-library-views-form__header, -.media-library-select-all, -.media-library-views-form > .views-table { - margin: 0 8px; -} - /** * Style the media library grid items. - * - * The media library item container receives screen reader focus when items are - * removed. Since it is not an interactive element, it does not need an - * outline. */ +.media-library-item { + position: relative; +} + +/** +* The media library item container receives screen reader focus when items are +* removed. Since it is not an interactive element, it does not need an +* outline. +*/ .media-library-item--grid { justify-content: center; box-sizing: border-box; @@ -332,6 +326,23 @@ width: 33.3%; } +.media-library-widget-modal .ui-dialog-buttonpane { + display: flex; + align-items: center; +} + +.media-library-widget-modal .ui-dialog-buttonpane .form-actions { + flex: 1; +} + +/** + * By default, the dialog is too narrow to be usable. + * @see Drupal.ckeditor.openDialog() + */ +.ui-dialog--narrow.media-library-widget-modal { + max-width: 75%; +} + @media screen and (min-width: 45em) { .media-library-item--grid { width: 33.3%; @@ -409,6 +420,18 @@ border-color: #0076c0; } +.media-library-item__click-to-select-checkbox { + position: absolute; + z-index: 1; + top: 16px; + left: 16px; /* LTR */ + display: block; +} +[dir="rtl"] .media-library-item__click-to-select-checkbox { + right: 16px; + left: auto; +} + .media-library-item__click-to-select-checkbox input { width: 20px; height: 20px; @@ -418,6 +441,12 @@ margin: 0; } +.media-library-item__click-to-select-trigger { + overflow: hidden; + height: 100%; + cursor: pointer; +} + /* Media library item table styles. */ .media-library-item--table img { max-width: 100px; @@ -427,15 +456,24 @@ /* Media library entity view display styles. */ .media-library-item__preview { padding-bottom: 34px; + cursor: move; } .media-library-item__status { + position: absolute; + top: 40px; + left: 5px; /* LTR */ padding: 5px 10px; + pointer-events: none; color: #e4e4e4; background: #666; font-size: 12px; font-style: italic; } +[dir="rtl"] .media-library-item__status { + right: 5px; + left: auto; +} .media-library-item__attributes { position: absolute; @@ -472,6 +510,7 @@ } .media-library-item--disabled { + pointer-events: none; opacity: 0.5; } @@ -560,7 +599,7 @@ } .media-library-item__edit { - background: url("../../../misc/icons/787878/pencil.svg") #fff center no-repeat; + background: url("../../../../misc/icons/787878/pencil.svg") #fff center no-repeat; background-size: 13px; } .media-library-item__remove, @@ -570,7 +609,7 @@ .media-library-item__remove.button:disabled:active, .media-library-item__remove.button:hover, .media-library-item__remove.button:focus { - background: url("../../../misc/icons/787878/ex.svg") #fff center no-repeat; + background: url("../../../../misc/icons/787878/ex.svg") #fff center no-repeat; background-size: 13px; } .media-library-item__edit:hover, @@ -656,7 +695,7 @@ color: transparent; border: 0; border-radius: 0; - background: transparent url(../../../misc/icons/787878/ex.svg) right 2px no-repeat; /* LTR */ + background: transparent url(../../../../misc/icons/787878/ex.svg) right 2px no-repeat; /* LTR */ font-weight: normal; line-height: 16px; } @@ -673,7 +712,7 @@ .media-library-add-form__remove-button.button:focus { color: #787878; border: 0; - background: transparent url(../../../misc/icons/787878/ex.svg) right 2px no-repeat; /* LTR */ + background: transparent url(../../../../misc/icons/787878/ex.svg) right 2px no-repeat; /* LTR */ } [dir="rtl"] .media-library-add-form__remove-button:focus, [dir="rtl"] .media-library-add-form__remove-button.button:disabled, @@ -686,10 +725,15 @@ .media-library-add-form__remove-button.button:hover { color: #e00; border: 0; - background: transparent url(../../../misc/icons/ee0000/ex.svg) right 2px no-repeat; /* LTR */ + background: transparent url(../../../../misc/icons/ee0000/ex.svg) right 2px no-repeat; /* LTR */ box-shadow: none; } [dir="rtl"] .media-library-add-form__remove-button:hover, [dir="rtl"] .media-library-add-form__remove-button.button:hover { background-position: left 2px; } + +/* @todo Remove in https://www.drupal.org/project/drupal/issues/3064914 */ +.views-live-preview .media-library-view div.views-row + div.views-row { + margin-top: 0; +} diff --git a/core/themes/seven/seven.info.yml b/core/themes/seven/seven.info.yml index f00d3959148..5f5763d03f0 100644 --- a/core/themes/seven/seven.info.yml +++ b/core/themes/seven/seven.info.yml @@ -46,6 +46,10 @@ libraries-override: css: component: css/components/details.css: false + classy/media_library: + css: + layout: + css/layout/media-library.css: false libraries-extend: core/ckeditor: @@ -54,6 +58,10 @@ libraries-extend: - seven/vertical-tabs core/jquery.ui: - seven/seven.jquery.ui + media_library/view: + - seven/media_library + media_library/widget: + - seven/media_library tour/tour-styling: - seven/tour-styling quickedit_stylesheets: diff --git a/core/themes/seven/seven.libraries.yml b/core/themes/seven/seven.libraries.yml index 645f4d3439d..c08424f6484 100644 --- a/core/themes/seven/seven.libraries.yml +++ b/core/themes/seven/seven.libraries.yml @@ -132,6 +132,12 @@ media-form: dependencies: - media/form +media_library: + version: VERSION + css: + theme: + css/theme/media-library.css: {} + layout_builder_content_translation_admin: version: VERSION css: diff --git a/core/themes/seven/seven.theme b/core/themes/seven/seven.theme index 078d2adc806..7908b0bddf7 100644 --- a/core/themes/seven/seven.theme +++ b/core/themes/seven/seven.theme @@ -8,6 +8,8 @@ use Drupal\Core\Url; use Drupal\Core\Form\FormStateInterface; use Drupal\media\MediaForm; +use Drupal\views\Form\ViewsForm; +use Drupal\views\ViewExecutable; /** * Implements hook_preprocess_HOOK() for HTML document templates. @@ -186,3 +188,189 @@ function seven_form_media_form_alter(&$form, FormStateInterface $form_state) { function seven_form_language_content_settings_form_alter(array &$form, FormStateInterface $form_state) { $form['#attached']['library'][] = 'seven/layout_builder_content_translation_admin'; } + +/** + * Implements hook_preprocess_views_view_fields(). + * + * This targets each rendered media item in the grid display of the media + * library's modal dialog. + */ +function seven_preprocess_views_view_fields__media_library(array &$variables) { + // Add classes to media rendered entity field so it can be targeted for + // styling. Adding this class in a template is very difficult to do. + if (isset($variables['fields']['rendered_entity']->wrapper_attributes)) { + $variables['fields']['rendered_entity']->wrapper_attributes->addClass('media-library-item__click-to-select-trigger'); + } +} + +/** + * Implements hook_form_alter(). + */ +function seven_form_alter(array &$form, FormStateInterface $form_state, $form_id) { + $form_object = $form_state->getFormObject(); + if ($form_object instanceof ViewsForm && strpos($form_object->getBaseFormId(), 'views_form_media_library') === 0) { + if (isset($form['header'])) { + $form['header']['#attributes']['class'][] = 'media-library-views-form__header'; + $form['header']['media_bulk_form']['#attributes']['class'][] = 'media-library-views-form__bulk_form'; + } + $form['actions']['submit']['#attributes']['class'] = ['media-library-select']; + } + // Add after build to add a CSS class to the form actions. + if ($form_id === 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-media-library-widget') === 0) { + $form['actions']['#attributes']['class'][] = 'media-library-view--form-actions'; + } +} + +/** + * Implements hook_form_BASE_FORM_ID_alter(). + */ +function seven_form_media_library_add_form_alter(array &$form, FormStateInterface $form_state) { + $form['#attributes']['class'][] = 'media-library-add-form'; + $form['#attached']['library'][] = 'seven/media_library'; + + // If there are unsaved media items, apply styling classes to various parts + // of the form. + if (isset($form['media'])) { + $form['#attributes']['class'][] = 'media-library-add-form--with-input'; + + // Put a wrapper around the informational message above the unsaved media + // items. + $form['description']['#template'] = '

{{ text }}

'; + } + else { + $form['#attributes']['class'][] = 'media-library-add-form--without-input'; + } +} + +/** + * Implements hook_form_FORM_ID_alter(). + */ +function seven_form_media_library_add_form_upload_alter(array &$form, FormStateInterface $form_state) { + $form['attributes']['class'][] = 'media-library-add-form--upload'; + + if (isset($form['container'])) { + $form['container']['#attributes']['class'][] = 'media-library-add-form__input-wrapper'; + } +} + +/** + * Implements hook_form_FORM_ID_alter(). + */ +function seven_form_media_library_add_form_oembed_alter(array &$form, FormStateInterface $form_state) { + $form['attributes']['class'][] = 'media-library-add-form--oembed'; + + // If no media items have been added yet, add a couple of styling classes + // to the initial URL form. + if (isset($form['container'])) { + $form['container']['#attributes']['class'][] = 'media-library-add-form__input-wrapper'; + $form['container']['url']['#attributes']['class'][] = 'media-library-add-form-oembed-url'; + $form['container']['submit']['#attributes']['class'][] = 'media-library-add-form-oembed-submit'; + } +} + +/** + * Implements hook_preprocess_item_list__media_library_add_form_media_list(). + * + * This targets each new, unsaved media item added to the media library, before + * they are saved. + */ +function seven_preprocess_item_list__media_library_add_form_media_list(array &$variables) { + foreach ($variables['items'] as &$item) { + $item['value']['preview']['#attributes']['class'][] = 'media-library-add-form__preview'; + $item['value']['fields']['#attributes']['class'][] = 'media-library-add-form__fields'; + $item['value']['remove_button']['#attributes']['class'][] = 'media-library-add-form__remove-button'; + + // #source_field_name is set by AddFormBase::buildEntityFormElement() + // to help themes and form_alter hooks identify the source field. + $fields = &$item['value']['fields']; + $source_field_name = $fields['#source_field_name']; + if (isset($fields[$source_field_name])) { + $fields[$source_field_name]['#attributes']['class'][] = 'media-library-add-form__source-field'; + } + } +} + +/** + * Implements hook_preprocess_media_library_item__widget(). + * + * This targets each media item selected in an entity reference field. + */ +function seven_preprocess_media_library_item__widget(array &$variables) { + $variables['content']['remove_button']['#attributes']['class'][] = 'media-library-item__remove'; +} + +/** + * Implements hook_preprocess_media_library_item__small(). + * + * This targets each pre-selected media item selected when adding new media in + * the modal media library dialog. + */ +function seven_preprocess_media_library_item__small(array &$variables) { + $variables['content']['select']['#attributes']['class'][] = 'media-library-item__click-to-select-checkbox'; +} + +/** + * @todo Remove this when https://www.drupal.org/project/drupal/issues/2999549 + * lands. + * + * @see \Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget::formElement() + */ +function seven_preprocess_fieldset__media_library_widget(array &$variables) { + if (isset($variables['prefix']['weight_toggle'])) { + $variables['prefix']['weight_toggle']['#attributes']['class'][] = 'media-library-widget__toggle-weight'; + } + if (isset($variables['suffix']['open_button'])) { + $variables['suffix']['open_button']['#attributes']['class'][] = 'media-library-open-button'; + } +} + +/** + * Implements hook_views_pre_render(). + */ +function seven_views_pre_render(ViewExecutable $view) { + $add_classes = function (&$option, array $classes_to_add) { + $classes = preg_split('/\s+/', $option); + $classes = array_filter($classes); + $classes = array_merge($classes, $classes_to_add); + $option = implode(' ', array_unique($classes)); + }; + + if ($view->id() === 'media_library') { + if ($view->display_handler->options['defaults']['css_class']) { + $add_classes($view->displayHandlers->get('default')->options['css_class'], ['media-library-view']); + } + else { + $add_classes($view->display_handler->options['css_class'], ['media-library-view']); + } + + if ($view->current_display === 'page') { + if (array_key_exists('media_bulk_form', $view->field)) { + $add_classes($view->field['media_bulk_form']->options['element_class'], ['media-library-item__click-to-select-checkbox']); + } + if (array_key_exists('rendered_entity', $view->field)) { + $add_classes($view->field['rendered_entity']->options['element_class'], ['media-library-item__content']); + } + if (array_key_exists('edit_media', $view->field)) { + $add_classes($view->field['edit_media']->options['alter']['link_class'], ['media-library-item__edit']); + } + if (array_key_exists('delete_media', $view->field)) { + $add_classes($view->field['delete_media']->options['alter']['link_class'], ['media-library-item__remove']); + } + } + elseif (strpos($view->current_display, 'widget') === 0) { + if (array_key_exists('rendered_entity', $view->field)) { + $add_classes($view->field['rendered_entity']->options['element_class'], ['media-library-item__content']); + } + if (array_key_exists('media_library_select_form', $view->field)) { + $add_classes($view->field['media_library_select_form']->options['element_wrapper_class'], ['media-library-item__click-to-select-checkbox']); + } + + if ($view->display_handler->options['defaults']['css_class']) { + $add_classes($view->displayHandlers->get('default')->options['css_class'], ['media-library-view--widget']); + } + else { + $add_classes($view->display_handler->options['css_class'], ['media-library-view--widget']); + } + } + } +} diff --git a/core/themes/seven/templates/media-library/details--media-library-add-form-selected-media.html.twig b/core/themes/seven/templates/media-library/details--media-library-add-form-selected-media.html.twig new file mode 100644 index 00000000000..6d62c3fced7 --- /dev/null +++ b/core/themes/seven/templates/media-library/details--media-library-add-form-selected-media.html.twig @@ -0,0 +1,20 @@ +{% extends "details.html.twig" %} +{# +/** + * @file + * Theme override for the "Additional selected media" area of the modal media + * library dialog. + * + * Available variables + * - attributes: A list of HTML attributes for the details element. + * - errors: (optional) Any errors for this details element, may not be set. + * - title: (optional) The title of the element, may not be set. + * - summary_attributes: A list of HTML attributes for the summary element. + * - description: (optional) The description of the element, may not be set. + * - children: (optional) The children of the element, may not be set. + * - value: (optional) The value of the element, may not be set. + * + * @see template_preprocess_details() + */ +#} +{% set attributes = attributes.addClass('media-library-add-form__selected-media seven-details') %} diff --git a/core/themes/seven/templates/media-library/fieldset--media-library-widget.html.twig b/core/themes/seven/templates/media-library/fieldset--media-library-widget.html.twig new file mode 100644 index 00000000000..cd7044c9696 --- /dev/null +++ b/core/themes/seven/templates/media-library/fieldset--media-library-widget.html.twig @@ -0,0 +1,64 @@ +{# +/** + * @file + * Theme override for the media library widget. + * + * Available variables: + * - attributes: HTML attributes for the fieldset element. + * - errors: (optional) Any errors for this fieldset element, may not be set. + * - required: Boolean indicating whether the fieldeset element is required. + * - legend: The legend element containing the following properties: + * - title: Title of the fieldset, intended for use as the text of the legend. + * - attributes: HTML attributes to apply to the legend. + * - description: The description element containing the following properties: + * - content: The description content of the fieldset. + * - attributes: HTML attributes to apply to the description container. + * - children: The rendered child elements of the fieldset. + * - prefix: The content to add before the fieldset children. + * - suffix: The content to add after the fieldset children. + * + * @see seven_preprocess_fieldset__media_library_widget() + * @see template_preprocess_fieldset() + */ +#} +{% + set classes = [ + 'js-form-item', + 'form-item', + 'js-form-wrapper', + 'form-wrapper', + 'media-library-widget', + ] +%} + + {% + set legend_span_classes = [ + 'fieldset-legend', + required ? 'js-form-required', + required ? 'form-required', + ] + %} + {# Always wrap fieldset legends in a for CSS positioning. #} + + {{ legend.title }} + +
+ {% if errors %} +
+ {{ errors }} +
+ {% endif %} + {% if prefix.empty_selection %} +

{{ prefix.empty_selection }}

+ {% elseif prefix.weight_toggle %} + {{ prefix.weight_toggle }} + {% endif %} + {{ children }} + {% if suffix %} + {{ suffix }} + {% endif %} + {% if description.content %} + {{ description.content }}
+ {% endif %} + + diff --git a/core/themes/seven/templates/media-library/item-list--media-library-add-form-media-list.html.twig b/core/themes/seven/templates/media-library/item-list--media-library-add-form-media-list.html.twig new file mode 100644 index 00000000000..27cfe2bd26a --- /dev/null +++ b/core/themes/seven/templates/media-library/item-list--media-library-add-form-media-list.html.twig @@ -0,0 +1,33 @@ +{# +/** + * @file + * Theme override for a list of new, unsaved media items being added in the + * modal media library dialog. + * + * Available variables: + * - items: A list of items. Each item contains: + * - attributes: HTML attributes to be applied to each list item. + * - value: The content of the list element. + * - title: The title of the list. + * - list_type: The tag for list element ("ul" or "ol"). + * - wrapper_attributes: HTML attributes to be applied to the list wrapper. + * - attributes: HTML attributes to be applied to the list. + * - empty: A message to display when there are no items. Allowed value is a + * string or render array. + * - context: A list of contextual data associated with the list. May contain: + * - list_style: The custom list style. + * + * @see seven_preprocess_item_list__media_library_add_form_media_list() + * @see template_preprocess_item_list() + */ +#} +{% if items -%} + {%- if title is not empty -%} +

{{ title }}

+ {%- endif -%} + <{{ list_type }}{{ attributes.addClass('media-library-add-form__added-media') }}> + {%- for item in items -%} + {{ item.value }} + {%- endfor -%} + +{%- endif %} diff --git a/core/themes/seven/templates/media-library/views-view--media_library.html.twig b/core/themes/seven/templates/media-library/views-view--media_library.html.twig new file mode 100644 index 00000000000..b3fde507eb0 --- /dev/null +++ b/core/themes/seven/templates/media-library/views-view--media_library.html.twig @@ -0,0 +1,95 @@ +{# +/** + * @file + * Theme override for the media_library view template. + * + * Available variables: + * - attributes: Remaining HTML attributes for the element. + * - css_name: A css-safe version of the view name. + * - css_class: The user-specified classes names, if any. + * - header: The optional header. + * - footer: The optional footer. + * - rows: The results of the view query, if any. + * - empty: The content to display if there are no rows. + * - pager: The optional pager next/prev links to display. + * - exposed: Exposed widget form/info to display. + * - feed_icons: Optional feed icons to display. + * - more: An optional link to the next page of results. + * - title: Title of the view, only used when displaying in the admin preview. + * - title_prefix: Additional output populated by modules, intended to be + * displayed in front of the view title. + * - title_suffix: Additional output populated by modules, intended to be + * displayed after the view title. + * - attachment_before: An optional attachment view to be displayed before the + * view content. + * - attachment_after: An optional attachment view to be displayed after the + * view content. + * - dom_id: Unique id for every view being printed to give unique class for + * Javascript. + * + * @see template_preprocess_views_view() + */ +#} +{% + set classes = [ + 'view', + 'view-' ~ id|clean_class, + 'view-id-' ~ id, + 'view-display-id-' ~ display_id, + dom_id ? 'js-view-dom-id-' ~ dom_id, + ] +%} + + {{ title_prefix }} + {% if title %} + {{ title }} + {% endif %} + {{ title_suffix }} + {% if exposed %} +
+ {{ exposed }} +
+ {% endif %} + {% if header %} +
+ {{ header }} +
+ {% endif %} + {% if attachment_before %} +
+ {{ attachment_before }} +
+ {% endif %} + + {% if rows %} +
+ {{ rows }} +
+ {% elseif empty %} +
+ {{ empty }} +
+ {% endif %} + + {% if pager %} + {{ pager }} + {% endif %} + {% if attachment_after %} +
+ {{ attachment_after }} +
+ {% endif %} + {% if more %} + {{ more }} + {% endif %} + {% if footer %} + + {% endif %} + {% if feed_icons %} +
+ {{ feed_icons }} +
+ {% endif %} + diff --git a/core/themes/seven/templates/media-library/views-view-unformatted--media-library.html.twig b/core/themes/seven/templates/media-library/views-view-unformatted--media-library.html.twig new file mode 100644 index 00000000000..4bc33e0e869 --- /dev/null +++ b/core/themes/seven/templates/media-library/views-view-unformatted--media-library.html.twig @@ -0,0 +1,34 @@ +{# +/** + * @file + * Theme override for the media_library display of unformatted rows. + * + * Available variables: + * - title: The title of this group of rows. May be empty. + * - rows: A list of the view's row items. + * - attributes: The row's HTML attributes. + * - content: The row's content. + * - view: The view object. + * - default_row_class: A flag indicating whether default classes should be + * used on rows. + * + * @see template_preprocess_views_view_unformatted() + */ +#} +{% if title %} +

{{ title }}

+{% endif %} +
+ {% for row in rows %} + {% + set row_classes = [ + default_row_class ? 'views-row', + 'media-library-item', + 'media-library-item--grid', + ] + %} + + {{- row.content -}} +
+ {% endfor %} + diff --git a/core/themes/stable/templates/media-library/media--media-library.html.twig b/core/themes/stable/templates/media-library/media--media-library.html.twig new file mode 100644 index 00000000000..6262e7d5062 --- /dev/null +++ b/core/themes/stable/templates/media-library/media--media-library.html.twig @@ -0,0 +1,49 @@ +{# +/** + * @file + * Default theme implementation to present a media entity in the media library. + * + * Available variables: + * - media: The entity with limited access to object properties and methods. + * Only method names starting with "get", "has", or "is" and a few common + * methods such as "id", "label", and "bundle" are available. For example: + * - entity.getEntityTypeId() will return the entity type ID. + * - entity.hasField('field_example') returns TRUE if the entity includes + * field_example. (This does not indicate the presence of a value in this + * field.) + * Calling other methods, such as entity.delete(), will result in an exception. + * See \Drupal\Core\Entity\EntityInterface for a full list of methods. + * - name: Name of the media. + * - content: Media content. + * - title_prefix: Additional output populated by modules, intended to be + * displayed in front of the main title tag that appears in the template. + * - title_suffix: Additional output populated by modules, intended to be + * displayed after the main title tag that appears in the template. + * - view_mode: View mode; for example, "teaser" or "full". + * - attributes: HTML attributes for the containing element. + * - title_attributes: Same as attributes, except applied to the main title + * tag that appears in the template. + * - url: Direct URL of the media. + * - preview_attributes: HTML attributes for the preview wrapper. + * - metadata_attributes: HTML attributes for the expandable metadata area. + * - status: Whether or not the Media is published. + * + * @see template_preprocess_media() + * @see media_library_preprocess_media() + * + * @ingroup themeable + */ +#} + + {% if content %} + + {{ content|without('name') }} + + {% if not status %} + {{ "unpublished" | t }} + {% endif %} + + {{ name }} + + {% endif %} + diff --git a/core/themes/stable/templates/media-library/media-library-item.html.twig b/core/themes/stable/templates/media-library/media-library-item.html.twig new file mode 100644 index 00000000000..a765d04c11b --- /dev/null +++ b/core/themes/stable/templates/media-library/media-library-item.html.twig @@ -0,0 +1,22 @@ +{# +/** + * @file + * Default theme implementation of a media library item. + * + * This is used when displaying selected media items, either in the field + * widget or in the "Additional selected media" area when adding new + * media items in the media library modal dialog. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - content: The content of the media library item, plus any additional + * fields or elements surrounding it. + * + * @see template_preprocess_media_library_item() + * + * @ingroup themeable + */ +#} + + {{ content }} + diff --git a/core/themes/stable/templates/media-library/media-library-wrapper.html.twig b/core/themes/stable/templates/media-library/media-library-wrapper.html.twig new file mode 100644 index 00000000000..344637cd62c --- /dev/null +++ b/core/themes/stable/templates/media-library/media-library-wrapper.html.twig @@ -0,0 +1,21 @@ +{# +/** + * @file + * Default theme implementation of a container used to wrap the media library's + * modal dialog interface. + * + * Available variables: + * - attributes: HTML attributes for the containing element. + * - menu: The menu of availble media types to choose from. + * - content: The form to add new media items, followed by the grid or table of + * existing media items to choose from. + * + * @see template_preprocess_media_library_wrapper() + * + * @ingroup themeable + */ +#} + + {{ menu }} + {{ content }} +