Drupal 8.0.0 beta 12. More info: https://www.drupal.org/node/2514176
This commit is contained in:
commit
9921556621
13277 changed files with 1459781 additions and 0 deletions
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\responsive_image\Element\ResponsiveImage.
|
||||
*/
|
||||
|
||||
namespace Drupal\responsive_image\Element;
|
||||
|
||||
use Drupal\Core\Render\Element\RenderElement;
|
||||
|
||||
/**
|
||||
* Provides a responsive image element.
|
||||
*
|
||||
* @RenderElement("responsive_image")
|
||||
*/
|
||||
class ResponsiveImage extends RenderElement {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getInfo() {
|
||||
return [
|
||||
'#theme' => 'responsive_image',
|
||||
'#attached' => [
|
||||
'library' => ['core/picturefill'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\responsive_image\Entity\ResponsiveImageStyle.
|
||||
*/
|
||||
|
||||
namespace Drupal\responsive_image\Entity;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityBase;
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
use Drupal\responsive_image\ResponsiveImageStyleInterface;
|
||||
|
||||
/**
|
||||
* Defines the responsive image style entity.
|
||||
*
|
||||
* @ConfigEntityType(
|
||||
* id = "responsive_image_style",
|
||||
* label = @Translation("Responsive image style"),
|
||||
* handlers = {
|
||||
* "list_builder" = "Drupal\responsive_image\ResponsiveImageStyleListBuilder",
|
||||
* "form" = {
|
||||
* "edit" = "Drupal\responsive_image\ResponsiveImageStyleForm",
|
||||
* "add" = "Drupal\responsive_image\ResponsiveImageStyleForm",
|
||||
* "delete" = "Drupal\Core\Entity\EntityDeleteForm",
|
||||
* "duplicate" = "Drupal\responsive_image\ResponsiveImageStyleForm"
|
||||
* }
|
||||
* },
|
||||
* list_path = "admin/config/media/responsive-image-style",
|
||||
* admin_permission = "administer responsive images",
|
||||
* config_prefix = "styles",
|
||||
* entity_keys = {
|
||||
* "id" = "id",
|
||||
* "label" = "label"
|
||||
* },
|
||||
* links = {
|
||||
* "edit-form" = "/admin/config/media/responsive-image-style/{responsive_image_style}",
|
||||
* "duplicate-form" = "/admin/config/media/responsive-image-style/{responsive_image_style}/duplicate",
|
||||
* "delete-form" = "/admin/config/media/responsive-image-style/{responsive_image_style}/delete",
|
||||
* "collection" = "/admin/config/media/responsive-image-style",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class ResponsiveImageStyle extends ConfigEntityBase implements ResponsiveImageStyleInterface {
|
||||
|
||||
/**
|
||||
* The responsive image ID (machine name).
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
/**
|
||||
* The responsive image label.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $label;
|
||||
|
||||
/**
|
||||
* The image style mappings.
|
||||
*
|
||||
* Each image style mapping array contains the following keys:
|
||||
* - image_mapping_type: Either 'image_style' or 'sizes'.
|
||||
* - image_mapping:
|
||||
* - If image_mapping_type is 'image_style', the image style ID (a
|
||||
* string).
|
||||
* - If image_mapping_type is 'sizes', an array with following keys:
|
||||
* - sizes: The value for the 'sizes' attribute.
|
||||
* - sizes_image_styles: The image styles to use for the 'srcset'
|
||||
* attribute.
|
||||
* - breakpoint_id: The breakpoint ID for this image style mapping.
|
||||
* - multiplier: The multiplier for this image style mapping.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $image_style_mappings = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $keyedImageStyleMappings;
|
||||
|
||||
/**
|
||||
* The responsive image breakpoint group.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $breakpoint_group = '';
|
||||
|
||||
/**
|
||||
* The fallback image style.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fallback_image_style = '';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct(array $values, $entity_type_id = 'responsive_image_style') {
|
||||
parent::__construct($values, $entity_type_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addImageStyleMapping($breakpoint_id, $multiplier, array $image_style_mapping) {
|
||||
// If there is an existing mapping, overwrite it.
|
||||
foreach ($this->image_style_mappings as &$mapping) {
|
||||
if ($mapping['breakpoint_id'] === $breakpoint_id && $mapping['multiplier'] === $multiplier) {
|
||||
$mapping = array(
|
||||
'breakpoint_id' => $breakpoint_id,
|
||||
'multiplier' => $multiplier,
|
||||
) + $image_style_mapping;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
$this->image_style_mappings[] = array(
|
||||
'breakpoint_id' => $breakpoint_id,
|
||||
'multiplier' => $multiplier,
|
||||
) + $image_style_mapping;
|
||||
$this->keyedImageStyleMappings = NULL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasImageStyleMappings() {
|
||||
$mappings = $this->getKeyedImageStyleMappings();
|
||||
return !empty($mappings);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getKeyedImageStyleMappings() {
|
||||
if (!$this->keyedImageStyleMappings) {
|
||||
$this->keyedImageStyleMappings = array();
|
||||
foreach($this->image_style_mappings as $mapping) {
|
||||
if (!static::isEmptyImageStyleMapping($mapping)) {
|
||||
$this->keyedImageStyleMappings[$mapping['breakpoint_id']][$mapping['multiplier']] = $mapping;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->keyedImageStyleMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getImageStyleMappings() {
|
||||
return $this->image_style_mappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setBreakpointGroup($breakpoint_group) {
|
||||
// If the breakpoint group is changed then the image style mappings are
|
||||
// invalid.
|
||||
if ($breakpoint_group !== $this->breakpoint_group) {
|
||||
$this->removeImageStyleMappings();
|
||||
}
|
||||
$this->breakpoint_group = $breakpoint_group;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBreakpointGroup() {
|
||||
return $this->breakpoint_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFallbackImageStyle($fallback_image_style) {
|
||||
$this->fallback_image_style = $fallback_image_style;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFallbackImageStyle() {
|
||||
return $this->fallback_image_style;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function removeImageStyleMappings() {
|
||||
$this->image_style_mappings = array();
|
||||
$this->keyedImageStyleMappings = NULL;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function calculateDependencies() {
|
||||
parent::calculateDependencies();
|
||||
$providers = \Drupal::service('breakpoint.manager')->getGroupProviders($this->breakpoint_group);
|
||||
foreach ($providers as $provider => $type) {
|
||||
$this->addDependency($type, $provider);
|
||||
}
|
||||
// Extract all the styles from the image style mappings.
|
||||
$styles = ImageStyle::loadMultiple($this->getImageStyleIds());
|
||||
array_walk($styles, function ($style) {
|
||||
$this->addDependency('config', $style->getConfigDependencyName());
|
||||
});
|
||||
return $this->dependencies;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function isEmptyImageStyleMapping(array $image_style_mapping) {
|
||||
if (!empty($image_style_mapping)) {
|
||||
switch ($image_style_mapping['image_mapping_type']) {
|
||||
case 'sizes':
|
||||
// The image style mapping must have a sizes attribute defined and one
|
||||
// or more image styles selected.
|
||||
if ($image_style_mapping['image_mapping']['sizes'] && $image_style_mapping['image_mapping']['sizes_image_styles']) {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 'image_style':
|
||||
// The image style mapping must have an image style selected.
|
||||
if ($image_style_mapping['image_mapping']) {
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getImageStyleMapping($breakpoint_id, $multiplier) {
|
||||
$map = $this->getKeyedImageStyleMappings();
|
||||
if (isset($map[$breakpoint_id][$multiplier])) {
|
||||
return $map[$breakpoint_id][$multiplier];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getImageStyleIds() {
|
||||
$image_styles = [$this->getFallbackImageStyle()];
|
||||
foreach ($this->getImageStyleMappings() as $image_style_mapping) {
|
||||
// Only image styles of non-empty mappings should be loaded.
|
||||
if (!$this::isEmptyImageStyleMapping($image_style_mapping)) {
|
||||
switch ($image_style_mapping['image_mapping_type']) {
|
||||
case 'image_style':
|
||||
$image_styles[] = $image_style_mapping['image_mapping'];
|
||||
break;
|
||||
case 'sizes':
|
||||
$image_styles = array_merge($image_styles, $image_style_mapping['image_mapping']['sizes_image_styles']);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return array_values(array_filter(array_unique($image_styles)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\responsive_image\Plugin\Field\FieldFormatter\ResponsiveImageFormatter.
|
||||
*/
|
||||
|
||||
namespace Drupal\responsive_image\Plugin\Field\FieldFormatter;
|
||||
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Entity\EntityStorageInterface;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemListInterface;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\image\Plugin\Field\FieldFormatter\ImageFormatterBase;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Plugin for responsive image formatter.
|
||||
*
|
||||
* @FieldFormatter(
|
||||
* id = "responsive_image",
|
||||
* label = @Translation("Responsive image"),
|
||||
* field_types = {
|
||||
* "image",
|
||||
* }
|
||||
* )
|
||||
*/
|
||||
class ResponsiveImageFormatter extends ImageFormatterBase implements ContainerFactoryPluginInterface {
|
||||
|
||||
/**
|
||||
* @var EntityStorageInterface
|
||||
*/
|
||||
protected $responsiveImageStyleStorage;
|
||||
|
||||
/*
|
||||
* The image style entity storage.
|
||||
*
|
||||
* @var \Drupal\Core\Entity\EntityStorageInterface
|
||||
*/
|
||||
protected $imageStyleStorage;
|
||||
|
||||
/**
|
||||
* Constructs a ResponsiveImageFormatter object.
|
||||
*
|
||||
* @param string $plugin_id
|
||||
* The plugin_id for the formatter.
|
||||
* @param mixed $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
|
||||
* The definition of the field to which the formatter is associated.
|
||||
* @param array $settings
|
||||
* The formatter settings.
|
||||
* @param string $label
|
||||
* The formatter label display setting.
|
||||
* @param string $view_mode
|
||||
* The view mode.
|
||||
* @param array $third_party_settings
|
||||
* Any third party settings.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $responsive_image_style_storage
|
||||
* The responsive image style storage.
|
||||
* @param \Drupal\Core\Entity\EntityStorageInterface $image_style_storage
|
||||
* The image style storage.
|
||||
*/
|
||||
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityStorageInterface $responsive_image_style_storage, EntityStorageInterface $image_style_storage) {
|
||||
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
|
||||
|
||||
$this->responsiveImageStyleStorage = $responsive_image_style_storage;
|
||||
$this->imageStyleStorage = $image_style_storage;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@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['label'],
|
||||
$configuration['view_mode'],
|
||||
$configuration['third_party_settings'],
|
||||
$container->get('entity.manager')->getStorage('responsive_image_style'),
|
||||
$container->get('entity.manager')->getStorage('image_style')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function defaultSettings() {
|
||||
return array(
|
||||
'responsive_image_style' => '',
|
||||
'image_link' => '',
|
||||
) + parent::defaultSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsForm(array $form, FormStateInterface $form_state) {
|
||||
$responsive_image_options = array();
|
||||
$responsive_image_styles = $this->responsiveImageStyleStorage->loadMultiple();
|
||||
if ($responsive_image_styles && !empty($responsive_image_styles)) {
|
||||
foreach ($responsive_image_styles as $machine_name => $responsive_image_style) {
|
||||
if ($responsive_image_style->hasImageStyleMappings()) {
|
||||
$responsive_image_options[$machine_name] = $responsive_image_style->label();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$elements['responsive_image_style'] = array(
|
||||
'#title' => t('Responsive image style'),
|
||||
'#type' => 'select',
|
||||
'#default_value' => $this->getSetting('responsive_image_style'),
|
||||
'#required' => TRUE,
|
||||
'#options' => $responsive_image_options,
|
||||
);
|
||||
|
||||
$link_types = array(
|
||||
'content' => t('Content'),
|
||||
'file' => t('File'),
|
||||
);
|
||||
$elements['image_link'] = array(
|
||||
'#title' => t('Link image to'),
|
||||
'#type' => 'select',
|
||||
'#default_value' => $this->getSetting('image_link'),
|
||||
'#empty_option' => t('Nothing'),
|
||||
'#options' => $link_types,
|
||||
);
|
||||
|
||||
return $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function settingsSummary() {
|
||||
$summary = array();
|
||||
|
||||
$responsive_image_style = $this->responsiveImageStyleStorage->load($this->getSetting('responsive_image_style'));
|
||||
if ($responsive_image_style) {
|
||||
$summary[] = t('Responsive image style: @responsive_image_style', array('@responsive_image_style' => $responsive_image_style->label()));
|
||||
|
||||
$link_types = array(
|
||||
'content' => t('Linked to content'),
|
||||
'file' => t('Linked to file'),
|
||||
);
|
||||
// Display this setting only if image is linked.
|
||||
if (isset($link_types[$this->getSetting('image_link')])) {
|
||||
$summary[] = $link_types[$this->getSetting('image_link')];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$summary[] = t('Select a responsive image style.');
|
||||
}
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function viewElements(FieldItemListInterface $items) {
|
||||
$elements = array();
|
||||
$files = $this->getEntitiesToView($items);
|
||||
|
||||
// Early opt-out if the field is empty.
|
||||
if (empty($files)) {
|
||||
return $elements;
|
||||
}
|
||||
|
||||
$url = NULL;
|
||||
// Check if the formatter involves a link.
|
||||
if ($this->getSetting('image_link') == 'content') {
|
||||
$entity = $items->getEntity();
|
||||
if (!$entity->isNew()) {
|
||||
$url = $entity->urlInfo();
|
||||
}
|
||||
}
|
||||
elseif ($this->getSetting('image_link') == 'file') {
|
||||
$link_file = TRUE;
|
||||
}
|
||||
|
||||
// Collect cache tags to be added for each item in the field.
|
||||
$responsive_image_style = $this->responsiveImageStyleStorage->load($this->getSetting('responsive_image_style'));
|
||||
$image_styles_to_load = array();
|
||||
$cache_tags = [];
|
||||
if ($responsive_image_style) {
|
||||
$cache_tags = Cache::mergeTags($cache_tags, $responsive_image_style->getCacheTags());
|
||||
$image_styles_to_load = $responsive_image_style->getImageStyleIds();
|
||||
}
|
||||
|
||||
$image_styles = $this->imageStyleStorage->loadMultiple($image_styles_to_load);
|
||||
foreach ($image_styles as $image_style) {
|
||||
$cache_tags = Cache::mergeTags($cache_tags, $image_style->getCacheTags());
|
||||
}
|
||||
|
||||
foreach ($files as $delta => $file) {
|
||||
// Link the <picture> element to the original file.
|
||||
if (isset($link_file)) {
|
||||
$url = Url::fromUri(file_create_url($file->getFileUri()));
|
||||
}
|
||||
// Extract field item attributes for the theme function, and unset them
|
||||
// from the $item so that the field template does not re-render them.
|
||||
$item = $file->_referringItem;
|
||||
$item_attributes = $item->_attributes;
|
||||
unset($item->_attributes);
|
||||
|
||||
$elements[$delta] = array(
|
||||
'#theme' => 'responsive_image_formatter',
|
||||
'#item' => $item,
|
||||
'#item_attributes' => $item_attributes,
|
||||
'#responsive_image_style_id' => $responsive_image_style ? $responsive_image_style->id() : '',
|
||||
'#url' => $url,
|
||||
'#cache' => array(
|
||||
'tags' => $cache_tags,
|
||||
),
|
||||
);
|
||||
}
|
||||
return $elements;
|
||||
}
|
||||
}
|
||||
192
core/modules/responsive_image/src/ResponsiveImageStyleForm.php
Normal file
192
core/modules/responsive_image/src/ResponsiveImageStyleForm.php
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\responsive_image\ResponsiveImageStyleForm.
|
||||
*/
|
||||
|
||||
namespace Drupal\responsive_image;
|
||||
|
||||
use Drupal\breakpoint\BreakpointManagerInterface;
|
||||
use Drupal\Core\Entity\EntityForm;
|
||||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* Form controller for the responsive image edit/add forms.
|
||||
*/
|
||||
class ResponsiveImageStyleForm extends EntityForm {
|
||||
|
||||
/**
|
||||
* The breakpoint manager.
|
||||
*
|
||||
* @var \Drupal\breakpoint\BreakpointManagerInterface
|
||||
*/
|
||||
protected $breakpointManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function create(ContainerInterface $container) {
|
||||
return new static(
|
||||
$container->get('breakpoint.manager')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the responsive image style form.
|
||||
*
|
||||
* @param \Drupal\breakpoint\BreakpointManagerInterface $breakpoint_manager
|
||||
* The breakpoint manager.
|
||||
*/
|
||||
public function __construct(BreakpointManagerInterface $breakpoint_manager) {
|
||||
$this->breakpointManager = $breakpoint_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Drupal\Core\Entity\EntityForm::form().
|
||||
*
|
||||
* @param array $form
|
||||
* A nested array form elements comprising the form.
|
||||
* @param \Drupal\Core\Form\FormStateInterface $form_state
|
||||
* The current state of the form.
|
||||
*
|
||||
* @return array
|
||||
* The array containing the complete form.
|
||||
*/
|
||||
public function form(array $form, FormStateInterface $form_state) {
|
||||
if ($this->operation == 'duplicate') {
|
||||
$form['#title'] = $this->t('<em>Duplicate responsive image style</em> @label', array('@label' => $this->entity->label()));
|
||||
$this->entity = $this->entity->createDuplicate();
|
||||
}
|
||||
if ($this->operation == 'edit') {
|
||||
$form['#title'] = $this->t('<em>Edit responsive image style</em> @label', array('@label' => $this->entity->label()));
|
||||
}
|
||||
|
||||
/** @var \Drupal\responsive_image\ResponsiveImageStyleInterface $responsive_image_style */
|
||||
$responsive_image_style = $this->entity;
|
||||
$form['label'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => $this->t('Label'),
|
||||
'#maxlength' => 255,
|
||||
'#default_value' => $responsive_image_style->label(),
|
||||
'#description' => $this->t("Example: 'Hero image' or 'Author image'."),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['id'] = array(
|
||||
'#type' => 'machine_name',
|
||||
'#default_value' => $responsive_image_style->id(),
|
||||
'#machine_name' => array(
|
||||
'exists' => '\Drupal\responsive_image\Entity\ResponsiveImageStyle::load',
|
||||
'source' => array('label'),
|
||||
),
|
||||
'#disabled' => (bool) $responsive_image_style->id() && $this->operation != 'duplicate',
|
||||
);
|
||||
|
||||
if ((bool) $responsive_image_style->id() && $this->operation != 'duplicate') {
|
||||
$description = $this->t('Select a breakpoint group from the installed themes.') . ' ' . $this->t("Warning: if you change the breakpoint group you lose all your selected image style mappings.");
|
||||
}
|
||||
else {
|
||||
$description = $this->t('Select a breakpoint group from the installed themes.');
|
||||
}
|
||||
$form['breakpoint_group'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $this->t('Breakpoint group'),
|
||||
'#default_value' => $responsive_image_style->getBreakpointGroup(),
|
||||
'#options' => $this->breakpointManager->getGroups(),
|
||||
'#required' => TRUE,
|
||||
'#description' => $description,
|
||||
);
|
||||
|
||||
$image_styles = image_style_options(TRUE);
|
||||
$image_styles[RESPONSIVE_IMAGE_EMPTY_IMAGE] = $this->t('- empty image -');
|
||||
|
||||
$form['fallback_image_style'] = array(
|
||||
'#title' => $this->t('Fallback image style'),
|
||||
'#type' => 'select',
|
||||
'#default_value' => $responsive_image_style->getFallbackImageStyle(),
|
||||
'#options' => $image_styles,
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
$breakpoints = $this->breakpointManager->getBreakpointsByGroup($responsive_image_style->getBreakpointGroup());
|
||||
foreach ($breakpoints as $breakpoint_id => $breakpoint) {
|
||||
foreach ($breakpoint->getMultipliers() as $multiplier) {
|
||||
$label = $multiplier . ' ' . $breakpoint->getLabel() . ' [' . $breakpoint->getMediaQuery() . ']';
|
||||
$form['keyed_styles'][$breakpoint_id][$multiplier] = array(
|
||||
'#type' => 'container',
|
||||
);
|
||||
$image_style_mapping = $responsive_image_style->getImageStyleMapping($breakpoint_id, $multiplier);
|
||||
// @todo The image_mapping_type is only temporarily hardcoded, until
|
||||
// support for the other responsive image mapping type ('sizes') is
|
||||
// added in https://www.drupal.org/node/2334387.
|
||||
$form['keyed_styles'][$breakpoint_id][$multiplier]['image_mapping_type'] = array(
|
||||
'#type' => 'value',
|
||||
'#value' => 'image_style',
|
||||
);
|
||||
$form['keyed_styles'][$breakpoint_id][$multiplier]['image_mapping'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $label,
|
||||
'#options' => $image_styles,
|
||||
'#default_value' => isset($image_style_mapping['image_mapping']) ? $image_style_mapping['image_mapping'] : array(),
|
||||
'#description' => $this->t('Select an image style for this breakpoint.'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$form['#tree'] = TRUE;
|
||||
|
||||
return parent::form($form, $form_state, $responsive_image_style);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function validate(array $form, FormStateInterface $form_state) {
|
||||
// Only validate on edit.
|
||||
if ($form_state->hasValue('keyed_styles')) {
|
||||
// Check if another breakpoint group is selected.
|
||||
if ($form_state->getValue('breakpoint_group') != $form_state->getCompleteForm()['breakpoint_group']['#default_value']) {
|
||||
// Remove the image style mappings since the breakpoint ID has changed.
|
||||
$form_state->unsetValue('keyed_styles');
|
||||
}
|
||||
// @todo Filter 'sizes_image_styles' to a normal array in
|
||||
// https://www.drupal.org/node/2334387. For an example see
|
||||
// \Drupal\Core\Block\BlockBase::validateConfigurationForm().
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function save(array $form, FormStateInterface $form_state) {
|
||||
/** @var \Drupal\responsive_image\ResponsiveImageStyleInterface $responsive_image_style */
|
||||
$responsive_image_style = $this->entity;
|
||||
// Remove all the existing mappings and replace with submitted values.
|
||||
$responsive_image_style->removeImageStyleMappings();
|
||||
if ($form_state->hasValue('keyed_styles')) {
|
||||
foreach ($form_state->getValue('keyed_styles') as $breakpoint_id => $multipliers) {
|
||||
foreach ($multipliers as $multiplier => $image_style_mapping) {
|
||||
$responsive_image_style->addImageStyleMapping($breakpoint_id, $multiplier, $image_style_mapping);
|
||||
}
|
||||
}
|
||||
}
|
||||
$responsive_image_style->save();
|
||||
|
||||
$this->logger('responsive_image')->notice('Responsive image style @label saved.', array('@label' => $responsive_image_style->label()));
|
||||
drupal_set_message($this->t('Responsive image style %label saved.', array('%label' => $responsive_image_style->label())));
|
||||
|
||||
// Redirect to edit form after creating a new responsive image style or
|
||||
// after selecting another breakpoint group.
|
||||
if (!$responsive_image_style->hasImageStyleMappings()) {
|
||||
$form_state->setRedirect(
|
||||
'entity.responsive_image_style.edit_form',
|
||||
array('responsive_image_style' => $responsive_image_style->id())
|
||||
);
|
||||
}
|
||||
else {
|
||||
$form_state->setRedirectUrl($this->entity->urlInfo('collection'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\responsive_image\ResponsiveImageStyleInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\responsive_image;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
||||
|
||||
/**
|
||||
* Provides an interface defining a responsive_image mapping entity.
|
||||
*/
|
||||
interface ResponsiveImageStyleInterface extends ConfigEntityInterface {
|
||||
|
||||
/**
|
||||
* Checks if there is at least one mapping defined.
|
||||
*
|
||||
* @return bool
|
||||
* Whether the entity has any image style mappings.
|
||||
*/
|
||||
public function hasImageStyleMappings();
|
||||
|
||||
/**
|
||||
* Returns the mappings of breakpoint ID and multiplier to image style.
|
||||
*
|
||||
* @return array[]
|
||||
* The image style mappings. Keyed by breakpoint ID then multiplier.
|
||||
* The value is the image style mapping array with following keys:
|
||||
* - image_mapping_type: Either 'image_style' or 'sizes'.
|
||||
* - image_mapping:
|
||||
* - If image_mapping_type is 'image_style', the image style ID.
|
||||
* - If image_mapping_type is 'sizes', an array with following keys:
|
||||
* - sizes: The value for the 'sizes' attribute.
|
||||
* - sizes_image_styles: The image styles to use for the 'srcset'
|
||||
* attribute.
|
||||
* - breakpoint_id: The breakpoint ID for this mapping.
|
||||
* - multiplier: The multiplier for this mapping.
|
||||
*/
|
||||
public function getKeyedImageStyleMappings();
|
||||
|
||||
/**
|
||||
* Returns the image style mappings for the responsive image style.
|
||||
*
|
||||
* @return array[]
|
||||
* An array of image style mappings. Each image style mapping array
|
||||
* contains the following keys:
|
||||
* - breakpoint_id
|
||||
* - multiplier
|
||||
* - image_mapping_type
|
||||
* - image_mapping
|
||||
*/
|
||||
public function getImageStyleMappings();
|
||||
|
||||
/**
|
||||
* Sets the breakpoint group for the responsive image style.
|
||||
*
|
||||
* @param string $breakpoint_group
|
||||
* The responsive image style breakpoint group.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBreakpointGroup($breakpoint_group);
|
||||
|
||||
/**
|
||||
* Returns the breakpoint group for the responsive image style.
|
||||
*
|
||||
* @return string
|
||||
* The breakpoint group.
|
||||
*/
|
||||
public function getBreakpointGroup();
|
||||
|
||||
/**
|
||||
* Sets the fallback image style for the responsive image style.
|
||||
*
|
||||
* @param string $fallback_image_style
|
||||
* The fallback image style ID.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFallbackImageStyle($fallback_image_style);
|
||||
|
||||
/**
|
||||
* Returns the fallback image style ID for the responsive image style.
|
||||
*
|
||||
* @return string
|
||||
* The fallback image style ID.
|
||||
*/
|
||||
public function getFallbackImageStyle();
|
||||
|
||||
/**
|
||||
* Gets the image style mapping for a breakpoint ID and multiplier.
|
||||
*
|
||||
* @param string $breakpoint_id
|
||||
* The breakpoint ID.
|
||||
* @param string $multiplier
|
||||
* The multiplier.
|
||||
*
|
||||
* @return array|null
|
||||
* The image style mapping. NULL if the mapping does not exist.
|
||||
* The image style mapping has following keys:
|
||||
* - image_mapping_type: Either 'image_style' or 'sizes'.
|
||||
* - image_mapping:
|
||||
* - If image_mapping_type is 'image_style', the image style ID.
|
||||
* - If image_mapping_type is 'sizes', an array with following keys:
|
||||
* - sizes: The value for the 'sizes' attribute.
|
||||
* - sizes_image_styles: The image styles to use for the 'srcset'
|
||||
* attribute.
|
||||
* - breakpoint_id: The breakpoint ID for this image style mapping.
|
||||
* - multiplier: The multiplier for this image style mapping.
|
||||
*/
|
||||
public function getImageStyleMapping($breakpoint_id, $multiplier);
|
||||
|
||||
/**
|
||||
* Checks if there is at least one image style mapping defined.
|
||||
*
|
||||
* @param array $image_style_mapping
|
||||
* The image style mapping.
|
||||
*
|
||||
* @return bool
|
||||
* Whether the image style mapping is empty.
|
||||
*/
|
||||
public static function isEmptyImageStyleMapping(array $image_style_mapping);
|
||||
|
||||
/**
|
||||
* Adds a image style mapping to the responsive image configuration entity.
|
||||
*
|
||||
* @param string $breakpoint_id
|
||||
* The breakpoint ID.
|
||||
* @param string $multiplier
|
||||
* The multiplier.
|
||||
* @param array $image_style_mapping
|
||||
* The mapping image style mapping.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addImageStyleMapping($breakpoint_id, $multiplier, array $image_style_mapping);
|
||||
|
||||
/**
|
||||
* Removes all image style mappings from the responsive image style.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeImageStyleMappings();
|
||||
|
||||
/**
|
||||
* Gets all the image styles IDs involved in the responsive image mapping.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getImageStyleIds();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\responsive_image\ResponsiveImageStyleListBuilder.
|
||||
*/
|
||||
|
||||
namespace Drupal\responsive_image;
|
||||
|
||||
use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
|
||||
/**
|
||||
* Provides a listing of responsive image styles.
|
||||
*/
|
||||
class ResponsiveImageStyleListBuilder extends ConfigEntityListBuilder {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildHeader() {
|
||||
$header['label'] = t('Label');
|
||||
$header['id'] = t('Machine name');
|
||||
return $header + parent::buildHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildRow(EntityInterface $entity) {
|
||||
$row['label'] = $this->getLabel($entity);
|
||||
$row['id'] = $entity->id();
|
||||
return $row + parent::buildRow($entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefaultOperations(EntityInterface $entity) {
|
||||
$operations = parent::getDefaultOperations($entity);
|
||||
$operations['duplicate'] = array(
|
||||
'title' => t('Duplicate'),
|
||||
'weight' => 15,
|
||||
'url' => $entity->urlInfo('duplicate-form'),
|
||||
);
|
||||
return $operations;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\responsive_image\Tests\ResponsiveImageAdminUITest.
|
||||
*/
|
||||
|
||||
namespace Drupal\responsive_image\Tests;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Thoroughly test the administrative interface of the Responsive Image module.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class ResponsiveImageAdminUITest extends WebTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('responsive_image', 'responsive_image_test_module');
|
||||
|
||||
/**
|
||||
* Drupal\simpletest\WebTestBase\setUp().
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->drupalLogin($this->drupalCreateUser([
|
||||
'administer responsive images',
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test responsive image administration functionality.
|
||||
*/
|
||||
public function testResponsiveImageAdmin() {
|
||||
// We start without any default styles.
|
||||
$this->drupalGet('admin/config/media/responsive-image-style');
|
||||
$this->assertText('There is no Responsive image style yet.');
|
||||
|
||||
// Add a new responsive image style, our breakpoint set should be selected.
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/add');
|
||||
$this->assertFieldByName('breakpoint_group', 'responsive_image_test_module');
|
||||
|
||||
// Create a new group.
|
||||
$edit = array(
|
||||
'label' => 'Style One',
|
||||
'id' => 'style_one',
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
'fallback_image_style' => 'thumbnail',
|
||||
);
|
||||
$this->drupalPostForm('admin/config/media/responsive-image-style/add', $edit, t('Save'));
|
||||
|
||||
// Check if the new group is created.
|
||||
$this->assertResponse(200);
|
||||
$this->drupalGet('admin/config/media/responsive-image-style');
|
||||
$this->assertNoText('There is no Responsive image style yet.');
|
||||
$this->assertText('Style One');
|
||||
$this->assertText('style_one');
|
||||
|
||||
// Edit the group.
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/style_one');
|
||||
$this->assertFieldByName('label', 'Style One');
|
||||
$this->assertFieldByName('breakpoint_group', 'responsive_image_test_module');
|
||||
$this->assertFieldByName('fallback_image_style', 'thumbnail');
|
||||
|
||||
$cases = array(
|
||||
array('mobile', '1x'),
|
||||
array('mobile', '2x'),
|
||||
array('narrow', '1x'),
|
||||
array('narrow', '2x'),
|
||||
array('wide', '1x'),
|
||||
array('wide', '2x'),
|
||||
);
|
||||
|
||||
foreach ($cases as $case) {
|
||||
// Check if the radio buttons are present.
|
||||
$this->assertFieldByName('keyed_styles[responsive_image_test_module.' . $case[0] . '][' . $case[1] . '][image_mapping]', '');
|
||||
}
|
||||
|
||||
// Save styles for 1x variant only.
|
||||
$edit = array(
|
||||
'label' => 'Style One',
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
'fallback_image_style' => 'thumbnail',
|
||||
'keyed_styles[responsive_image_test_module.mobile][1x][image_mapping]' => 'thumbnail',
|
||||
'keyed_styles[responsive_image_test_module.narrow][1x][image_mapping]' => 'medium',
|
||||
'keyed_styles[responsive_image_test_module.wide][1x][image_mapping]' => 'large',
|
||||
);
|
||||
$this->drupalPostForm('admin/config/media/responsive-image-style/style_one', $edit, t('Save'));
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/style_one');
|
||||
|
||||
// Check the style for multipliers 1x and 2x for the mobile breakpoint.
|
||||
$this->assertFieldByName('keyed_styles[responsive_image_test_module.mobile][1x][image_mapping]', 'thumbnail');
|
||||
$this->assertFieldByName('keyed_styles[responsive_image_test_module.mobile][2x][image_mapping]', '');
|
||||
|
||||
// Check the style for multipliers 1x and 2x for the narrow breakpoint.
|
||||
$this->assertFieldByName('keyed_styles[responsive_image_test_module.narrow][1x][image_mapping]', 'medium');
|
||||
$this->assertFieldByName('keyed_styles[responsive_image_test_module.narrow][2x][image_mapping]', '');
|
||||
|
||||
// Check the style for multipliers 1x and 2x for the wide breakpoint.
|
||||
$this->assertFieldByName('keyed_styles[responsive_image_test_module.wide][1x][image_mapping]', 'large');
|
||||
$this->assertFieldByName('keyed_styles[responsive_image_test_module.wide][2x][image_mapping]', '');
|
||||
|
||||
// Delete the style.
|
||||
$this->drupalGet('admin/config/media/responsive-image-style/style_one/delete');
|
||||
$this->drupalPostForm(NULL, array(), t('Delete'));
|
||||
$this->drupalGet('admin/config/media/responsive-image-style');
|
||||
$this->assertText('There is no Responsive image style yet.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,430 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\responsive_image\Tests\ResponsiveImageFieldDisplayTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\responsive_image\Tests;
|
||||
|
||||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\image\Tests\ImageFieldTestBase;
|
||||
use Drupal\image\Entity\ImageStyle;
|
||||
use Drupal\node\Entity\Node;
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Tests responsive image display formatter.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class ResponsiveImageFieldDisplayTest extends ImageFieldTestBase {
|
||||
|
||||
protected $dumpHeaders = TRUE;
|
||||
|
||||
/**
|
||||
* Responsive image style entity instance we test with.
|
||||
*
|
||||
* @var \Drupal\responsive_image\Entity\ResponsiveImageStyle
|
||||
*/
|
||||
protected $responsiveImgStyle;
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('field_ui', 'responsive_image', 'responsive_image_test_module');
|
||||
|
||||
/**
|
||||
* Drupal\simpletest\WebTestBase\setUp().
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// Create user.
|
||||
$this->adminUser = $this->drupalCreateUser(array(
|
||||
'administer responsive images',
|
||||
'access content',
|
||||
'access administration pages',
|
||||
'administer site configuration',
|
||||
'administer content types',
|
||||
'administer node display',
|
||||
'administer nodes',
|
||||
'create article content',
|
||||
'edit any article content',
|
||||
'delete any article content',
|
||||
'administer image styles'
|
||||
));
|
||||
$this->drupalLogin($this->adminUser);
|
||||
// Add responsive image style.
|
||||
$this->responsiveImgStyle = entity_create('responsive_image_style', array(
|
||||
'id' => 'style_one',
|
||||
'label' => 'Style One',
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
'fallback_image_style' => 'large',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters on node display for public files.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersPublic() {
|
||||
$this->addTestImageStyleMappings();
|
||||
$this->doTestResponsiveImageFieldFormatters('public');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters on node display for private files.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersPrivate() {
|
||||
$this->addTestImageStyleMappings();
|
||||
// Remove access content permission from anonymous users.
|
||||
user_role_change_permissions(RoleInterface::ANONYMOUS_ID, array('access content' => FALSE));
|
||||
$this->doTestResponsiveImageFieldFormatters('private');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test responsive image formatters when image style is empty.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersEmptyStyle() {
|
||||
$this->addTestImageStyleMappings(TRUE);
|
||||
$this->doTestResponsiveImageFieldFormatters('public', TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add image style mappings to the responsive image style entity.
|
||||
*
|
||||
* @param bool $empty_styles
|
||||
* If true, the image style mappings will get empty image styles.
|
||||
*/
|
||||
protected function addTestImageStyleMappings($empty_styles = FALSE) {
|
||||
if ($empty_styles) {
|
||||
$this->responsiveImgStyle
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => '',
|
||||
))
|
||||
->addImageStyleMapping('responsive_image_test_module.narrow', '1x', array(
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => array(
|
||||
'sizes' => '(min-width: 700px) 700px, 100vw',
|
||||
'sizes_image_styles' => array(),
|
||||
),
|
||||
))
|
||||
->addImageStyleMapping('responsive_image_test_module.wide', '1x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => '',
|
||||
))
|
||||
->save();
|
||||
}
|
||||
else {
|
||||
$this->responsiveImgStyle
|
||||
// Test the output of an empty image.
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => RESPONSIVE_IMAGE_EMPTY_IMAGE,
|
||||
))
|
||||
// Test the output with a 1.5x multiplier.
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1.5x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
))
|
||||
// Test the output of the 'sizes' attribute.
|
||||
->addImageStyleMapping('responsive_image_test_module.narrow', '1x', array(
|
||||
'image_mapping_type' => 'sizes',
|
||||
'image_mapping' => array(
|
||||
'sizes' => '(min-width: 700px) 700px, 100vw',
|
||||
'sizes_image_styles' => array(
|
||||
'large',
|
||||
'medium',
|
||||
),
|
||||
),
|
||||
))
|
||||
// Test the normal output of mapping to an image style.
|
||||
->addImageStyleMapping('responsive_image_test_module.wide', '1x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
))
|
||||
->save();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Test responsive image formatters on node display.
|
||||
*
|
||||
* If the empty styles param is set, then the function only tests for the
|
||||
* fallback image style (large).
|
||||
*
|
||||
* @param string $scheme
|
||||
* File scheme to use.
|
||||
* @param bool $empty_styles
|
||||
* If true, use an empty string for image style names.
|
||||
* Defaults to false.
|
||||
*/
|
||||
protected function doTestResponsiveImageFieldFormatters($scheme, $empty_styles = FALSE) {
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = $this->container->get('renderer');
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$field_name = Unicode::strtolower($this->randomMachineName());
|
||||
$this->createImageField($field_name, 'article', array('uri_scheme' => $scheme));
|
||||
// Create a new node with an image attached. Make sure we use a large image
|
||||
// so the scale effects of the image styles always have an effect.
|
||||
$test_image = current($this->drupalGetTestFiles('image', 39325));
|
||||
|
||||
// Create alt text for the image.
|
||||
$alt = $this->randomMachineName();
|
||||
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $alt);
|
||||
$node_storage->resetCache(array($nid));
|
||||
$node = $node_storage->load($nid);
|
||||
|
||||
// Test that the default formatter is being used.
|
||||
$image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
|
||||
$image = array(
|
||||
'#theme' => 'image',
|
||||
'#uri' => $image_uri,
|
||||
'#width' => 360,
|
||||
'#height' => 240,
|
||||
'#alt' => $alt,
|
||||
);
|
||||
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
|
||||
$this->assertRaw($default_output, 'Default formatter displaying correctly on full node view.');
|
||||
|
||||
// Use the responsive image formatter linked to file formatter.
|
||||
$display_options = array(
|
||||
'type' => 'responsive_image',
|
||||
'settings' => array(
|
||||
'image_link' => 'file',
|
||||
'responsive_image_style' => 'style_one',
|
||||
),
|
||||
);
|
||||
$display = entity_get_display('node', 'article', 'default');
|
||||
$display->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
$default_output = '<a href="' . file_create_url($image_uri) . '"><picture';
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
|
||||
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
|
||||
|
||||
$this->assertRaw($default_output, 'Image linked to file formatter displaying correctly on full node view.');
|
||||
// Verify that the image can be downloaded.
|
||||
$this->assertEqual(file_get_contents($test_image->uri), $this->drupalGet(file_create_url($image_uri)), 'File was downloaded successfully.');
|
||||
if ($scheme == 'private') {
|
||||
// Only verify HTTP headers when using private scheme and the headers are
|
||||
// sent by Drupal.
|
||||
$this->assertEqual($this->drupalGetHeader('Content-Type'), 'image/png', 'Content-Type header was sent.');
|
||||
$this->assertTrue(strstr($this->drupalGetHeader('Cache-Control'), 'private') !== FALSE, 'Cache-Control header was sent.');
|
||||
|
||||
// Log out and try to access the file.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet(file_create_url($image_uri));
|
||||
$this->assertResponse('403', 'Access denied to original image as anonymous user.');
|
||||
|
||||
// Log in again.
|
||||
$this->drupalLogin($this->adminUser);
|
||||
}
|
||||
|
||||
// Use the responsive image formatter with a responsive image style.
|
||||
$display_options['settings']['responsive_image_style'] = 'style_one';
|
||||
$display_options['settings']['image_link'] = '';
|
||||
$display->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
// Create a derivative so at least one MIME type will be known.
|
||||
$large_style = ImageStyle::load('large');
|
||||
$large_style->createDerivative($image_uri, $large_style->buildUri($image_uri));
|
||||
|
||||
// Output should contain all image styles and all breakpoints.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
if (!$empty_styles) {
|
||||
$this->assertRaw('/styles/medium/');
|
||||
// Make sure the IE9 workaround is present.
|
||||
$this->assertRaw('<!--[if IE 9]><video style="display: none;"><![endif]-->');
|
||||
$this->assertRaw('<!--[if IE 9]></video><![endif]-->');
|
||||
// Assert the empty image is present.
|
||||
$this->assertRaw('data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==');
|
||||
$thumbnail_style = ImageStyle::load('thumbnail');
|
||||
// Assert the output of the 'srcset' attribute (small multipliers first).
|
||||
$this->assertRaw('data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 1x, ' . $thumbnail_style->buildUrl($image_uri) . ' 1.5x');
|
||||
$this->assertRaw('/styles/medium/');
|
||||
// Assert the output of the breakpoints.
|
||||
$this->assertRaw('media="(min-width: 0px)"');
|
||||
$this->assertRaw('media="(min-width: 560px)"');
|
||||
// Assert the output of the 'sizes' attribute.
|
||||
$this->assertRaw('sizes="(min-width: 700px) 700px, 100vw"');
|
||||
$this->assertPattern('/media="\(min-width: 560px\)".+?sizes="\(min-width: 700px\) 700px, 100vw"/');
|
||||
// Assert the output of the 'srcset' attribute (small images first).
|
||||
$medium_style = ImageStyle::load('medium');
|
||||
$this->assertRaw($medium_style->buildUrl($image_uri) . ' 220w, ' . $large_style->buildUrl($image_uri) . ' 360w');
|
||||
$this->assertRaw('media="(min-width: 851px)"');
|
||||
}
|
||||
$this->assertRaw('/styles/large/');
|
||||
$cache_tags = explode(' ', $this->drupalGetHeader('X-Drupal-Cache-Tags'));
|
||||
$this->assertTrue(in_array('config:responsive_image.styles.style_one', $cache_tags));
|
||||
if (!$empty_styles) {
|
||||
$this->assertTrue(in_array('config:image.style.medium', $cache_tags));
|
||||
$this->assertTrue(in_array('config:image.style.thumbnail', $cache_tags));
|
||||
$this->assertRaw('type="image/png"');
|
||||
}
|
||||
$this->assertTrue(in_array('config:image.style.large', $cache_tags));
|
||||
|
||||
// Test the fallback image style.
|
||||
$image = \Drupal::service('image.factory')->get($image_uri);
|
||||
$fallback_image = array(
|
||||
'#theme' => 'image',
|
||||
'#alt' => $alt,
|
||||
'#srcset' => array(
|
||||
array(
|
||||
'uri' => $large_style->buildUrl($image->getSource()),
|
||||
),
|
||||
),
|
||||
);
|
||||
// The image.html.twig template has a newline after the <img> tag but
|
||||
// responsive-image.html.twig doesn't have one after the fallback image, so
|
||||
// we remove it here.
|
||||
$default_output = trim($renderer->renderRoot($fallback_image));
|
||||
$this->assertRaw($default_output, 'Image style large formatter displaying correctly on full node view.');
|
||||
|
||||
if ($scheme == 'private') {
|
||||
// Log out and try to access the file.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet($large_style->buildUrl($image_uri));
|
||||
$this->assertResponse('403', 'Access denied to image style large as anonymous user.');
|
||||
$cache_tags_header = $this->drupalGetHeader('X-Drupal-Cache-Tags');
|
||||
$this->assertTrue(!preg_match('/ image_style\:/', $cache_tags_header), 'No image style cache tag found.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters on node display linked to the file.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersLinkToFile() {
|
||||
$this->addTestImageStyleMappings();
|
||||
$this->assertResponsiveImageFieldFormattersLink('file');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters on node display linked to the node.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersLinkToNode() {
|
||||
$this->addTestImageStyleMappings();
|
||||
$this->assertResponsiveImageFieldFormattersLink('content');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatter on node display with an empty media query.
|
||||
*/
|
||||
public function testResponsiveImageFieldFormattersEmptyMediaQuery() {
|
||||
$this->responsiveImgStyle
|
||||
// Test the output of an empty media query.
|
||||
->addImageStyleMapping('responsive_image_test_module.empty', '1x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => RESPONSIVE_IMAGE_EMPTY_IMAGE,
|
||||
))
|
||||
// Test the output with a 1.5x multiplier.
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
))
|
||||
->save();
|
||||
$node_storage = $this->container->get('entity.manager')->getStorage('node');
|
||||
$field_name = Unicode::strtolower($this->randomMachineName());
|
||||
$this->createImageField($field_name, 'article', array('uri_scheme' => 'public'));
|
||||
// Create a new node with an image attached.
|
||||
$test_image = current($this->drupalGetTestFiles('image'));
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $this->randomMachineName());
|
||||
$node_storage->resetCache(array($nid));
|
||||
|
||||
// Use the responsive image formatter linked to file formatter.
|
||||
$display_options = array(
|
||||
'type' => 'responsive_image',
|
||||
'settings' => array(
|
||||
'image_link' => '',
|
||||
'responsive_image_style' => 'style_one',
|
||||
),
|
||||
);
|
||||
$display = entity_get_display('node', 'article', 'default');
|
||||
$display->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
// View the node.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
|
||||
// Assert an empty media attribute is not output.
|
||||
$this->assertNoPattern('@srcset="data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== 1x".+?media=".+?/><source@');
|
||||
|
||||
// Assert the media attribute is present if it has a value.
|
||||
$thumbnail_style = ImageStyle::load('thumbnail');
|
||||
$node = $node_storage->load($nid);
|
||||
$image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
|
||||
$this->assertPattern('/srcset="' . preg_quote($thumbnail_style->buildUrl($image_uri), '/') . ' 1x".+?media="\(min-width: 0px\)"/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests responsive image formatters linked to the file or node.
|
||||
*
|
||||
* @param string $link_type
|
||||
* The link type to test. Either 'file' or 'content'.
|
||||
*/
|
||||
private function assertResponsiveImageFieldFormattersLink($link_type) {
|
||||
$field_name = Unicode::strtolower($this->randomMachineName());
|
||||
$field_settings = array('alt_field_required' => 0);
|
||||
$this->createImageField($field_name, 'article', array('uri_scheme' => 'public'), $field_settings);
|
||||
// Create a new node with an image attached.
|
||||
$test_image = current($this->drupalGetTestFiles('image'));
|
||||
|
||||
// Test the image linked to file formatter.
|
||||
$display_options = array(
|
||||
'type' => 'responsive_image',
|
||||
'settings' => array(
|
||||
'image_link' => $link_type,
|
||||
'responsive_image_style' => 'style_one',
|
||||
),
|
||||
);
|
||||
entity_get_display('node', 'article', 'default')
|
||||
->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
// Ensure that preview works.
|
||||
$this->previewNodeImage($test_image, $field_name, 'article');
|
||||
|
||||
// Look for a picture tag in the preview output
|
||||
$this->assertPattern('/picture/');
|
||||
|
||||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article');
|
||||
$this->container->get('entity.manager')->getStorage('node')->resetCache(array($nid));
|
||||
$node = Node::load($nid);
|
||||
|
||||
// Use the responsive image formatter linked to file formatter.
|
||||
$display_options = array(
|
||||
'type' => 'responsive_image',
|
||||
'settings' => array(
|
||||
'image_link' => $link_type,
|
||||
'responsive_image_style' => 'style_one',
|
||||
),
|
||||
);
|
||||
entity_get_display('node', 'article', 'default')
|
||||
->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
// Create a derivative so at least one MIME type will be known.
|
||||
$large_style = ImageStyle::load('large');
|
||||
$image_uri = File::load($node->{$field_name}->target_id)->getFileUri();
|
||||
$large_style->createDerivative($image_uri, $large_style->buildUri($image_uri));
|
||||
|
||||
// Output should contain all image styles and all breakpoints.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
switch ($link_type) {
|
||||
case 'file':
|
||||
// Make sure the link to the file is present.
|
||||
$this->assertPattern('/<a(.*?)href="' . preg_quote(file_create_url($image_uri), '/') . '"(.*?)><picture/');
|
||||
break;
|
||||
|
||||
case 'content':
|
||||
// Make sure the link to the node is present.
|
||||
$this->assertPattern('/<a(.*?)href="' . preg_quote($node->url(), '/') . '"(.*?)><picture/');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\responsive_image\Tests\ResponsiveImageFieldUiTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\responsive_image\Tests;
|
||||
|
||||
|
||||
use Drupal\field_ui\Tests\FieldUiTestTrait;
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Tests the "Responsive Image" formatter settings form.
|
||||
*
|
||||
* @group responsive_image
|
||||
*/
|
||||
class ResponsiveImageFieldUiTest extends WebTestBase {
|
||||
|
||||
use FieldUiTestTrait;
|
||||
|
||||
/**
|
||||
* Modules to install.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('node', 'field_ui', 'image', 'responsive_image', 'responsive_image_test_module', 'block');
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->drupalPlaceBlock('system_breadcrumb_block');
|
||||
// Create a test user.
|
||||
$admin_user = $this->drupalCreateUser(array('access content', 'administer content types', 'administer node fields', 'administer node form display', 'administer node display', 'bypass node access'));
|
||||
$this->drupalLogin($admin_user);
|
||||
|
||||
// Create content type, with underscores.
|
||||
$type_name = strtolower($this->randomMachineName(8)) . '_test';
|
||||
$type = $this->drupalCreateContentType(array('name' => $type_name, 'type' => $type_name));
|
||||
$this->type = $type->id();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests formatter settings.
|
||||
*/
|
||||
function testResponsiveImageFormatterUI() {
|
||||
$manage_fields = 'admin/structure/types/manage/' . $this->type;
|
||||
$manage_display = $manage_fields . '/display';
|
||||
|
||||
// Create a field, and a node with some data for the field.
|
||||
$this->fieldUIAddNewField($manage_fields, 'image', 'Image field', 'image');
|
||||
// Display the "Manage display".
|
||||
$this->drupalGet($manage_display);
|
||||
|
||||
// Change the formatter and check that the summary is updated.
|
||||
$edit = array('fields[field_image][type]' => 'responsive_image', 'refresh_rows' => 'field_image');
|
||||
$this->drupalPostAjaxForm(NULL, $edit, array('op' => t('Refresh')));
|
||||
$this->assertText("Select a responsive image style.", 'The expected summary is displayed.');
|
||||
|
||||
// Submit the form.
|
||||
$this->drupalPostForm(NULL, array(), t('Save'));
|
||||
$this->assertText("Select a responsive image style.", 'The expected summary is displayed.');
|
||||
|
||||
// Create responsive image styles.
|
||||
$responsive_image_style = entity_create('responsive_image_style', array(
|
||||
'id' => 'style_one',
|
||||
'label' => 'Style One',
|
||||
'breakpoint_group' => 'responsive_image_test_module',
|
||||
'fallback_image_style' => 'thumbnail',
|
||||
));
|
||||
$responsive_image_style
|
||||
->addImageStyleMapping('responsive_image_test_module.mobile', '1x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'thumbnail',
|
||||
))
|
||||
->addImageStyleMapping('responsive_image_test_module.narrow', '1x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'medium'
|
||||
))
|
||||
// Test the normal output of mapping to an image style.
|
||||
->addImageStyleMapping('responsive_image_test_module.wide', '1x', array(
|
||||
'image_mapping_type' => 'image_style',
|
||||
'image_mapping' => 'large',
|
||||
))
|
||||
->save();
|
||||
\Drupal::entityManager()->clearCachedFieldDefinitions();
|
||||
// Refresh the page.
|
||||
$this->drupalGet($manage_display);
|
||||
$this->assertText("Select a responsive image style.", 'The expected summary is displayed.');
|
||||
|
||||
// Click on the formatter settings button to open the formatter settings
|
||||
// form.
|
||||
$this->drupalPostAjaxForm(NULL, array(), "field_image_settings_edit");
|
||||
|
||||
// Assert that the correct fields are present.
|
||||
$fieldnames = array(
|
||||
'fields[field_image][settings_edit_form][settings][responsive_image_style]',
|
||||
'fields[field_image][settings_edit_form][settings][image_link]',
|
||||
);
|
||||
foreach ($fieldnames as $fieldname) {
|
||||
$this->assertField($fieldname);
|
||||
}
|
||||
$edit = array(
|
||||
'fields[field_image][settings_edit_form][settings][responsive_image_style]' => 'style_one',
|
||||
'fields[field_image][settings_edit_form][settings][image_link]' => 'content',
|
||||
);
|
||||
$this->drupalPostAjaxForm(NULL, $edit, "field_image_plugin_settings_update");
|
||||
|
||||
// Save the form to save the settings.
|
||||
$this->drupalPostForm(NULL, array(), t('Save'));
|
||||
$this->assertText('Responsive image style: Style One');
|
||||
$this->assertText('Linked to content');
|
||||
|
||||
// Click on the formatter settings button to open the formatter settings
|
||||
// form.
|
||||
$this->drupalPostAjaxForm(NULL, array(), "field_image_settings_edit");
|
||||
$edit = array(
|
||||
'fields[field_image][settings_edit_form][settings][responsive_image_style]' => 'style_one',
|
||||
'fields[field_image][settings_edit_form][settings][image_link]' => 'file',
|
||||
);
|
||||
$this->drupalPostAjaxForm(NULL, $edit, "field_image_plugin_settings_update");
|
||||
|
||||
// Save the form to save the third party settings.
|
||||
$this->drupalPostForm(NULL, array(), t('Save'));
|
||||
$this->assertText('Responsive image style: Style One');
|
||||
$this->assertText('Linked to file');
|
||||
}
|
||||
|
||||
}
|
||||
Reference in a new issue