diff --git a/composer.json b/composer.json index 8de26d8ad57143a7b098312f4904d154fb2fc8a6..6d0bc3ed7f409059f1bb32994e15466201aff89e 100644 --- a/composer.json +++ b/composer.json @@ -124,7 +124,7 @@ "drupal/field_group": "3.0-rc1", "drupal/field_permissions": "1.0-beta1", "drupal/file_browser": "1.1", - "drupal/focal_point": "1.0-beta6", + "drupal/focal_point": "1.2", "drupal/geolocation": "1.10", "drupal/google_analytics": "2.4", "drupal/google_tag": "^1.3", @@ -316,4 +316,4 @@ "php": "7.0.8" } } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index e304ef53bba33d66a4e3b4eb9dcf9b8e5df5f190..1c0772ded8d30076f2d45a52c2fa2bf6146b0f1e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "9cebdfa2dca9a89bb18005ed1f9db499", + "content-hash": "19f334e1ee259cbebcd4efa4d74e3e58", "packages": [ { "name": "alchemy/zippy", @@ -4826,17 +4826,17 @@ }, { "name": "drupal/focal_point", - "version": "1.0.0-beta6", + "version": "1.2.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/focal_point.git", - "reference": "8.x-1.0-beta6" + "reference": "8.x-1.2" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/focal_point-8.x-1.0-beta6.zip", - "reference": "8.x-1.0-beta6", - "shasum": "b06d3540ee49113e266191b2dba3af5d82990f38" + "url": "https://ftp.drupal.org/files/projects/focal_point-8.x-1.2.zip", + "reference": "8.x-1.2", + "shasum": "b274a5f4484ce99dece492dc7ae7149b34982244" }, "require": { "drupal/core": "*", @@ -4851,11 +4851,11 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.0-beta6", - "datestamp": "1519932484", + "version": "8.x-1.2", + "datestamp": "1569333485", "security-coverage": { - "status": "not-covered", - "message": "Beta releases are not covered by Drupal security advisories." + "status": "covered", + "message": "Covered by Drupal's security advisory policy" } } }, @@ -4872,7 +4872,7 @@ "description": "Allows users to specify the focal point of an image for use during cropping.", "homepage": "https://www.drupal.org/project/focal_point", "support": { - "source": "http://cgit.drupalcode.org/focal_point" + "source": "https://git.drupalcode.org/project/focal_point" } }, { diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 899a4506a1d473357d69d2564c08238e90f63dce..39e8a063eead4a181e15e36fc0a904005f589d66 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -4972,18 +4972,18 @@ }, { "name": "drupal/focal_point", - "version": "1.0.0-beta6", - "version_normalized": "1.0.0.0-beta6", + "version": "1.2.0", + "version_normalized": "1.2.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/focal_point.git", - "reference": "8.x-1.0-beta6" + "reference": "8.x-1.2" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/focal_point-8.x-1.0-beta6.zip", - "reference": "8.x-1.0-beta6", - "shasum": "b06d3540ee49113e266191b2dba3af5d82990f38" + "url": "https://ftp.drupal.org/files/projects/focal_point-8.x-1.2.zip", + "reference": "8.x-1.2", + "shasum": "b274a5f4484ce99dece492dc7ae7149b34982244" }, "require": { "drupal/core": "*", @@ -4998,11 +4998,11 @@ "dev-1.x": "1.x-dev" }, "drupal": { - "version": "8.x-1.0-beta6", - "datestamp": "1519932484", + "version": "8.x-1.2", + "datestamp": "1569333485", "security-coverage": { - "status": "not-covered", - "message": "Beta releases are not covered by Drupal security advisories." + "status": "covered", + "message": "Covered by Drupal's security advisory policy" } } }, @@ -5020,7 +5020,7 @@ "description": "Allows users to specify the focal point of an image for use during cropping.", "homepage": "https://www.drupal.org/project/focal_point", "support": { - "source": "http://cgit.drupalcode.org/focal_point" + "source": "https://git.drupalcode.org/project/focal_point" } }, { diff --git a/web/modules/focal_point/README.md b/web/modules/focal_point/README.md index e0c93490515bca9430de198a12331496f79073e6..f2d3474f3d21955a54e902fde9c358fdb7b19f40 100644 --- a/web/modules/focal_point/README.md +++ b/web/modules/focal_point/README.md @@ -1,4 +1,16 @@ -##ABOUT +CONTENTS OF THIS FILE +--------------------- + + * Introduction + * Usage + * Requirements + * Installation + * Configuration + * Maintainers + + +INTRODUCTION +------------ Focal Point allows you to specify the portion of an image that is most important. This information can be used when the image is cropped or cropped and @@ -7,41 +19,61 @@ subject's head. This module borrows heavily from the ImageField Focus module but it works in a fundamentally different way. In this module the focus is defined as a single -point on the image. Among other things this helps to solve the problem of -guaranteeing the size of a cropped image as described here: -https://drupal.org/node/1889542. +point on the image. + + * For a full description of the module, visit the project page: + https://www.drupal.org/project/focal_point + + * To submit bug reports and feature suggestions, or to track changes: + https://www.drupal.org/project/issues/focal_point + + +REQUIREMENTS +------------ + +This module requires the following module outside of Drupal core: + + * Crop API - https://www.drupal.org/project/crop + + +INSTALLATION +------------ -Currently, Focal Point integrates with the standard image fields. + * Install the Focal Point module as you would normally install a contributed + Drupal module. Visit https://www.drupal.org/node/1897420 for further + information. -##DEPENDENCIES -- image -- crop +CONFIGURATION +------------- -##USAGE + 1. Navigate to Administration > Extend and enable the module. + 2. Navigate to Administration > Structure > Content types > [Content type to + edit] > Manage Form Display and choose the "Image (Focal Point)" widget + for the image field. -### Setting up image fields + * Setting the focal point for an image: + To set the focal point on an image, go to the content edit form (ex. the node + edit form) and upload an image. You will notice a crosshair in the middle of + the newly uploaded image. Drag this crosshair to the most important part of + your image. Done. -Install the module as usual. On the "Manage Form Display" page (e.g. -admin/structure/types/manage/article/form-display) choose the "Image (Focal -Point)" widget for your image field. + Pro tip: you can double-click the crosshair to see the exact coordinates (in + percentages) of the focal point. -### Setting the focal point for an image + * Cropping your image: + The focal point module comes with two image effects: -To set the focal point on an image, go to the content edit form (ex. the node -edit form) and upload an image. You will notice a crosshair in the middle of the -newly uploaded image. Drag this crosshair to the most important part of your -image. Done. + 1. focal point crop + 2. focal point crop and scale -Pro tip: you can double-click the crosshair to see the exact coordinates (in -percentages) of the focal point. + Both effects will make sure that the defined focal point is as close to the + center of your image as possible. It guarantees the focal point will be not + be cropped out of your image and that the image size will be the specified + size. -### Cropping your image -The focal point module comes with two image effects: -1. focal point crop -2. focal point crop and scale +MAINTAINERS +----------- -Both effects will make sure that the defined focal point is as close to the -center of your image as possible. It guarantees the focal point will be not be -cropped out of your image and that the image size will be the specified size. + * Alexander Ross (bleen) - https://www.drupal.org/u/bleen diff --git a/web/modules/focal_point/config/schema/focal_point.schema.yml b/web/modules/focal_point/config/schema/focal_point.schema.yml index 34e69ffaf4beb591462f4094b364ac2af7bad317..db4745f5db12bf830f0bc5a3d31d93fe57f6f7a8 100644 --- a/web/modules/focal_point/config/schema/focal_point.schema.yml +++ b/web/modules/focal_point/config/schema/focal_point.schema.yml @@ -21,9 +21,9 @@ image.effect.focal_point_crop: type: image_size label: 'Focal Point Crop' mapping: - anchor: - label: 'Anchor' + crop_type: type: string + label: 'Crop type to be used with Focal point' field.widget.settings.image_focal_point: type: mapping diff --git a/web/modules/focal_point/css/focal_point.css b/web/modules/focal_point/css/focal_point.css index 469fd3b900821545c6591d8bc6ab5aa2a4d7a46e..e7db132de53d51b0dd19c22717f3e43e8fc07272 100644 --- a/web/modules/focal_point/css/focal_point.css +++ b/web/modules/focal_point/css/focal_point.css @@ -1,37 +1,37 @@ .focal-point-indicator { - width: 1px; - height:1px; - cursor: move; + width: 1px; + height: 1px; + cursor: move; } .focal-point-indicator:after { - content: '+'; - color: white; - cursor: move; - text-shadow: 1px 1px 0 black, 1px -1px 0 black, -1px 1px 0 black, -1px -1px 0 black; - width: .75em; - height: .75em; - font-size: 1.5em; - line-height: .75em; - display: block; - position: relative; - top: -.375em; - left: -.375em; + content: '+'; + color: white; + cursor: move; + text-shadow: 1px 1px 0 black, 1px -1px 0 black, -1px 1px 0 black, -1px -1px 0 black; + width: .75em; + height: .75em; + font-size: 1.5em; + line-height: .75em; + display: block; + position: relative; + top: -.375em; + left: -.375em; } .focal-point-wrapper { - display: inline-block; - position: relative; - direction: ltr; + display: inline-block; + position: relative; + direction: ltr; } .focal-point-preview-link { - display: block; - direction: initial; - text-align: center; + display: block; + direction: initial; + text-align: center; } .focal-point-preview-link:before { - content: "\1F50D"; - font-size: x-large; - vertical-align: middle; + content: "\1F50D"; + font-size: x-large; + vertical-align: middle; } .focal-point-preview-link:hover { - text-decoration: none; + text-decoration: none; } diff --git a/web/modules/focal_point/css/focal_point_preview.css b/web/modules/focal_point/css/focal_point_preview.css index 56b4ec054c667c3c3cba2f468892ca0a677ce23e..3a23dd4148fc25467b5238b159e139fa7bacb27b 100644 --- a/web/modules/focal_point/css/focal_point_preview.css +++ b/web/modules/focal_point/css/focal_point_preview.css @@ -22,15 +22,15 @@ font-size: 1em; margin: .5em 1em 1em 0; padding: 0 1em 1em 1em; - border: 1px solid #CCCCCC; - background: #EEEEEE; + border: 1px solid #cccccc; + background: #eeeeee; min-height: 11.5em; vertical-align: top; cursor: pointer; } .focal-point-derivative-preview.active { - background: #CCCCCC; + background: #cccccc; border-color: #999999; } diff --git a/web/modules/focal_point/focal_point.info.yml b/web/modules/focal_point/focal_point.info.yml index cacc2f460adcc2e93e155f17d2cc0dd7944698d4..d8e30ca5ef103e214d0ade91f484e32dfc6f5082 100644 --- a/web/modules/focal_point/focal_point.info.yml +++ b/web/modules/focal_point/focal_point.info.yml @@ -1,16 +1,15 @@ name: Focal Point type: module description: Allows users to specify the focal point of an image for use during cropping. -# core: 8.x -package: Images +core: 8.x +package: Media test_dependencies: - - crop + - crop:crop dependencies: - - image - - crop + - drupal:image + - crop:crop -# Information added by Drupal.org packaging script on 2018-03-01 -version: '8.x-1.0-beta6' -core: '8.x' +# Information added by Drupal.org packaging script on 2019-09-24 +version: '8.x-1.2' project: 'focal_point' -datestamp: 1519932491 +datestamp: 1569333492 diff --git a/web/modules/focal_point/focal_point.install b/web/modules/focal_point/focal_point.install index 554a8bb187a6c5d7866cdbec1310e9f0c2680c38..0979bfca2a1f31d252d8251019a278d4a639857a 100644 --- a/web/modules/focal_point/focal_point.install +++ b/web/modules/focal_point/focal_point.install @@ -6,7 +6,6 @@ */ use Drupal\Core\Database\Database; -use Drupal\Core\Utility\UpdateException; /** * Implements hook_uninstall(). diff --git a/web/modules/focal_point/focal_point.module b/web/modules/focal_point/focal_point.module index ffedfd3e1d54661d120c2837a9af465056a9d1dc..8c591e65019dfcef86434c2fb1e5242487589d45 100644 --- a/web/modules/focal_point/focal_point.module +++ b/web/modules/focal_point/focal_point.module @@ -4,13 +4,12 @@ * @file * Allow users to specify a focal point on content images. * - * @todo add support for default foal point value calculation method. + * @todo add support for default focal point value calculation method. * @todo add test drive functionality? */ use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\FieldableEntityInterface; -use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; /** @@ -62,13 +61,25 @@ function focal_point_entity_update(EntityInterface $entity) { // Loop all the fields and save focal point values for images. foreach ($entity->getFieldDefinitions() as $key => $field) { if ($field->getType() == 'image' && $entity->hasField($field->getName())) { + $crop_type = \Drupal::config('focal_point.settings')->get('crop_type'); // Loop through all values for this field. Its cardinality might be > 1. foreach ($entity->{$field->getName()} as $item) { - if (isset($item->focal_point)) { - list($x, $y) = explode(',', $item->focal_point); - $crop_type = \Drupal::config('focal_point.settings')->get('crop_type'); - $crop = \Drupal::service('focal_point.manager')->getCropEntity($item->entity, $crop_type); - \Drupal::service('focal_point.manager')->saveCropEntity($x, $y, $item->width, $item->height, $crop); + /** @var \Drupal\focal_point\FocalPointManagerInterface $focal_point_manager */ + $focal_point_manager = \Drupal::service('focal_point.manager'); + $crop = $focal_point_manager->getCropEntity($item->entity, $crop_type); + + $focal_point = NULL; + // Use the default focal point on new crop entities. + if ($crop->isNew()) { + $focal_point = \Drupal::config('focal_point.settings')->get('default_value'); + } + // Use the focal point set over the UI. + if (!empty($item->focal_point)) { + $focal_point = $item->focal_point; + } + if ($focal_point) { + list($x, $y) = explode(',', $focal_point); + $focal_point_manager->saveCropEntity($x, $y, $item->width, $item->height, $crop); } } } @@ -82,6 +93,6 @@ function focal_point_entity_update(EntityInterface $entity) { * @param array $widgets * The existing list of widgets to add to. */ -function focal_point_imce_supported_widgets_alter(&$widgets) { +function focal_point_imce_supported_widgets_alter(array &$widgets) { $widgets[] = 'image_focal_point'; } diff --git a/web/modules/focal_point/js/focal_point.js b/web/modules/focal_point/js/focal_point.js index a255732dafd51f9612a60a112c1e7aaeb8fdbe0b..22aa739b60c6d69a81d3851642d4b73126d0ca74 100644 --- a/web/modules/focal_point/js/focal_point.js +++ b/web/modules/focal_point/js/focal_point.js @@ -10,13 +10,21 @@ * Focal Point indicator. */ Drupal.behaviors.focalPointIndicator = { - attach: function(context, settings) { + attach: function(context) { $(".focal-point", context).once('focal-point-hide-field').each(function() { - // Hide the focal_point form item. We do this with js so that a non-js - // user can still set the focal point values. Also, add functionality so - // that if the indicator is double clicked, the form item is displayed. + var $wrapper = $(this).closest('.focal-point-wrapper'); + // Add the "visually-hidden" class unless the focal point offset field + // has an error. This will show the field for everyone when there is an + // error and for non-sighted users no matter what. We add it the + // form item to make sure the field is focusable while + // the entire form item is hidden for sighted users. if (!$(this).hasClass('error')) { - $(this).closest('.form-item').hide(); + $wrapper.addClass('visually-hidden'); + $(this).on('focus', function () { + $wrapper.removeClass('visually-hidden'); + }).on('blur', function () { + $wrapper.addClass('visually-hidden'); + }); } }); @@ -84,7 +92,7 @@ // Allow users to double-click the indicator to reveal the focal point form // element. this.$indicator.on('dblclick', function() { - self.$field.closest('.form-item').toggle(); + self.$field.closest('.focal-point-wrapper').toggleClass('visually-hidden'); }); // Allow users to click on the image preview in order to set the focal_point @@ -95,13 +103,9 @@ this.$img.css('cursor', 'crosshair'); // Add a change event to the focal point field so it will properly update - // the indicator position. + // the indicator position and preview link. this.$field.on('change', function() { - // Update the indicator position in case someone has typed in a value. - self.setIndicator(); - - // Update the href of the preview link. - self.updatePreviewLink($(this).attr('data-selector'), $(this).val()); + $(document).trigger('drupalFocalPointSet', { $focalPoint: self }); }); // Wrap the focal point indicator and thumbnail image in a div so that @@ -120,7 +124,8 @@ Drupal.FocalPoint.prototype.set = function(offsetX, offsetY) { var focalPoint = this.calculate(offsetX, offsetY); this.$field.val(focalPoint.x + ',' + focalPoint.y).trigger('change'); - this.setIndicator(); + + $(document).trigger('drupalFocalPointSet', { $focalPoint: this }); }; /** @@ -177,14 +182,14 @@ /** * Updates the preview link to include the correct focal point value. * - * @param selector string + * @param dataSelector string * The data-selector value for the preview link. * @param value string * The new focal point value in the form x,y where x and y are integers from * 0 to 100. */ - Drupal.FocalPoint.prototype.updatePreviewLink = function (selector, value) { - var $previewLink = $('a.focal-point-preview-link[data-selector=' + selector + ']'); + Drupal.FocalPoint.prototype.updatePreviewLink = function (dataSelector, value) { + var $previewLink = $('a.focal-point-preview-link[data-selector=' + dataSelector + ']'); if ($previewLink.length > 0) { var href = $previewLink.attr('href').split('/'); href.pop(); @@ -193,6 +198,30 @@ href.push(value.replace(',', 'x').concat($previewLink[0].search ? $previewLink[0].search : '')); $previewLink.attr('href', href.join('/')); } - } + + // Update the ajax binding to reflect the new preview link href value. + Drupal.ajax.instances.forEach(function(instance, index) { + if (instance && $(instance.element).data('selector') === dataSelector) { + var href = $(instance.selector).attr('href'); + Drupal.ajax.instances[index].url = href; + Drupal.ajax.instances[index].options.url = href; + } + }); + }; + + /** + * Update the Focal Point indicator and preview link when focal point changes. + * + * @param {jQuery.Event} event + * The `drupalFocalPointSet` event. + * @param {object} data + * An object containing the data relevant to the event. + * + * @listens event:drupalFocalPointSet + */ + $(document).on('drupalFocalPointSet', function (event, data) { + data.$focalPoint.setIndicator(); + data.$focalPoint.updatePreviewLink(data.$focalPoint.$field.attr('data-selector'), data.$focalPoint.$field.val()); + }); })(jQuery, Drupal); diff --git a/web/modules/focal_point/js/focal_point_preview.js b/web/modules/focal_point/js/focal_point_preview.js index 89c6391940929124f7bb589f8b11395098115216..a12c8acbeee1c1e1f91a6f6747f47cc32c542e10 100644 --- a/web/modules/focal_point/js/focal_point_preview.js +++ b/web/modules/focal_point/js/focal_point_preview.js @@ -22,17 +22,25 @@ // Add a click event to each derivative preview. $focalPointDerivativePreviews.each(function () { $(this).click(function(event) { + // Remove any image style classes added by active previews. + $(".focal-point-derivative-preview.active").each(function () { + $focalPointImagePreview.removeClass($(this).data('image-style')) + }); // Before adding the active class, remove the active class from all // derivative previews in case one is already active. $(".focal-point-derivative-preview").removeClass('active'); - $(this).addClass('active'); + var $this = $(this); + var image_style = $this.data('image-style'); + $this.addClass('active'); // Set the main preview label and image to this derivative since it // was just clicked. - var imageSrc = $(this).find("img").attr('src'); - var imageLabel = $(this).find('h3').html(); + var imageSrc = $this.find("img").attr('src'); + var imageLabel = $this.find('h3').html(); $focalPointImagePreviewLabel.html(imageLabel); $focalPointImagePreview.attr('src', imageSrc); + $focalPointImagePreview.addClass(image_style); + $focalPointImagePreview.data('image-style', image_style); // Prevent the window click event from running. event.stopPropagation(); @@ -58,8 +66,8 @@ */ function resetPreview() { $focalPointDerivativePreviews.removeClass('active'); - $focalPointImagePreviewLabel.html(originalImagePreviewLabel); + $focalPointImagePreview.removeClass($focalPointImagePreview.data('image-style')); $focalPointImagePreview.attr('src', originalImageURL); } diff --git a/web/modules/focal_point/src/Controller/FocalPointPreviewController.php b/web/modules/focal_point/src/Controller/FocalPointPreviewController.php index 25064f6fb8bbf4482946d968aa67ebcb3ad447b4..7068b04df563993f5c126c928433c8b292e282b9 100644 --- a/web/modules/focal_point/src/Controller/FocalPointPreviewController.php +++ b/web/modules/focal_point/src/Controller/FocalPointPreviewController.php @@ -11,6 +11,11 @@ use Drupal\Core\Access\AccessResult; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Url; +use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Ajax\OpenModalDialogCommand; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Drupal\Core\Image\ImageFactory; +use Symfony\Component\HttpFoundation\RequestStack; /** * Class FocalPointPreviewController. @@ -19,6 +24,51 @@ */ class FocalPointPreviewController extends ControllerBase { + /** + * The image factory service. + * + * @var \Drupal\Core\Image\ImageFactory + */ + protected $imageFactory; + + /** + * The request service. + * + * @var \Symfony\Component\HttpFoundation\RequestStack + */ + protected $request; + + /** + * The file storage service. + * + * @var \Drupal\file\FileStorage + */ + protected $fileStorage; + + /** + * {@inheritdoc} + * + * @param \Drupal\Core\Image\ImageFactory $image_factory + * The image_factory parameter. + * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack + * The request parameter. + */ + public function __construct(ImageFactory $image_factory, RequestStack $request_stack) { + $this->imageFactory = $image_factory; + $this->request = $request_stack->getCurrentRequest(); + $this->fileStorage = $this->entityTypeManager()->getStorage('file'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('image.factory'), + $container->get('request_stack') + ); + } + /** * {@inheritdoc} * @@ -26,9 +76,8 @@ class FocalPointPreviewController extends ControllerBase { */ public function content($fid, $focal_point_value) { $output = []; - - $file = File::load($fid); - $image = \Drupal::service('image.factory')->get($file->getFileUri()); + $file = $this->fileStorage->load($fid); + $image = $this->imageFactory->get($file->getFileUri()); if (!$image->isValid()) { throw new InvalidArgumentException('The file with id = $fid is not an image.'); } @@ -47,7 +96,7 @@ public function content($fid, $focal_point_value) { $original_image = [ '#theme' => 'image', '#uri' => $image->getSource(), - '#alt' => t('Focal Point Preview Image'), + '#alt' => $this->t('Focal Point Preview Image'), '#attributes' => [ 'id' => 'focal-point-preview-image', ], @@ -76,7 +125,11 @@ public function content($fid, $focal_point_value) { else { // There are no styles that use a focal point effect to preview. $image_styles_url = Url::fromRoute('entity.image_style.collection')->toString(); - drupal_set_message($this->t('You must have at least one <a href=":url">image style</a> defined that uses a focal point effect in order to preview.', [':url' => $image_styles_url]), 'warning'); + $this->messenger()->addWarning( + $this->t('You must have at least one <a href=":url">image style</a> defined that uses a focal point effect in order to preview.', + [':url' => $image_styles_url] + ) + ); } $output['focal_point_preview_page'] = [ @@ -88,7 +141,18 @@ public function content($fid, $focal_point_value) { '#derivative_image_note' => $derivative_image_note, ]; - return $output; + $html = render($output); + + $options = [ + 'dialogClass' => 'popup-dialog-class', + 'width' => '80%', + ]; + $response = new AjaxResponse(); + $response->addCommand( + new OpenModalDialogCommand($this->t('Images preview'), $html, $options) + ); + + return $response; } /** @@ -104,15 +168,15 @@ public function content($fid, $focal_point_value) { * @param int $fid * The file id for the image being previewed from the URL. * - * @return AccessResult + * @return \Drupal\Core\Access\AccessResult * An AccessResult object defining if permission is granted or not. */ public function access(AccountInterface $account, $fid) { $access = AccessResult::forbidden(); // @todo: I should be able to use "magic args" to load the file directly. - $file = File::load($fid); - $image = \Drupal::service('image.factory')->get($file->getFileUri()); + $file = $this->fileStorage->load($fid); + $image = $this->imageFactory->get($file->getFileUri()); if (!$image->isValid()) { throw new InvalidArgumentException('The file with id = $fid is not an image.'); } @@ -120,7 +184,7 @@ public function access(AccountInterface $account, $fid) { // Check if there was a valid token provided in with the HTTP request so // that preview is available on a "create entity" form. if ($this->validTokenProvided()) { - $access = AccessResult::allowed();; + $access = AccessResult::allowed(); } // If access has not yet been granted and the file module is enabled, check @@ -128,7 +192,7 @@ public function access(AccountInterface $account, $fid) { // has access to edit. if (function_exists('file_get_file_references') && !$access->isAllowed()) { $references = file_get_file_references($file, NULL, EntityStorageInterface::FIELD_LOAD_REVISION, ''); - foreach ($references as $field_name => $data) { + foreach ($references as $data) { foreach (array_keys($data) as $entity_type_id) { if ($account->hasPermission($entity_type_id . ".edit")) { $access = AccessResult::allowed(); @@ -200,8 +264,13 @@ protected function buildUrl(ImageStyle $style, File $image, $focal_point_value) */ protected function validTokenProvided() { try { - $token = \Drupal::request()->query->get('focal_point_token'); - return FocalPointImageWidget::validatePreviewToken($token); + if (\Drupal::request()->query->has('focal_point_token')) { + $token = \Drupal::request()->query->get('focal_point_token'); + return FocalPointImageWidget::validatePreviewToken($token); + } + else { + return FALSE; + } } catch (\InvalidArgumentException $e) { return FALSE; diff --git a/web/modules/focal_point/src/FocalPointEffectBase.php b/web/modules/focal_point/src/FocalPointEffectBase.php index dc1145e20e114fe70a6df74d1c6060b1e12911e3..36b08c596a916279c43ef9f046f38b60c3813cc4 100644 --- a/web/modules/focal_point/src/FocalPointEffectBase.php +++ b/web/modules/focal_point/src/FocalPointEffectBase.php @@ -92,7 +92,7 @@ public static function create(ContainerInterface $container, array $configuratio $plugin_id, $plugin_definition, $container->get('logger.factory')->get('image'), - new FocalPointManager($container->get('entity_type.manager')), + $container->get('focal_point.manager'), $container->get('entity_type.manager')->getStorage('crop'), $container->get('config.factory')->get('focal_point.settings'), \Drupal::request() @@ -132,21 +132,21 @@ public static function calculateResizeData($image_width, $image_height, $crop_wi if ($crop_width > $crop_height) { $resize_data['width'] = (int) $crop_width; - $resize_data['height'] = (int) ($crop_width * $image_height / $image_width); + $resize_data['height'] = (int) ceil(($crop_width * $image_height) / $image_width); // Ensure there is enough area to crop. if ($resize_data['height'] < $crop_height) { - $resize_data['width'] = (int) ($crop_height * $resize_data['width'] / $resize_data['height']); + $resize_data['width'] = (int) ceil(($crop_height * $resize_data['width']) / $resize_data['height']); $resize_data['height'] = (int) $crop_height; } } else { - $resize_data['width'] = (int) ($crop_height * $image_width / $image_height); + $resize_data['width'] = (int) ceil(($crop_height * $image_width) / $image_height); $resize_data['height'] = (int) $crop_height; // Ensure there is enough area to crop. if ($resize_data['width'] < $crop_width) { - $resize_data['height'] = (int) ($crop_width * $resize_data['height'] / $resize_data['width']); + $resize_data['height'] = (int) ceil(($crop_width * $resize_data['height']) / $resize_data['width']); $resize_data['width'] = (int) $crop_width; } } @@ -157,9 +157,9 @@ public static function calculateResizeData($image_width, $image_height, $crop_wi /** * Applies the crop effect to an image. * - * @param ImageInterface $image + * @param \Drupal\Core\Image\ImageInterface $image * The image resource to crop. - * @param CropInterface $crop + * @param \Drupal\crop\CropInterface $crop * A crop object containing the relevant crop information. * * @return bool @@ -187,10 +187,13 @@ public function applyCrop(ImageInterface $image, CropInterface $crop) { } /** + * Get the cropped image. + * * @param \Drupal\Core\Image\ImageInterface $image * The image resource whose crop is being requested. * * @return \Drupal\crop\CropInterface + * The crop. */ public function getCrop(ImageInterface $image) { $crop_type = $this->focalPointConfig->get('crop_type'); @@ -270,15 +273,15 @@ public function getOriginalImageSize() { * * @param array $focal_point * The focal point value. - * @param ImageInterface $image + * @param \Drupal\Core\Image\ImageInterface $image * The original image to be cropped. - * @param CropInterface $crop + * @param \Drupal\crop\CropInterface $crop * The crop object used to define the crop. * * @return array * An array with the keys 'x' and 'y'. */ - protected function calculateAnchor($focal_point, ImageInterface $image, CropInterface $crop) { + protected function calculateAnchor(array $focal_point, ImageInterface $image, CropInterface $crop) { $crop_size = $crop->size(); // The anchor must be the top-left coordinate of the crop area but the focal @@ -303,15 +306,15 @@ protected function calculateAnchor($focal_point, ImageInterface $image, CropInte * @param array $anchor * An array with the keys 'x' and 'y'. Values are in pixels representing the * top left corner of the of the crop area relative to the image. - * @param ImageInterface $image + * @param \Drupal\Core\Image\ImageInterface $image * The image to which the crop area must be constrained. - * @param CropInterface $crop + * @param \Drupal\crop\CropInterface $crop * The crop object used to define the crop. * * @return array * An array with the keys 'x' and 'y'. */ - protected function constrainCropArea($anchor, ImageInterface $image, CropInterface $crop) { + protected function constrainCropArea(array $anchor, ImageInterface $image, CropInterface $crop) { $image_size = [ 'width' => $image->getWidth(), 'height' => $image->getHeight(), @@ -363,7 +366,7 @@ protected function getOriginalFocalPoint(CropInterface $crop, FocalPointManager /** * Returns the focal point value (in pixels) relative to the provided image. * - * @param ImageInterface $image + * @param \Drupal\Core\Image\ImageInterface $image * Image object that the focal point must be applied to. * @param array $original_focal_point * An array with keys 'x' and 'y' which represent the focal point in pixels @@ -372,7 +375,7 @@ protected function getOriginalFocalPoint(CropInterface $crop, FocalPointManager * @return array * An array with the keys 'x' and 'y'. Values are in pixels. */ - protected function transformFocalPoint(ImageInterface $image, $original_focal_point) { + protected function transformFocalPoint(ImageInterface $image, array $original_focal_point) { $image_size = [ 'width' => $image->getWidth(), 'height' => $image->getHeight(), diff --git a/web/modules/focal_point/src/FocalPointManager.php b/web/modules/focal_point/src/FocalPointManager.php index 591210dfff841924e93dfff2c3180351febd6921..b6e5b67f732383949290f3c3b21e25df8c8b8103 100644 --- a/web/modules/focal_point/src/FocalPointManager.php +++ b/web/modules/focal_point/src/FocalPointManager.php @@ -81,8 +81,7 @@ public function getCropEntity(FileInterface $file, $crop_type) { 'uri' => $file->getFileUri(), ]; - $crop = \Drupal::entityTypeManager() - ->getStorage('crop') + $crop = $this->cropStorage ->create($values); } diff --git a/web/modules/focal_point/src/Plugin/Field/FieldWidget/FocalPointImageWidget.php b/web/modules/focal_point/src/Plugin/Field/FieldWidget/FocalPointImageWidget.php old mode 100644 new mode 100755 index c0eb137f7f26ea89e1d76379f4c3d26339a81610..b5161f69655d9b73c94011cbb0f76fc95a55707d --- a/web/modules/focal_point/src/Plugin/Field/FieldWidget/FocalPointImageWidget.php +++ b/web/modules/focal_point/src/Plugin/Field/FieldWidget/FocalPointImageWidget.php @@ -47,7 +47,7 @@ public function settingsForm(array $form, FormStateInterface $form_state) { unset($form['preview_image_style']['#empty_option']); // @todo Implement https://www.drupal.org/node/2872960 // The preview image should not be generated using a focal point effect - // and should maintain teh aspect ratio of the original image. + // and should maintain the aspect ratio of the original image. $form['preview_image_style']['#description'] = t( $form['preview_image_style']['#description']->getUntranslatedString() . "<br/>Do not choose an image style that alters the aspect ratio of the original image nor an image style that uses a focal point effect.", $form['preview_image_style']['#description']->getArguments(), @@ -129,6 +129,14 @@ public static function process($element, FormStateInterface $form_state, $form) $default_focal_point_value = isset($item['focal_point']) ? $item['focal_point'] : $element['#focal_point']['offsets']; + // Override the default Image Widget template when using the Media Library + // module so we can use the image field's preview rather than the preview + // provided by Media Library. + if ($form['#form_id'] == 'media_library_upload_form' || $form['#form_id'] == 'media_library_add_form') { + $element['#theme'] = 'focal_point_media_library_image_widget'; + unset($form['media'][0]['preview']); + } + // Add the focal point indicator to preview. if (isset($element['preview'])) { $preview = [ @@ -249,10 +257,10 @@ public static function validatePreviewToken($token) { * @param string $default_focal_point_value * The default focal point value in the form x,y. * - * @return array The preview link form element. + * @return array * The preview link form element. */ - private static function createFocalPointField($field_name, $element_selectors, $default_focal_point_value) { + private static function createFocalPointField($field_name, array $element_selectors, $default_focal_point_value) { $field = [ '#type' => 'textfield', '#title' => new TranslatableMarkup('Focal point'), @@ -264,6 +272,9 @@ private static function createFocalPointField($field_name, $element_selectors, $ 'data-selector' => $element_selectors['focal_point'], 'data-field-name' => $field_name, ], + '#wrapper_attributes' => [ + 'class' => ['focal-point-wrapper'], + ], '#attached' => [ 'library' => ['focal_point/drupal.focal_point'], ], @@ -283,7 +294,7 @@ private static function createFocalPointField($field_name, $element_selectors, $ * @return array * The focal point field form element. */ - private static function createFocalPointIndicator($delta, $element_selectors) { + private static function createFocalPointIndicator($delta, array $element_selectors) { $indicator = [ '#type' => 'html_tag', '#tag' => 'div', @@ -309,10 +320,10 @@ private static function createFocalPointIndicator($delta, $element_selectors) { * @param string $default_focal_point_value * The default focal point value in the form x,y. * - * @return array The preview link form element. + * @return array * The preview link form element. */ - private static function createPreviewLink($fid, $field_name, $element_selectors, $default_focal_point_value) { + private static function createPreviewLink($fid, $field_name, array $element_selectors, $default_focal_point_value) { // Replace comma (,) with an x to make javascript handling easier. $preview_focal_point_value = str_replace(',', 'x', $default_focal_point_value); @@ -330,10 +341,14 @@ private static function createPreviewLink($fid, $field_name, $element_selectors, [ 'query' => ['focal_point_token' => $token], ]), + '#attached' => [ + 'library' => ['core/drupal.dialog.ajax'], + ], '#attributes' => [ - 'class' => ['focal-point-preview-link'], + 'class' => ['focal-point-preview-link', 'use-ajax'], 'data-selector' => $element_selectors['focal_point'], 'data-field-name' => $field_name, + 'data-dialog-type' => 'modal', 'target' => '_blank', ], ]; @@ -341,5 +356,4 @@ private static function createPreviewLink($fid, $field_name, $element_selectors, return $preview_link; } - } diff --git a/web/modules/focal_point/src/Plugin/ImageEffect/FocalPointScaleAndCropImageEffect.php b/web/modules/focal_point/src/Plugin/ImageEffect/FocalPointScaleAndCropImageEffect.php index ac8de46e38391dd63b87c35fb2f0385dad9df623..3e3979665fbfee81f1ce109dd0fb8374c8a83e59 100644 --- a/web/modules/focal_point/src/Plugin/ImageEffect/FocalPointScaleAndCropImageEffect.php +++ b/web/modules/focal_point/src/Plugin/ImageEffect/FocalPointScaleAndCropImageEffect.php @@ -52,7 +52,7 @@ public function defaultConfiguration() { // @see crop_file_url_alter() // @see https://www.drupal.org/node/2842260 return parent::defaultConfiguration() + [ - 'crop_type' => 'focal_point' + 'crop_type' => 'focal_point', ]; } diff --git a/web/modules/focal_point/templates/focal-point-media-library-image-widget.html.twig b/web/modules/focal_point/templates/focal-point-media-library-image-widget.html.twig new file mode 100644 index 0000000000000000000000000000000000000000..8beef21f81a0e66298a014d1cc7181f450f48000 --- /dev/null +++ b/web/modules/focal_point/templates/focal-point-media-library-image-widget.html.twig @@ -0,0 +1,10 @@ +{# +/** + * @file + * Override of the image field widget to display the preview image after other fields. + */ +#} +<div{{ attributes }}> + {{ data|without('preview') }} + {{ data.preview }} +</div> diff --git a/web/modules/focal_point/templates/focal-point-preview-page.html.twig b/web/modules/focal_point/templates/focal-point-preview-page.html.twig index f06197550cc796d40db3be0c9ea110f0f3e0c67b..b487b8896d30dfe5f60a62564e8d163d84b510d1 100644 --- a/web/modules/focal_point/templates/focal-point-preview-page.html.twig +++ b/web/modules/focal_point/templates/focal-point-preview-page.html.twig @@ -4,7 +4,7 @@ <span class="derivatives-note note">{{ derivative_image_note }}</span> <div id="focal-point-derivatives"> {% for style,derivative in derivative_images %} - <div id="focal-point-derivative-preview-{{ style }}" class="focal-point-derivative-preview"> + <div id="focal-point-derivative-preview-{{ style }}" class="focal-point-derivative-preview" data-image-style="{{ style }}"> <h3 class="focal-point-derivative-preview-label">{{ derivative.style }}</h3> {{ derivative.image }} </div> diff --git a/web/modules/focal_point/tests/src/Functional/FocalPointFunctionalTestCase.php b/web/modules/focal_point/tests/src/Functional/FocalPointFunctionalTestCase.php new file mode 100644 index 0000000000000000000000000000000000000000..e0fdd40eb485ee69e29f3ff621125a88bb4f7423 --- /dev/null +++ b/web/modules/focal_point/tests/src/Functional/FocalPointFunctionalTestCase.php @@ -0,0 +1,109 @@ +<?php + +namespace Drupal\Tests\focal_point\Functional; + +use Drupal\file\Entity\File; +use Drupal\Tests\BrowserTestBase; +use Drupal\Tests\image\Kernel\ImageFieldCreationTrait; +use Drupal\Tests\TestFileCreationTrait; + +/** + * Tests that the Focal Point widget works properly. + * + * @group focal_point + */ +class FocalPointWidgetTest extends BrowserTestBase { + + use ImageFieldCreationTrait; + use TestFileCreationTrait; + + /** + * Modules to enable. + * + * @var array + */ + protected static $modules = ['node', 'focal_point']; + + /** + * {@inheritdoc} + */ + public function setUp() { + parent::setUp(); + + // Create an article content type that we will use for testing. + $type = $this->container->get('entity_type.manager')->getStorage('node_type') + ->create([ + 'type' => 'article', + 'name' => 'Article', + ]); + $type->save(); + $this->container->get('router.builder')->rebuild(); + + + } + + /** + * Tests that the reaction rule listing page works. + */ + public function testFocalPointWidget() { + $account = $this->drupalCreateUser(['administer nodes']); + $this->drupalLogin($account); + + $this->drupalGet('admin'); + $this->assertSession()->statusCodeEquals(200); + + // Test that there is an empty reaction rule listing. +// $this->assertSession()->pageTextContains('There is no Reaction Rule yet.'); + } + + public function testResave() { + + $field_name = strtolower($this->randomMachineName()); + + $this->createImageField($field_name, 'article', [], [ + 'file_extensions' => 'png jpg gif', + ], [], [ + 'image_style' => 'large', + 'image_link' => '', + ]); + + // Find images that match our field settings. + $images = $this->getTestFiles('image'); + + // Create a File entity for the initial image. + $file = File::create([ + 'uri' => $images[0]->uri, + 'uid' => 0, + 'status' => FILE_STATUS_PERMANENT, + ]); + $file->save(); + + // Use the first valid image to create a new Node. + $image_factory = $this->container->get('image.factory'); + $image = $image_factory->get($images[0]->uri); + + /** @var \Drupal\focal_point\FocalPointManagerInterface $focalPointManager */ + $focalPointManager = \Drupal::service('focal_point.manager'); + + $crop = $focalPointManager->getCropEntity($file, 'focal_point'); + $focalPointManager->saveCropEntity(5, 5, $image->getWidth(), $image->getHeight(), $crop); + + $this->drupalCreateNode([ + 'type' => 'article', + 'title' => t('Test Node'), + $field_name => [ + 'target_id' => $file->id(), + 'width' => $image->getWidth(), + 'height' => $image->getHeight(), + ], + ]); + + $crop = $focalPointManager->getCropEntity($file, 'focal_point'); + + $this->assertEquals(2, $crop->get('x')->value); + $this->assertEquals(1, $crop->get('y')->value); + $this->assertEquals(0, $crop->get('width')->value); + $this->assertEquals(0, $crop->get('height')->value); + } + +} diff --git a/web/modules/focal_point/tests/src/Unit/Effects/FocalPointEffectsTest.php b/web/modules/focal_point/tests/src/Unit/Effects/FocalPointEffectsTest.php index 599047e8f65c761f35a86c28ea81c3dc266e4f0e..aac801c8cd13960809216be6220494be05fc3772 100644 --- a/web/modules/focal_point/tests/src/Unit/Effects/FocalPointEffectsTest.php +++ b/web/modules/focal_point/tests/src/Unit/Effects/FocalPointEffectsTest.php @@ -69,7 +69,7 @@ public function calculateResizeDataProvider() { $data['vertical_image_horizontal_crop'] = [480, 640, 300, 100, ['width' => 300, 'height' => 400]]; $data['vertical_image_vertical_crop'] = [480, 640, 100, 300, ['width' => 225, 'height' => 300]]; $data['horizontal_image_too_large_crop'] = [640, 480, 3000, 1000, ['width' => 3000, 'height' => 2250]]; - $data['image_too_narrow_to_crop_after_resize'] = [1920, 1080, 400, 300, ['width' => 533, 'height' => 300]]; + $data['image_too_narrow_to_crop_after_resize'] = [1920, 1080, 400, 300, ['width' => 534, 'height' => 300]]; $data['image_too_short_to_crop_after_resize'] = [200, 400, 1000, 1000, ['width' => 1000, 'height' => 2000]]; // @codingStandardsIgnoreEnd return $data;