Commit 01621e58 authored by catch's avatar catch

Issue #2831274 by slashrsm, seanB, Wim Leers, chr.fritsch, phenaproxima,...

Issue #2831274 by slashrsm, seanB, Wim Leers, chr.fritsch, phenaproxima, naveenvalecha, marcoscano, webflo, Gábor Hojtsy, amateescu, Boobaa, iMiksu, mtodor, effulgentsia, xjm, Berdir, tim.plunkett, dawehner, tkoleary, tstoeckler, tedbow, alexpott, yoroy, catch, Bojhan, andypost, jhedstrom, jibran, aspilicious, boztek, cbr, bigbaldy, alex0412, dagmar, blueminds, ekes, Dave Reid, Sam152, bojanz, pixelmord, jonathanshaw, CTaPByK, webchick, samuel.mortenson, dbt102, dishabhadra, proweb.ua, rakesh.gectcr, rasikap, paranojik, pameeela, neardark, NormySan, Primsi, nicolas.rafaelli, romainj, royal121, vladan.me, vpeltot, woprrr, vilepickle, toni04, scheban, tduong, temkin, tim-e, mbovan, mashermike, felribeiro, giancarlosotelo, hctom, euphoric_mv, eric.duran7@gmail.com, edurenye, eelkeblok, H1ghlander, Jaesin, hkirsman, ja_ca, NickWilde, joachim, joshi.rohit100, marcingy, NerOcrO, Mixologic, jcisio, jfrederick, Lukas von Blarer, Maouna: Bring Media entity module to core as Media module
parent f186fa6c
......@@ -114,6 +114,7 @@
"drupal/link": "self.version",
"drupal/locale": "self.version",
"drupal/minimal": "self.version",
"drupal/media": "self.version",
"drupal/menu_link_content": "self.version",
"drupal/menu_ui": "self.version",
"drupal/migrate": "self.version",
......
langcode: en
status: false
dependencies:
module:
- media
id: media.full
label: 'Full content'
targetEntityType: media
cache: true
icon_base_uri: 'public://media-icons/generic'
This diff is collapsed.
media.settings:
type: config_object
label: 'Media settings'
mapping:
icon_base_uri:
type: string
label: 'Full URI to a folder where the media icons will be installed'
media.type.*:
type: config_entity
label: 'Media type'
mapping:
id:
type: string
label: 'Machine name'
label:
type: label
label: 'Name'
description:
type: text
label: 'Description'
source:
type: string
label: 'Source'
source_configuration:
type: media.source.[%parent.source]
queue_thumbnail_downloads:
type: boolean
label: 'Whether the thumbnail downloads should be queued'
new_revision:
type: boolean
label: 'Whether a new revision should be created by default'
field_map:
type: sequence
label: 'Field map'
sequence:
type: string
field.formatter.settings.media_thumbnail:
type: field.formatter.settings.image
label: 'Media thumbnail field display format settings'
media.source.*:
type: mapping
label: 'Media source settings'
media.source.field_aware:
type: mapping
mapping:
source_field:
type: string
label: 'Source field'
# Schema for the views plugins of the Media module.
views.field.media_bulk_form:
type: views_field_bulk_form
label: 'Media bulk form'
/**
* @file
* Defines Javascript behaviors for the media form.
*/
(function ($, Drupal) {
'use strict';
/**
* Behaviors for summaries for tabs in the media edit form.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches summary behavior for tabs in the media edit form.
*/
Drupal.behaviors.mediaFormSummaries = {
attach: function (context) {
var $context = $(context);
$context.find('.media-form-author').drupalSetSummary(function (context) {
var $authorContext = $(context);
var name = $authorContext.find('.field--name-uid input').val();
var date = $authorContext.find('.field--name-created input').val();
if (name && date) {
return Drupal.t('By @name on @date', {'@name': name, '@date': date});
}
else if (name) {
return Drupal.t('By @name', {'@name': name});
}
else if (date) {
return Drupal.t('Authored on @date', {'@date': date});
}
});
}
};
})(jQuery, Drupal);
/**
* @file
* Defines JavaScript behaviors for the media type form.
*/
(function ($, Drupal) {
'use strict';
/**
* Behaviors for setting summaries on media type form.
*
* @type {Drupal~behavior}
*
* @prop {Drupal~behaviorAttach} attach
* Attaches summary behaviors on media type edit forms.
*/
Drupal.behaviors.mediaTypeFormSummaries = {
attach: function (context) {
var $context = $(context);
// Provide the vertical tab summaries.
$context.find('#edit-workflow').drupalSetSummary(function (context) {
var vals = [];
$(context).find('input[name^="options"]:checked').parent().each(function () {
vals.push(Drupal.checkPlain($(this).find('label').text()));
});
if (!$(context).find('#edit-options-status').is(':checked')) {
vals.unshift(Drupal.t('Not published'));
}
return vals.join(', ');
});
$(context).find('#edit-language').drupalSetSummary(function (context) {
var vals = [];
vals.push($(context).find('.js-form-item-language-configuration-langcode select option:selected').text());
$(context).find('input:checked').next('label').each(function () {
vals.push(Drupal.checkPlain($(this).text()));
});
return vals.join(', ');
});
}
};
})(jQuery, Drupal);
<?php
/**
* @file
* Hooks related to Media and its plugins.
*/
/**
* @addtogroup hooks
* @{
*/
/**
* Alters the information provided in \Drupal\media\Annotation\MediaSource.
*
* @param array $sources
* The array of media source plugin definitions, keyed by plugin ID.
*/
function hook_media_source_info_alter(array &$sources) {
$sources['youtube']['label'] = t('Youtube rocks!');
}
/**
* @} End of "addtogroup hooks".
*/
name: Media
description: 'Create reusable media.'
type: module
package: Core (Experimental)
version: VERSION
core: 8.x
dependencies:
- file
- image
- user
<?php
/**
* @file
* Install, uninstall and update hooks for Media module.
*/
/**
* Implements hook_install().
*/
function media_install() {
$source = drupal_get_path('module', 'media') . '/images/icons';
$destination = \Drupal::config('media.settings')->get('icon_base_uri');
file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
$files = file_scan_directory($source, '/.*\.(svg|png|jpg|jpeg|gif)$/');
foreach ($files as $file) {
file_unmanaged_copy($file->uri, $destination, FILE_EXISTS_ERROR);
}
}
/**
* Implements hook_requirements().
*/
function media_requirements($phase) {
$requirements = [];
if ($phase == 'install') {
$destination = 'public://media-icons/generic';
file_prepare_directory($destination, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
$is_writable = is_writable($destination);
$is_directory = is_dir($destination);
if (!$is_writable || !$is_directory) {
if (!$is_directory) {
$error = t('The directory %directory does not exist.', ['%directory' => $destination]);
}
else {
$error = t('The directory %directory is not writable.', ['%directory' => $destination]);
}
$description = t('An automated attempt to create this directory failed, possibly due to a permissions problem. To proceed with the installation, either create the directory and modify its permissions manually or ensure that the installer has the permissions to create it automatically. For more information, see INSTALL.txt or the <a href=":handbook_url">online handbook</a>.', [':handbook_url' => 'https://www.drupal.org/server-permissions']);
if (!empty($error)) {
$description = $error . ' ' . $description;
$requirements['media']['description'] = $description;
$requirements['media']['severity'] = REQUIREMENT_ERROR;
}
}
}
return $requirements;
}
media_form:
version: VERSION
js:
js/media_form.js: {}
dependencies:
- core/drupal.form
media_type_form:
version: VERSION
js:
js/media_type_form.js: {}
dependencies:
- core/drupal.form
media.bundle_add:
route_name: entity.media_type.add_form
title: 'Add media type'
appears_on:
- entity.media_type.collection
media.add:
route_name: entity.media.add_page
title: 'Add media'
weight: 10
appears_on:
- view.media.media_page_list
entity.media.edit_form:
route_name: entity.media.edit_form
group: media
title: Edit
entity.media.delete_form:
route_name: entity.media.delete_form
group: media
title: Delete
weight: 10
entity.media_type.collection:
title: 'Media types'
parent: system.admin_structure
description: 'Manage media types.'
route_name: entity.media_type.collection
entity.media.canonical:
title: View
route_name: entity.media.canonical
base_route: entity.media.canonical
entity.media.edit_form:
title: Edit
route_name: entity.media.edit_form
base_route: entity.media.canonical
entity.media.delete_form:
title: Delete
route_name: entity.media.delete_form
base_route: entity.media.canonical
weight: 10
entity.media_type.edit_form:
title: Edit
route_name: entity.media_type.edit_form
base_route: entity.media_type.edit_form
entity.media_type.collection:
title: List
route_name: entity.media_type.collection
base_route: entity.media_type.collection
<?php
/**
* @file
* Provides media items.
*/
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Session\AccountInterface;
use Drupal\field\FieldConfigInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url;
/**
* Implements hook_help().
*/
function media_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
case 'help.page.media':
$output = '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Media module manages the creation, editing, deletion, settings and display of media. Items are typically images, documents, slideshows, YouTube videos, tweets, Instagram photos, etc. You can reference media items from any other content on your site. For more information, see the <a href=":media">online documentation for the Media module</a>.', [':media' => 'https://www.drupal.org/docs/8/core/modules/media']) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Creating media items') . '</dt>';
$output .= '<dd>' . t('When a new media item is created, the Media module records basic information about it, including the author, date of creation, and the <a href=":media-type">media type</a>. It also manages the <em>publishing options</em>, which define whether or not the item is published. Default settings can be configured for each type of media on your site.', [':media-type' => Url::fromRoute('entity.media_type.collection')->toString()]) . '</dd>';
$output .= '<dt>' . t('Creating custom media types') . '</dt>';
$output .= '<dd>' . t('The Media module gives users with the <em>Administer media types</em> permission the ability to <a href=":media-new">create new media types</a> in addition to the default ones already configured. Each media type has an associated media source (such as the image source) which support thumbnail generation and metadata extraction. Fields managed by the <a href=":field">Field module</a> may be added for storing that metadata, such as width and height, as well as any other associated values.', [':media-new' => Url::fromRoute('entity.media_type.add_form')->toString(), ':field' => Url::fromRoute('help.page', ['name' => 'field'])->toString()]) . '</dd>';
$output .= '<dt>' . t('Creating revisions') . '</dt>';
$output .= '<dd>' . t('The Media module also enables you to create multiple versions of any media item, and revert to older versions using the <em>Revision information</em> settings.') . '</dd>';
$output .= '<dt>' . t('User permissions') . '</dt>';
$output .= '<dd>' . t('The Media module makes a number of permissions available, which can be set by role on the <a href=":permissions">permissions page</a>.', [':permissions' => Url::fromRoute('user.admin_permissions', [], ['fragment' => 'module-media'])->toString()]) . '</dd>';
$output .= '</dl>';
return $output;
}
}
/**
* Implements hook_theme().
*/
function media_theme() {
return [
'media' => [
'render element' => 'elements',
],
];
}
/**
* Implements hook_entity_operation_alter().
*
* Fix broken operations array in field UI for entities with restricted access.
*
* @todo This hook can be removed when issue #2836384 is done.
* @see https://www.drupal.org/node/2836384
*/
function media_entity_operation_alter(array &$operations, EntityInterface $entity) {
if ($entity instanceof FieldConfigInterface && $entity->getTargetEntityTypeId() === 'media') {
/** @var \Drupal\media\MediaTypeInterface $media_type */
$media_type = \Drupal::entityTypeManager()->getStorage('media_type')->load($entity->getTargetBundle());
if ($entity->id() === 'media.' . $media_type->id() . '.' . $media_type->getSource()->getConfiguration()['source_field']) {
unset($operations['delete']);
}
}
}
/**
* Implements hook_entity_access().
*/
function media_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
if ($operation === 'delete' && $entity instanceof FieldConfigInterface && $entity->getTargetEntityTypeId() === 'media') {
/** @var \Drupal\media\MediaTypeInterface $media_type */
$media_type = \Drupal::entityTypeManager()->getStorage('media_type')->load($entity->getTargetBundle());
return AccessResult::forbiddenIf($entity->id() === 'media.' . $media_type->id() . '.' . $media_type->getSource()->getConfiguration()['source_field']);
}
return AccessResult::neutral();
}
/**
* Implements hook_theme_suggestions_HOOK().
*/
function media_theme_suggestions_media(array $variables) {
$suggestions = [];
$media = $variables['elements']['#media'];
$sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
$suggestions[] = 'media__' . $sanitized_view_mode;
$suggestions[] = 'media__' . $media->bundle();
$suggestions[] = 'media__' . $media->bundle() . '__' . $sanitized_view_mode;
return $suggestions;
}
/**
* Prepares variables for media templates.
*
* Default template: media.html.twig.
*
* @param array $variables
* An associative array containing:
* - elements: An array of elements to display in view mode.
* - media: The media item.
* - name: The label for the media item.
* - view_mode: View mode; e.g., 'full', 'teaser', etc.
*/
function template_preprocess_media(array &$variables) {
$variables['media'] = $variables['elements']['#media'];
$variables['view_mode'] = $variables['elements']['#view_mode'];
$variables['name'] = $variables['media']->label();
// Helpful $content variable for templates.
foreach (Element::children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
}
}
administer media:
title: 'Administer media'
restrict access: TRUE
administer media types:
title: 'Administer media types'
restrict access: TRUE
view media:
title: 'View media'
update media:
title: 'Update own media'
update any media:
title: 'Update any media'
delete media:
title: 'Delete own media'
delete any media:
title: 'Delete any media'
create media:
title: 'Create media'
entity.media.multiple_delete_confirm:
path: '/admin/content/media/delete'
defaults:
_form: '\Drupal\media\Form\MediaDeleteMultipleConfirmForm'
requirements:
_permission: 'administer media+delete any media'
services:
plugin.manager.media.source:
class: Drupal\media\MediaSourceManager
parent: default_plugin_manager
<?php
namespace Drupal\media\Annotation;
use Drupal\Component\Annotation\Plugin;
/**
* Defines a media source plugin annotation object.
*
* Media sources are responsible for implementing all the logic for dealing
* with a particular type of media. They provide various universal and
* type-specific metadata about media of the type they handle.
*
* Plugin namespace: Plugin\media\Source
*
* For a working example, see \Drupal\media\Plugin\media\Source\File.
*
* @see \Drupal\media\MediaSourceInterface
* @see \Drupal\media\MediaSourceBase
* @see \Drupal\media\MediaSourceManager
* @see hook_media_source_info_alter()
* @see plugin_api
*
* @Annotation
*/
class MediaSource extends Plugin {
/**
* The plugin ID.
*
* @var string
*/
public $id;
/**
* The human-readable name of the media source.
*
* @var \Drupal\Core\Annotation\Translation
*
* @ingroup plugin_translatable
*/
public $label;
/**
* A brief description of the media source.
*
* @var \Drupal\Core\Annotation\Translation
*
* @ingroup plugin_translatable
*/
public $description = '';
/**
* The field types that can be used as a source field for this media source.
*
* @var string[]
*/
public $allowed_field_types = [];
/**
* A filename for the default thumbnail.
*
* The thumbnails are placed in the directory defined by the config setting
* 'media.settings.icon_base_uri'. When using custom icons, make sure the
* module provides a hook_install() implementation to copy the custom icons
* to this directory. The media_install() function provides a clear example
* of how to do this.
*
* @var string
*
* @see media_install()
*/
public $default_thumbnail_filename = 'generic.png';
/**
* The metadata attribute name to provide the thumbnail URI.
*
* @var string
*/
public $thumbnail_uri_metadata_attribute = 'thumbnail_uri';
/**
* (optional) The metadata attribute name to provide the thumbnail alt.
*
* "Thumbnail" will be used if the attribute name is not provided.
*
* @var string|null
*/
public $thumbnail_alt_metadata_attribute;
/**
* (optional) The metadata attribute name to provide the thumbnail title.
*
* The name of the media entity will be used if the attribute name is not
* provided.
*
* @var string|null
*/
public $thumbnail_title_metadata_attribute;
/**
* The metadata attribute name to provide the default name.
*
* @var string
*/
public $default_name_metadata_attribute = 'default_name';
}
This diff is collapsed.
<?php
namespace Drupal\media\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
use Drupal\media\MediaTypeInterface;
/**
* Defines the Media type configuration entity.
*
* @ConfigEntityType(
* id = "media_type",
* label = @Translation("Media type"),
* label_collection = @Translation("Media"),
* label_singular = @Translation("media type"),
* label_plural = @Translation("media types"),
* label_count = @PluralTranslation(
* singular = "@count media type",
* plural = "@count media types"
* ),
* handlers = {
* "form" = {
* "add" = "Drupal\media\MediaTypeForm",
* "edit" = "Drupal\media\MediaTypeForm",
* "delete" = "Drupal\media\Form\MediaTypeDeleteConfirmForm"
* },
* "list_builder" = "Drupal\media\MediaTypeListBuilder",
* "route_provider" = {
* "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
* }
* },
* admin_permission = "administer media types",
* config_prefix = "type",
* bundle_of = "media",
* entity_keys = {
* "id" = "id",
* "label" = "label",
* "status" = "status",
* },
* config_export = {
* "id",
* "label",
* "description",
* "source",
* "queue_thumbnail_downloads",
* "new_revision",
* "source_configuration",
* "field_map",
* "status",
* },
* links = {
* "add-form" = "/admin/structure/media/add",
* "edit-form" = "/admin/structure/media/manage/{media_type}",
* "delete-form" = "/admin/structure/media/manage/{media_type}/delete",
* "collection" = "/admin/structure/media",
* },
* )
*/
class MediaType extends ConfigEntityBundleBase implements MediaTypeInterface, EntityWithPluginCollectionInterface {
/**
* The machine name of this media type.
*
* @var string
*/
protected $id;
/**
* The human-readable name of the media type.
*
* @var string
*/
protected $label;
/**
* A brief description of this media type.
*
* @var string
*/
protected $description;
/**
* The media source ID.
*
* @var string
*/
protected $source;
/**
* Whether media items should be published by default.
*
* @var bool
*/
protected $status = TRUE;
/**