/**
* Tests embedded users on node pages.
*/
function testPictureOnNodeComment()
{
$this->drupalLogin($this->webUser);
// Save a new picture.
$image = current($this->drupalGetTestFiles('image'));
$file = $this->saveUserPicture($image);
$node = $this->drupalCreateNode(array('type' => 'article'));
// Enable user pictures on nodes.
$this->config('system.theme.global')->set('features.node_user_picture', TRUE)->save();
$image_style_id = $this->config('core.entity_view_display.user.user.compact')->get('content.user_picture.settings.image_style');
$style = ImageStyle::load($image_style_id);
$image_url = file_url_transform_relative($style->buildUrl($file->getfileUri()));
$alt_text = 'Profile picture for user ' . $this->webUser->getUsername();
// Verify that the image is displayed on the node page.
$this->drupalGet('node/' . $node->id());
$elements = $this->cssSelect('.node__meta .field--name-user-picture img[alt="' . $alt_text . '"][src="' . $image_url . '"]');
$this->assertEqual(count($elements), 1, 'User picture with alt text found on node page.');
// Enable user pictures on comments, instead of nodes.
$this->config('system.theme.global')->set('features.node_user_picture', FALSE)->set('features.comment_user_picture', TRUE)->save();
$edit = array('comment_body[0][value]' => $this->randomString());
$this->drupalPostForm('comment/reply/node/' . $node->id() . '/comment', $edit, t('Save'));
$elements = $this->cssSelect('.comment__meta .field--name-user-picture img[alt="' . $alt_text . '"][src="' . $image_url . '"]');
$this->assertEqual(count($elements), 1, 'User picture with alt text found on the comment.');
// Disable user pictures on comments and nodes.
$this->config('system.theme.global')->set('features.node_user_picture', FALSE)->set('features.comment_user_picture', FALSE)->save();
$this->drupalGet('node/' . $node->id());
$this->assertNoRaw(file_uri_target($file->getFileUri()), 'User picture not found on node and comment.');
}
/**
* {@inheritdoc}
*/
public function process($text, $langcode)
{
$result = new FilterProcessResult($text);
if (stristr($text, 'data-entity-type="file"') !== FALSE) {
$dom = Html::load($text);
$xpath = new \DOMXPath($dom);
$processed_uuids = array();
foreach ($xpath->query('//*[@data-entity-type="file" and @data-entity-uuid]') as $node) {
$uuid = $node->getAttribute('data-entity-uuid');
// If there is a 'src' attribute, set it to the file entity's current
// URL. This ensures the URL works even after the file location changes.
if ($node->hasAttribute('src')) {
$file = $this->entityManager->loadEntityByUuid('file', $uuid);
if ($file) {
$node->setAttribute('src', file_url_transform_relative(file_create_url($file->getFileUri())));
}
}
// Only process the first occurrence of each file UUID.
if (!isset($processed_uuids[$uuid])) {
$processed_uuids[$uuid] = TRUE;
$file = $this->entityManager->loadEntityByUuid('file', $uuid);
if ($file) {
$result->addCacheTags($file->getCacheTags());
}
}
}
$result->setProcessedText(Html::serialize($dom));
}
return $result;
}
/**
* Method tests CKEditor image buttons.
*/
public function testImageButtonDisplay()
{
$this->drupalLogin($this->admin_user);
// Install the Arabic language (which is RTL) and configure as the default.
$edit = [];
$edit['predefined_langcode'] = 'ar';
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add language'));
$edit = ['site_default_language' => 'ar'];
$this->drupalPostForm('admin/config/regional/language', $edit, t('Save configuration'));
// Once the default language is changed, go to the tested text format
// configuration page.
$this->drupalGet('admin/config/content/formats/manage/full_html');
// Check if any image button is loaded in CKEditor json.
$json_encode = function ($html) {
return trim(Json::encode($html), '"');
};
$markup = $json_encode(file_url_transform_relative(file_create_url('core/modules/ckeditor/js/plugins/drupalimage/image.png')));
$this->assertRaw($markup);
}
/**
* Test the field formatter with a file field and file upload widget.
*/
public function testFile()
{
// Create a test node with an image file.
$this->createNodeWithFile();
$node = $this->node;
$xml_path = 'juicebox/xml/field/node/' . $node->id() . '/' . $this->instFieldName . '/full';
$xml_url = \Drupal::url('juicebox.xml_field', array('entityType' => 'node', 'entityId' => $node->id(), 'fieldName' => $this->instFieldName, 'displayName' => 'full'));
// Get the urls to the test image and thumb derivative used by default.
$uri = \Drupal\file\Entity\File::load($node->{$this->instFieldName}[0]->target_id)->getFileUri();
$test_image_url = entity_load('image_style', 'juicebox_medium')->buildUrl($uri);
$test_thumb_url = entity_load('image_style', 'juicebox_square_thumb')->buildUrl($uri);
// Check for correct embed markup as anon user.
$this->drupalLogout();
$this->drupalGet('node/' . $node->id());
$this->assertRaw(trim(json_encode(array('configUrl' => $xml_url)), '{}"'), 'Gallery setting found in Drupal.settings.');
$this->assertRaw('id="node--' . $node->id() . '--' . str_replace('_', '-', $this->instFieldName) . '--full"', 'Embed code wrapper found.');
$this->assertRaw(Html::escape(file_url_transform_relative($test_image_url)), 'Test image found in embed code');
// Check for correct XML.
$this->drupalGet($xml_path);
$this->assertRaw('<?xml version="1.0" encoding="UTF-8"?>', 'Valid XML detected.');
$this->assertRaw('imageURL="' . Html::escape($test_image_url), 'Test image found in XML.');
$this->assertRaw('thumbURL="' . Html::escape($test_thumb_url), 'Test thumbnail found in XML.');
$this->assertRaw('<juicebox gallerywidth="100%" galleryheight="100%" backgroundcolor="#222222" textcolor="rgba(255,255,255,1)" thumbframecolor="rgba(255,255,255,.5)" showopenbutton="TRUE" showexpandbutton="TRUE" showthumbsbutton="TRUE" usethumbdots="FALSE" usefullscreenexpand="FALSE">', 'Expected default configuration options set in XML.');
}
/**
* Tests usage of the image style theme function.
*/
function testImageStyleTheme()
{
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
// Create an image.
$files = $this->drupalGetTestFiles('image');
$file = reset($files);
$original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME);
// Create a style.
$style = ImageStyle::create(array('name' => 'image_test', 'label' => 'Test'));
$style->save();
$url = file_url_transform_relative($style->buildUrl($original_uri));
// Create the base element that we'll use in the tests below.
$base_element = array('#theme' => 'image_style', '#style_name' => 'image_test', '#uri' => $original_uri);
$element = $base_element;
$this->setRawContent($renderer->renderRoot($element));
$elements = $this->xpath('//img[@class="image-style-image-test" and @src=:url and @alt=""]', array(':url' => $url));
$this->assertEqual(count($elements), 1, 'theme_image_style() renders an image correctly.');
// Test using theme_image_style() with a NULL value for the alt option.
$element = $base_element;
$element['#alt'] = NULL;
$this->setRawContent($renderer->renderRoot($element));
$elements = $this->xpath('//img[@class="image-style-image-test" and @src=:url]', array(':url' => $url));
$this->assertEqual(count($elements), 1, 'theme_image_style() renders an image correctly with a NULL value for the alt option.');
}
/**
* Tests the Color module functionality using the given theme.
*
* @param string $theme
* The machine name of the theme being tested.
* @param array $test_values
* An associative array of test settings (i.e. 'Main background', 'Text
* color', 'Color set', etc) for the theme which being tested.
*/
function _testColor($theme, $test_values)
{
$this->config('system.theme')->set('default', $theme)->save();
$settings_path = 'admin/appearance/settings/' . $theme;
$this->drupalLogin($this->bigUser);
$this->drupalGet($settings_path);
$this->assertResponse(200);
$this->assertUniqueText('Color set');
$edit['scheme'] = '';
$edit[$test_values['palette_input']] = '#123456';
$this->drupalPostForm($settings_path, $edit, t('Save configuration'));
$this->drupalGet('<front>');
$stylesheets = $this->config('color.theme.' . $theme)->get('stylesheets');
foreach ($stylesheets as $stylesheet) {
$this->assertPattern('|' . file_url_transform_relative(file_create_url($stylesheet)) . '|', 'Make sure the color stylesheet is included in the content. (' . $theme . ')');
$stylesheet_content = join("\n", file($stylesheet));
$this->assertTrue(strpos($stylesheet_content, 'color: #123456') !== FALSE, 'Make sure the color we changed is in the color stylesheet. (' . $theme . ')');
}
$this->drupalGet($settings_path);
$this->assertResponse(200);
$edit['scheme'] = $test_values['scheme'];
$this->drupalPostForm($settings_path, $edit, t('Save configuration'));
$this->drupalGet('<front>');
$stylesheets = $this->config('color.theme.' . $theme)->get('stylesheets');
foreach ($stylesheets as $stylesheet) {
$stylesheet_content = join("\n", file($stylesheet));
$this->assertTrue(strpos($stylesheet_content, 'color: ' . $test_values['scheme_color']) !== FALSE, 'Make sure the color we changed is in the color stylesheet. (' . $theme . ')');
}
// Test with aggregated CSS turned on.
$config = $this->config('system.performance');
$config->set('css.preprocess', 1);
$config->save();
$this->drupalGet('<front>');
$stylesheets = \Drupal::state()->get('drupal_css_cache_files') ?: array();
$stylesheet_content = '';
foreach ($stylesheets as $uri) {
$stylesheet_content .= join("\n", file(drupal_realpath($uri)));
}
$this->assertTrue(strpos($stylesheet_content, 'public://') === FALSE, 'Make sure the color paths have been translated to local paths. (' . $theme . ')');
$config->set('css.preprocess', 0);
$config->save();
}
/**
* Tests for image field settings.
*/
function testImageFieldSettings()
{
/** @var \Drupal\Core\Render\RendererInterface $renderer */
$renderer = $this->container->get('renderer');
$node_storage = $this->container->get('entity.manager')->getStorage('node');
$test_image = current($this->drupalGetTestFiles('image'));
list(, $test_image_extension) = explode('.', $test_image->filename);
$field_name = strtolower($this->randomMachineName());
$field_settings = array('alt_field' => 1, 'file_extensions' => $test_image_extension, 'max_filesize' => '50 KB', 'max_resolution' => '100x100', 'min_resolution' => '10x10', 'title_field' => 1);
$widget_settings = array('preview_image_style' => 'medium');
$field = $this->createImageField($field_name, 'article', array(), $field_settings, $widget_settings);
// Verify that the min/max resolution set on the field are properly
// extracted, and displayed, on the image field's configuration form.
$this->drupalGet('admin/structure/types/manage/article/fields/' . $field->id());
$this->assertFieldByName('settings[max_resolution][x]', '100', 'Expected max resolution X value of 100.');
$this->assertFieldByName('settings[max_resolution][y]', '100', 'Expected max resolution Y value of 100.');
$this->assertFieldByName('settings[min_resolution][x]', '10', 'Expected min resolution X value of 10.');
$this->assertFieldByName('settings[min_resolution][y]', '10', 'Expected min resolution Y value of 10.');
$this->drupalGet('node/add/article');
$this->assertText(t('50 KB limit.'), 'Image widget max file size is displayed on article form.');
$this->assertText(t('Allowed types: @extensions.', array('@extensions' => $test_image_extension)), 'Image widget allowed file types displayed on article form.');
$this->assertText(t('Images must be larger than 10x10 pixels. Images larger than 100x100 pixels will be resized.'), 'Image widget allowed resolution displayed on article form.');
// We have to create the article first and then edit it because the alt
// and title fields do not display until the image has been attached.
// Create alt text for the image.
$alt = $this->randomMachineName();
$nid = $this->uploadNodeImage($test_image, $field_name, 'article', $alt);
$this->drupalGet('node/' . $nid . '/edit');
$this->assertFieldByName($field_name . '[0][alt]', '', 'Alt field displayed on article form.');
$this->assertFieldByName($field_name . '[0][title]', '', 'Title field displayed on article form.');
// Verify that the attached image is being previewed using the 'medium'
// style.
$node_storage->resetCache(array($nid));
$node = $node_storage->load($nid);
$file = $node->{$field_name}->entity;
$url = file_url_transform_relative(file_create_url(ImageStyle::load('medium')->buildUrl($file->getFileUri())));
$this->assertTrue($this->cssSelect('img[width=40][height=20][class=image-style-medium][src="' . $url . '"]'));
// Add alt/title fields to the image and verify that they are displayed.
$image = array('#theme' => 'image', '#uri' => $file->getFileUri(), '#alt' => $alt, '#title' => $this->randomMachineName(), '#width' => 40, '#height' => 20);
$edit = array($field_name . '[0][alt]' => $image['#alt'], $field_name . '[0][title]' => $image['#title']);
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published'));
$default_output = str_replace("\n", NULL, $renderer->renderRoot($image));
$this->assertRaw($default_output, 'Image displayed using user supplied alt and title attributes.');
// Verify that alt/title longer than allowed results in a validation error.
$test_size = 2000;
$edit = array($field_name . '[0][alt]' => $this->randomMachineName($test_size), $field_name . '[0][title]' => $this->randomMachineName($test_size));
$this->drupalPostForm('node/' . $nid . '/edit', $edit, t('Save and keep published'));
$schema = $field->getFieldStorageDefinition()->getSchema();
$this->assertRaw(t('Alternative text cannot be longer than %max characters but is currently %length characters long.', array('%max' => $schema['columns']['alt']['length'], '%length' => $test_size)));
$this->assertRaw(t('Title cannot be longer than %max characters but is currently %length characters long.', array('%max' => $schema['columns']['title']['length'], '%length' => $test_size)));
// Set cardinality to unlimited and add upload a second image.
// The image widget is extending on the file widget, but the image field
// type does not have the 'display_field' setting which is expected by
// the file widget. This resulted in notices before when cardinality is not
// 1, so we need to make sure the file widget prevents these notices by
// providing all settings, even if they are not used.
// @see FileWidget::formMultipleElements().
$this->drupalPostForm('admin/structure/types/manage/article/fields/node.article.' . $field_name . '/storage', array('cardinality' => FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED), t('Save field settings'));
$edit = array('files[' . $field_name . '_1][]' => drupal_realpath($test_image->uri));
$this->drupalPostForm('node/' . $node->id() . '/edit', $edit, t('Save and keep published'));
// Add the required alt text.
$this->drupalPostForm(NULL, [$field_name . '[1][alt]' => $alt], t('Save and keep published'));
$this->assertText(format_string('Article @title has been updated.', array('@title' => $node->getTitle())));
// Assert ImageWidget::process() calls FieldWidget::process().
$this->drupalGet('node/' . $node->id() . '/edit');
$edit = array('files[' . $field_name . '_2][]' => drupal_realpath($test_image->uri));
$this->drupalPostAjaxForm(NULL, $edit, $field_name . '_2_upload_button');
$this->assertNoRaw('<input multiple type="file" id="edit-' . strtr($field_name, '_', '-') . '-2-upload" name="files[' . $field_name . '_2][]" size="22" class="js-form-file form-file">');
$this->assertRaw('<input multiple type="file" id="edit-' . strtr($field_name, '_', '-') . '-3-upload" name="files[' . $field_name . '_3][]" size="22" class="js-form-file form-file">');
}
/**
* Test configuration options that are specific to the Juicebox field
* formatter.
*/
public function testFieldFormatterConf()
{
$node = $this->node;
// Do a set of control requests as an anon user that will also prime any
// caches.
$this->drupalGet('node/' . $node->id());
$this->assertResponse(200, 'Control request of test node was successful.');
$this->drupalGet('juicebox/xml/field/node/' . $node->id() . '/' . $this->instFieldName . '/full');
$this->assertResponse(200, 'Control request of XML was successful.');
// Alter field formatter specific settings to contain custom values.
$this->drupalLogin($this->webUser);
$this->drupalPostAjaxForm('admin/structure/types/manage/' . $this->instBundle . '/display', array(), $this->instFieldName . '_settings_edit', NULL, array(), array(), 'entity-view-display-edit-form');
$edit = array('fields[' . $this->instFieldName . '][settings_edit_form][settings][image_style]' => '', 'fields[' . $this->instFieldName . '][settings_edit_form][settings][thumb_style]' => 'thumbnail', 'fields[' . $this->instFieldName . '][settings_edit_form][settings][caption_source]' => 'alt', 'fields[' . $this->instFieldName . '][settings_edit_form][settings][title_source]' => 'title');
$this->drupalPostForm(NULL, $edit, t('Save'));
$this->assertText(t('Your settings have been saved.'), 'Gallery configuration changes saved.');
// Get the urls to the image and thumb derivatives expected.
$uri = \Drupal\file\Entity\File::load($node->{$this->instFieldName}[0]->target_id)->getFileUri();
$test_formatted_image_url = file_create_url($uri);
$test_formatted_thumb_url = entity_load('image_style', 'thumbnail')->buildUrl($uri);
// Check for correct embed markup as anon user.
$this->drupalLogout();
$this->drupalGet('node/' . $node->id());
$this->assertRaw(Html::escape(file_url_transform_relative($test_formatted_image_url)), 'Test styled image found in embed code');
// Check for correct XML.
$this->drupalGet('juicebox/xml/field/node/' . $node->id() . '/' . $this->instFieldName . '/full');
$this->assertRaw('imageURL="' . Html::escape($test_formatted_image_url), 'Test styled image found in XML.');
$this->assertRaw('thumbURL="' . Html::escape($test_formatted_thumb_url), 'Test styled thumbnail found in XML.');
// Note the intended title and caption text does not contain any block-level
// tags as long as the global title and caption output filter is working.
// So this acts as a test for that feature as well.
$this->assertRaw('<title><![CDATA[Some title text for field ' . $this->instFieldName . ' on node ' . $node->id() . ']]></title>', 'Image title text found in XML');
$this->assertRaw('<caption><![CDATA[Some alt text for field ' . $this->instFieldName . ' on node ' . $node->id() . ' <strong>with formatting</strong>]]></caption>', 'Image caption text found in XML');
// Now that we have title and caption data set, also ensure this text can
// be found in search results. First we update the search index by marking
// our test node as dirty and running cron.
$this->drupalLogin($this->webUser);
$this->drupalPostForm('node/' . $node->id() . '/edit', array(), t('Save and keep published'));
$this->cronRun();
$this->drupalPostForm('search', array('keys' => '"Some title text"'), t('Search'));
$this->assertText('Test Juicebox Gallery Node', 'Juicebox node found in search for title text.');
// The Juicebox javascript should have been excluded from the search results
// page.
$this->assertNoRaw('"configUrl":"', 'Juicebox Drupal.settings vars not included on search result page.');
}
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode)
{
$elements = array();
$files = $this->getEntitiesToView($items, $langcode);
// 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 = file_url_transform_relative(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;
}
请发表评论