diff --git a/core/modules/image/src/Plugin/Filter/FilterImageStyle.php b/core/modules/image/src/Plugin/Filter/FilterImageStyle.php index d80eb53..5791530 100644 --- a/core/modules/image/src/Plugin/Filter/FilterImageStyle.php +++ b/core/modules/image/src/Plugin/Filter/FilterImageStyle.php @@ -89,46 +89,27 @@ public static function create(ContainerInterface $container, array $configuratio */ public function process($text, $langcode) { if (stristr($text, 'data-image-style') !== FALSE) { + // Load all the image styles so each img found in the text can be checked + // to ensure it has a valid image style. $image_styles = $this->loadImageStyles(); + // Load the text that is being processed into XML to find images. $dom = HTML::load($text); $xpath = new \DOMXPath($dom); + + // Process each img element DOM node found with the necessary attributes. foreach ($xpath->query('//*[@data-entity-type="file" and @data-entity-uuid and @data-image-style]') as $dom_node) { + // Get the UUID and image style for the file. $file_uuid = $dom_node->getAttribute('data-entity-uuid'); - $dom_node->removeAttribute('data-entity-uuid'); $image_style_id = $dom_node->getAttribute('data-image-style'); - $dom_node->removeAttribute('data-image-style'); // If the image style is not a valid one, then don't transform the HTML. if (empty($file_uuid) || !in_array($image_style_id, $image_styles)) { continue; } - $image_info = $this->getImageInfo($file_uuid); - $image_uri = $image_info['uri']; - $image_width = $image_info['width']; - $image_height = $image_info['height']; - - // Make sure all non-regenerated attributes are retained. - $dom_node->removeAttribute('width'); - $dom_node->removeAttribute('height'); - $dom_node->removeAttribute('src'); - $attributes = array(); - for ($i = 0; $i < $dom_node->attributes->length; $i++) { - $attr = $dom_node->attributes->item($i); - $attributes[$attr->name] = $attr->value; - } - - // Re-render as an image style. - $image = array( - '#theme' => 'image_style', - '#style_name' => $image_style_id, - '#uri' => $image_uri, - '#width' => $image_width, - '#height' => $image_height, - '#attributes' => $attributes, - ); - $altered_html = $this->renderer->render($image); + // Transform the HTML for the img element by applying an image style. + $altered_html = $this->getImageStyleHtml($file_uuid, $image_style_id, $dom_node); // Load the altered HTML into a new DOMDocument and retrieve the element. $updated_node = HTML::load($altered_html)->getElementsByTagName('body') @@ -139,13 +120,16 @@ public function process($text, $langcode) { // Import the updated node from the new DOMDocument into the original // one, importing also the child nodes of the updated node. $updated_node = $dom->importNode($updated_node, TRUE); - // Finally, replace the original image node with the new image node! + + // Finally, replace the original image node with the new image node. $dom_node->parentNode->replaceChild($updated_node, $dom_node); } + // Process the filter with the newly updated DOM. return new FilterProcessResult(HTML::serialize($dom)); } + // Process the filter if no image style img elements are found. return new FilterProcessResult($text); } @@ -161,7 +145,8 @@ protected function loadImageStyles() { /** * Get the the width and height of an image based on the file UUID. * - * @param $file_uuid + * @param string $file_uuid + * The UUID for the file. * * @return array */ @@ -188,6 +173,64 @@ protected function getImageInfo($file_uuid) { } /** + * Removes attributes that will be generated from image style theme function. + * + * @param \DOMNode $dom_node + * The DOM node for the img element. + * + * @return \DOMNode + */ + protected function prepareImageAttributes($dom_node) { + // Make sure all non-regenerated attributes are retained. + $dom_node->removeAttribute('data-entity-uuid'); + $dom_node->removeAttribute('data-image-style'); + $dom_node->removeAttribute('width'); + $dom_node->removeAttribute('height'); + $dom_node->removeAttribute('src'); + $attributes = array(); + for ($i = 0; $i < $dom_node->attributes->length; $i++) { + $attr = $dom_node->attributes->item($i); + $attributes[$attr->name] = $attr->value; + } + + return $dom_node; + } + + /** + * Get the HTML for the img element after image style is applied. + * + * @param string $file_uuid + * The UUID for the file. + * @param string $image_style_id + * The ID for the image style. + * @param \DOMNode $dom_node + * The DOM node for the image element. + * + * @return string + */ + protected function getImageStyleHtml($file_uuid, $image_style_id, $dom_node) { + $image_info = $this->getImageInfo($file_uuid); + $image_uri = $image_info['uri']; + $image_width = $image_info['width']; + $image_height = $image_info['height']; + + // Remove attributes that will be generated by the image style. + $attributes = $this->prepareImageAttributes($dom_node); + + // Re-render as an image style. + $image = array( + '#theme' => 'image_style', + '#style_name' => $image_style_id, + '#uri' => $image_uri, + '#width' => $image_width, + '#height' => $image_height, + '#attributes' => $attributes, + ); + + return $this->renderer->render($image); + } + + /** * {@inheritdoc} */ public function tips($long = FALSE) { diff --git a/core/modules/image/tests/src/Unit/FilterImageStyleTest.php b/core/modules/image/tests/src/Unit/FilterImageStyleTest.php index 810c5e9..a5455cc 100644 --- a/core/modules/image/tests/src/Unit/FilterImageStyleTest.php +++ b/core/modules/image/tests/src/Unit/FilterImageStyleTest.php @@ -55,7 +55,9 @@ protected function setUp() { ]) ->setMethods([ 'loadImageStyles', - 'getImageInfo' + 'getImageInfo', + 'prepareImageAttributes', + 'getImageStyleHtml' ]) ->getMock(); } @@ -65,10 +67,62 @@ public function testProcessWithoutImage() { $this->assertEquals('', $output); } + /** + * @covers ::process + */ public function testProcessWithImage() { - $this->filterImageStyle->method('loadImageStyles')->willReturn(['thumbnail', 'medium', 'large']); - $this->filterImageStyle->method('getImageInfo')->with($this->equalTo('abcd-1234-ghij-5678'))->willReturn(['uri' => 'styles/medium/public/image.png', 'width' => '200', 'height'=> '150']); - $output = $this->filterImageStyle->process('', 'en'); - $this->assertEquals('', $output); + $original_src = 'image.png'; + $original_uuid = 'abcd-1234-ghij-5678'; + $original_image_style = 'medium'; + $original_width = '400'; + $original_height = '300'; + $original_alt = 'A wooly mammoth trumpets as a crevasse breaks open in the glacier.'; + + $original_img = '' . $original_alt .''; + + $processed_img = '' . $original_alt .''; + + $generated_src = 'styles/medium/public/image.png'; + $generated_width = '200'; + $generated_height = '150'; + $generated_img = '' . $original_alt .''; + + $this->filterImageStyle + ->method('loadImageStyles') + ->willReturn([ + 'thumbnail', + 'medium', + 'large' + ]); + + $this->filterImageStyle + ->method('getImageInfo') + ->with( + $this->equalTo($original_uuid) + ) + ->willReturn([ + 'uri' => 'styles/medium/public/image.png', + 'width' => '200', + 'height'=> '150' + ]); + + $this->filterImageStyle + ->method('prepareImageAttributes') + ->with( + $this->equalTo($original_img) + ) + ->willReturn($processed_img); + + $this->filterImageStyle + ->method('getImageStyleHtml') + ->with( + $this->equalTo($original_uuid), + $this->equalTo($original_image_style), + $this->equalTo($original_img) + ) + ->willReturn($generated_img); + + $output = $this->filterImageStyle->process($original_img, 'en'); + $this->assertEquals($generated_img, $output); } }