diff --git a/core/modules/media_library/config/install/core.entity_view_mode.media.media_library.yml b/core/modules/media_library/config/install/core.entity_view_mode.media.media_library.yml new file mode 100644 index 0000000..8c9ddd3 --- /dev/null +++ b/core/modules/media_library/config/install/core.entity_view_mode.media.media_library.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: + module: + - media +id: media.media_library +label: 'Media Library' +targetEntityType: media +cache: true 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 new file mode 100644 index 0000000..04a91a1 --- /dev/null +++ b/core/modules/media_library/config/install/views.view.media_library.yml @@ -0,0 +1,647 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.media.media_library + module: + - media + - media_library + - system + - user +id: media_library +label: Media +module: views +description: '' +tag: '' +base_table: media_field_data +base_field: mid +core: 8.x +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'view media' + cache: + type: tag + options: { } + query: + type: views_query + options: + disable_sql_rewrite: false + distinct: false + replica: false + query_comment: '' + query_tags: { } + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: false + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: mini + options: + items_per_page: 25 + offset: 0 + id: 0 + total_pages: null + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + tags: + previous: ‹‹ + next: ›› + style: + type: default + options: + grouping: { } + row_class: media-library-item + default_row_class: true + row: + type: fields + options: + default_field_elements: true + inline: { } + separator: '' + hide_empty: false + fields: + media_bulk_form: + id: media_bulk_form + table: media + field: media_bulk_form + 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-checkbox + 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 + action_title: Action + include_exclude: exclude + selected_actions: { } + entity_type: media + plugin_id: bulk_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: 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 + filters: + status: + id: status + table: media_field_data + field: status + relationship: none + group_type: group + admin_label: '' + operator: '=' + value: '1' + group: 1 + exposed: true + expose: + operator_id: '' + label: 'Publishing status' + description: null + use_operator: false + operator: status_op + identifier: status + required: true + remember: false + multiple: false + remember_roles: + authenticated: authenticated + is_grouped: true + group_info: + label: Published + description: '' + identifier: status + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: + 1: + title: Published + operator: '=' + value: '1' + 2: + title: Unpublished + operator: '=' + value: '0' + plugin_id: boolean + entity_type: media + entity_field: status + name: + id: name + table: media_field_data + field: name + relationship: none + group_type: group + admin_label: '' + operator: contains + value: '' + group: 1 + exposed: true + expose: + operator_id: name_op + label: Name + description: '' + use_operator: false + operator: name_op + identifier: name + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + administrator: '0' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + entity_type: media + entity_field: name + plugin_id: string + sorts: + created: + id: created + table: media_field_data + field: created + relationship: none + group_type: group + admin_label: '' + order: DESC + exposed: true + expose: + label: 'Newest first' + granularity: second + entity_type: media + entity_field: created + plugin_id: date + title: Media + header: { } + footer: { } + empty: { } + relationships: { } + arguments: + bundle: + id: bundle + table: media_field_data + field: bundle + relationship: none + group_type: group + admin_label: '' + default_action: ignore + exception: + value: all + title_enable: false + title: All + title_enable: false + title: '' + default_argument_type: fixed + default_argument_options: + argument: '' + default_argument_skip_url: false + summary_options: + base_path: '' + count: true + items_per_page: 25 + override: false + summary: + sort_order: asc + number_of_records: 0 + format: default_summary + specify_validation: true + validate: + type: 'entity:media_type' + fail: 'access denied' + validate_options: + access: true + operation: view + multiple: 0 + bundles: { } + glossary: false + limit: 0 + case: none + path_case: none + transform_dash: false + break_phrase: false + entity_type: media + entity_field: bundle + plugin_id: string + display_extenders: { } + use_ajax: true + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_interface' + - url + - url.query_args + - 'url.query_args:sort_by' + - user.permissions + tags: + - 'config:core.entity_view_display.media.type_one.default' + - 'config:core.entity_view_display.media.type_two.default' + bundle_page: + display_plugin: page + id: bundle_page + display_title: 'Bundle Page' + position: 2 + display_options: + display_extenders: { } + path: admin/content/media/%bundle + display_description: '' + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_interface' + - url + - url.query_args + - 'url.query_args:sort_by' + - user.permissions + tags: + - 'config:core.entity_view_display.media.type_one.default' + - 'config:core.entity_view_display.media.type_two.default' + embed: + display_plugin: embed + id: embed + display_title: Embed + position: 4 + display_options: + display_extenders: { } + fields: + media_select_media: + id: media_select_media + table: media + field: media_select_media + 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-checkbox + 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 + entity_type: media + plugin_id: select_media + 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 + defaults: + fields: false + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_interface' + - url + - url.query_args + - 'url.query_args:sort_by' + - user.permissions + tags: + - 'config:core.entity_view_display.media.type_one.default' + - 'config:core.entity_view_display.media.type_two.default' + page: + display_plugin: page + id: page + display_title: Page + position: 1 + display_options: + display_extenders: { } + path: admin/content/media + menu: + type: tab + title: Media + description: 'Allows users to administer Media' + expanded: false + parent: system.admin_content + weight: 5 + context: '0' + menu_name: admin + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_interface' + - url + - url.query_args + - 'url.query_args:sort_by' + - user.permissions + tags: + - 'config:core.entity_view_display.media.type_one.default' + - 'config:core.entity_view_display.media.type_two.default' + widget: + display_plugin: page + id: widget + display_title: Widget + position: 4 + display_options: + display_extenders: { } + fields: + media_select_media: + id: media_select_media + table: media + field: media_select_media + 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-checkbox + 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 + entity_type: media + plugin_id: select_media + 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 + defaults: + fields: false + display_description: '' + path: admin/media_field_widget + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_interface' + - url + - url.query_args + - 'url.query_args:sort_by' + - user.permissions + tags: + - 'config:core.entity_view_display.media.type_one.default' + - 'config:core.entity_view_display.media.type_two.default' diff --git a/core/modules/media_library/css/media_library.css b/core/modules/media_library/css/media_library.css new file mode 100644 index 0000000..82d6826 --- /dev/null +++ b/core/modules/media_library/css/media_library.css @@ -0,0 +1,83 @@ +/** +* @file media_library.view.css +*/ + +.media-library-item { + display: inline-flex; + justify-content: center; + flex-wrap: wrap; + vertical-align: top; + position: relative; + border: 5px solid #ebebeb; + outline: 10px solid transparent; + margin: 20px 20px 0 0; + width: 160px; + height: 160px; + overflow: hidden; + cursor: pointer; + background: #ebebeb; + transition: border-color .2s, outline-color .2s; +} + +.media-library-item.checked { + outline-color: #cfddfd; +} + +.media-library-item::after { + display: block; + width: 25px; + height: 25px; + content: ""; + position: absolute; + top: 0; + right: 0; + background: url('../icons/checkbox.svg'); + background-size: cover; + margin: 5px 5px 0 0; + opacity: 0; + transition: opacity .2s; +} + +.media-library-item:hover { + border-color: #5792fb; +} + +.media-library-item-checkbox { + display: none; +} + +.media-library-item-attributes { + position: absolute; + left: 0; + width: 100%; + bottom: 0; + padding: 5px; + user-select: none; + background: rgba(87, 146, 251, 0.5); + color: black; + opacity: 0; + transition: opacity .2s; +} + +.media-library-item:hover .media-library-item-attributes, +.media-library-item.checked::after, +.media-library-item:hover .media-library-item-remove { + opacity: 1; +} + +.media-library-item-name { + font-size: 16px; +} + +.media-library-item .media-library-item-remove { + position: absolute; + opacity: 0; + margin: 5px; + right: 0; + top: 0; + transition: opacity .2s; +} + +.media-library-open-button { + margin-top: 10px; +} diff --git a/core/modules/media_library/icons/checkbox.svg b/core/modules/media_library/icons/checkbox.svg new file mode 100644 index 0000000..5c17e04 --- /dev/null +++ b/core/modules/media_library/icons/checkbox.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/core/modules/media_library/js/media_library.view.js b/core/modules/media_library/js/media_library.view.js new file mode 100644 index 0000000..bab6ac4 --- /dev/null +++ b/core/modules/media_library/js/media_library.view.js @@ -0,0 +1,118 @@ +/** + * @file media_library.view.js + */ + +(function ($, Drupal) { + + "use strict"; + + // Locally-scoped variable that stores the current View selection. We track + // this in a variable as users may click a media item and then re-load the + // View with AJAX (filters, pagers, sorts, etc.), which will lose what is + // currently selected in the bulk form. This could likely be back-ported to + // core. + var MediaLibrarySelectedEntities = {}; + + /** + * Allows users to click on hidden Views select checkboxes by clicking on the + * media item (which is also a Views row). + */ + Drupal.behaviors.MediaLibraryCheckboxes = { + attach: function (context) { + $('.media-library-item', context).once('media-library-checkbox').on('click', function (event) { + // Links inside the rendered media item should not be click-able. + event.preventDefault(); + // Click the hidden checkbox when the media item is clicked. + var $input = $(this).find('.media-library-item-checkbox input'); + $input.prop('checked', !$input.prop('checked')); + if ($input.prop('checked')) { + $(this).addClass('checked'); + } + else { + $(this).removeClass('checked'); + } + $input.trigger('change'); + }); + } + }; + + /** + * Persists bulk and select form selections across AJAX View re-renders. + */ + Drupal.behaviors.MediaLibraryPersistentSelection = { + attach: function (context) { + // For each View on the page, store the dom-id as a data attribute so + // that we can easily access it later. This is normally only stored in a + // class. + $('[class*="js-view-dom-id-"]', context).once('set-dom-id-data-attribute').each(function () { + var element = $(this); + var classes = $(this).attr('class').split(/\s+/); + $(classes).each(function (i, class_name) { + var dom_id = class_name.match(new RegExp('^js-view-dom-id-(.*)$')); + if (dom_id) { + element.attr('data-views-dom-id', dom_id[1]); + if (!MediaLibrarySelectedEntities[dom_id[1]]) { + MediaLibrarySelectedEntities[dom_id[1]] = []; + } + } + }); + }); + + // Check/uncheck checkboxes in the view based on the selected media. + $('.media-library-item-checkbox input', context).once('data-media-select').each(function (i, element) { + $(this).on('change', function () { + var checked = $(this).prop('checked'); + var views_dom_id = $(this).closest('[data-views-dom-id]').data('views-dom-id'); + var entity = $(this).val(); + if (checked) { + MediaLibrarySelectedEntities[views_dom_id].push(entity); + } + else { + MediaLibrarySelectedEntities[views_dom_id] = $(MediaLibrarySelectedEntities[views_dom_id]).filter(function (i, value) { + return !(entity == value); + }); + } + }); + }); + } + }; + + /** + * Attaches extra POST data when the Views bulk form is submitted, to ensure + * that selections that may be off-screen persist during the submit process. + */ + Drupal.behaviors.MediaLibraryViewsSubmit = { + attach: function (context, settings) { + $('[data-views-dom-id]', context).once('media-library-checkbox-submit').each(function () { + var $view = $(this); + var views_dom_id = $(this).data('views-dom-id'); + $.each(MediaLibrarySelectedEntities[views_dom_id], function(index, items) { + $view.find('input[value="' + items + '"]').prop('checked', true); + $view.find('input[value="' + items + '"]').closest('.media-library-item').addClass('checked'); + }); + + // Propagate all selected entities to the form submission. + $view.find('[data-media-select-submit]').each(function () { + var button = $(this); + $.each(Drupal.ajax.instances, function () { + if (this && $(this.element).is(button)) { + if (settings && settings.views && settings.views.ajaxViews) { + var ajaxViews = settings.views.ajaxViews; + for (var i in ajaxViews) { + var ajaxViewsInstance = Drupal.views.instances[i]; + if (ajaxViewsInstance.settings.view_dom_id == views_dom_id) { + this.submit = $.extend(this.submit, ajaxViewsInstance.settings, { + selected_entities: MediaLibrarySelectedEntities[views_dom_id], + media_library_input: settings.media_library.media_library_inputs[views_dom_id] + }); + } + } + } + } + }); + }); + }); + } + }; + +})(jQuery, Drupal); diff --git a/core/modules/media_library/js/media_library.widget.js b/core/modules/media_library/js/media_library.widget.js new file mode 100644 index 0000000..3914ace --- /dev/null +++ b/core/modules/media_library/js/media_library.widget.js @@ -0,0 +1,18 @@ +/** + * @file media_library.widget.js + */ + +(function ($, Drupal) { + + "use strict"; + + /** + * Provides custom JS behaviors related to the media library field widget. + */ + Drupal.behaviors.MediaLibraryWidget = { + attach: function (context) { + // @todo Enable jQuery sort on the media items to support weight changes. + } + }; + +})(jQuery, Drupal); diff --git a/core/modules/media_library/media_library.info.yml b/core/modules/media_library/media_library.info.yml new file mode 100644 index 0000000..4bb4583 --- /dev/null +++ b/core/modules/media_library/media_library.info.yml @@ -0,0 +1,10 @@ +name: 'Media library' +type: module +description: 'Provides a library for adding and re-using Media Items.' +package: Core (Experimental) +version: VERSION +core: 8.x +dependencies: + - drupal:media + - drupal:views + - drupal:user diff --git a/core/modules/media_library/media_library.libraries.yml b/core/modules/media_library/media_library.libraries.yml new file mode 100644 index 0000000..43c480b --- /dev/null +++ b/core/modules/media_library/media_library.libraries.yml @@ -0,0 +1,27 @@ +style: + version: VERSION + css: + theme: + css/media_library.css: {} + +view: + version: VERSION + js: + js/media_library.view.js: {} + css: + theme: + css/media_library.css: {} + dependencies: + - core/drupal + - core/drupal.dialog.ajax + - core/jquery + - core/jquery.once + +widget: + version: VERSION + js: + js/media_library.widget.js: {} + dependencies: + - core/drupal + - core/jquery + - media_library/style diff --git a/core/modules/media_library/media_library.links.action.yml b/core/modules/media_library/media_library.links.action.yml new file mode 100644 index 0000000..be1484b --- /dev/null +++ b/core/modules/media_library/media_library.links.action.yml @@ -0,0 +1,6 @@ +media_library.add: + route_name: entity.media.add_page + title: 'Add media' + appears_on: + - view.media_library.page + - view.media_library.bundle_page diff --git a/core/modules/media_library/media_library.links.task.yml b/core/modules/media_library/media_library.links.task.yml new file mode 100644 index 0000000..4d3000c --- /dev/null +++ b/core/modules/media_library/media_library.links.task.yml @@ -0,0 +1,8 @@ +media_library.local_tasks: + deriver: 'Drupal\media_library\Plugin\Derivative\MediaLibraryLocalTasks' + weight: 1 + +media_library.local_tasks.all: + title: 'All categories' + route_name: view.media_library.page + parent_id: views_view:view.media_library.page diff --git a/core/modules/media_library/media_library.module b/core/modules/media_library/media_library.module new file mode 100644 index 0000000..73e96c4 --- /dev/null +++ b/core/modules/media_library/media_library.module @@ -0,0 +1,73 @@ + [ + 'base hook' => 'media', + ], + ]; +} + +/** + * Implements hook_views_post_render(). + */ +function media_library_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) { + if ($view->id() === 'media_library') { + $output['#attached']['library'][] = 'media_library/view'; + } +} + +/** + * Implements hook_preprocess_media(). + */ +function media_library_preprocess_media(&$variables) { + if ($variables['view_mode'] === 'media_library') { + /** @var \Drupal\media\MediaInterface $media */ + $media = $variables['media']; + /** @var \Drupal\user\UserInterface $user */ + $user = $media->getRevisionUser(); + $variables['author_info'] = [ + '#markup' => t('Created by %author', ['%author' => $user->getDisplayName()]), + ]; + $variables['created_ago'] = [ + '#markup' => _media_library_pretty_time($media->getCreatedTime()), + ]; + } +} + +/** + * Displays a timestamp in a human-readable fashion. + * + * @todo This might be suitable for core as a Twig function. + * + * @param int $time + * A timestamp. + * + * @return \Drupal\Core\StringTranslation\TranslatableMarkup + * Markup representing a formatted time. + */ +function _media_library_pretty_time($time) { + $time = (int) $time; + $too_old = strtotime('-1 month'); + // Show formatted time differences for edits younger than a month. + if ($time > $too_old) { + $diff = \Drupal::service('date.formatter')->formatTimeDiffSince($time, ['granularity' => 1]); + $time_pretty = t('@diff ago', ['@diff' => $diff]); + } + else { + $date = date('m/d/Y - h:i A', $time); + $time_pretty = t('on @date', ['@date' => $date]); + } + return $time_pretty; +} diff --git a/core/modules/media_library/media_library.views.inc b/core/modules/media_library/media_library.views.inc new file mode 100644 index 0000000..6a8b182 --- /dev/null +++ b/core/modules/media_library/media_library.views.inc @@ -0,0 +1,20 @@ +getDefinitions() as $entity_type => $entity_info) { + $data[$entity_info->getBaseTable()][$entity_type . '_select_media'] = array( + 'title' => t('Select media'), + 'help' => t('Provides a field for selecting media entities in our media library view'), + 'real field' => $entity_info->getKey('id'), + 'field' => array( + 'id' => 'select_media', + ), + ); + } + return $data; +} diff --git a/core/modules/media_library/src/Plugin/Derivative/MediaLibraryLocalTasks.php b/core/modules/media_library/src/Plugin/Derivative/MediaLibraryLocalTasks.php new file mode 100644 index 0000000..97e399d --- /dev/null +++ b/core/modules/media_library/src/Plugin/Derivative/MediaLibraryLocalTasks.php @@ -0,0 +1,29 @@ + $bundle) { + $this->derivatives[$id] = $base_plugin_definition; + $this->derivatives[$id]['title'] = $bundle->label(); + $this->derivatives[$id]['route_name'] = 'view.media_library.bundle_page'; + $this->derivatives[$id]['parent_id'] = 'views_view:view.media_library.page'; + $this->derivatives[$id]['weight'] = ++$weight; + $this->derivatives[$id]['route_parameters'] = ['bundle' => $id]; + } + return $this->derivatives; + } + +} diff --git a/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php new file mode 100644 index 0000000..6ef9823 --- /dev/null +++ b/core/modules/media_library/src/Plugin/Field/FieldWidget/MediaLibraryWidget.php @@ -0,0 +1,338 @@ +entityTypeManager = $entity_type_manager; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { + return new static( + $plugin_id, + $plugin_definition, + $configuration['field_definition'], + $configuration['settings'], + $configuration['third_party_settings'], + $container->get('entity_type.manager') + ); + } + + /** + * {@inheritdoc} + */ + public static function isApplicable(FieldDefinitionInterface $field_definition) { + return $field_definition->getSetting('target_type') === 'media'; + } + + /** + * {@inheritdoc} + */ + public function form(FieldItemListInterface $items, array &$form, FormStateInterface $form_state, $get_delta = NULL) { + $field_name = $this->fieldDefinition->getName(); + $parents = $form['#parents']; + + // Load the items for form rebuilds from the field state as they might not be + // in $form_state['values'] because of validation limitations. + $field_state = static::getWidgetState($parents, $field_name, $form_state); + if ($field_state && isset($field_state['items'])) { + $items->setValue($field_state['items']); + } + + $build = parent::form($items, $form, $form_state, $get_delta); + + return $build; + } + + /** + * {@inheritdoc} + */ + public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) { + /** @var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $items */ + $referenced_entities = $items->referencedEntities(); + $view_builder = $this->entityTypeManager->getViewBuilder($this->getFieldSetting('target_type')); + $field_name = $this->fieldDefinition->getName(); + $wrapper_id = $field_name . '-media-library-wrapper'; + $parents = $form['#parents']; + + $element += [ + '#type' => 'fieldset', + '#cardinality' => $this->fieldDefinition->getFieldStorageDefinition()->getCardinality(), + 'selection' => [ + '#type' => 'container', + '#attributes' => ['id' => $wrapper_id], + ], + ]; + + if (empty($referenced_entities)) { + $element['selection']['empty_selection'] = [ + '#markup' => $this->t('

