Commit 9008a595 authored by alexpott's avatar alexpott
Browse files

Issue #1443606 by claudiu.cristea: Alt, title, width and height for default images.

parent a464d065
...@@ -58,6 +58,17 @@ function image_requirements($phase) { ...@@ -58,6 +58,17 @@ function image_requirements($phase) {
return $requirements; return $requirements;
} }
/**
* Implements hook_update_dependencies().
*/
function image_update_dependencies() {
// Convert image field and instance setting 'default_image' from integer to
// array only after fields and instances were converted to config.
$dependencies['image'][8003] = array('field' => 8006);
return $dependencies;
}
/** /**
* Loads all effects for an image style from backend. * Loads all effects for an image style from backend.
* *
...@@ -237,3 +248,42 @@ function image_update_8002() { ...@@ -237,3 +248,42 @@ function image_update_8002() {
'image_style_preview_image' => 'preview_image', 'image_style_preview_image' => 'preview_image',
)); ));
} }
/**
* Convert image field and instance setting 'default_image' from integer to
* array by adding alt, title, width, and height options.
*/
function image_update_8003() {
$image_factory = \Drupal::service('image.factory');
foreach (array('field', 'instance') as $type) {
$prefix = "field.$type";
foreach (config_get_storage_names_with_prefix($prefix) as $config_id) {
$config = \Drupal::config($config_id);
$is_image = ($type == 'field' && $config->get('type') == 'image') || ($type == 'instance' && $config->get('field_type') == 'image');
// Not dealing with an image field or image field instance?
if (!$is_image) {
continue;
}
$width = 0;
$height = 0;
if ($fid = (int) $config->get('settings.default_image')) {
$uri = db_query('SELECT fid FROM {file_managed} WHERE fid = :fid', array(':fid' => $fid))->fetchField();
if ($uri) {
$image = $image_factory->get($uri);
$width = $image->getWidth();
$height = $image->getHeight();
}
}
$default_image = array(
'fid' => $fid ?: NULL,
'alt' => '',
'title' => '',
'width' => $width ?: NULL,
'height' => $height ?: NULL,
);
$config
->set('settings.default_image', $default_image)
->save();
}
}
}
...@@ -424,14 +424,31 @@ function image_entity_presave(EntityInterface $entity, $type) { ...@@ -424,14 +424,31 @@ function image_entity_presave(EntityInterface $entity, $type) {
elseif ($entity instanceof Field) { elseif ($entity instanceof Field) {
$field = $entity; $field = $entity;
} }
if ($field && $field->type == 'image' && is_array($entity->settings['default_image'])) { // Exit, if not saving an image field or image field instance entity.
if (!empty($entity->settings['default_image'][0])) { if (!$field || $field->type != 'image') {
$entity->settings['default_image'] = $entity->settings['default_image'][0]; return;
} }
else {
$entity->settings['default_image'] = 0; if (!empty($entity->settings['default_image']['fid'][0])) {
$entity->settings['default_image']['fid'] = $entity->settings['default_image']['fid'][0];
}
if ($fid = $entity->settings['default_image']['fid']) {
$original_fid = isset($entity->original) ? $entity->original->settings['default_image']['fid'] : NULL;
if ($fid != $original_fid) {
$image = \Drupal::service('image.factory')->get(file_load($fid)->getFileUri());
$entity->settings['default_image']['width'] = $image->getWidth();
$entity->settings['default_image']['height'] = $image->getHeight();
} }
} }
else {
$entity->settings['default_image'] = array(
'fid' => NULL,
'alt' => '',
'title' => '',
'width' => NULL,
'height' => NULL,
);
}
} }
/** /**
...@@ -446,10 +463,11 @@ function image_field_entity_update(FieldInterface $field) { ...@@ -446,10 +463,11 @@ function image_field_entity_update(FieldInterface $field) {
$prior_field = $field->original; $prior_field = $field->original;
// The value of a managed_file element can be an array if #extended == TRUE. // The value of a managed_file element can be an array if #extended == TRUE.
$fid_new = (isset($field->settings['default_image']['fids']) ? $field->settings['default_image']['fids'] : $field->settings['default_image']); $fid_new = isset($field->settings['default_image']['fid']['fids']) ? $field->settings['default_image']['fid']['fids'] : $field->settings['default_image']['fid'];
$fid_old = (isset($prior_field->settings['default_image']['fids']) ? $prior_field->settings['default_image']['fids'] : $prior_field->settings['default_image']); $fid_old = isset($prior_field->settings['default_image']['fid']['fids']) ? $prior_field->settings['default_image']['fid']['fids'] : $prior_field->settings['default_image']['fid'];
// Ensure sure that fid_new and old are arrays, because default_image might // Ensure that $fid_new and $fid_old are arrays, because the field setting
// be the fallback value 0, see image_field_info(). // 'default_image' key 'fid' might be the fallback value 0, see the annotation
// block of \Drupal\image\Plugin\Field\FieldType\ImageItem.
$fid_old = (array) $fid_old; $fid_old = (array) $fid_old;
$fid_new = (array) $fid_new; $fid_new = (array) $fid_new;
...@@ -492,11 +510,11 @@ function image_field_instance_update(FieldInstanceInterface $field_instance) { ...@@ -492,11 +510,11 @@ function image_field_instance_update(FieldInstanceInterface $field_instance) {
// The value of a managed_file element can be an array if the #extended // The value of a managed_file element can be an array if the #extended
// property is set to TRUE. // property is set to TRUE.
$fid_new = $field_instance->settings['default_image']; $fid_new = $field_instance->settings['default_image']['fid'];
if (isset($fid_new['fids'])) { if (isset($fid_new['fids'])) {
$fid_new = $fid_new['fids']; $fid_new = $fid_new['fids'];
} }
$fid_old = $prior_instance->settings['default_image']; $fid_old = $prior_instance->settings['default_image']['fid'];
if (isset($fid_old['fids'])) { if (isset($fid_old['fids'])) {
$fid_old = $fid_old['fids']; $fid_old = $fid_old['fids'];
} }
...@@ -534,7 +552,7 @@ function image_field_entity_delete(FieldInterface $field) { ...@@ -534,7 +552,7 @@ function image_field_entity_delete(FieldInterface $field) {
} }
// The value of a managed_file element can be an array if #extended == TRUE. // The value of a managed_file element can be an array if #extended == TRUE.
$fid = (isset($field->settings['default_image']['fids']) ? $field->settings['default_image']['fids'] : $field->settings['default_image']); $fid = (isset($field->settings['default_image']['fid']['fids']) ? $field->settings['default_image']['fid']['fids'] : $field->settings['default_image']['fid']);
if ($fid && ($file = file_load($fid[0]))) { if ($fid && ($file = file_load($fid[0]))) {
file_usage()->delete($file, 'image', 'default_image', $field->uuid); file_usage()->delete($file, 'image', 'default_image', $field->uuid);
} }
...@@ -552,7 +570,7 @@ function image_field_instance_delete(FieldInstanceInterface $field_instance) { ...@@ -552,7 +570,7 @@ function image_field_instance_delete(FieldInstanceInterface $field_instance) {
// The value of a managed_file element can be an array if the #extended // The value of a managed_file element can be an array if the #extended
// property is set to TRUE. // property is set to TRUE.
$fid = $field_instance->settings['default_image']; $fid = $field_instance->settings['default_image']['fid'];
if (is_array($fid)) { if (is_array($fid)) {
$fid = $fid['fid']; $fid = $fid['fid'];
} }
......
...@@ -25,18 +25,20 @@ public function prepareView(array $entities_items) { ...@@ -25,18 +25,20 @@ public function prepareView(array $entities_items) {
foreach ($entities_items as $items) { foreach ($entities_items as $items) {
if ($items->isEmpty()) { if ($items->isEmpty()) {
// Add the default image if one is found. // Add the default image if one is found.
$fid = $this->getFieldSetting('default_image'); $default_image = $this->getFieldSetting('default_image');
// If we are dealing with a configurable field, look in both // If we are dealing with a configurable field, look in both
// instance-level and field-level settings. // instance-level and field-level settings.
if (empty($fid) && $this->fieldDefinition instanceof FieldInstanceInterface) { if (empty($default_image['fid']) && $this->fieldDefinition instanceof FieldInstanceInterface) {
$fid = $this->fieldDefinition->getField()->getFieldSetting('default_image'); $default_image = $this->fieldDefinition->getField()->getFieldSetting('default_image');
} }
if ($fid && ($file = file_load($fid))) { if (!empty($default_image['fid']) && ($file = file_load($default_image['fid']))) {
$items->setValue(array(array( $items->setValue(array(array(
'is_default' => TRUE, 'is_default' => TRUE,
'alt' => '', 'alt' => $default_image['alt'],
'title' => '', 'title' => $default_image['title'],
'width' => $default_image['width'],
'height' => $default_image['height'],
'entity' => $file, 'entity' => $file,
'target_id' => $file->id(), 'target_id' => $file->id(),
))); )));
......
...@@ -19,7 +19,13 @@ ...@@ -19,7 +19,13 @@
* description = @Translation("This field stores the ID of an image file as an integer value."), * description = @Translation("This field stores the ID of an image file as an integer value."),
* settings = { * settings = {
* "uri_scheme" = "", * "uri_scheme" = "",
* "default_image" = "0", * "default_image" = {
* "fid" = NULL,
* "alt" = "",
* "title" = "",
* "width" = NULL,
* "height" = NULL
* },
* "column_groups" = { * "column_groups" = {
* "file" = { * "file" = {
* "label" = @Translation("File"), * "label" = @Translation("File"),
...@@ -45,7 +51,13 @@ ...@@ -45,7 +51,13 @@
* "title_field_required" = "0", * "title_field_required" = "0",
* "max_resolution" = "", * "max_resolution" = "",
* "min_resolution" = "", * "min_resolution" = "",
* "default_image" = "0" * "default_image" = {
* "fid" = NULL,
* "alt" = "",
* "title" = "",
* "width" = NULL,
* "height" = NULL
* }
* }, * },
* default_widget = "image_image", * default_widget = "image_image",
* default_formatter = "image", * default_formatter = "image",
...@@ -153,13 +165,9 @@ public function settingsForm(array $form, array &$form_state, $has_data) { ...@@ -153,13 +165,9 @@ public function settingsForm(array $form, array &$form_state, $has_data) {
'#description' => t('Select where the final files should be stored. Private file storage has significantly more overhead than public files, but allows restricted access to files within this field.'), '#description' => t('Select where the final files should be stored. Private file storage has significantly more overhead than public files, but allows restricted access to files within this field.'),
); );
$element['default_image'] = array( // Add default_image element.
'#title' => t('Default image'), static::defaultImageForm($element, $settings);
'#type' => 'managed_file', $element['default_image']['#description'] = t('If no image is uploaded, this image will be shown on display.');
'#description' => t('If no image is uploaded, this image will be shown on display.'),
'#default_value' => empty($settings['default_image']) ? array() : array($settings['default_image']),
'#upload_location' => $settings['uri_scheme'] . '://default_images/',
);
return $element; return $element;
} }
...@@ -269,14 +277,9 @@ public function instanceSettingsForm(array $form, array &$form_state) { ...@@ -269,14 +277,9 @@ public function instanceSettingsForm(array $form, array &$form_state) {
), ),
); );
// Add the default image to the instance. // Add default_image element.
$element['default_image'] = array( static::defaultImageForm($element, $settings);
'#title' => t('Default image'), $element['default_image']['#description'] = t("If no image is uploaded, this image will be shown on display and will override the field's default image.");
'#type' => 'managed_file',
'#description' => t("If no image is uploaded, this image will be shown on display and will override the field's default image."),
'#default_value' => empty($settings['default_image']) ? array() : array($settings['default_image']),
'#upload_location' => $settings['uri_scheme'] . '://default_images/',
);
return $element; return $element;
} }
...@@ -316,6 +319,51 @@ public static function validateResolution($element, &$form_state) { ...@@ -316,6 +319,51 @@ public static function validateResolution($element, &$form_state) {
} }
} }
/**
* Builds the default_image details element.
*
* @param array $element
* The form associative array passed by reference.
* @param array $settings
* The field settings array.
*/
protected function defaultImageForm(array &$element, array $settings) {
$element['default_image'] = array(
'#type' => 'details',
'#title' => t('Default image'),
'#open' => TRUE,
);
$element['default_image']['fid'] = array(
'#type' => 'managed_file',
'#title' => t('Image'),
'#description' => t('Image to be shown if no image is uploaded.'),
'#default_value' => empty($settings['default_image']['fid']) ? array() : array($settings['default_image']['fid']),
'#upload_location' => $settings['uri_scheme'] . '://default_images/',
);
$element['default_image']['alt'] = array(
'#type' => 'textfield',
'#title' => t('Alternate text'),
'#description' => t('This text will be used by screen readers, search engines, and when the image cannot be loaded.'),
'#default_value' => $settings['default_image']['alt'],
'#maxlength' => 512,
);
$element['default_image']['title'] = array(
'#type' => 'textfield',
'#title' => t('Title'),
'#description' => t('The title attribute is used as a tooltip when the mouse hovers over the image.'),
'#default_value' => $settings['default_image']['title'],
'#maxlength' => 1024,
);
$element['default_image']['width'] = array(
'#type' => 'value',
'#value' => $settings['default_image']['width'],
);
$element['default_image']['height'] = array(
'#type' => 'value',
'#value' => $settings['default_image']['height'],
);
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
......
...@@ -42,11 +42,19 @@ public function testDefaultImages() { ...@@ -42,11 +42,19 @@ public function testDefaultImages() {
// Create an image field and add an instance to the article content type. // Create an image field and add an instance to the article content type.
$field_name = strtolower($this->randomName()); $field_name = strtolower($this->randomName());
$field_settings = array( $field_settings['default_image'] = array(
'default_image' => $default_images['field']->id(), 'fid' => $default_images['field']->id(),
'alt' => '',
'title' => '',
'width' => 0,
'height' => 0,
); );
$instance_settings = array( $instance_settings['default_image'] = array(
'default_image' => $default_images['instance']->id(), 'fid' => $default_images['instance']->id(),
'alt' => '',
'title' => '',
'width' => 0,
'height' => 0,
); );
$widget_settings = array( $widget_settings = array(
'preview_image_style' => 'medium', 'preview_image_style' => 'medium',
...@@ -54,20 +62,22 @@ public function testDefaultImages() { ...@@ -54,20 +62,22 @@ public function testDefaultImages() {
$instance = $this->createImageField($field_name, 'article', $field_settings, $instance_settings, $widget_settings); $instance = $this->createImageField($field_name, 'article', $field_settings, $instance_settings, $widget_settings);
// The instance default image id should be 2. // The instance default image id should be 2.
$this->assertEqual($instance->getFieldSetting('default_image'), $default_images['instance']->id()); $default_image = $instance->getFieldSetting('default_image');
$this->assertEqual($default_image['fid'], $default_images['instance']->id());
// Also test \Drupal\field\Entity\FieldInstance::getFieldSetting(). // Also test \Drupal\field\Entity\FieldInstance::getFieldSetting().
$instance_field_settings = $instance->getFieldSettings(); $instance_field_settings = $instance->getFieldSettings();
$this->assertEqual($instance_field_settings['default_image'], $default_images['instance']->id()); $this->assertEqual($instance_field_settings['default_image']['fid'], $default_images['instance']->id());
$field = $instance->getField(); $field = $instance->getField();
// The field default image id should be 1. // The field default image id should be 1.
$this->assertEqual($field->getFieldSetting('default_image'), $default_images['field']->id()); $default_image = $field->getFieldSetting('default_image');
$this->assertEqual($default_image['fid'], $default_images['field']->id());
// Also test \Drupal\field\Entity\Field::getFieldSettings(). // Also test \Drupal\field\Entity\Field::getFieldSettings().
$field_field_settings = $field->getFieldSettings(); $field_field_settings = $field->getFieldSettings();
$this->assertEqual($field_field_settings['default_image'], $default_images['field']->id()); $this->assertEqual($field_field_settings['default_image']['fid'], $default_images['field']->id());
// Add another instance with another default image to the page content type. // Add another instance with another default image to the page content type.
$instance2 = entity_create('field_instance', array( $instance2 = entity_create('field_instance', array(
...@@ -77,7 +87,13 @@ public function testDefaultImages() { ...@@ -77,7 +87,13 @@ public function testDefaultImages() {
'label' => $instance->label(), 'label' => $instance->label(),
'required' => $instance->required, 'required' => $instance->required,
'settings' => array( 'settings' => array(
'default_image' => $default_images['instance2']->id(), 'default_image' => array(
'fid' => $default_images['instance2']->id(),
'alt' => '',
'title' => '',
'width' => 0,
'height' => 0,
),
), ),
)); ));
$instance2->save(); $instance2->save();
...@@ -93,7 +109,7 @@ public function testDefaultImages() { ...@@ -93,7 +109,7 @@ public function testDefaultImages() {
// Confirm the defaults are present on the article field settings form. // Confirm the defaults are present on the article field settings form.
$this->drupalGet("admin/structure/types/manage/article/fields/$instance->id/field"); $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id/field");
$this->assertFieldByXpath( $this->assertFieldByXpath(
'//input[@name="field[settings][default_image][fids]"]', '//input[@name="field[settings][default_image][fid][fids]"]',
$default_images['field']->id(), $default_images['field']->id(),
format_string( format_string(
'Article image field default equals expected file ID of @fid.', 'Article image field default equals expected file ID of @fid.',
...@@ -103,7 +119,7 @@ public function testDefaultImages() { ...@@ -103,7 +119,7 @@ public function testDefaultImages() {
// Confirm the defaults are present on the article field edit form. // Confirm the defaults are present on the article field edit form.
$this->drupalGet("admin/structure/types/manage/article/fields/$instance->id"); $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id");
$this->assertFieldByXpath( $this->assertFieldByXpath(
'//input[@name="instance[settings][default_image][fids]"]', '//input[@name="instance[settings][default_image][fid][fids]"]',
$default_images['instance']->id(), $default_images['instance']->id(),
format_string( format_string(
'Article image field instance default equals expected file ID of @fid.', 'Article image field instance default equals expected file ID of @fid.',
...@@ -114,7 +130,7 @@ public function testDefaultImages() { ...@@ -114,7 +130,7 @@ public function testDefaultImages() {
// Confirm the defaults are present on the page field settings form. // Confirm the defaults are present on the page field settings form.
$this->drupalGet("admin/structure/types/manage/page/fields/$instance->id/field"); $this->drupalGet("admin/structure/types/manage/page/fields/$instance->id/field");
$this->assertFieldByXpath( $this->assertFieldByXpath(
'//input[@name="field[settings][default_image][fids]"]', '//input[@name="field[settings][default_image][fid][fids]"]',
$default_images['field']->id(), $default_images['field']->id(),
format_string( format_string(
'Page image field default equals expected file ID of @fid.', 'Page image field default equals expected file ID of @fid.',
...@@ -124,7 +140,7 @@ public function testDefaultImages() { ...@@ -124,7 +140,7 @@ public function testDefaultImages() {
// Confirm the defaults are present on the page field edit form. // Confirm the defaults are present on the page field edit form.
$this->drupalGet("admin/structure/types/manage/page/fields/$instance2->id"); $this->drupalGet("admin/structure/types/manage/page/fields/$instance2->id");
$this->assertFieldByXpath( $this->assertFieldByXpath(
'//input[@name="instance[settings][default_image][fids]"]', '//input[@name="instance[settings][default_image][fid][fids]"]',
$default_images['instance2']->id(), $default_images['instance2']->id(),
format_string( format_string(
'Page image field instance default equals expected file ID of @fid.', 'Page image field instance default equals expected file ID of @fid.',
...@@ -157,13 +173,13 @@ public function testDefaultImages() { ...@@ -157,13 +173,13 @@ public function testDefaultImages() {
); );
// Upload a new default for the field. // Upload a new default for the field.
$field->settings['default_image'] = array($default_images['field_new']->id()); $field->settings['default_image']['fid'] = array($default_images['field_new']->id());
$field->save(); $field->save();
// Confirm that the new default is used on the article field settings form. // Confirm that the new default is used on the article field settings form.
$this->drupalGet("admin/structure/types/manage/article/fields/$instance->id/field"); $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id/field");
$this->assertFieldByXpath( $this->assertFieldByXpath(
'//input[@name="field[settings][default_image][fids]"]', '//input[@name="field[settings][default_image][fid][fids]"]',
$default_images['field_new']->id(), $default_images['field_new']->id(),
format_string( format_string(
'Updated image field default equals expected file ID of @fid.', 'Updated image field default equals expected file ID of @fid.',
...@@ -192,14 +208,14 @@ public function testDefaultImages() { ...@@ -192,14 +208,14 @@ public function testDefaultImages() {
); );
// Upload a new default for the article's field instance. // Upload a new default for the article's field instance.
$instance->settings['default_image'] = $default_images['instance_new']->id(); $instance->settings['default_image']['fid'] = $default_images['instance_new']->id();
$instance->save(); $instance->save();
// Confirm the new field instance default is used on the article field // Confirm the new field instance default is used on the article field
// admin form. // admin form.
$this->drupalGet("admin/structure/types/manage/article/fields/$instance->id"); $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id");
$this->assertFieldByXpath( $this->assertFieldByXpath(
'//input[@name="instance[settings][default_image][fids]"]', '//input[@name="instance[settings][default_image][fid][fids]"]',
$default_images['instance_new']->id(), $default_images['instance_new']->id(),
format_string( format_string(
'Updated article image field instance default equals expected file ID of @fid.', 'Updated article image field instance default equals expected file ID of @fid.',
...@@ -231,13 +247,13 @@ public function testDefaultImages() { ...@@ -231,13 +247,13 @@ public function testDefaultImages() {
); );
// Remove the instance default from articles. // Remove the instance default from articles.
$instance->settings['default_image'] = 0; $instance->settings['default_image']['fid'] = 0;
$instance->save(); $instance->save();
// Confirm the article field instance default has been removed. // Confirm the article field instance default has been removed.
$this->drupalGet("admin/structure/types/manage/article/fields/$instance->id"); $this->drupalGet("admin/structure/types/manage/article/fields/$instance->id");
$this->assertFieldByXpath( $this->assertFieldByXpath(
'//input[@name="instance[settings][default_image][fids]"]', '//input[@name="instance[settings][default_image][fid][fids]"]',
'', '',
'Updated article image field instance default has been successfully removed.' 'Updated article image field instance default has been successfully removed.'
); );
......
...@@ -241,18 +241,27 @@ function testImageFieldDefaultImage() { ...@@ -241,18 +241,27 @@ function testImageFieldDefaultImage() {
// Add a default image to the public imagefield instance. // Add a default image to the public imagefield instance.
$images = $this->drupalGetTestFiles('image'); $images = $this->drupalGetTestFiles('image');
$alt = $this->randomString(512);
$title = $this->randomString(1024);
$edit = array( $edit = array(
'files[field_settings_default_image]' => drupal_realpath($images[0]->uri), 'files[field_settings_default_image_fid]' => drupal_realpath($images[0]->uri),
'field[settings][default_image][alt]' => $alt,
'field[settings][default_image][title]' => $title,
); );
$this->drupalPostForm("admin/structure/types/manage/article/fields/node.article.$field_name/field", $edit, t('Save field settings')); $this->drupalPostForm