Commit d57d4e24 authored by webchick's avatar webchick

Issue #1775530 by attiks: Added Move picture into core.

parent 99e6cef6
......@@ -242,6 +242,9 @@ Path module
PHP module
- ?
Picture module
- Peter Droogmans 'attiks' http://drupal.org/user/105002
Poll module
- Andrei Mateescu 'amateescu' http://drupal.org/user/729614
......
<?php
/**
* @file
* Definition of Drupal\picture\PictureFormController.
*/
namespace Drupal\picture;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityFormController;
use Drupal\picture\PictureMapping;
/**
* Form controller for the picture edit/add forms.
*/
class PictureMappingFormController extends EntityFormController {
/**
* Overrides Drupal\Core\Entity\EntityFormController::form().
*
* @param array $form
* A nested array form elements comprising the form.
* @param array $form_state
* An associative array containing the current state of the form.
* @param \Drupal\picture\PictureMapping $picture_mapping
* The entity being edited.
*
* @return array
* The array containing the complete form.
*/
public function form(array $form, array &$form_state, EntityInterface $picture_mapping) {
$form['label'] = array(
'#type' => 'textfield',
'#title' => t('Label'),
'#maxlength' => 255,
'#default_value' => $picture_mapping->label(),
'#description' => t("Example: 'Hero image' or 'Author image'."),
'#required' => TRUE,
);
$form['id'] = array(
'#type' => 'machine_name',
'#default_value' => $picture_mapping->id(),
'#machine_name' => array(
'exists' => 'picture_mapping_load',
'source' => array('label'),
),
'#disabled' => (bool) $picture_mapping->id() && $this->operation != 'duplicate',
);
if ((bool) $picture_mapping->id() && $this->operation != 'duplicate') {
$description = t('Select a breakpoint group from the enabled themes.') . ' ' . t("Warning: if you change the breakpoint group you lose all you're selected mappings.");
}
else {
$description = t('Select a breakpoint group from the enabled themes.');
}
$form['breakpointGroup'] = array(
'#type' => 'select',
'#title' => t('Breakpoint Group'),
'#default_value' => !empty($picture_mapping->breakpointGroup) ? $picture_mapping->breakpointGroup->id() : '',
'#options' => breakpoint_group_select_options(),
'#required' => TRUE,
'#description' => $description,
);
$image_styles = image_style_options(TRUE);
foreach ($picture_mapping->mappings as $breakpoint_id => $mapping) {
foreach ($mapping as $multiplier => $image_style) {
$label = $multiplier . ' ' . $picture_mapping->breakpointGroup->breakpoints[$breakpoint_id]->name . ' [' . $picture_mapping->breakpointGroup->breakpoints[$breakpoint_id]->mediaQuery . ']';
$form['mappings'][$breakpoint_id][$multiplier] = array(
'#type' => 'select',
'#title' => check_plain($label),
'#options' => $image_styles,
'#default_value' => $image_style,
'#description' => t('Select an image style for this breakpoint.'),
);
}
}
$form['#tree'] = TRUE;
return parent::form($form, $form_state, $picture_mapping);
}
/**
* Overrides Drupal\Core\Entity\EntityFormController::actions().
*/
protected function actions(array $form, array &$form_state) {
// Only includes a Save action for the entity, no direct Delete button.
return array(
'submit' => array(
'#value' => t('Save'),
'#validate' => array(
array($this, 'validate'),
),
'#submit' => array(
array($this, 'submit'),
array($this, 'save'),
),
),
);
}
/**
* Overrides Drupal\Core\Entity\EntityFormController::validate().
*/
public function validate(array $form, array &$form_state) {
$picture_mapping = $this->getEntity($form_state);
// Only validate on edit.
if (isset($form_state['values']['mappings'])) {
$picture_mapping->mappings = $form_state['values']['mappings'];
// Check if another breakpoint group is selected.
if ($form_state['values']['breakpointGroup'] != $form_state['complete_form']['breakpointGroup']['#default_value']) {
// Remove the mappings.
unset($form_state['values']['mappings']);
}
// Make sure at least one mapping is defined.
elseif (!$picture_mapping->isNew() && !$picture_mapping->hasMappings()) {
form_set_error('mappings', t('Please select at least one mapping.'));
}
}
}
/**
* Overrides Drupal\Core\Entity\EntityFormController::save().
*/
public function save(array $form, array &$form_state) {
$picture_mapping = $this->getEntity($form_state);
$picture_mapping->save();
watchdog('picture', 'Picture mapping @label saved.', array('@label' => $picture_mapping->label()), WATCHDOG_NOTICE);
drupal_set_message(t('Picture mapping %label saved.', array('%label' => $picture_mapping->label())));
// Redirect to edit form after creating a new mapping or after selecting
// another breakpoint group.
if (!$picture_mapping->hasMappings()) {
$uri = $picture_mapping->uri();
$form_state['redirect'] = $uri['path'] . '/edit';
}
else {
$form_state['redirect'] = 'admin/config/media/picturemapping';
}
}
}
<?php
/**
* @file
* Definition of Drupal\picture\PictureListController.
*/
namespace Drupal\picture;
use Drupal\Core\Config\Entity\ConfigEntityListController;
use Drupal\Core\Entity\EntityInterface;
use Drupal\picture\PictureMapping;
/**
* Provides a listing of Pictures.
*/
class PictureMappingListController extends ConfigEntityListController {
/**
* Overrides Drupal\config\EntityListControllerBase::hookMenu().
*/
public function hookMenu() {
$path = $this->entityInfo['list path'];
$items = parent::hookMenu();
// Override the access callback.
$items[$path]['title'] = 'Picture Mappings';
$items[$path]['description'] = 'Manage list of picture mappings.';
$items[$path]['access callback'] = 'user_access';
$items[$path]['access arguments'] = array('administer pictures');
return $items;
}
/**
* Overrides Drupal\config\ConfigEntityListController::getOperations();
*/
public function getOperations(EntityInterface $entity) {
$operations = parent::getOperations($entity);
$uri = $entity->uri();
$operations['duplicate'] = array(
'title' => t('Duplicate'),
'href' => $uri['path'] . '/duplicate',
'options' => $uri['options'],
'weight' => 15,
);
return $operations;
}
}
<?php
/**
* @file
* Definition of Drupal\picture\PictureMapping.
*/
namespace Drupal\picture\Plugin\Core\Entity;
use Drupal\Core\Config\Entity\ConfigEntityBase;
use Drupal\Core\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
/**
* Defines the Picture entity.
*
* @Plugin(
* id = "picture_mapping",
* label = @Translation("Picture mapping"),
* module = "picture",
* controller_class = "Drupal\Core\Config\Entity\ConfigStorageController",
* form_controller_class = {
* "default" = "Drupal\picture\PictureMappingFormController",
* "add" = "Drupal\picture\PictureMappingFormController",
* "duplicate" = "Drupal\picture\PictureMappingFormController"
* },
* list_controller_class = "Drupal\picture\PictureMappingListController",
* list_path = "admin/config/media/picturemapping",
* uri_callback = "picture_mapping_uri",
* config_prefix = "picture.mappings",
* entity_keys = {
* "id" = "id",
* "label" = "label",
* "uuid" = "uuid"
* }
* )
*/
class PictureMapping extends ConfigEntityBase {
/**
* The picture ID (machine name).
*
* @var string
*/
public $id;
/**
* The picture UUID.
*
* @var string
*/
public $uuid;
/**
* The picture label.
*
* @var string
*/
public $label;
/**
* The picture mappings.
*
* @var array
*/
public $mappings = array();
/**
* The picture breakpoint group.
*
* @var BreakpointGroup
*/
public $breakpointGroup = '';
/**
* Overrides Drupal\config\ConfigEntityBase::__construct().
*/
public function __construct(array $values, $entity_type) {
parent::__construct($values, $entity_type);
$this->loadBreakpointGroup();
$this->loadAllMappings();
}
/**
* Overrides Drupal\Core\Entity::save().
*/
public function save() {
// Only save the keys, but return the full objects.
if (isset($this->breakpointGroup) && is_object($this->breakpointGroup)) {
$this->breakpointGroup = $this->breakpointGroup->id();
}
parent::save();
$this->loadBreakpointGroup();
$this->loadAllMappings();
}
/**
* Implements EntityInterface::createDuplicate().
*/
public function createDuplicate() {
return entity_create('picture_mapping', array(
'id' => '',
'label' => t('Clone of !label', array('!label' => check_plain($this->label()))),
'mappings' => $this->mappings,
));
}
/**
* Load breakpoint group.
*/
protected function loadBreakpointGroup() {
if ($this->breakpointGroup) {
$breakpoint_group = entity_load('breakpoint_group', $this->breakpointGroup);
$this->breakpointGroup = $breakpoint_group;
}
}
/**
* Load all mappings, remove non-existing ones.
*/
protected function loadAllMappings() {
$loaded_mappings = $this->mappings;
$this->mappings = array();
if ($this->breakpointGroup) {
foreach ($this->breakpointGroup->breakpoints as $breakpoint_id => $breakpoint) {
// Get the mapping for the default multiplier.
$this->mappings[$breakpoint_id]['1x'] = '';
if (isset($loaded_mappings[$breakpoint_id]['1x'])) {
$this->mappings[$breakpoint_id]['1x'] = $loaded_mappings[$breakpoint_id]['1x'];
}
// Get the mapping for the other multipliers.
if (isset($breakpoint->multipliers) && !empty($breakpoint->multipliers)) {
foreach ($breakpoint->multipliers as $multiplier => $status) {
if ($status) {
$this->mappings[$breakpoint_id][$multiplier] = '';
if (isset($loaded_mappings[$breakpoint_id][$multiplier])) {
$this->mappings[$breakpoint_id][$multiplier] = $loaded_mappings[$breakpoint_id][$multiplier];
}
}
}
}
}
}
}
/**
* Check if there's at least one mapping defined.
*/
public function hasMappings() {
$mapping_found = FALSE;
foreach ($this->mappings as $breakpoint => $multipliers) {
$filtered_array = array_filter($multipliers);
if (!empty($filtered_array)) {
$mapping_found = TRUE;
break;
}
}
return $mapping_found;
}
}
<?php
/**
* @file
* Definition of Drupal\picture\Plugin\field\formatter\PictureFormatter.
*/
namespace Drupal\picture\Plugin\field\formatter;
use Drupal\Core\Annotation\Plugin;
use Drupal\Core\Annotation\Translation;
use Drupal\field\Plugin\Type\Formatter\FormatterBase;
use Drupal\Core\Entity\EntityInterface;
/**
* Plugin for picture formatter.
*
* @Plugin(
* id = "picture",
* module = "picture",
* label = @Translation("Picture"),
* field_types = {
* "image",
* },
* settings = {
* "picture_mapping" = "",
* "fallback_image_style" = "",
* "image_link" = "",
* }
* )
*/
class PictureFormatter extends FormatterBase {
/**
* Implements Drupal\field\Plugin\Type\Formatter\FormatterInterface::settingsForm().
*/
public function settingsForm(array $form, array &$form_state) {
$picture_options = array();
$picture_mappings = entity_load_multiple('picture_mapping');
if ($picture_mappings && !empty($picture_mappings)) {
foreach ($picture_mappings as $machine_name => $picture_mapping) {
if ($picture_mapping->hasMappings()) {
$picture_options[$machine_name] = $picture_mapping->label();
}
}
}
$elements['picture_mapping'] = array(
'#title' => t('Picture mapping'),
'#type' => 'select',
'#default_value' => $this->getSetting('picture_mapping'),
'#required' => TRUE,
'#options' => $picture_options,
);
$image_styles = image_style_options(FALSE);
$elements['fallback_image_style'] = array(
'#title' => t('Fallback image style'),
'#type' => 'select',
'#default_value' => $this->getSetting('fallback_image_style'),
'#empty_option' => t('Automatic'),
'#options' => $image_styles,
);
$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;
}
/**
* Implements Drupal\field\Plugin\Type\Formatter\FormatterInterface::settingsForm().
*/
public function settingsSummary() {
$summary = array();
$picture_mapping = entity_load('picture_mapping', $this->getSetting('picture_mapping'));
if ($picture_mapping) {
$summary[] = t('Picture mapping: @picture_mapping', array('@picture_mapping' => $picture_mapping->label()));
$image_styles = image_style_options(FALSE);
unset($image_styles['']);
if (isset($image_styles[$this->getSetting('fallback_image_style')])) {
$summary[] = t('Fallback Image style: @style', array('@style' => $image_styles[$this->getSetting('fallback_image_style')]));
}
else {
$summary[] = t('Automatic fallback');
}
$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('Please select a picture mapping');
}
return implode('<br />', $summary);
}
/**
* Implements Drupal\field\Plugin\Type\Formatter\FormatterInterface::viewElements().
*/
public function viewElements(EntityInterface $entity, $langcode, array $items) {
$elements = array();
// Check if the formatter involves a link.
if ($this->getSetting('image_link') == 'content') {
$uri = $entity->uri();
}
elseif ($this->getSetting('image_link') == 'file') {
$link_file = TRUE;
}
$breakpoint_styles = array();
$fallback_image_style = '';
$picture_mapping = entity_load('picture_mapping', $this->getSetting('picture_mapping'));
if ($picture_mapping) {
foreach ($picture_mapping->mappings as $breakpoint_name => $multipliers) {
// Make sure there are multipliers.
if (!empty($multipliers)) {
// Make sure that the breakpoint exists and is enabled.
// @todo add the following when breakpoint->status is added again:
// $picture_mapping->breakpointGroup->breakpoints[$breakpoint_name]->status
if (isset($picture_mapping->breakpointGroup->breakpoints[$breakpoint_name])) {
$breakpoint = $picture_mapping->breakpointGroup->breakpoints[$breakpoint_name];
// Determine the enabled multipliers.
$multipliers = array_intersect_key($multipliers, $breakpoint->multipliers);
foreach ($multipliers as $multiplier => $image_style) {
// Make sure the multiplier still exists.
//if (!empty(array_intersect($multiplier, $breakpoint->multipliers))) {
if (!empty($image_style)) {
// First mapping found is used as fallback.
if (empty($fallback_image_style)) {
$fallback_image_style = $image_style;
}
if (!isset($breakpoint_styles[$breakpoint_name])) {
$breakpoint_styles[$breakpoint_name] = array();
}
$breakpoint_styles[$breakpoint_name][$multiplier] = $image_style;
}
}
}
}
}
}
// Check if the user defined a custom fallback image style.
if ($this->getSetting('fallback_image_style')) {
$fallback_image_style = $this->getSetting('fallback_image_style');
}
foreach ($items as $delta => $item) {
if (isset($link_file)) {
$uri = array(
'path' => file_create_url($item['uri']),
'options' => array(),
);
}
$elements[$delta] = array(
'#theme' => 'picture_formatter',
'#attached' => array('library' => array(
array('picture', 'picturefill'),
)),
'#item' => $item,
'#image_style' => $fallback_image_style,
'#breakpoints' => $breakpoint_styles,
'#path' => isset($uri) ? $uri : '',
);
}
return $elements;
}
}
<?php
/**
* @file
* Definition of Drupal\picture\Tests\PictureAdminUITest.
*/
namespace Drupal\picture\Tests;
use Drupal\simpletest\WebTestBase;
use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
/**
* Tests for breakpoint sets admin interface.
*/
class PictureAdminUITest extends WebTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = array('picture');
/**
* Drupal\simpletest\WebTestBase\getInfo().
*/
public static function getInfo() {
return array(
'name' => 'Picture administration functionality',
'description' => 'Thoroughly test the administrative interface of the picture module.',
'group' => 'Picture',
);
}
/**
* Drupal\simpletest\WebTestBase\setUp().
*/
public function setUp() {
parent::setUp();
// Create user.
$this->admin_user = $this->drupalCreateUser(array(
'administer pictures',
));
$this->drupalLogin($this->admin_user);
// Add breakpoint_group and breakpoints.
$breakpoint_group = entity_create('breakpoint_group', array(
'id' => 'atestset',
'label' => 'A test set',
'sourceType' => Breakpoint::SOURCE_TYPE_USER_DEFINED,
));
$breakpoints = array();
$breakpoint_names = array('small', 'medium', 'large');
for ($i = 0; $i < 3; $i++) {
$width = ($i + 1) * 200;
$breakpoint = entity_create('breakpoint', array(
'name' => $breakpoint_names[$i],
'mediaQuery' => "(min-width: {$width}px)",
'source' => 'user',
'sourceType' => Breakpoint::SOURCE_TYPE_USER_DEFINED,
'multipliers' => array(
'1.5x' => 0,
'2x' => '2x',
),
));
$breakpoint->save();
$breakpoint_group->breakpoints[$breakpoint->id()] = $breakpoint;
}
$breakpoint_group->save();
}
/**
* Test picture administration functionality.
*/
public function testPictureAdmin() {
// We start without any default mappings.
$this->drupalGet('admin/config/media/picturemapping');
$this->assertText('There is no Picture mapping yet.');
// Add a new picture mapping, our breakpoint set should be selected.
$this->drupalGet('admin/config/media/picturemapping/add');
$this->assertFieldByName('breakpointGroup', 'atestset');
// Create a new group.
$edit = array(
'label' => 'Mapping One',
'id' => 'mapping_one',
'breakpointGroup' => 'atestset',
);
$this->drupalPost('admin/config/media/picturemapping/add', $edit, t('Save'));
// Check if the new group is created.
$this->assertResponse(200);
$this->drupalGet('admin/config/media/picturemapping');
$this->assertNoText('There is no Picture mapping yet.');
$this->assertText('Mapping One');
$this->assertText('mapping_one');
// Edit the group.
$this->drupalGet('admin/config/media/picturemapping/mapping_one/edit');
$this->assertFieldByName('label', 'Mapping One');
$this->assertFieldByName('breakpointGroup', 'atestset');
// Check if the dropdows are present for the mappings.
$this->assertFieldByName('mappings[custom.user.small][1x]', '');
$this->assertFieldByName('mappings[custom.user.small][2x]', '');
$this->assertFieldByName('mappings[custom.user.medium][1x]', '');
$this->assertFieldByName('mappings[custom.user.medium][2x]', '');
$this->assertFieldByName('mappings[custom.user.large][1x]', '');
$this->assertFieldByName('mappings[custom.user.large][2x]', '');
// Save mappings for 1x variant only.
$edit = array(
'label' => 'Mapping One',
'breakpointGroup' => 'atestset',
'mappings[custom.user.small][1x]' => 'thumbnail',
'mappings[custom.user.medium][1x]' => 'medium',
'mappings[custom.user.large][1x]' => 'large',
);
$this->drupalPost('admin/config/media/picturemapping/mapping_one/edit', $edit, t('Save'));
$this->drupalGet('admin/config/media/picturemapping/mapping_one/edit');
$this->assertFieldByName('mappings[custom.user.small][1x]', 'thumbnail');
$this->assertFieldByName('mappings[custom.user.small][2x]', '');
$this->assertFieldByName('mappings[custom.user.medium][1x]', 'medium');