No media selected.

' + )]; + } + else { + foreach ($referenced_entities as $delta => $media_item) { + $element['selection'][$delta] = [ + '#type' => 'container', + '#attributes' => [ + 'class' => ['media-library-item', 'media-library-item-in-widget'], + ], + 'preview' => [ + '#type' => 'container', + 'view' => $view_builder->view($media_item, 'media_library'), + '#attached' => [ + 'library' => ['media_library/widget'], + ], + 'remove_button' => [ + '#type' => 'submit', + '#media_library_remove_delta' =>$delta, + '#name' => $field_name . '-' . $delta . '-media-library-remove-button', + '#value' => $this->t('Remove'), + '#attributes' => [ + 'class' => ['media-library-item-remove'], + ], + '#ajax' => [ + 'callback' => [static::class, 'updateWidget'], + 'wrapper' => $wrapper_id, + ], + '#submit' => [[static::class, 'removeItem']], + '#limit_validation_errors' => [array_merge($form['#parents'], [$field_name])], + ], + ], + 'target_id' => [ + '#type' => 'hidden', + '#value' => $media_item->id(), + ], + ]; + } + } + + // @todo We use a use-ajax link here as it is the only way we've seen + // contextual filters work when using a view in a modal. Unfortunately + // this only works the first time you open the modal - opening it twice + // in one page load breaks Views AJAX. + $element['media_library_open_container'] = [ + '#type' => 'container', + 'media_library_open_button' => [ + '#type' => 'link', + '#title' => $this->t('Select from library'), + '#name' => $field_name . '-media-library-open-button', + '#url' => Url::fromRoute('view.media_library.widget', [], [ + 'query' => ['media_library_input' => $field_name], + ]), + '#attributes' => [ + 'class' => ['button', 'use-ajax', 'media-library-open-button'], + 'data-dialog-type' => 'modal', + 'data-dialog-options' => json_encode([ + 'height' => '500', + 'width' => '70%', + 'title' => $this->t('Media library'), + ]), + ], + '#limit_validation_errors' => [array_merge($parents, [$field_name])], + ], + ]; + + // Add a hidden textfield to the form, which is used by the select_media + // Views field to pass values from the modal to the widget. This is similar + // to how the EntityReferenceAutocompleteWidget stores values. + $element['media_library_selection'] = [ + '#type' => 'textfield', + '#name' => $field_name . '-media-library-selection', + '#attributes' => [ + 'data-media-library-input-id' => $field_name, + 'class' => ['visually-hidden'], + ], + ]; + + $element['media_library_update_widget'] = [ + '#type' => 'submit', + '#value' => $this->t('Update widget'), + '#name' => $field_name . '-media-library-update-button', + '#ajax' => [ + 'callback' => [static::class, 'updateWidget'], + 'wrapper' => $wrapper_id, + ], + '#attributes' => [ + 'data-media-library-submit-id' => $field_name, + 'class' => ['visually-hidden'], + ], + '#submit' => [[static::class, 'addItems']], + '#limit_validation_errors' => [array_merge($parents, [$field_name])], + ]; + + return $element; + } + + /** + * {@inheritdoc} + */ + public function errorElement(array $element, ConstraintViolationInterface $error, array $form, FormStateInterface $form_state) { + return isset($element['target_id']) ? $element['target_id'] : FALSE; + } + + /** + * {@inheritdoc} + */ + public function massageFormValues(array $values, array $form, FormStateInterface $form_state) { + return isset($values['selection']) ? $values['selection'] : []; + } + + /** + * AJAX callback to update the widget when the selection changes. + * + * @param array $form + * The form array. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + * + * @return array + * An array representing the updated widget. + */ + public static function updateWidget($form, FormStateInterface $form_state) { + $triggering_element = $form_state->getTriggeringElement(); + $length = isset($triggering_element['#media_library_remove_delta']) ? -4 : -1; + $parents = $triggering_element['#array_parents']; + $parents = array_slice($parents, 0, $length); + $element = NestedArray::getValue($form, $parents); + return $element['selection']; + } + + /** + * Submit callback for remove buttons. + * + * @param array $form + * The form array. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + */ + public static function removeItem($form, FormStateInterface $form_state) { + $triggering_element = $form_state->getTriggeringElement(); + + $parents = $triggering_element['#array_parents']; + $parents = array_slice($parents, 0, -4); + $element = NestedArray::getValue($form, $parents); + $field_name = $element['#field_name']; + $parents = $element['#field_parents']; + $delta = $triggering_element['#media_library_remove_delta']; + + // Find and remove correct entity. + $values = $form_state->getValue($field_name); + $field_state = static::getWidgetState($parents, $field_name, $form_state); + if (isset($values['selection'])) { + if (isset($values['selection'][$delta])) { + array_splice($values['selection'], $delta, 1); + $field_state['items'] = $values['selection']; + $field_state['items_count'] = count($field_state['items']); + } + } + $form_state->setValue($field_name, $values); + static::setWidgetState($parents, $field_name, $form_state, $field_state); + + // Rebuild form. + $form_state->setRebuild(); + } + + /** + * Submission handler for the hidden "Select entities" button. + * + * @param array $form + * The form array. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The form state. + */ + public static function addItems($form, FormStateInterface $form_state) { + $button = $form_state->getTriggeringElement(); + + // Go one level up in the form, to the widgets container. + $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1)); + $field_name = $element['#field_name']; + $parents = $element['#field_parents']; + + // Get the new media ids passed to our hidden button. + $user_input = $form_state->getUserInput(); + $input_key = $field_name . '-media-library-selection'; + if (isset($user_input[$input_key])) { + $field_state = static::getWidgetState($parents, $field_name, $form_state); + + $ids = explode(',', $user_input[$input_key]); + /** @var \Drupal\media\MediaInterface[] $media */ + $media = Media::loadMultiple($ids); + $delta = 0; + $field_state['items_count'] = 0; + $cardinality_unlimited = ($element['#cardinality'] == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); + foreach ($media as $media_item) { + if ($cardinality_unlimited || ($delta < $element['#cardinality'])) { + if ($media && $media_item->access('view')) { + $field_state['items'][$delta] = [ + 'target_id' => $media_item->id(), + ]; + $delta++; + } + } + } + + $field_state['items_count'] = count($field_state['items']); + static::setWidgetState($parents, $field_name, $form_state, $field_state); + + $form_state->setRebuild(); + } + } + +} diff --git a/core/modules/media_library/src/Plugin/views/field/SelectMedia.php b/core/modules/media_library/src/Plugin/views/field/SelectMedia.php new file mode 100644 index 0000000..9b01e48 --- /dev/null +++ b/core/modules/media_library/src/Plugin/views/field/SelectMedia.php @@ -0,0 +1,96 @@ +options['id']])) { + foreach (Element::children($form[$this->options['id']]) as $index) { + $item = &$form[$this->options['id']][$index]; + $item['#attributes']['data-media-select'] = TRUE; + } + } + if (isset($form['actions']['submit'])) { + $form['actions']['submit']['#attributes']['data-media-select-submit'] = TRUE; + $form['actions']['submit']['#ajax']['url'] = Url::fromRoute(''); + $form['actions']['submit']['#ajax']['callback'] = function ($form, FormStateInterface $form_state) { + $response = new AjaxResponse(); + $response->addCommand(new CloseModalDialogCommand()); + $form_state->setResponse($response); + }; + } + if ($media_library_input = \Drupal::request()->get('media_library_input')) { + $form['#attached']['drupalSettings']['media_library']['media_library_inputs'][$this->view->dom_id] = $media_library_input; + } + } + + /** + * Submit handler for the bulk form. + * + * @param array $form + * An associative array containing the structure of the form. + * @param \Drupal\Core\Form\FormStateInterface $form_state + * The current state of the form. + * + * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException + * Thrown when the user tried to access an action without access to it. + */ + public function viewsFormSubmit(&$form, FormStateInterface $form_state) { + if ($form_state->get('step') == 'views_form_views_form') { + // Prefer the js provided selection, because it contains selected entities + // that aren't currently on screen and tracks the order of the selection. + if (\Drupal::request()->request->has('selected_entities')) { + $selected = \Drupal::request()->request->get('selected_entities'); + } + else { + // Filter only selected checkboxes. + $selected = array_filter($form_state->getValue($this->options['id'])); + } + + $entities = []; + + foreach ($selected as $bulk_form_key) { + $entity = $this->loadEntityFromBulkFormKey($bulk_form_key); + $entities[$bulk_form_key] = $entity; + } + + $ids = []; + foreach ($entities as $entity) { + $ids[] = $entity->id(); + } + + $response = new AjaxResponse(); + $library_input = \Drupal::request()->get('media_library_input'); + $input_selector = '[data-media-library-input-id="' . $library_input . '"]'; + $submit_selector = '[data-media-library-submit-id="' . $library_input . '"]'; + $response->addCommand(new InvokeCommand($input_selector, 'val', [implode(',', $ids)])); + $response->addCommand(new InvokeCommand($submit_selector, 'trigger', ['mousedown'])); + $response->addCommand(new CloseModalDialogCommand()); + $form_state->setResponse($response); + } + } + +} diff --git a/core/modules/media_library/templates/media--media-library.html.twig b/core/modules/media_library/templates/media--media-library.html.twig new file mode 100644 index 0000000..533b820 --- /dev/null +++ b/core/modules/media_library/templates/media--media-library.html.twig @@ -0,0 +1,50 @@ +{# +/** + * @file + * Default theme implementation to present a media entity in the media library. + * + * The major difference between this template and the default template is that + * "name" is omitted, as "name" is output as a field in the Media library view. + * Other themes are welcome to override this template, which will not break the + * functionality of 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. + * - author_info: This is a Media Library specific variable that contains the + * display name of the author for this media. + * - created_ago: This is a Media Library specific variable that contains a + * formatted "time ago" version of the created date. + * + * @see template_preprocess_media() + * + * @ingroup themeable + */ +#} + + {% if content %} + {{ content|without('name', 'created', 'uid') }} +
+
{{ name }}
+
{{ created_ago }}
+
{{ author_info }}
+
+ {% endif %} + diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_one.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_one.default.yml new file mode 100644 index 0000000..212daf8 --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_one.default.yml @@ -0,0 +1,43 @@ +langcode: en +status: true +dependencies: + config: + - field.field.media.type_one.field_media_test + - media.type.type_one +id: media.type_one.default +targetEntityType: media +bundle: type_one +mode: default +content: + created: + type: datetime_timestamp + weight: 10 + region: content + settings: { } + third_party_settings: { } + field_media_test: + settings: + size: 60 + placeholder: '' + third_party_settings: { } + type: string_textfield + weight: 11 + region: content + name: + type: string_textfield + weight: -5 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 5 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + region: content + third_party_settings: { } +hidden: { } diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_two.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_two.default.yml new file mode 100644 index 0000000..fabd13b --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.media.type_two.default.yml @@ -0,0 +1,43 @@ +langcode: en +status: true +dependencies: + config: + - field.field.media.type_two.field_media_test_1 + - media.type.type_two +id: media.type_two.default +targetEntityType: media +bundle: type_two +mode: default +content: + created: + type: datetime_timestamp + weight: 10 + region: content + settings: { } + third_party_settings: { } + field_media_test_1: + settings: + size: 60 + placeholder: '' + third_party_settings: { } + type: string_textfield + weight: 11 + region: content + name: + type: string_textfield + weight: -5 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 5 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + region: content + third_party_settings: { } +hidden: { } diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.node.media_library_test.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.node.media_library_test.default.yml new file mode 100644 index 0000000..775319d --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_form_display.node.media_library_test.default.yml @@ -0,0 +1,71 @@ +langcode: en +status: true +dependencies: + config: + - field.field.node.media_library_test.field_media + - field.field.node.media_library_test.field_multivalue_media + - node.type.media_library_test + module: + - media_library + - path +id: node.media_library_test.default +targetEntityType: node +bundle: media_library_test +mode: default +content: + created: + type: datetime_timestamp + weight: 10 + region: content + settings: { } + third_party_settings: { } + field_media: + weight: 31 + settings: { } + third_party_settings: { } + type: media_library_widget + region: content + field_multivalue_media: + weight: 32 + settings: { } + third_party_settings: { } + type: media_library_widget + region: content + path: + type: path + weight: 30 + region: content + settings: { } + third_party_settings: { } + promote: + type: boolean_checkbox + settings: + display_label: true + weight: 15 + region: content + third_party_settings: { } + sticky: + type: boolean_checkbox + settings: + display_label: true + weight: 16 + region: content + third_party_settings: { } + title: + type: string_textfield + weight: -5 + region: content + settings: + size: 60 + placeholder: '' + third_party_settings: { } + uid: + type: entity_reference_autocomplete + weight: 5 + settings: + match_operator: CONTAINS + size: 60 + placeholder: '' + region: content + third_party_settings: { } +hidden: { } diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_one.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_one.default.yml new file mode 100644 index 0000000..8f5f22a --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_one.default.yml @@ -0,0 +1,50 @@ +langcode: en +status: true +dependencies: + config: + - field.field.media.type_one.field_media_test + - image.style.thumbnail + - media.type.type_one + module: + - image + - user +id: media.type_one.default +targetEntityType: media +bundle: type_one +mode: default +content: + created: + label: hidden + type: timestamp + weight: 0 + region: content + settings: + date_format: medium + custom_date_format: '' + timezone: '' + third_party_settings: { } + field_media_test: + label: above + settings: + link_to_entity: false + third_party_settings: { } + type: string + weight: 6 + region: content + thumbnail: + type: image + weight: 5 + label: hidden + settings: + image_style: thumbnail + image_link: '' + region: content + third_party_settings: { } + uid: + label: hidden + type: author + weight: 0 + region: content + settings: { } + third_party_settings: { } +hidden: { } diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_two.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_two.default.yml new file mode 100644 index 0000000..a884fee --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.media.type_two.default.yml @@ -0,0 +1,50 @@ +langcode: en +status: true +dependencies: + config: + - field.field.media.type_two.field_media_test_1 + - image.style.thumbnail + - media.type.type_two + module: + - image + - user +id: media.type_two.default +targetEntityType: media +bundle: type_two +mode: default +content: + created: + label: hidden + type: timestamp + weight: 0 + region: content + settings: + date_format: medium + custom_date_format: '' + timezone: '' + third_party_settings: { } + field_media_test_1: + label: above + settings: + link_to_entity: false + third_party_settings: { } + type: string + weight: 6 + region: content + thumbnail: + type: image + weight: 5 + label: hidden + settings: + image_style: thumbnail + image_link: '' + region: content + third_party_settings: { } + uid: + label: hidden + type: author + weight: 0 + region: content + settings: { } + third_party_settings: { } +hidden: { } diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.node.media_library_test.default.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.node.media_library_test.default.yml new file mode 100644 index 0000000..3650d3b --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/core.entity_view_display.node.media_library_test.default.yml @@ -0,0 +1,34 @@ +langcode: en +status: true +dependencies: + config: + - field.field.node.media_library_test.field_media + - field.field.node.media_library_test.field_multivalue_media + - node.type.media_library_test + module: + - user +id: node.media_library_test.default +targetEntityType: node +bundle: media_library_test +mode: default +content: + field_media: + weight: 101 + label: above + settings: + link: true + third_party_settings: { } + type: entity_reference_label + region: content + field_multivalue_media: + weight: 102 + label: above + settings: + link: true + third_party_settings: { } + type: entity_reference_label + region: content + links: + weight: 100 + region: content +hidden: { } diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_one.field_media_test.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_one.field_media_test.yml new file mode 100644 index 0000000..f19207c --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_one.field_media_test.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.media.field_media_test + - media.type.type_one +id: media.type_one.field_media_test +field_name: field_media_test +entity_type: media +bundle: type_one +label: field_media_test +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_two.field_media_test_1.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_two.field_media_test_1.yml new file mode 100644 index 0000000..5b093ca --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.media.type_two.field_media_test_1.yml @@ -0,0 +1,18 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.media.field_media_test_1 + - media.type.type_two +id: media.type_two.field_media_test_1 +field_name: field_media_test_1 +entity_type: media +bundle: type_two +label: field_media_test_1 +description: '' +required: false +translatable: true +default_value: { } +default_value_callback: '' +settings: { } +field_type: string diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.media_library_test.field_media.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.media_library_test.field_media.yml new file mode 100644 index 0000000..e5773ab --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.media_library_test.field_media.yml @@ -0,0 +1,29 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_media + - media.type.type_one + - media.type.type_two + - node.type.media_library_test +id: node.media_library_test.field_media +field_name: field_media +entity_type: node +bundle: media_library_test +label: Media +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:media' + handler_settings: + target_bundles: + type_one: type_one + type_two: type_two + sort: + field: _none + auto_create: false + auto_create_bundle: type_one +field_type: entity_reference diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.media_library_test.field_multivalue_media.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.media_library_test.field_multivalue_media.yml new file mode 100644 index 0000000..f92f30f --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.field.node.media_library_test.field_multivalue_media.yml @@ -0,0 +1,29 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_multivalue_media + - media.type.type_one + - media.type.type_two + - node.type.media_library_test +id: node.media_library_test.field_multivalue_media +field_name: field_multivalue_media +entity_type: node +bundle: media_library_test +label: 'Multivalue Media' +description: '' +required: false +translatable: false +default_value: { } +default_value_callback: '' +settings: + handler: 'default:media' + handler_settings: + target_bundles: + type_one: type_one + type_two: type_two + sort: + field: _none + auto_create: false + auto_create_bundle: type_one +field_type: entity_reference diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test.yml new file mode 100644 index 0000000..40a7791 --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test.yml @@ -0,0 +1,20 @@ +langcode: en +status: true +dependencies: + module: + - media +id: media.field_media_test +field_name: field_media_test +entity_type: media +type: string +settings: + max_length: 255 + is_ascii: false + case_sensitive: false +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_1.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_1.yml new file mode 100644 index 0000000..73b1105 --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.media.field_media_test_1.yml @@ -0,0 +1,20 @@ +langcode: en +status: true +dependencies: + module: + - media +id: media.field_media_test_1 +field_name: field_media_test_1 +entity_type: media +type: string +settings: + max_length: 255 + is_ascii: false + case_sensitive: false +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.node.field_media.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.node.field_media.yml new file mode 100644 index 0000000..bbec21d --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.node.field_media.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - media + - node +id: node.field_media +field_name: field_media +entity_type: node +type: entity_reference +settings: + target_type: media +module: core +locked: false +cardinality: 1 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.node.field_multivalue_media.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.node.field_multivalue_media.yml new file mode 100644 index 0000000..9937919 --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/field.storage.node.field_multivalue_media.yml @@ -0,0 +1,19 @@ +langcode: en +status: true +dependencies: + module: + - media + - node +id: node.field_multivalue_media +field_name: field_multivalue_media +entity_type: node +type: entity_reference +settings: + target_type: media +module: core +locked: false +cardinality: 5 +translatable: true +indexes: { } +persist_with_no_fields: false +custom_storage: false diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_one.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_one.yml new file mode 100644 index 0000000..c3f7cf3 --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_one.yml @@ -0,0 +1,16 @@ +langcode: en +status: true +dependencies: + module: + - media + - media_test_handler +id: type_one +label: 'Type One' +description: '' +handler: test +queue_thumbnail_downloads: false +new_revision: false +handler_configuration: + source_field: field_media_test + test_config_value: 'This is default value.' +field_map: { } diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_two.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_two.yml new file mode 100644 index 0000000..1e0ad59 --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/media.type.type_two.yml @@ -0,0 +1,16 @@ +langcode: en +status: true +dependencies: + module: + - media + - media_test_handler +id: type_two +label: 'Type Two' +description: '' +handler: test +queue_thumbnail_downloads: false +new_revision: false +handler_configuration: + source_field: field_media_test_1 + test_config_value: 'This is default value.' +field_map: { } diff --git a/core/modules/media_library/tests/modules/media_library_test/config/install/node.type.media_library_test.yml b/core/modules/media_library/tests/modules/media_library_test/config/install/node.type.media_library_test.yml new file mode 100644 index 0000000..2c3ba17 --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/config/install/node.type.media_library_test.yml @@ -0,0 +1,17 @@ +langcode: en +status: true +dependencies: + module: + - menu_ui +third_party_settings: + menu_ui: + available_menus: + - main + parent: 'main:' +name: 'Media Library Test' +type: media_library_test +description: '' +help: '' +new_revision: true +preview_mode: 1 +display_submitted: true diff --git a/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml b/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml new file mode 100644 index 0000000..b9e8789 --- /dev/null +++ b/core/modules/media_library/tests/modules/media_library_test/media_library_test.info.yml @@ -0,0 +1,9 @@ +name: 'Media library test' +type: module +description: 'Test module for Media Library.' +package: Testing +core: 8.x +dependencies: + - drupal:media_library + - drupal:media_test_handler + - drupal:node