From 48b3fee9abdaafcab6e99f694d0c35edbbe8d8d8 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 23 Jun 2021 20:32:33 +0200 Subject: [PATCH 01/14] Wrap media item into MediaWithCrops --- src/Umbraco.Core/Models/MediaWithCrops.cs | 13 ++++++++++--- .../MediaPickerWithCropsValueConverter.cs | 16 +++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Core/Models/MediaWithCrops.cs b/src/Umbraco.Core/Models/MediaWithCrops.cs index ef3205bd9436..b3cb0d407beb 100644 --- a/src/Umbraco.Core/Models/MediaWithCrops.cs +++ b/src/Umbraco.Core/Models/MediaWithCrops.cs @@ -6,10 +6,17 @@ namespace Umbraco.Core.Models /// /// Model used in Razor Views for rendering /// - public class MediaWithCrops + public class MediaWithCrops : PublishedContentWrapped { - public IPublishedContent MediaItem { get; set; } + public IPublishedContent MediaItem { get; } - public ImageCropperValue LocalCrops { get; set; } + public ImageCropperValue LocalCrops { get; } + + public MediaWithCrops(IPublishedContent content, ImageCropperValue localCrops) + : base(content) + { + MediaItem = content; + LocalCrops = localCrops; + } } } diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs index f2f055d69821..6290cb1a10d6 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs @@ -57,16 +57,14 @@ public override object ConvertIntermediateToObject(IPublishedElement owner, IPub var mediaItem = _publishedSnapshotAccessor.PublishedSnapshot.Media.GetById(preview, dto.MediaKey); if (mediaItem != null) { - mediaItems.Add(new MediaWithCrops + var localCrops = new ImageCropperValue { - MediaItem = mediaItem, - LocalCrops = new ImageCropperValue - { - Crops = dto.Crops, - FocalPoint = dto.FocalPoint, - Src = mediaItem.Url() - } - }); + Crops = dto.Crops, + FocalPoint = dto.FocalPoint, + Src = mediaItem.Url() + }; + + mediaItems.Add(new MediaWithCrops(mediaItem, localCrops)); if (!isMultiple) { From 9684d1d369ff5719b94722e8ed22b83b3bb92ded Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 23 Jun 2021 21:56:08 +0200 Subject: [PATCH 02/14] Merge local crops with media item crops, add GetCropUrl overloads --- .../ValueConverters/ImageCropperValue.cs | 33 +++++- .../ImageCropperTemplateCoreExtensions.cs | 102 ++++++++++++++---- .../ImageCropperTemplateExtensions.cs | 32 ++++-- 3 files changed, 139 insertions(+), 28 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValue.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValue.cs index 2c6ec9b8aa88..8e0e45c280a9 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValue.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValue.cs @@ -140,7 +140,7 @@ public bool HasFocalPoint() /// Determines whether the value has a specified crop. /// public bool HasCrop(string alias) - => Crops.Any(x => x.Alias == alias); + => Crops != null && Crops.Any(x => x.Alias == alias); /// /// Determines whether the value has a source image. @@ -190,6 +190,37 @@ internal void ApplyConfiguration(ImageCropperConfiguration configuration) Crops = crops; } + internal ImageCropperValue Merge(ImageCropperValue imageCropperValue) + { + var crops = Crops?.ToList() ?? new List(); + + var incomingCrops = imageCropperValue?.Crops; + if (incomingCrops != null) + { + foreach (var incomingCrop in incomingCrops) + { + var crop = crops.FirstOrDefault(x => x.Alias == incomingCrop.Alias); + if (crop == null) + { + // Add incoming crop + crops.Add(incomingCrop); + } + else if (crop.Coordinates == null) + { + // Use incoming crop coordinates + crop.Coordinates = incomingCrop.Coordinates; + } + } + } + + return new ImageCropperValue() + { + Src = !string.IsNullOrWhiteSpace(Src) ? Src : imageCropperValue?.Src, + Crops = crops, + FocalPoint = FocalPoint ?? imageCropperValue?.FocalPoint + }; + } + #region IEquatable /// diff --git a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs index 766cb1e99f91..0c532d45834d 100644 --- a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs +++ b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs @@ -28,6 +28,12 @@ public static string GetCropUrl(this IPublishedContent mediaItem, string cropAli return mediaItem.GetCropUrl(imageUrlGenerator, cropAlias: cropAlias, useCropDimensions: true); } + public static string GetCropUrl(this MediaWithCrops mediaWithCrops, string cropAlias, IImageUrlGenerator imageUrlGenerator) + { + return mediaWithCrops.GetCropUrl(imageUrlGenerator, cropAlias: cropAlias, useCropDimensions: true); + } + + [Obsolete("This method does not get the crops or cache buster value from the media item.")] public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias, IImageUrlGenerator imageUrlGenerator, ImageCropperValue imageCropperValue) { return mediaItem.Url().GetCropUrl(imageUrlGenerator, imageCropperValue, cropAlias: cropAlias, useCropDimensions: true); @@ -53,6 +59,11 @@ public static string GetCropUrl(this IPublishedContent mediaItem, string propert return mediaItem.GetCropUrl(imageUrlGenerator, propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true); } + public static string GetCropUrl(this MediaWithCrops mediaWithCrops, string propertyAlias, string cropAlias, IImageUrlGenerator imageUrlGenerator) + { + return mediaWithCrops.GetCropUrl(imageUrlGenerator, propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true); + } + /// /// Gets the ImageProcessor URL from the IPublishedContent item. /// @@ -122,6 +133,47 @@ public static string GetCropUrl( string furtherOptions = null, ImageCropRatioMode? ratioMode = null, bool upScale = true) + { + return mediaItem.GetCropUrl(imageUrlGenerator, null, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); + } + + public static string GetCropUrl( + this MediaWithCrops mediaWithCrops, + IImageUrlGenerator imageUrlGenerator, + int? width = null, + int? height = null, + string propertyAlias = Constants.Conventions.Media.File, + string cropAlias = null, + int? quality = null, + ImageCropMode? imageCropMode = null, + ImageCropAnchor? imageCropAnchor = null, + bool preferFocalPoint = false, + bool useCropDimensions = false, + bool cacheBuster = true, + string furtherOptions = null, + ImageCropRatioMode? ratioMode = null, + bool upScale = true) + { + return mediaWithCrops.MediaItem.GetCropUrl(imageUrlGenerator, mediaWithCrops.LocalCrops, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); + } + + private static string GetCropUrl( + this IPublishedContent mediaItem, + IImageUrlGenerator imageUrlGenerator, + ImageCropperValue localCrops, + int? width, + int? height, + string propertyAlias, + string cropAlias, + int? quality, + ImageCropMode? imageCropMode, + ImageCropAnchor? imageCropAnchor, + bool preferFocalPoint, + bool useCropDimensions, + bool cacheBuster, + string furtherOptions, + ImageCropRatioMode? ratioMode, + bool upScale) { if (mediaItem == null) throw new ArgumentNullException("mediaItem"); @@ -132,31 +184,38 @@ public static string GetCropUrl( var mediaItemUrl = mediaItem.MediaUrl(propertyAlias: propertyAlias); - //get the default obj from the value converter - var cropperValue = mediaItem.Value(propertyAlias); - - //is it strongly typed? - var stronglyTyped = cropperValue as ImageCropperValue; - if (stronglyTyped != null) + // Only get crops when used + if (imageCropMode == ImageCropMode.Crop || imageCropMode == null) { - return GetCropUrl( - mediaItemUrl, imageUrlGenerator, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, - cacheBusterValue, furtherOptions, ratioMode, upScale); - } + // Get the default cropper value from the value converter + var cropperValue = mediaItem.Value(propertyAlias); - //this shouldn't be the case but we'll check - var jobj = cropperValue as JObject; - if (jobj != null) - { - stronglyTyped = jobj.ToObject(); - return GetCropUrl( - mediaItemUrl, imageUrlGenerator, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, - cacheBusterValue, furtherOptions, ratioMode, upScale); + var mediaCrops = cropperValue as ImageCropperValue; + + if (mediaCrops == null && cropperValue is JObject jobj) + { + mediaCrops = jobj.ToObject(); + } + + if (mediaCrops == null && cropperValue is string imageCropperValue && + string.IsNullOrEmpty(imageCropperValue) == false && imageCropperValue.DetectIsJson()) + { + mediaCrops = imageCropperValue.DeserializeImageCropperValue(); + } + + // Merge crops + if (localCrops == null) + { + localCrops = mediaCrops; + } + else if (mediaCrops != null) + { + localCrops = localCrops.Merge(mediaCrops); + } } - //it's a single string return GetCropUrl( - mediaItemUrl, imageUrlGenerator, width, height, mediaItemUrl, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, + mediaItemUrl, imageUrlGenerator, localCrops, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale); } @@ -237,6 +296,7 @@ public static string GetCropUrl( { cropDataSet = imageCropperValue.DeserializeImageCropperValue(); } + return GetCropUrl( imageUrl, imageUrlGenerator, cropDataSet, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale); @@ -381,10 +441,10 @@ public static string GetCropUrl( return imageUrlGenerator.GetImageUrl(options); } + [Obsolete("Use GetCrop to merge local and media crops, get automatic cache buster value and have more parameters.")] public static string GetLocalCropUrl(this MediaWithCrops mediaWithCrops, string alias, IImageUrlGenerator imageUrlGenerator, string cacheBusterValue) { return mediaWithCrops.LocalCrops.Src + mediaWithCrops.LocalCrops.GetCropUrl(alias, imageUrlGenerator, cacheBusterValue: cacheBusterValue); - } } } diff --git a/src/Umbraco.Web/ImageCropperTemplateExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateExtensions.cs index 51845946f133..396cd63620f7 100644 --- a/src/Umbraco.Web/ImageCropperTemplateExtensions.cs +++ b/src/Umbraco.Web/ImageCropperTemplateExtensions.cs @@ -30,6 +30,9 @@ public static class ImageCropperTemplateExtensions /// public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, cropAlias, Current.ImageUrlGenerator); + public static string GetCropUrl(this MediaWithCrops mediaWithCrops, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaWithCrops, cropAlias, Current.ImageUrlGenerator); + + [Obsolete("This method does not get the crops or cache buster value from the media item.")] public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias, ImageCropperValue imageCropperValue) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, cropAlias, Current.ImageUrlGenerator, imageCropperValue); /// @@ -49,6 +52,8 @@ public static class ImageCropperTemplateExtensions /// public static string GetCropUrl(this IPublishedContent mediaItem, string propertyAlias, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, propertyAlias, cropAlias, Current.ImageUrlGenerator); + public static string GetCropUrl(this MediaWithCrops mediaWithCrops, string propertyAlias, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaWithCrops, propertyAlias, cropAlias, Current.ImageUrlGenerator); + /// /// Gets the ImageProcessor URL from the IPublishedContent item. /// @@ -118,12 +123,21 @@ public static string GetCropUrl( ImageCropRatioMode? ratioMode = null, bool upScale = true) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, Current.ImageUrlGenerator, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); - public static string GetLocalCropUrl(this MediaWithCrops mediaWithCrops, - string alias, - string cacheBusterValue = null) - => ImageCropperTemplateCoreExtensions.GetLocalCropUrl(mediaWithCrops, alias, Current.ImageUrlGenerator, cacheBusterValue); - - + public static string GetCropUrl( + this MediaWithCrops mediaWithCrops, + int? width = null, + int? height = null, + string propertyAlias = Constants.Conventions.Media.File, + string cropAlias = null, + int? quality = null, + ImageCropMode? imageCropMode = null, + ImageCropAnchor? imageCropAnchor = null, + bool preferFocalPoint = false, + bool useCropDimensions = false, + bool cacheBuster = true, + string furtherOptions = null, + ImageCropRatioMode? ratioMode = null, + bool upScale = true) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaWithCrops, Current.ImageUrlGenerator, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); /// /// Gets the ImageProcessor URL from the image path. @@ -261,6 +275,12 @@ public static string GetCropUrl( ImageCropRatioMode? ratioMode = null, bool upScale = true) => ImageCropperTemplateCoreExtensions.GetCropUrl(imageUrl, Current.ImageUrlGenerator, cropDataSet, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale); + [Obsolete("Use GetCrop to merge local and media crops, get automatic cache buster value and have more parameters.")] + public static string GetLocalCropUrl(this MediaWithCrops mediaWithCrops, + string alias, + string cacheBusterValue = null) + => ImageCropperTemplateCoreExtensions.GetLocalCropUrl(mediaWithCrops, alias, Current.ImageUrlGenerator, cacheBusterValue); + private static readonly JsonSerializerSettings ImageCropperValueJsonSerializerSettings = new JsonSerializerSettings { Culture = CultureInfo.InvariantCulture, From f786b5626cd369c13a7bab19c71baea5c3d97771 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 23 Jun 2021 22:25:59 +0200 Subject: [PATCH 03/14] Ensure crops removed from Image cropper configuration are not returned --- .../ImageCropperConfiguration.cs | 35 ++++++++++++++++ .../ValueConverters/ImageCropperValue.cs | 42 ------------------- 2 files changed, 35 insertions(+), 42 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs index 2ce6e2ec04b1..cf2d1cb18e9f 100644 --- a/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs @@ -1,4 +1,8 @@ using Newtonsoft.Json; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.PropertyEditors.ValueConverters; +using static Umbraco.Core.PropertyEditors.ValueConverters.ImageCropperValue; namespace Umbraco.Core.PropertyEditors { @@ -22,4 +26,35 @@ public class Crop public int Height { get; set; } } } + + internal static class ImageCropperConfigurationExtensions + { + /// + /// Applies the configuration to ensure only valid crops are kept and have the correct width/height. + /// + /// The configuration. + public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, ImageCropperConfiguration configuration) + { + var crops = new List(); + + var configuredCrops = configuration?.Crops; + if (configuredCrops != null) + { + foreach (var configuredCrop in configuredCrops) + { + var crop = imageCropperValue.Crops.FirstOrDefault(x => x.Alias == configuredCrop.Alias); + + crops.Add(new ImageCropperCrop + { + Alias = configuredCrop.Alias, + Width = configuredCrop.Width, + Height = configuredCrop.Height, + Coordinates = crop?.Coordinates + }); + } + } + + imageCropperValue.Crops = crops; + } + } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValue.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValue.cs index 8e0e45c280a9..f2151778d9ce 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValue.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValue.cs @@ -148,48 +148,6 @@ public bool HasCrop(string alias) public bool HasImage() => !string.IsNullOrWhiteSpace(Src); - /// - /// Applies a configuration. - /// - /// Ensures that all crops defined in the configuration exists in the value. - internal void ApplyConfiguration(ImageCropperConfiguration configuration) - { - // merge the crop values - the alias + width + height comes from - // configuration, but each crop can store its own coordinates - - var configuredCrops = configuration?.Crops; - if (configuredCrops == null) return; - - //Use Crops if it's not null, otherwise create a new list - var crops = Crops?.ToList() ?? new List(); - - foreach (var configuredCrop in configuredCrops) - { - var crop = crops.FirstOrDefault(x => x.Alias == configuredCrop.Alias); - if (crop != null) - { - // found, apply the height & width - crop.Width = configuredCrop.Width; - crop.Height = configuredCrop.Height; - } - else - { - // not found, add - crops.Add(new ImageCropperCrop - { - Alias = configuredCrop.Alias, - Width = configuredCrop.Width, - Height = configuredCrop.Height - }); - } - } - - // assume we don't have to remove the crops in value, that - // are not part of configuration anymore? - - Crops = crops; - } - internal ImageCropperValue Merge(ImageCropperValue imageCropperValue) { var crops = Crops?.ToList() ?? new List(); From 0619687e007bd8f78169479fe2be46344a6027ec Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 23 Jun 2021 22:26:51 +0200 Subject: [PATCH 04/14] Ensure local crops removed from Media picker configuration are not returned --- .../MediaPicker3Configuration.cs | 35 +++++++++++++++++++ .../MediaPickerWithCropsValueConverter.cs | 3 ++ 2 files changed, 38 insertions(+) diff --git a/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs b/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs index 4c3c6564a5da..a7f1f2902fff 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs @@ -1,6 +1,10 @@ using Newtonsoft.Json; +using System.Collections.Generic; +using System.Linq; using Umbraco.Core; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.PropertyEditors.ValueConverters; +using static Umbraco.Core.PropertyEditors.ValueConverters.ImageCropperValue; namespace Umbraco.Web.PropertyEditors { @@ -57,4 +61,35 @@ public class CropConfiguration public int Height { get; set; } } } + + internal static class MediaPicker3ConfigurationExtensions + { + /// + /// Applies the configuration to ensure only valid crops are kept and have the correct width/height. + /// + /// The configuration. + public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, MediaPicker3Configuration configuration) + { + var crops = new List(); + + var configuredCrops = configuration?.Crops; + if (configuredCrops != null) + { + foreach (var configuredCrop in configuredCrops) + { + var crop = imageCropperValue.Crops.FirstOrDefault(x => x.Alias == configuredCrop.Alias); + + crops.Add(new ImageCropperCrop + { + Alias = configuredCrop.Alias, + Width = configuredCrop.Width, + Height = configuredCrop.Height, + Coordinates = crop?.Coordinates + }); + } + } + + imageCropperValue.Crops = crops; + } + } } diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs index 6290cb1a10d6..b05a23efdb2e 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs @@ -51,6 +51,7 @@ public override object ConvertIntermediateToObject(IPublishedElement owner, IPub var mediaItems = new List(); var dtos = MediaPicker3PropertyEditor.MediaPicker3PropertyValueEditor.Deserialize(inter); + var configuration = propertyType.DataType.ConfigurationAs(); foreach (var dto in dtos) { @@ -64,6 +65,8 @@ public override object ConvertIntermediateToObject(IPublishedElement owner, IPub Src = mediaItem.Url() }; + localCrops.ApplyConfiguration(configuration); + mediaItems.Add(new MediaWithCrops(mediaItem, localCrops)); if (!isMultiple) From be41484764f0eae9e10062efe664d39075a998d5 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 23 Jun 2021 22:39:37 +0200 Subject: [PATCH 05/14] Remove local focal point when not enabled in configuration --- src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs b/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs index a7f1f2902fff..3508e69328cf 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs @@ -90,6 +90,11 @@ public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, } imageCropperValue.Crops = crops; + + if (!configuration.EnableLocalFocalPoint) + { + imageCropperValue.FocalPoint = null; + } } } } From bb45b62b814bc9820dc05e5c564c4d1a0977ae17 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 23 Jun 2021 22:44:16 +0200 Subject: [PATCH 06/14] Add additional null checks to ApplyConfiguration --- src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs | 2 +- src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs index cf2d1cb18e9f..855ec76a5a8d 100644 --- a/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs +++ b/src/Umbraco.Core/PropertyEditors/ImageCropperConfiguration.cs @@ -42,7 +42,7 @@ public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, { foreach (var configuredCrop in configuredCrops) { - var crop = imageCropperValue.Crops.FirstOrDefault(x => x.Alias == configuredCrop.Alias); + var crop = imageCropperValue.Crops?.FirstOrDefault(x => x.Alias == configuredCrop.Alias); crops.Add(new ImageCropperCrop { diff --git a/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs b/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs index 3508e69328cf..1a6a1cde0bbf 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPicker3Configuration.cs @@ -77,7 +77,7 @@ public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, { foreach (var configuredCrop in configuredCrops) { - var crop = imageCropperValue.Crops.FirstOrDefault(x => x.Alias == configuredCrop.Alias); + var crop = imageCropperValue.Crops?.FirstOrDefault(x => x.Alias == configuredCrop.Alias); crops.Add(new ImageCropperCrop { @@ -91,7 +91,7 @@ public static void ApplyConfiguration(this ImageCropperValue imageCropperValue, imageCropperValue.Crops = crops; - if (!configuration.EnableLocalFocalPoint) + if (configuration?.EnableLocalFocalPoint == false) { imageCropperValue.FocalPoint = null; } From fdb6171f712e6cb8c566daa028fc0903a65b6c7d Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 23 Jun 2021 23:02:43 +0200 Subject: [PATCH 07/14] Use Unwrap to return MediaItem --- src/Umbraco.Core/Models/MediaWithCrops.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Models/MediaWithCrops.cs b/src/Umbraco.Core/Models/MediaWithCrops.cs index b3cb0d407beb..e947bbcfcc84 100644 --- a/src/Umbraco.Core/Models/MediaWithCrops.cs +++ b/src/Umbraco.Core/Models/MediaWithCrops.cs @@ -8,14 +8,13 @@ namespace Umbraco.Core.Models /// public class MediaWithCrops : PublishedContentWrapped { - public IPublishedContent MediaItem { get; } + public IPublishedContent MediaItem => Unwrap(); public ImageCropperValue LocalCrops { get; } public MediaWithCrops(IPublishedContent content, ImageCropperValue localCrops) : base(content) { - MediaItem = content; LocalCrops = localCrops; } } From f8095be73c8b0a08324d55c562b654158ecfbc88 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 24 Jun 2021 09:01:57 +0200 Subject: [PATCH 08/14] Fix CanConvertImageCropperPropertyEditor test by providing correct configuration --- .../PropertyEditors/ImageCropperTest.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs index c5c2b4e61fba..c40708770e05 100644 --- a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs +++ b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs @@ -82,8 +82,20 @@ public void CanConvertImageCropperPropertyEditor(string val1, string val2, bool var mediaFileSystem = new MediaFileSystem(Mock.Of(), config, scheme, logger); + var imageCropperConfiguration = new ImageCropperConfiguration() + { + Crops = new[] + { + new ImageCropperConfiguration.Crop() + { + Alias = "thumb", + Width = 100, + Height = 100 + } + } + }; var dataTypeService = new TestObjects.TestDataTypeService( - new DataType(new ImageCropperPropertyEditor(Mock.Of(), mediaFileSystem, Mock.Of(), Mock.Of())) { Id = 1 }); + new DataType(new ImageCropperPropertyEditor(Mock.Of(), mediaFileSystem, Mock.Of(), Mock.Of())) { Id = 1, Configuration = imageCropperConfiguration }); var factory = new PublishedContentTypeFactory(Mock.Of(), new PropertyValueConverterCollection(Array.Empty()), dataTypeService); From 6027318f7c6b40712ba7333c73efa0f191f8008e Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 24 Jun 2021 10:12:05 +0200 Subject: [PATCH 09/14] Remove ambiguous GetCropUrl method on UrlHelper --- src/Umbraco.Web/UrlHelperRenderExtensions.cs | 26 -------------------- 1 file changed, 26 deletions(-) diff --git a/src/Umbraco.Web/UrlHelperRenderExtensions.cs b/src/Umbraco.Web/UrlHelperRenderExtensions.cs index 592c88945bae..0f5b0557f4a1 100644 --- a/src/Umbraco.Web/UrlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/UrlHelperRenderExtensions.cs @@ -262,32 +262,6 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); } - public static IHtmlString GetCropUrl(this UrlHelper urlHelper, - ImageCropperValue imageCropperValue, - string cropAlias, - int? width = null, - int? height = null, - int? quality = null, - ImageCropMode? imageCropMode = null, - ImageCropAnchor? imageCropAnchor = null, - bool preferFocalPoint = false, - bool useCropDimensions = true, - string cacheBusterValue = null, - string furtherOptions = null, - ImageCropRatioMode? ratioMode = null, - bool upScale = true, - bool htmlEncode = true) - { - if (imageCropperValue == null) return EmptyHtmlString; - - var imageUrl = imageCropperValue.Src; - var url = imageUrl.GetCropUrl(imageCropperValue, width, height, cropAlias, quality, imageCropMode, - imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, - upScale); - return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); - } - - #endregion /// From c1088a37828ce82cf39e96fca4bd10c88dc24cf4 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 24 Jun 2021 10:12:53 +0200 Subject: [PATCH 10/14] Add new GetCropUrl overload on UrlHelper for use with local crops --- src/Umbraco.Web/UrlHelperRenderExtensions.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Umbraco.Web/UrlHelperRenderExtensions.cs b/src/Umbraco.Web/UrlHelperRenderExtensions.cs index 0f5b0557f4a1..e760adba79a2 100644 --- a/src/Umbraco.Web/UrlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/UrlHelperRenderExtensions.cs @@ -237,6 +237,14 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); } + public static IHtmlString GetCropUrl(this UrlHelper urlHelper, ImageCropperValue imageCropperValue, string cropAlias, bool htmlEncode = true) + { + if (imageCropperValue == null) return EmptyHtmlString; + + var url = imageCropperValue.Src.GetCropUrl(imageCropperValue, cropAlias: cropAlias, useCropDimensions: true); + return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); + } + public static IHtmlString GetCropUrl(this UrlHelper urlHelper, ImageCropperValue imageCropperValue, int? width = null, From 3d75e394120be758bc91d6e97dca624891c36742 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 24 Jun 2021 11:14:28 +0200 Subject: [PATCH 11/14] Add GetCropUrl overloads accepting MediaWithCrops on UrlHelper --- src/Umbraco.Web/UrlHelperRenderExtensions.cs | 77 +++++++++++++++----- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web/UrlHelperRenderExtensions.cs b/src/Umbraco.Web/UrlHelperRenderExtensions.cs index e760adba79a2..a6f495b4d7e9 100644 --- a/src/Umbraco.Web/UrlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/UrlHelperRenderExtensions.cs @@ -4,6 +4,7 @@ using System.Web; using System.Web.Mvc; using Umbraco.Core; +using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors.ValueConverters; using Umbraco.Web.Composing; @@ -17,9 +18,10 @@ namespace Umbraco.Web /// public static class UrlHelperRenderExtensions { - private static readonly IHtmlString EmptyHtmlString = new HtmlString(string.Empty); + private static IHtmlString CreateHtmlString(string value, bool htmlEncode) => htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(value)) : new HtmlString(value); + #region GetCropUrl /// @@ -42,7 +44,17 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, IPublishedContent if (mediaItem == null) return EmptyHtmlString; var url = mediaItem.GetCropUrl(cropAlias: cropAlias, useCropDimensions: true); - return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); + + return CreateHtmlString(url, htmlEncode); + } + + public static IHtmlString GetCropUrl(this UrlHelper urlHelper, MediaWithCrops mediaWithCrops, string cropAlias, bool htmlEncode = true) + { + if (mediaWithCrops == null) return EmptyHtmlString; + + var url = mediaWithCrops.GetCropUrl(cropAlias: cropAlias, useCropDimensions: true); + + return CreateHtmlString(url, htmlEncode); } /// @@ -70,7 +82,17 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, IPublishedContent if (mediaItem == null) return EmptyHtmlString; var url = mediaItem.GetCropUrl(propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true); - return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); + + return CreateHtmlString(url, htmlEncode); + } + + public static IHtmlString GetCropUrl(this UrlHelper urlHelper, MediaWithCrops mediaWithCrops, string propertyAlias, string cropAlias, bool htmlEncode = true) + { + if (mediaWithCrops == null) return EmptyHtmlString; + + var url = mediaWithCrops.GetCropUrl(propertyAlias: propertyAlias, cropAlias: cropAlias, useCropDimensions: true); + + return CreateHtmlString(url, htmlEncode); } /// @@ -150,10 +172,33 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, { if (mediaItem == null) return EmptyHtmlString; - var url = mediaItem.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode, - imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, - upScale); - return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); + var url = mediaItem.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); + + return CreateHtmlString(url, htmlEncode); + } + + public static IHtmlString GetCropUrl(this UrlHelper urlHelper, + MediaWithCrops mediaWithCrops, + int? width = null, + int? height = null, + string propertyAlias = Umbraco.Core.Constants.Conventions.Media.File, + string cropAlias = null, + int? quality = null, + ImageCropMode? imageCropMode = null, + ImageCropAnchor? imageCropAnchor = null, + bool preferFocalPoint = false, + bool useCropDimensions = false, + bool cacheBuster = true, + string furtherOptions = null, + ImageCropRatioMode? ratioMode = null, + bool upScale = true, + bool htmlEncode = true) + { + if (mediaWithCrops == null) return EmptyHtmlString; + + var url = mediaWithCrops.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); + + return CreateHtmlString(url, htmlEncode); } /// @@ -231,10 +276,9 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, bool upScale = true, bool htmlEncode = true) { - var url = imageUrl.GetCropUrl(width, height, imageCropperValue, cropAlias, quality, imageCropMode, - imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, - upScale); - return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); + var url = imageUrl.GetCropUrl(width, height, imageCropperValue, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale); + + return CreateHtmlString(url, htmlEncode); } public static IHtmlString GetCropUrl(this UrlHelper urlHelper, ImageCropperValue imageCropperValue, string cropAlias, bool htmlEncode = true) @@ -242,7 +286,8 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, ImageCropperValue if (imageCropperValue == null) return EmptyHtmlString; var url = imageCropperValue.Src.GetCropUrl(imageCropperValue, cropAlias: cropAlias, useCropDimensions: true); - return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); + + return CreateHtmlString(url, htmlEncode); } public static IHtmlString GetCropUrl(this UrlHelper urlHelper, @@ -263,11 +308,9 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, { if (imageCropperValue == null) return EmptyHtmlString; - var imageUrl = imageCropperValue.Src; - var url = imageUrl.GetCropUrl(imageCropperValue, width, height, cropAlias, quality, imageCropMode, - imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, - upScale); - return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url); + var url = imageCropperValue.Src.GetCropUrl(imageCropperValue, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale); + + return CreateHtmlString(url, htmlEncode); } #endregion From dd8b451394aa117a53c3e3d591c3d95d0a866fba Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 24 Jun 2021 16:11:54 +0200 Subject: [PATCH 12/14] Add MediaWithCrops to get generic type access to the media item --- src/Umbraco.Core/Models/MediaWithCrops.cs | 57 ++++++++++++++++++- .../BlockListPropertyValueConverter.cs | 1 + .../MediaPickerWithCropsValueConverter.cs | 6 +- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Models/MediaWithCrops.cs b/src/Umbraco.Core/Models/MediaWithCrops.cs index e947bbcfcc84..a8999869767c 100644 --- a/src/Umbraco.Core/Models/MediaWithCrops.cs +++ b/src/Umbraco.Core/Models/MediaWithCrops.cs @@ -4,18 +4,73 @@ namespace Umbraco.Core.Models { /// - /// Model used in Razor Views for rendering + /// Represents a media item with local crops. /// + /// public class MediaWithCrops : PublishedContentWrapped { + /// + /// Gets the media item. + /// + /// + /// The media item. + /// public IPublishedContent MediaItem => Unwrap(); + /// + /// Gets the local crops. + /// + /// + /// The local crops. + /// public ImageCropperValue LocalCrops { get; } + /// + /// Initializes a new instance of the class. + /// + /// The content. + /// The local crops. public MediaWithCrops(IPublishedContent content, ImageCropperValue localCrops) : base(content) { LocalCrops = localCrops; } } + + /// + /// Represents a media item with local crops. + /// + /// The type of the media item. + /// + public class MediaWithCrops : MediaWithCrops + where T : IPublishedContent + { + /// + /// Gets the media item. + /// + /// + /// The media item. + /// + public new T MediaItem { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The content. + /// The local crops. + public MediaWithCrops(T content, ImageCropperValue localCrops) + : base(content, localCrops) + { + MediaItem = content; + } + + /// + /// Performs an implicit conversion from to . + /// + /// The media with crops. + /// + /// The result of the conversion. + /// + public static implicit operator T(MediaWithCrops mediaWithCrops) => mediaWithCrops.MediaItem; + } } diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs index f46c11817433..5d216f2b4c7a 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/BlockListPropertyValueConverter.cs @@ -120,6 +120,7 @@ public override object ConvertIntermediateToObject(IPublishedElement owner, IPub settingsData = null; } + // TODO: This should be optimized/cached, as calling Activator.CreateInstance is slow var layoutType = typeof(BlockListItem<,>).MakeGenericType(contentData.GetType(), settingsData?.GetType() ?? typeof(IPublishedElement)); var layoutRef = (BlockListItem)Activator.CreateInstance(layoutType, contentGuidUdi, contentData, settingGuidUdi, settingsData); diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs index b05a23efdb2e..17907e854689 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerWithCropsValueConverter.cs @@ -67,7 +67,11 @@ public override object ConvertIntermediateToObject(IPublishedElement owner, IPub localCrops.ApplyConfiguration(configuration); - mediaItems.Add(new MediaWithCrops(mediaItem, localCrops)); + // TODO: This should be optimized/cached, as calling Activator.CreateInstance is slow + var mediaWithCropsType = typeof(MediaWithCrops<>).MakeGenericType(mediaItem.GetType()); + var mediaWithCrops = (MediaWithCrops)Activator.CreateInstance(mediaWithCropsType, mediaItem, localCrops); + + mediaItems.Add(mediaWithCrops); if (!isMultiple) { From 384646b6df4172ea667c859fa8cdb3ceb05b8c31 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 24 Jun 2021 16:21:03 +0200 Subject: [PATCH 13/14] Obsolete MediaItem and add Content property --- src/Umbraco.Core/Models/MediaWithCrops.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Core/Models/MediaWithCrops.cs b/src/Umbraco.Core/Models/MediaWithCrops.cs index a8999869767c..fefb4e6b806e 100644 --- a/src/Umbraco.Core/Models/MediaWithCrops.cs +++ b/src/Umbraco.Core/Models/MediaWithCrops.cs @@ -1,3 +1,4 @@ +using System; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors.ValueConverters; @@ -15,7 +16,16 @@ public class MediaWithCrops : PublishedContentWrapped /// /// The media item. /// - public IPublishedContent MediaItem => Unwrap(); + [Obsolete("This instance now implements IPublishedContent by wrapping the media item, use the extension methods directly on MediaWithCrops or use the Content property to get the media item instead.")] + public IPublishedContent MediaItem => Content; + + /// + /// Gets the content/media item. + /// + /// + /// The content/media item. + /// + public IPublishedContent Content => Unwrap(); /// /// Gets the local crops. @@ -51,7 +61,7 @@ public class MediaWithCrops : MediaWithCrops /// /// The media item. /// - public new T MediaItem { get; } + public new T Content { get; } /// /// Initializes a new instance of the class. @@ -61,7 +71,7 @@ public class MediaWithCrops : MediaWithCrops public MediaWithCrops(T content, ImageCropperValue localCrops) : base(content, localCrops) { - MediaItem = content; + Content = content; } /// @@ -71,6 +81,6 @@ public MediaWithCrops(T content, ImageCropperValue localCrops) /// /// The result of the conversion. /// - public static implicit operator T(MediaWithCrops mediaWithCrops) => mediaWithCrops.MediaItem; + public static implicit operator T(MediaWithCrops mediaWithCrops) => mediaWithCrops.Content; } } From 2980ff9c54fe7c4bdf4f0c19a5672f148c3cd5d2 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 25 Jun 2021 10:20:50 +0200 Subject: [PATCH 14/14] Add GetCropUrl overloads to better handle local crops only, improve null checks --- .../ImageCropperTemplateCoreExtensions.cs | 58 ++++++++++++------- .../ImageCropperTemplateExtensions.cs | 15 ++++- src/Umbraco.Web/UrlHelperRenderExtensions.cs | 4 +- 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs index 0c532d45834d..8773f1bb3990 100644 --- a/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs +++ b/src/Umbraco.Web/ImageCropperTemplateCoreExtensions.cs @@ -33,10 +33,25 @@ public static string GetCropUrl(this MediaWithCrops mediaWithCrops, string cropA return mediaWithCrops.GetCropUrl(imageUrlGenerator, cropAlias: cropAlias, useCropDimensions: true); } - [Obsolete("This method does not get the crops or cache buster value from the media item.")] + [Obsolete("Use the GetCropUrl overload with the updated parameter order and note this implementation has changed to get the URL from the media item.")] public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias, IImageUrlGenerator imageUrlGenerator, ImageCropperValue imageCropperValue) { - return mediaItem.Url().GetCropUrl(imageUrlGenerator, imageCropperValue, cropAlias: cropAlias, useCropDimensions: true); + return mediaItem.GetCropUrl(imageCropperValue, cropAlias, imageUrlGenerator); + } + + /// + /// Gets the crop URL by using only the specified . + /// + /// The media item. + /// The image cropper value. + /// The crop alias. + /// The image URL generator. + /// + /// The image crop URL. + /// + public static string GetCropUrl(this IPublishedContent mediaItem, ImageCropperValue imageCropperValue, string cropAlias, IImageUrlGenerator imageUrlGenerator) + { + return mediaItem.GetCropUrl(imageUrlGenerator, imageCropperValue, true, cropAlias: cropAlias, useCropDimensions: true); } /// @@ -134,7 +149,7 @@ public static string GetCropUrl( ImageCropRatioMode? ratioMode = null, bool upScale = true) { - return mediaItem.GetCropUrl(imageUrlGenerator, null, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); + return mediaItem.GetCropUrl(imageUrlGenerator, null, false, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); } public static string GetCropUrl( @@ -154,28 +169,31 @@ public static string GetCropUrl( ImageCropRatioMode? ratioMode = null, bool upScale = true) { - return mediaWithCrops.MediaItem.GetCropUrl(imageUrlGenerator, mediaWithCrops.LocalCrops, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); + if (mediaWithCrops == null) throw new ArgumentNullException(nameof(mediaWithCrops)); + + return mediaWithCrops.Content.GetCropUrl(imageUrlGenerator, mediaWithCrops.LocalCrops, false, width, height, propertyAlias, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode, upScale); } private static string GetCropUrl( this IPublishedContent mediaItem, IImageUrlGenerator imageUrlGenerator, ImageCropperValue localCrops, - int? width, - int? height, - string propertyAlias, - string cropAlias, - int? quality, - ImageCropMode? imageCropMode, - ImageCropAnchor? imageCropAnchor, - bool preferFocalPoint, - bool useCropDimensions, - bool cacheBuster, - string furtherOptions, - ImageCropRatioMode? ratioMode, - bool upScale) + bool localCropsOnly, + int? width = null, + int? height = null, + string propertyAlias = Constants.Conventions.Media.File, + string cropAlias = null, + int? quality = null, + ImageCropMode? imageCropMode = null, + ImageCropAnchor? imageCropAnchor = null, + bool preferFocalPoint = false, + bool useCropDimensions = false, + bool cacheBuster = true, + string furtherOptions = null, + ImageCropRatioMode? ratioMode = null, + bool upScale = true) { - if (mediaItem == null) throw new ArgumentNullException("mediaItem"); + if (mediaItem == null) throw new ArgumentNullException(nameof(mediaItem)); var cacheBusterValue = cacheBuster ? mediaItem.UpdateDate.ToFileTimeUtc().ToString(CultureInfo.InvariantCulture) : null; @@ -184,8 +202,8 @@ private static string GetCropUrl( var mediaItemUrl = mediaItem.MediaUrl(propertyAlias: propertyAlias); - // Only get crops when used - if (imageCropMode == ImageCropMode.Crop || imageCropMode == null) + // Only get crops from media when required and used + if (localCropsOnly == false && (imageCropMode == ImageCropMode.Crop || imageCropMode == null)) { // Get the default cropper value from the value converter var cropperValue = mediaItem.Value(propertyAlias); diff --git a/src/Umbraco.Web/ImageCropperTemplateExtensions.cs b/src/Umbraco.Web/ImageCropperTemplateExtensions.cs index 396cd63620f7..d9218a897410 100644 --- a/src/Umbraco.Web/ImageCropperTemplateExtensions.cs +++ b/src/Umbraco.Web/ImageCropperTemplateExtensions.cs @@ -32,8 +32,19 @@ public static class ImageCropperTemplateExtensions public static string GetCropUrl(this MediaWithCrops mediaWithCrops, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaWithCrops, cropAlias, Current.ImageUrlGenerator); - [Obsolete("This method does not get the crops or cache buster value from the media item.")] - public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias, ImageCropperValue imageCropperValue) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, cropAlias, Current.ImageUrlGenerator, imageCropperValue); + [Obsolete("Use the GetCropUrl overload with the updated parameter order and note this implementation has changed to get the URL from the media item.")] + public static string GetCropUrl(this IPublishedContent mediaItem, string cropAlias, ImageCropperValue imageCropperValue) => mediaItem.GetCropUrl(imageCropperValue, cropAlias); + + /// + /// Gets the crop URL by using only the specified . + /// + /// The media item. + /// The image cropper value. + /// The crop alias. + /// + /// The image crop URL. + /// + public static string GetCropUrl(this IPublishedContent mediaItem, ImageCropperValue imageCropperValue, string cropAlias) => ImageCropperTemplateCoreExtensions.GetCropUrl(mediaItem, imageCropperValue, cropAlias, Current.ImageUrlGenerator); /// /// Gets the ImageProcessor URL by the crop alias using the specified property containing the image cropper Json data on the IPublishedContent item. diff --git a/src/Umbraco.Web/UrlHelperRenderExtensions.cs b/src/Umbraco.Web/UrlHelperRenderExtensions.cs index a6f495b4d7e9..2c547c841e0e 100644 --- a/src/Umbraco.Web/UrlHelperRenderExtensions.cs +++ b/src/Umbraco.Web/UrlHelperRenderExtensions.cs @@ -283,7 +283,7 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, public static IHtmlString GetCropUrl(this UrlHelper urlHelper, ImageCropperValue imageCropperValue, string cropAlias, bool htmlEncode = true) { - if (imageCropperValue == null) return EmptyHtmlString; + if (imageCropperValue == null || string.IsNullOrEmpty(imageCropperValue.Src)) return EmptyHtmlString; var url = imageCropperValue.Src.GetCropUrl(imageCropperValue, cropAlias: cropAlias, useCropDimensions: true); @@ -306,7 +306,7 @@ public static IHtmlString GetCropUrl(this UrlHelper urlHelper, bool upScale = true, bool htmlEncode = true) { - if (imageCropperValue == null) return EmptyHtmlString; + if (imageCropperValue == null || string.IsNullOrEmpty(imageCropperValue.Src)) return EmptyHtmlString; var url = imageCropperValue.Src.GetCropUrl(imageCropperValue, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale);